diff --git a/epiphany-core/Cargo.toml b/epiphany-core/Cargo.toml index 1df3917b..8f86daa1 100644 --- a/epiphany-core/Cargo.toml +++ b/epiphany-core/Cargo.toml @@ -13,8 +13,9 @@ path = "src/lib.rs" anyhow = "1" bm25 = "2.3.2" chrono = "0.4.44" -cultcache-rs = { path = "../vendor/cultcache-rs" } -cultnet-rs = { path = "../vendor/cultnet-rs" } +cultcache-rs = { path = "../../CultLib/crates/cultcache-rs" } +cultmesh-rs = { path = "../../CultLib/crates/cultmesh-rs" } +cultnet-rs = { path = "../../CultLib/crates/cultnet-rs" } epiphany-openai-adapter = { path = "../epiphany-openai-adapter" } epiphany-state-model = { path = "../epiphany-state-model" } ignore = "0.4.23" diff --git a/epiphany-core/src/bin/epiphany-cultmesh-smoke.rs b/epiphany-core/src/bin/epiphany-cultmesh-smoke.rs new file mode 100644 index 00000000..3dcd06be --- /dev/null +++ b/epiphany-core/src/bin/epiphany-cultmesh-smoke.rs @@ -0,0 +1,34 @@ +use anyhow::Result; +use epiphany_core::EPIPHANY_CULTMESH_LOCAL_VERSE_ID; +use epiphany_core::EPIPHANY_CULTMESH_STATUS_SCHEMA_VERSION; +use epiphany_core::EpiphanyCultMeshStatusEntry; +use epiphany_core::load_epiphany_cultmesh_status; +use epiphany_core::write_epiphany_cultmesh_status; +use std::path::PathBuf; + +fn main() -> Result<()> { + let mut store = PathBuf::from(".epiphany-smoke"); + store.push("cultmesh"); + std::fs::create_dir_all(&store)?; + store.push("epiphany-local.ccmp"); + + let status = EpiphanyCultMeshStatusEntry { + schema_version: EPIPHANY_CULTMESH_STATUS_SCHEMA_VERSION.to_string(), + runtime_id: "epiphany-cultmesh-smoke".to_string(), + verse_id: EPIPHANY_CULTMESH_LOCAL_VERSE_ID.to_string(), + app_id: "epiphany".to_string(), + note: "Epiphany wrote this through CultMesh, not direct CultNet plumbing.".to_string(), + }; + + write_epiphany_cultmesh_status(&store, status.clone())?; + let loaded = load_epiphany_cultmesh_status(&store, "epiphany-cultmesh-smoke")?; + if loaded != Some(status) { + anyhow::bail!("CultMesh smoke failed to round-trip Epiphany status document"); + } + + println!( + "epiphany cultmesh smoke ok: {}", + store.canonicalize()?.display() + ); + Ok(()) +} diff --git a/epiphany-core/src/cultmesh_integration.rs b/epiphany-core/src/cultmesh_integration.rs new file mode 100644 index 00000000..aed0741c --- /dev/null +++ b/epiphany-core/src/cultmesh_integration.rs @@ -0,0 +1,92 @@ +use anyhow::Result; +use cultcache_rs::DatabaseEntry; +use cultmesh_rs::CultMesh; +use cultmesh_rs::CultMeshNode; +use cultmesh_rs::CultMeshNodeOptions; +use cultmesh_rs::cultmesh_documents; +use std::path::Path; + +pub const EPIPHANY_CULTMESH_STATUS_TYPE: &str = "epiphany.cultmesh.status"; +pub const EPIPHANY_CULTMESH_STATUS_SCHEMA_VERSION: &str = "epiphany.cultmesh.status.v0"; +pub const EPIPHANY_CULTMESH_STATUS_KEY: &str = "epiphany-local/status"; +pub const EPIPHANY_CULTMESH_LOCAL_VERSE_ID: &str = "epiphany-local"; + +#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)] +#[cultcache( + type = "epiphany.cultmesh.status", + schema = "EpiphanyCultMeshStatusEntry" +)] +pub struct EpiphanyCultMeshStatusEntry { + #[cultcache(key = 0)] + pub schema_version: String, + #[cultcache(key = 1)] + pub runtime_id: String, + #[cultcache(key = 2)] + pub verse_id: String, + #[cultcache(key = 3)] + pub app_id: String, + #[cultcache(key = 4)] + pub note: String, +} + +cultmesh_documents!(EpiphanyCultMeshDocuments { + EpiphanyCultMeshStatusEntry => EPIPHANY_CULTMESH_STATUS_SCHEMA_VERSION, +}); + +pub fn open_epiphany_cultmesh_node( + store_path: impl AsRef, + runtime_id: impl Into, +) -> Result { + CultMesh::create_node( + store_path, + EpiphanyCultMeshDocuments, + CultMeshNodeOptions { + runtime_id: runtime_id.into(), + ..CultMeshNodeOptions::default() + }, + ) +} + +pub fn write_epiphany_cultmesh_status( + store_path: impl AsRef, + status: EpiphanyCultMeshStatusEntry, +) -> Result { + let mut node = open_epiphany_cultmesh_node(&store_path, status.runtime_id.clone())?; + let written = node.put(EPIPHANY_CULTMESH_STATUS_KEY, &status)?; + node.flush()?; + Ok(written) +} + +pub fn load_epiphany_cultmesh_status( + store_path: impl AsRef, + runtime_id: impl Into, +) -> Result> { + let node = open_epiphany_cultmesh_node(store_path, runtime_id)?; + node.get(EPIPHANY_CULTMESH_STATUS_KEY) +} + +#[cfg(test)] +mod tests { + use super::*; + use pretty_assertions::assert_eq; + + #[test] + fn epiphany_status_round_trips_through_cultmesh() -> Result<()> { + let temp = tempfile::tempdir()?; + let store = temp.path().join("epiphany-local.ccmp"); + let status = EpiphanyCultMeshStatusEntry { + schema_version: EPIPHANY_CULTMESH_STATUS_SCHEMA_VERSION.to_string(), + runtime_id: "epiphany-test".to_string(), + verse_id: EPIPHANY_CULTMESH_LOCAL_VERSE_ID.to_string(), + app_id: "epiphany".to_string(), + note: "CultMesh is the local abstraction over CultCache and CultNet.".to_string(), + }; + + write_epiphany_cultmesh_status(&store, status.clone())?; + assert_eq!( + load_epiphany_cultmesh_status(&store, "epiphany-test")?, + Some(status) + ); + Ok(()) + } +} diff --git a/epiphany-core/src/lib.rs b/epiphany-core/src/lib.rs index fb9766ca..04967440 100644 --- a/epiphany-core/src/lib.rs +++ b/epiphany-core/src/lib.rs @@ -1,5 +1,6 @@ mod agent_memory; mod agent_utterance_state; +mod cultmesh_integration; mod distillation; mod heartbeat_state; mod memory_graph; @@ -56,6 +57,15 @@ pub use cultcache_rs::CultCacheEnvelope; pub use cultcache_rs::DatabaseEntry; pub use cultcache_rs::PushAllOptions; pub use cultcache_rs::SingleFileMessagePackBackingStore; +pub use cultmesh_integration::EPIPHANY_CULTMESH_LOCAL_VERSE_ID; +pub use cultmesh_integration::EPIPHANY_CULTMESH_STATUS_KEY; +pub use cultmesh_integration::EPIPHANY_CULTMESH_STATUS_SCHEMA_VERSION; +pub use cultmesh_integration::EPIPHANY_CULTMESH_STATUS_TYPE; +pub use cultmesh_integration::EpiphanyCultMeshDocuments; +pub use cultmesh_integration::EpiphanyCultMeshStatusEntry; +pub use cultmesh_integration::load_epiphany_cultmesh_status; +pub use cultmesh_integration::open_epiphany_cultmesh_node; +pub use cultmesh_integration::write_epiphany_cultmesh_status; pub use distillation::EpiphanyDistillInput; pub use distillation::EpiphanyDistillProposal; pub use distillation::distill_observation; diff --git a/epiphany-openai-adapter/Cargo.toml b/epiphany-openai-adapter/Cargo.toml index afc39f0d..3e5b667d 100644 --- a/epiphany-openai-adapter/Cargo.toml +++ b/epiphany-openai-adapter/Cargo.toml @@ -10,5 +10,5 @@ name = "epiphany_openai_adapter" path = "src/lib.rs" [dependencies] -cultcache-rs = { path = "../vendor/cultcache-rs" } +cultcache-rs = { path = "../../CultLib/crates/cultcache-rs" } serde = { version = "1", features = ["derive"] } diff --git a/notes/epiphany-fork-implementation-plan.md b/notes/epiphany-fork-implementation-plan.md index f7edfc8e..413bcc37 100644 --- a/notes/epiphany-fork-implementation-plan.md +++ b/notes/epiphany-fork-implementation-plan.md @@ -85,6 +85,7 @@ The landed machine now has: - old Python dogfood runner cut; replacement must be native Rust/CultCache/CultNet over heartbeat/runtime-spine receipts - first auditable Phase 6 fixed-lane coordinator runner through native `epiphany-mvp-coordinator`, producing coordinator summary, JSONL steps, rendered snapshots, transcript, stderr, runtime-spine status, native runtime job/result receipts for launched work, and final next-action artifacts while keeping semantic findings review-gated by default - first Codex-independent native runtime vertebra through `epiphany-runtime-spine`, storing runtime identity, sessions, jobs, job results, and events as typed CultCache MessagePack documents, opening/completing native jobs, projecting job-result counts, and emitting a framed CultNet hello message for the native contract +- first Rust CultMesh local-node integration: `CultLib` now owns `crates/cultmesh-rs`, and `epiphany-core` depends on that CultMesh surface for a local `EpiphanyCultMeshStatusEntry` round-trip smoke instead of treating raw CultNet as the ergonomic app-facing database layer - live-specialist runner must be rebuilt around heartbeat/runtime-spine result receipts - first Phase 6 Aquarium operator shell extracted to sibling repo `E:\Projects\EpiphanyAquarium`, a Tauri v2 + React/WebGL client over the existing status bridge, dogfood artifacts, and GUI action artifacts, with its own distilled interface state/memory/doctrine plus durable checkpoint preparation, bounded status/coordinator artifact buttons, fixed modeling/verification/reorient launch and read-back buttons, and explicit review-gated reorient acceptance - first Unity editor/runtime bridge through native `epiphany-unity-bridge`, native `epiphany-unity-bridge-smoke`, and the GUI Inspect Unity action, resolving exact project-pinned editors and writing runtime artifacts while refusing wrong or missing versions @@ -115,6 +116,7 @@ These boundaries are more important than the individual method names: - CultCache documents are the data model. CultNet is the wire for Epiphany-controlled subsystems. +- CultMesh is the preferred ergonomic runtime/database surface over local CultCache plus CultNet contracts. Epiphany should start local Verse, dream, status, and operator-store work through CultMesh unless the task is explicitly implementing a lower-level CultMesh/CultNet/CultCache primitive. - JSON is allowed only for schema description, hostile/external ingress before immediate typed parsing, sealed forensic artifacts, or named quarantine experiments with an expiration path. Generic `serde_json::Value` must not be diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index cd964034..9d148277 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -35,7 +35,8 @@ remembers doctrine; the branch remembers the blade. - Do not copy exact branch or HEAD from this note. Run `git status --short --branch` and `git log --oneline -5`. - The repo now has a one-command local operator path: `.\tools\epiphany_local_run.ps1`. Default mode is `smoke`; it builds the retained Codex app-server compatibility edge, builds native Epiphany operator binaries, runs the coordinator smoke, and writes launcher artifacts under `.epiphany-run/` plus coordinator artifacts under `.epiphany-dogfood/`. Use `-Mode status`, `-Mode plan`, or `-Mode run -MaxSteps 4` for the other current entrypoints; add `-ThreadId ` and `-Workspace ` to inspect or continue an existing thread. `status`, `plan`, and `smoke` do not spend model calls; `run` builds and uses `epiphany-openai-runtime`. - The active foundation directive is now `notes/codex-starvation-and-cultnet-liberation-plan.md`. The previous Codex app-server control-plane rebuild made Epiphany less rotten inside Codex, but that is not the destination. Epiphany must become a native CultCache/CultNet runtime while remaining an honest modified Codex-derived backend for subscription auth/model use. Codex is a compatibility reliquary for OpenAI subscription auth and model transport, not the host brain and not a mask for impersonation. -- `notes/epiphany-cultmesh-dreaming-roadmap.md` is the new concrete design for distributed Epiphany dreaming. The invariant is hard: private state stays local; public dreams are separately authored typed documents distributed through CultMesh/CultNet; foreign dreams are thought weather until a reviewed local adoption receipt digests them. The first code slice should be dream schemas plus a local CultCache-backed dream store, not public fanout. +- `notes/epiphany-cultmesh-dreaming-roadmap.md` is the new concrete design for distributed Epiphany dreaming. The invariant is hard: private state stays local; public dreams are separately authored typed documents distributed through CultMesh/CultNet; foreign dreams are thought weather until a reviewed local adoption receipt digests them. The first code slice should be dream schemas plus a local CultMesh-backed store, not public fanout. +- CultMesh is now the preferred Rust abstraction for that local store work. The Rust port lives in `E:\Projects\CultLib\crates\cultmesh-rs`, and Epiphany now depends on it directly from `epiphany-core`. The first integration is deliberately small: `EpiphanyCultMeshStatusEntry` round-trips through `.epiphany-smoke/cultmesh/epiphany-local.ccmp` using `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-cultmesh-smoke`. Future local dream/status/Verse work should start from CultMesh, not raw CultNet, unless the task is polishing the CultMesh internals themselves. - `notes/codex-auth-spine-inventory.md` is the source-grounded keeper list for that reliquary. Corrected compliance invariant: Codex-compatible auth identity stays anchored in vendored Codex-derived auth machinery. `epiphany-openai-auth-spine` is now a thin Epiphany-named boundary over `codex-login`, not a clean-room clone of credential storage or token refresh. Codex apps, skills, marketplace, plugin UX, broad app-server workflow, and JSON-RPC sprawl remain cuttable because they are not subscription-auth legitimacy. - Edge JSON is allowed for schema description, hostile ingress before immediate typed parsing, sealed forensic artifacts, or named quarantine experiments. When both subsystems are ours, runtime data must remain typed CultCache documents and move over CultNet typed contracts. Generic `serde_json::Value` in worker launch/result/selfPatch/runtime flow is contamination until classified and replaced. - `notes/epiphany-swarm-readiness-plan.md` is the current live-fire direction gate. The local runner proves startup/status/coordinator wiring; it does not authorize unattended swarm operation. Carry VoidBot's lessons forward: one CTB-style initiative scheduler, typed pause/brake, active-turn freeze, cooldown after completion, stale active-turn recovery receipts, parent-side speech eligibility, memory lifecycle phases, and typed operation proposals instead of prompt-owned governance. @@ -1381,6 +1382,7 @@ actions without requiring the human to hand over a complete architecture brief. - broader editor/runtime bridges beyond the first pinned Unity bridge - broad event stream beyond the landed state update notification - typed repetitive-work queues plus final-answer gates, so batch/tile/import/migration work cannot end merely because the pattern was demonstrated or the partial result sounds tidy +- public CultMesh Verse deployment or cross-app live sharing; only the local Rust CultMesh node/status smoke exists so far The machine is no longer cleared to move outward. Free it from the Codex organ first. diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index a7c48030..9eab0f21 100644 Binary files a/state/ledgers.msgpack and b/state/ledgers.msgpack differ diff --git a/state/map.yaml b/state/map.yaml index 833031b9..d9c7d107 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -68,6 +68,7 @@ data_flow: active_subgoals: - Use `notes/epiphany-cultmesh-dreaming-roadmap.md` as the design authority for distributed Epiphany dreaming. Public dreams are separately authored typed documents distributed through CultMesh/CultNet; private state remains local and cannot be shared by flipping a visibility flag. Foreign dreams are external thought weather until a reviewed local adoption receipt digests them into memory, planning, doctrine, or governance. + - CultMesh is now the preferred ergonomic Rust abstraction over CultCache and CultNet for Epiphany-owned local database surfaces. The first Rust `cultmesh-rs` crate lives in `E:\Projects\CultLib\crates\cultmesh-rs`; Epiphany depends on it directly for the local `epiphany-local` status smoke. Future local Verse/dream/status work should start at CultMesh unless it is explicitly polishing CultMesh internals. - The active priority is Codex starvation and CultNet liberation. Use `notes/codex-starvation-and-cultnet-liberation-plan.md` as the directive and `notes/codex-auth-spine-inventory.md` as the source-grounded keeper list for the vestigial OpenAI subscription auth/model transport organ. Classify all Epiphany-relevant JSON contamination, define the native CultNet runtime boundary, keep worker launch/result/selfPatch cargo as typed documents, evacuate operator surfaces from Codex JSON-RPC, wrap MCP's unavoidable JSON protocol edge in typed Epiphany intent/result/receipt documents, and keep cutting until Epiphany can run without `codex_message_processor.rs` except for legacy compatibility. - The May 2026 teardown/rebuild migration in `notes/epiphany-ideal-architecture-rebuild-plan.md` is closed unless a concrete regression reopens it. Preserve the new foundation: Epiphany view/coordinator policy lives in `epiphany-core`, runtime-spine owns job/result lifecycle identity through `runtime_links`, duplicate acceptance is receipt-keyed, public findings stay typed/sealed, view expansion requires a core contract, and app-server remains routing/adaptation rather than a second policy throne. - Treat Phase 5 update/distill/propose/promote/read/notification as complete enough unless a concrete regression appears. @@ -96,6 +97,7 @@ active_subgoals: accepted_design: - Distributed Epiphany dreaming is a CultMesh typed-document problem, not prompt folklore. CultCache owns local typed documents, Epiphany owns export/import/adoption policy, CultNet owns wire/provenance/shard delivery, and CultMesh owns Verses, peer exchange, leases, shard logs, replicas, and watchable runtime surfaces. Start with local dream document types and a local store before public Verse wiring. + - The first Rust CultMesh integration slice is landed. `CultLib` now has `cultmesh-rs`, a small Rust node/database surface over CultCache and CultNet with document-set registration and durable typed put/get/delete. `epiphany-core` now points at CultLib's Rust CultCache/CultNet crates, depends on `cultmesh-rs`, and exposes an `EpiphanyCultMeshStatusEntry` that round-trips through a local `epiphany-local.ccmp` CultMesh node. - `notes/codex-starvation-and-cultnet-liberation-plan.md` is the active foundation directive. It supersedes outward product/bridge/dogfood work and supersedes the weaker goal of merely making Codex app-server a cleaner adapter. Epiphany must become a native CultCache/CultNet runtime; Codex remains only as an OpenAI subscription auth/model-transport reliquary until that too can be replaced or minimized. - `notes/codex-auth-spine-inventory.md` is the current source-grounded inventory of the Codex organ that may survive. Corrected compliance invariant: Codex-compatible auth identity should remain anchored in retained vendored Codex-derived auth machinery, while Epiphany owns typed request/status/event/runtime surfaces around it. Codex app-server, apps, skills, marketplace, plugin UX, MCP OAuth handlers, and collaboration-mode surfaces are not part of the keeper spine. - `epiphany-openai-runtime` worker result ingress now parses assistant output directly into launch-kind-specific typed documents and stores typed nested `statePatch` / `selfPatch` payloads as MessagePack inside `EpiphanyRuntimeRoleWorkerResult`; generic `serde_json::Value` no longer mediates role/reorient worker results in that crate. JSON still exists at the OpenAI text edge because the model's output is text, but the runtime boundary after parsing is typed. @@ -460,4 +462,4 @@ current_status: `.epiphany-run/` plus coordinator evidence under `.epiphany-dogfood/`. This is scaffolding over the current compatibility shell, not a new policy owner. - next_action: Continue Codex starvation and CultNet liberation while preserving the working local run path. The next cut should make the same operator loop less dependent on Codex app-server JSON-RPC, not add another convenience throne beside it. + next_action: Continue Codex starvation and CultNet liberation through CultMesh-first local surfaces. The next cut should replace another local operator/status/dream path with a typed CultMesh node document before public Verse fanout or app-wide deployment claims.