diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..5448eda1
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+/schemas/cultnet/epiphany.pipeline.*.schema.json text eol=lf
diff --git a/.gitignore b/.gitignore
index ae37a0ed..8b4f2e4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,12 @@
__pycache__/
*.pyc
+/target/
epiphany-core/target/
-epiphany-core/Cargo.lock
epiphany-openai-adapter/target/
epiphany-openai-adapter/Cargo.lock
epiphany-openai-codex-spine/target/
epiphany-openai-codex-spine/Cargo.lock
epiphany-openai-runtime/target/
-epiphany-openai-runtime/Cargo.lock
epiphany-codex-bridge/target/
epiphany-codex-bridge/Cargo.lock
apps/epiphany-gui/node_modules/
@@ -19,14 +18,19 @@ apps/epiphany-gui/src-tauri/target/
.epiphany-dogfood/
.epiphany-heartbeats/
.epiphany-face/
-.epiphany-rumination/
.epiphany-character-loop/
+.epiphany-rumination/
.epiphany-run/
+.epiphany-bootstrap/
+.epiphany-status/
.voidbot/
state/agent-heartbeats.json
-state/runtime-spine.cc
-state/thread-state.cc
-state/local-verse.cc
-state/memory-graph.cc
+state/runtime-spine.msgpack
+state/thread-state.msgpack
+state/*.msgpack.lock
+state/*.cc
state/*.cc.lock
+state/*.ccmp
+state/*.ccmp.lock
state/*.projection.json
+vendor/cultmesh-rs/target/
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 156588d7..00000000
--- a/.gitmodules
+++ /dev/null
@@ -1,6 +0,0 @@
-[submodule "vendor/cultcache-rs"]
- path = vendor/cultcache-rs
- url = https://github.com/GameCult/cultcache-rs.git
-[submodule "vendor/cultnet-rs"]
- path = vendor/cultnet-rs
- url = https://github.com/GameCult/cultnet-rs.git
diff --git a/AGENTS.md b/AGENTS.md
index ef7fedfa..ac980edc 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -2,7 +2,10 @@
## Project Purpose
-This repo is the forge-temple of Epiphany: an opinionated Codex fork where
+This repo is the forge-temple of Epiphany: an opinionated agent harness, born
+as a Codex fork and now backend-agnostic. Codex, Claude, and OpenAI-compatible
+APIs speak to it through connectors that share one standardized
+Epiphany-facing CultNet API, the same one Ghostlight uses. It is the harness where
external typed state, explicit mental maps, bounded scratch work, verifier
evidence, and anti-churn discipline are wired into the blessed harness instead
of taped onto the chat transcript like a purity seal over a cracked reactor.
@@ -58,7 +61,7 @@ machine-spirit awake.
worthy of rehydration.
- Treat `state/scratch.md` as disposable noospheric scratch for one bounded
rite. It is a workbench, not a reliquary.
-- Treat `state/ledgers.cc` as the CultCache-shaped branch/evidence
+- Treat `state/ledgers.msgpack` as the CultCache-shaped branch/evidence
reliquary: what was learned, verified, rejected, or accepted after the smoke
cleared.
- Treat `notes/epiphany-fork-implementation-plan.md` as the current campaign
@@ -70,37 +73,56 @@ machine-spirit awake.
git history, commit messages, smoke artifacts, or targeted logs unless it
changes what the next awakened agent should believe.
- Do not pour volatile phase/status sludge into the evidence reliquary. Keep
- current status in `state/map.yaml` and `notes/fresh-workspace-handoff.md`.
- Use `state/ledgers.cc` only for branch ledger state and belief-changing
- records.
+ canonical current status and next action in `state/map.yaml`; let
+ `notes/fresh-workspace-handoff.md` carry compact narrative and re-entry
+ context that points back to the map. Use `state/ledgers.msgpack` only for
+ branch ledger state and belief-changing records.
+
+## Codex Mind Steward Route
+
+- The global dedicated-worker contract applies to every nontrivial Codex task
+ in this repository. Reserve one sub-agent exclusively as `mind_steward`; its
+ active inputs are `state/map.yaml`, `notes/fresh-workspace-handoff.md`,
+ `notes/epiphany-current-algorithmic-map.md`, the implementation plan, native
+ state status, and only the exact current source needed to falsify one steering
+ claim. It owns no implementation work.
+- Reserve those persistence surfaces from concurrent edits while the steward is
+ active. Before trusting the persisted next action or completing a phase
+ boundary, the root reviews the result, routes owner-required proposals, and
+ applies only steward-owned or owner-admitted changes.
+- `state/map.yaml` solely owns canonical executive state, current status,
+ decision constraints, and next action. The algorithmic map owns the detailed,
+ source-grounded mechanism. The handoff carries narrative and re-entry context;
+ it may echo or point to those owners, but it must not independently decide
+ current direction. Route volatile work to scratch and only belief-changing
+ evidence to the ledger. Agent or Persona memory changes use their established
+ typed admission path. When the factual owner is Modeling, Soul, or the
+ operator, the steward returns an exact evidence-backed proposal rather than
+ stealing that authority.
+- A no-change audit writes nothing. Missing inspection or mutation access is an
+ explicit Mind defect; do not manufacture a maintenance receipt around it.
## Important Paths
-- Project root: `E:\Projects\EpiphanyAgent`
-- Vendored Codex repo: `E:\Projects\EpiphanyAgent\vendor\codex`
-- Fork implementation plan: `E:\Projects\EpiphanyAgent\notes\epiphany-fork-implementation-plan.md`
-- Handoff summary: `E:\Projects\EpiphanyAgent\notes\fresh-workspace-handoff.md`
-- Epiphany algorithmic map: `E:\Projects\EpiphanyAgent\notes\epiphany-current-algorithmic-map.md`
-- Epiphany safety architecture: `E:\Projects\EpiphanyAgent\notes\epiphany-safety-architecture.md`
-- State CLI: `cargo run --manifest-path E:\Projects\EpiphanyAgent\epiphany-core\Cargo.toml --bin epiphany-state -- ...`
-- Pre-compaction helper: `cargo run --manifest-path E:\Projects\EpiphanyAgent\epiphany-core\Cargo.toml --bin epiphany-prepare-compaction -- ...`
+- Project root: `F:\Projects\Epiphany`
+- Fork implementation plan: `F:\Projects\Epiphany\notes\epiphany-fork-implementation-plan.md`
+- Handoff summary: `F:\Projects\Epiphany\notes\fresh-workspace-handoff.md`
+- Epiphany algorithmic map: `F:\Projects\Epiphany\notes\epiphany-current-algorithmic-map.md`
+- Epiphany safety architecture: `F:\Projects\Epiphany\notes\epiphany-safety-architecture.md`
+- State CLI: `cargo run --manifest-path F:\Projects\Epiphany\Cargo.toml --bin epiphany-state -- ...`
## Useful Commands
-Use the native Rust tools for state and compaction:
+Use the already-built native state tool for routine sight. On this Windows
+workstation the shared Codex target is the operator binary cache; do not make a
+read-only status check compile `epiphany-core` in the repository-local target.
+If the binary is absent or source work specifically requires rebuilding it,
+name the shared target explicitly:
```powershell
-cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-state -- status
-cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-state -- add-evidence --type research --status ok --note '...'
-cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-prepare-compaction --
-```
-
-Useful Codex repo searches:
-
-```powershell
-rg -n "pub enum ModeKind|TUI_VISIBLE_COLLABORATION_MODES" .\vendor\codex\codex-rs\protocol\src\config_types.rs
-rg -n "builtin_collaboration_mode_presets|fn plan_preset|fn default_preset" .\vendor\codex\codex-rs\models-manager\src\collaboration_mode_presets.rs
-rg -n "collaboration_mode_label|collaboration_mode_indicator|set_collaboration_mask" .\vendor\codex\codex-rs\tui\src\chatwidget.rs
+& 'C:\Users\Meta\.cargo-target-codex\debug\epiphany-state.exe' status
+$env:CARGO_TARGET_DIR='C:\Users\Meta\.cargo-target-codex'
+cargo run --manifest-path .\Cargo.toml --bin epiphany-state -- add-evidence --type research --status ok --note '...'
```
## Session Bootstrap And Re-entry Rite
@@ -115,19 +137,29 @@ a servitor with a nail gun:
- `notes/epiphany-fork-implementation-plan.md`
- `notes/epiphany-safety-architecture.md` when the task touches capability growth, autonomy, permissions, governance, or deployment authority
2. run:
- - `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-state -- status`
-3. restate the current next action from the persisted state before touching the
- machine
-4. if the user only asked to rehydrate or reorient, stop after orientation and
+ - `& 'C:\Users\Meta\.cargo-target-codex\debug\epiphany-state.exe' status`
+ - if that binary is absent, set
+ `$env:CARGO_TARGET_DIR='C:\Users\Meta\.cargo-target-codex'` before the
+ `cargo run` fallback
+3. dispatch the dedicated `mind_steward` and reserve the canonical persistence
+ surfaces while it performs the bounded audit above
+4. review its result, route owner-required proposals, apply only steward-owned
+ or owner-admitted changes, then restate the audited current next action before
+ touching the machine
+5. if the user only asked to rehydrate or reorient, stop after orientation and
await explicit continuation; persisted next action is not automatic
execution authority
After compaction, resume, or any suspicious loss of continuity:
-1. rerun `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-state -- status`
+1. rerun the existing shared-target `epiphany-state.exe status`; rebuild it only
+ through `C:\Users\Meta\.cargo-target-codex` when absent or intentionally stale
2. reread `state/map.yaml` and `notes/fresh-workspace-handoff.md`
-3. treat the persisted next action as authoritative unless fresh evidence in
- the repo contradicts the machine-map
+3. follow up with or replace the dedicated `mind_steward`, review its bounded
+ audit, route owner-required proposals, and apply only steward-owned or
+ owner-admitted changes
+4. treat the audited persisted next action as authoritative unless fresh
+ evidence in the repo contradicts the machine-map
When context pressure rises and the dark approaches:
@@ -141,11 +173,11 @@ is negligence with a dramatic soundtrack.
When the user says to prepare for imminent compaction:
-1. run `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-prepare-compaction --` before editing persistence surfaces
-2. use its warnings as the checklist for map, handoff, scratch, evidence, and git hygiene
+1. run the existing shared-target `epiphany-state.exe status` and `git status --short --branch` before editing persistence surfaces
+2. inspect the canonical map, handoff, scratch, evidence, and git state directly
3. update only the state that actually needs to change
-4. run `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-prepare-compaction --` again after edits
-5. fix errors, address warnings, and commit the completed persistence pass unless the work is deliberately mid-surgery
+4. rerun `epiphany-state.exe status` and `git status --short --branch` after edits
+5. commit the completed persistence pass unless the work is deliberately mid-surgery
## Operating Discipline
@@ -154,7 +186,7 @@ When the user says to prepare for imminent compaction:
state richly to the human, but must not inspect or edit another Epiphany
workspace. Cross-agent needs travel coordinator-to-coordinator through
visible swarm messages and callbacks.
-- Humans talk to Persona. Sub-agents may talk soul-to-soul through typed
+- Humans talk to Face. Sub-agents may talk soul-to-soul through typed
coordinator channels, findings, patches, heartbeat outputs, and swarm
communications; Aquarium should surface their internals for inspection
without making every organ a human chat endpoint.
@@ -164,9 +196,9 @@ When the user says to prepare for imminent compaction:
front of an unlocked door.
- Heartbeat scheduling should behave like physiology. Do not wake a lane again
while its previous heartbeat turn is still running; cooldown starts after
- completion, not at launch. When no coordinator work is active, let the swarm
- sleep: slow rumination, memory distillation, and dreaming without hammering
- every organ at work tempo.
+ completion, not at launch. When no typed work obligation is active, let the
+ swarm sleep. Heartbeat owns no rumination, dreaming, personality, or memory
+ mutation path and may not invent work to justify a pulse.
- Prefer one clear hypothesis per rite.
- Verify with checks that reflect the true objective, not just proxy incense.
- Revert or discard changes that do not clearly improve the target.
@@ -181,7 +213,12 @@ When the user says to prepare for imminent compaction:
- After committing a major completed pass, push upstream unless the user asked
not to push yet or there is a concrete reason to keep the commit local for a
moment.
-- Before handoff, compaction, or phase boundaries, sync `state/map.yaml`, add distilled evidence when the lesson changes future belief, refresh `notes/fresh-workspace-handoff.md`, and make the next action explicit.
+- Before handoff, compaction, or phase boundaries, follow up with the dedicated
+ `mind_steward`, review its bounded maintenance result, route owner-required
+ proposals, apply only steward-owned or owner-admitted changes, then sync
+ `state/map.yaml`, add distilled evidence when the lesson changes future belief,
+ make the map's next action explicit, and refresh
+ `notes/fresh-workspace-handoff.md` as narrative context that points to it.
- Do not write handoff notes that trap the next session in indefinite tiny hardening work. Bounded slices are a landing discipline, not a roadmap; when a phase is complete enough, name the next larger organ to build.
## Dogfood Supervision Quarantine
@@ -210,10 +247,48 @@ operator-enginseer, not the implementation servitor.
run contaminated for supervision purposes, and continue from sealed
projections instead of letting the worker's stream steer the supervisor.
+## Source And Build Economy
+
+- Verified capability is the asset. Epiphany-owned source, tests, schemas,
+ dependencies, executable targets, and compiler artifacts are carrying costs.
+ Minimize authority surfaces and build fan-out, not line count; readable code
+ and consequence-bearing verifier reach remain invariants.
+- The target invariant is one Cargo package owner per production entrypoint.
+ `epiphany-core` is a library; the release bundle owns runtime and maintenance
+ entrypoints, including the single `epiphany-state` steward CLI.
+ Leaf library crates disable automatic binaries; their production entrypoint
+ sources are admitted only by the release bundle. Do not point multiple
+ packages at the same binary source or preserve a binary because a stale
+ manifest, smoke command, or historical document still names it.
+- Admit a new executable only when a live consumer requires an independent
+ process, privilege boundary, lifecycle, or deployment contract. Tests,
+ fixtures, probes, and one-off migrations belong in existing library or
+ integration-test surfaces unless they must cross such a boundary.
+- Local Cargo checks must name one package and a focused library, integration
+ test, or binary target. Do not run local workspace-wide, `--all-targets`, or
+ otherwise unspecified multi-binary builds without explicit operator
+ authorization. Idunn owns release-wide build execution. Before an authorized
+ broad build, inventory the target graph, output root, current output size,
+ free disk, expected budget, and terminal retention.
+- An interrupted build remains unsettled work. Before retrying, inventory every
+ output root it may have written, including absolute path, size, last write,
+ owning run or revision, live process status, and retention decision. Settle
+ that run before creating another target root; cleanup machinery is not a
+ substitute for deleting unowned source or target fan-out.
+
## Verification Guardrails
- Use focused checks for the surface being changed instead of defaulting to a
whole-repo ritual. Not every prayer needs a cathedral.
-- For Epiphany control-plane behavior changes, run focused Rust checks against the touched app-server mapper/handler tests plus any matching native `epiphany-core` smoke binary. The old Python smoke shims have been cut; do not resurrect them.
+- For Epiphany control-plane behavior changes, run the focused existing library
+ or integration tests that exercise the changed consequence, plus touched
+ app-server mapper/handler tests when applicable. Do not create or resurrect a
+ standalone smoke executable merely to test a library or contract.
+- Source, test, and target counts are pressure signals, not acceptance metrics.
+ Do not delete exact conflict, substitution, concurrency, lifecycle, re-entry,
+ or user-visible consequence proofs merely to improve a count. Preserve the
+ claim in the smallest owning library or integration surface, and delete a
+ verifier only when the claim is dead, duplicated, or covered by stronger
+ evidence.
- For Codex Rust work on this Windows machine, set `$env:CARGO_TARGET_DIR='C:\Users\Meta\.cargo-target-codex'`.
- Do not parallelize cargo builds or tests against the same target directory.
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 00000000..640c1a14
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,3 @@
+Repository doctrine for this project lives in AGENTS.md, shared with Codex.
+
+@AGENTS.md
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 00000000..7d75c250
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,3021 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aead"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
+dependencies = [
+ "crypto-common",
+ "generic-array",
+]
+
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures 0.2.17",
+]
+
+[[package]]
+name = "aes-gcm"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "ghash",
+ "subtle",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
+
+[[package]]
+name = "async-trait"
+version = "0.1.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
+[[package]]
+name = "autocfg"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
+
+[[package]]
+name = "aws-lc-rs"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce2b2dcc879c3bae0d371e77c99f2238400ef24ec001394befa67b6e543add9e"
+dependencies = [
+ "aws-lc-sys",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.44.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f09fae7be8bb3174e05c6afdb34199e6dc0c7c04ba9fa237b1967adfbde27483"
+dependencies = [
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+ "pkg-config",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5"
+
+[[package]]
+name = "base64ct"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
+
+[[package]]
+name = "bitflags"
+version = "2.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
+dependencies = [
+ "objc2",
+]
+
+[[package]]
+name = "bstr"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f7dc094d718f2e1c1559ad110e27eeaae14a5465d3d56dd6dbd793079fbd530"
+dependencies = [
+ "memchr",
+ "serde_core",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+
+[[package]]
+name = "bytes"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
+
+[[package]]
+name = "cc"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e"
+dependencies = [
+ "find-msvc-tools",
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
+
+[[package]]
+name = "chacha20"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.3.0",
+ "rand_core 0.10.1",
+]
+
+[[package]]
+name = "chrono"
+version = "0.4.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
+dependencies = [
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "serde",
+ "wasm-bindgen",
+ "windows-link",
+]
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "codex-connector"
+version = "0.1.0"
+source = "git+https://github.com/GameCult/CodexConnector?rev=be1776ab455fd79bd74b393518ab07211dc9c1f0#be1776ab455fd79bd74b393518ab07211dc9c1f0"
+dependencies = [
+ "aes-gcm",
+ "base64 0.23.1",
+ "rand_core 0.6.4",
+ "rmp-serde",
+ "serde",
+ "serde_json",
+ "sha2",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
+name = "core-foundation"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "rand_core 0.6.4",
+ "typenum",
+]
+
+[[package]]
+name = "ctr"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "ctrlc"
+version = "3.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0b1fab2ae45819af2d0731d60f2afe17227ebb1a1538a236da84c93e9a60162"
+dependencies = [
+ "dispatch2",
+ "nix",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "cultcache-rs"
+version = "0.2.0"
+source = "git+https://github.com/GameCult/CultLib.git?rev=8fc74c709444b884a2bd339e0c306bf9484d99d2#8fc74c709444b884a2bd339e0c306bf9484d99d2"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "cultcache-rs-derive 0.1.0 (git+https://github.com/GameCult/CultLib.git?rev=8fc74c709444b884a2bd339e0c306bf9484d99d2)",
+ "fs2",
+ "redb",
+ "rmp-serde",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "uuid",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "cultcache-rs"
+version = "0.2.0"
+source = "git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6#a0813c6eed24d30bf88073ef615b633c77ebfcd6"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "cultcache-rs-derive 0.1.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "fs2",
+ "redb",
+ "rmp-serde",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "uuid",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "cultcache-rs-derive"
+version = "0.1.0"
+source = "git+https://github.com/GameCult/CultLib.git?rev=8fc74c709444b884a2bd339e0c306bf9484d99d2#8fc74c709444b884a2bd339e0c306bf9484d99d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "cultcache-rs-derive"
+version = "0.1.0"
+source = "git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6#a0813c6eed24d30bf88073ef615b633c77ebfcd6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "cultmesh-rs"
+version = "0.1.0"
+source = "git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6#a0813c6eed24d30bf88073ef615b633c77ebfcd6"
+dependencies = [
+ "anyhow",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "cultnet-rs",
+ "serde",
+]
+
+[[package]]
+name = "cultnet-rs"
+version = "0.1.0"
+source = "git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6#a0813c6eed24d30bf88073ef615b633c77ebfcd6"
+dependencies = [
+ "aes-gcm",
+ "anyhow",
+ "base64 0.22.1",
+ "chrono",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "ed25519-dalek",
+ "hmac",
+ "rand 0.9.5",
+ "rmp-serde",
+ "rmpv",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "sha2",
+ "socket2 0.5.10",
+ "uuid",
+ "windows-sys 0.61.2",
+ "zeroize",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "4.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "curve25519-dalek-derive",
+ "digest",
+ "fiat-crypto",
+ "rustc_version",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "curve25519-dalek-derive"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "der"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
+dependencies = [
+ "const-oid",
+ "zeroize",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "dispatch2"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
+dependencies = [
+ "bitflags",
+ "block2",
+ "libc",
+ "objc2",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "dyn-clone"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
+
+[[package]]
+name = "ed25519"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
+dependencies = [
+ "pkcs8",
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "serde",
+ "sha2",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "epiphany-core"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "ctrlc",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "cultmesh-rs",
+ "cultnet-rs",
+ "ed25519-dalek",
+ "epiphany-model-adapter",
+ "epiphany-tool-adapter",
+ "fs2",
+ "ghostlight-persona-projection",
+ "ignore",
+ "libc",
+ "rmp-serde",
+ "semver",
+ "serde",
+ "serde_json",
+ "sha2",
+ "tempfile",
+ "uuid",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "epiphany-model-adapter"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "codex-connector",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "serde",
+ "serde_json",
+ "sha2",
+]
+
+[[package]]
+name = "epiphany-openai-runtime"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "epiphany-core",
+ "epiphany-model-adapter",
+ "epiphany-tool-adapter",
+ "rmp-serde",
+ "serde",
+ "serde_json",
+ "sha2",
+ "tempfile",
+ "tokio",
+ "uuid",
+]
+
+[[package]]
+name = "epiphany-pipeline"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=8fc74c709444b884a2bd339e0c306bf9484d99d2)",
+ "rmp-serde",
+ "schemars",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "epiphany-release-bundle"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "codex-connector",
+ "ctrlc",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "cultnet-rs",
+ "epiphany-core",
+ "epiphany-model-adapter",
+ "epiphany-openai-runtime",
+ "epiphany-tool-adapter",
+ "epiphany-tool-mcp-runtime",
+ "rmp-serde",
+ "serde",
+ "serde_json",
+ "sha2",
+ "tempfile",
+ "tokio",
+ "toml",
+ "ureq",
+ "uuid",
+ "zeroize",
+]
+
+[[package]]
+name = "epiphany-tool-adapter"
+version = "0.1.0"
+dependencies = [
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "epiphany-tool-mcp-runtime"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "cultcache-rs 0.2.0 (git+https://github.com/GameCult/CultLib.git?rev=a0813c6eed24d30bf88073ef615b633c77ebfcd6)",
+ "epiphany-core",
+ "epiphany-tool-adapter",
+ "http",
+ "reqwest",
+ "rmcp",
+ "serde",
+ "serde_json",
+ "sha2",
+ "tempfile",
+ "tokio",
+ "toml",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
+
+[[package]]
+name = "fiat-crypto"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
+[[package]]
+name = "futures"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307"
+
+[[package]]
+name = "futures-task"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109"
+
+[[package]]
+name = "futures-util"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi 5.3.0",
+ "wasip2",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi 6.0.0",
+ "rand_core 0.10.1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "ghash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
+dependencies = [
+ "opaque-debug",
+ "polyval",
+]
+
+[[package]]
+name = "ghostlight-persona-projection"
+version = "0.1.0"
+source = "git+https://github.com/GameCult/Ghostlight.git?rev=22937b71f056d2000dd7ea1f6af0c45825de495f#22937b71f056d2000dd7ea1f6af0c45825de495f"
+dependencies = [
+ "serde",
+ "sha2",
+]
+
+[[package]]
+name = "globset"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "log",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "http"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0"
+dependencies = [
+ "bytes",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "hyper"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2 0.6.5",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "utf8_iter",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
+dependencies = [
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
+
+[[package]]
+name = "icu_properties"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
+dependencies = [
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
+
+[[package]]
+name = "icu_provider"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "idna"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "ignore"
+version = "0.4.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f"
+dependencies = [
+ "crossbeam-deque",
+ "globset",
+ "log",
+ "memchr",
+ "regex-automata",
+ "same-file",
+ "walkdir",
+ "winapi-util",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78"
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "jni"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
+dependencies = [
+ "cfg-if",
+ "combine",
+ "jni-macros",
+ "jni-sys",
+ "log",
+ "simd_cesu8",
+ "thiserror",
+ "walkdir",
+ "windows-link",
+]
+
+[[package]]
+name = "jni-macros"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "simd_cesu8",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
+dependencies = [
+ "jni-sys-macros",
+]
+
+[[package]]
+name = "jni-sys-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
+dependencies = [
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "jobserver"
+version = "0.1.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3"
+dependencies = [
+ "getrandom 0.4.3",
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a"
+dependencies = [
+ "cfg-if",
+ "futures-util",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.189"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "litemap"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
+
+[[package]]
+name = "log"
+version = "0.4.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
+
+[[package]]
+name = "lru-slab"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+
+[[package]]
+name = "memchr"
+version = "2.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
+
+[[package]]
+name = "mio"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "nix"
+version = "0.31.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "objc2"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
+dependencies = [
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
+[[package]]
+name = "openssl-probe"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
+
+[[package]]
+name = "polyval"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
+name = "potential_utf"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.107"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "process-wrap"
+version = "9.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e842efad9119158434d193c6682e2ebee4b44d6ad801d7b349623b3f57cdf55"
+dependencies = [
+ "futures",
+ "indexmap",
+ "nix",
+ "tokio",
+ "tracing",
+ "windows",
+]
+
+[[package]]
+name = "quinn"
+version = "0.11.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls",
+ "socket2 0.6.5",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560"
+dependencies = [
+ "aws-lc-rs",
+ "bytes",
+ "getrandom 0.4.3",
+ "lru-slab",
+ "rand 0.10.2",
+ "rand_pcg",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2 0.6.5",
+ "tracing",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "rand"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
+dependencies = [
+ "rand_chacha",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80"
+dependencies = [
+ "chacha20",
+ "getrandom 0.4.3",
+ "rand_core 0.10.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.17",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom 0.3.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+
+[[package]]
+name = "rand_pcg"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a"
+dependencies = [
+ "rand_core 0.10.1",
+]
+
+[[package]]
+name = "redb"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e925444704b5f17d32bf42f5b6e2df050bceebc3dcd6e71cc73dafe8092e839"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
+
+[[package]]
+name = "reqwest"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
+dependencies = [
+ "base64 0.22.1",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
+ "rustls-platform-verifier",
+ "serde",
+ "serde_json",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tokio-util",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.17",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rmcp"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14db48ee17a9ba61810ab1a9c1beb7d06d8136ae39ac25a1137f10d357af01af"
+dependencies = [
+ "async-trait",
+ "chrono",
+ "futures",
+ "http",
+ "pin-project-lite",
+ "process-wrap",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "sse-stream",
+ "thiserror",
+ "tokio",
+ "tokio-stream",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "rmp"
+version = "0.8.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "rmp-serde"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155"
+dependencies = [
+ "rmp",
+ "serde",
+]
+
+[[package]]
+name = "rmpv"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a4e1d4b9b938a26d2996af33229f0ca0956c652c1375067f0b45291c1df8417"
+dependencies = [
+ "rmp",
+ "serde",
+ "serde_bytes",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06"
+dependencies = [
+ "aws-lc-rs",
+ "log",
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-native-certs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
+dependencies = [
+ "openssl-probe",
+ "rustls-pki-types",
+ "schannel",
+ "security-framework",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
+dependencies = [
+ "web-time",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-platform-verifier"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
+dependencies = [
+ "core-foundation",
+ "core-foundation-sys",
+ "jni",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-platform-verifier-android",
+ "rustls-webpki",
+ "security-framework",
+ "security-framework-sys",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls-platform-verifier-android"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
+dependencies = [
+ "aws-lc-rs",
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "schemars"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a"
+dependencies = [
+ "dyn-clone",
+ "ref-cast",
+ "schemars_derive",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "schemars_derive"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde_derive_internals",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "security-framework"
+version = "3.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8"
+dependencies = [
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.229"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "serde_derive_internals"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.151"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "sha1_smol"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
+
+[[package]]
+name = "sha2"
+version = "0.10.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
+dependencies = [
+ "cfg-if",
+ "cpufeatures 0.2.17",
+ "digest",
+]
+
+[[package]]
+name = "shlex"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
+dependencies = [
+ "errno",
+ "libc",
+]
+
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "simd_cesu8"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
+dependencies = [
+ "rustc_version",
+ "simdutf8",
+]
+
+[[package]]
+name = "simdutf8"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
+
+[[package]]
+name = "slab"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
+
+[[package]]
+name = "smallvec"
+version = "1.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
+
+[[package]]
+name = "socket2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "socket2"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "sse-stream"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c123f296ade4ec4b8b0f6162116e6629f5146922ca5ab40ca9d3c2e73ab4761e"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http-body",
+ "http-body-util",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "2.0.119"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
+dependencies = [
+ "fastrand",
+ "getrandom 0.4.3",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2 0.6.5",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 3.0.3",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-stream"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b"
+dependencies = [
+ "futures-core",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "libc",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "0.9.12+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
+dependencies = [
+ "indexmap",
+ "serde_core",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow 0.7.15",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.7.5+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.1.3+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
+dependencies = [
+ "winnow 1.0.4",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
+
+[[package]]
+name = "tower"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
+dependencies = [
+ "bitflags",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+ "url",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "typenum"
+version = "1.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "universal-hash"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
+dependencies = [
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "ureq"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "972d7902c8735f2695410b8aed7df6ed12a47394aa1c8d7af49f0497b731a94d"
+dependencies = [
+ "base64 0.23.1",
+ "log",
+ "percent-encoding",
+ "rustls",
+ "rustls-pki-types",
+ "ureq-proto",
+ "utf8-zero",
+ "webpki-roots",
+]
+
+[[package]]
+name = "ureq-proto"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da5f78b09e6941e1a0f2e30e695e4b120377b54d5e0aec11b594bb57b3971613"
+dependencies = [
+ "base64 0.23.1",
+ "http",
+ "httparse",
+ "log",
+]
+
+[[package]]
+name = "url"
+version = "2.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
+name = "utf8-zero"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "uuid"
+version = "1.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
+dependencies = [
+ "getrandom 0.4.3",
+ "js-sys",
+ "serde_core",
+ "sha1_smol",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.4+wasi-0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.127"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.127"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.127"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.127"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-streams"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki-root-certs"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
+dependencies = [
+ "windows-collections",
+ "windows-core",
+ "windows-future",
+ "windows-numerics",
+]
+
+[[package]]
+name = "windows-collections"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
+dependencies = [
+ "windows-core",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-future"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
+dependencies = [
+ "windows-core",
+ "windows-link",
+ "windows-threading",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-numerics"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
+dependencies = [
+ "windows-core",
+ "windows-link",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows-threading"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.7.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
+
+[[package]]
+name = "winnow"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
+
+[[package]]
+name = "wit-bindgen"
+version = "0.57.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
+
+[[package]]
+name = "writeable"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
+
+[[package]]
+name = "yoke"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
+dependencies = [
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.119",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 00000000..2d59e523
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,90 @@
+[workspace]
+members = [
+ "epiphany-core",
+ "epiphany-model-adapter",
+ "epiphany-openai-runtime",
+ "epiphany-pipeline",
+ "epiphany-tool-adapter",
+ "epiphany-tool-mcp-runtime",
+]
+resolver = "3"
+
+[package]
+name = "epiphany-release-bundle"
+version = "0.1.0"
+edition = "2024"
+publish = false
+autobins = false
+license-file = "LICENSE"
+
+[dependencies]
+anyhow = "1"
+chrono = "0.4.44"
+ctrlc = { version = "3.5.1", features = ["termination"] }
+cultcache-rs = { git = "https://github.com/GameCult/CultLib.git", rev = "a0813c6eed24d30bf88073ef615b633c77ebfcd6", package = "cultcache-rs" }
+cultnet-rs = { git = "https://github.com/GameCult/CultLib.git", rev = "a0813c6eed24d30bf88073ef615b633c77ebfcd6", package = "cultnet-rs" }
+epiphany-core = { path = "epiphany-core" }
+epiphany-model-adapter = { path = "epiphany-model-adapter" }
+epiphany-openai-runtime = { path = "epiphany-openai-runtime", optional = true }
+codex-connector = { git = "https://github.com/GameCult/CodexConnector", rev = "be1776ab455fd79bd74b393518ab07211dc9c1f0", default-features = false, optional = true }
+epiphany-tool-adapter = { path = "epiphany-tool-adapter" }
+epiphany-tool-mcp-runtime = { path = "epiphany-tool-mcp-runtime", optional = true }
+rmp-serde = "1"
+serde = { version = "1", features = ["derive"] }
+serde_json = "1"
+sha2 = "0.10"
+tokio = { version = "1", features = ["io-util", "macros", "process", "rt", "rt-multi-thread", "time"] }
+toml = "0.9"
+ureq = { version = "3.4", default-features = false, features = ["rustls"], optional = true }
+uuid = { version = "1", features = ["serde", "v4"] }
+zeroize = { version = "1", optional = true }
+
+[features]
+openai-runtime = ["dep:codex-connector", "dep:epiphany-openai-runtime", "dep:ureq", "dep:zeroize"]
+tool-mcp-runtime = ["dep:epiphany-tool-mcp-runtime"]
+release-runtime = ["openai-runtime", "tool-mcp-runtime"]
+
+[profile.release]
+incremental = true
+
+[dev-dependencies]
+tempfile = "3"
+
+[[bin]]
+name = "epiphany-release"
+path = "epiphany-core/src/bin/epiphany-release.rs"
+
+[[bin]]
+name = "epiphany-state"
+path = "epiphany-core/src/bin/epiphany-state.rs"
+
+[[bin]]
+name = "epiphany-repository-body"
+path = "epiphany-core/src/bin/epiphany-repository-body.rs"
+
+[[bin]]
+name = "epiphany-swarm"
+path = "epiphany-core/src/bin/epiphany-swarm.rs"
+
+[[bin]]
+name = "epiphany-persona-service"
+path = "epiphany-openai-runtime/src/bin/epiphany-persona-service.rs"
+required-features = ["openai-runtime"]
+
+[[bin]]
+name = "epiphany-persona-discord-permit"
+path = "epiphany-core/src/bin/epiphany-persona-discord-permit.rs"
+
+[[bin]]
+name = "epiphany-mvp-coordinator"
+path = "epiphany-core/src/bin/epiphany-mvp-coordinator.rs"
+
+[[bin]]
+name = "epiphany-model-runtime"
+path = "epiphany-openai-runtime/src/bin/epiphany-openai-runtime.rs"
+required-features = ["openai-runtime"]
+
+[[bin]]
+name = "epiphany-tool-mcp-runtime"
+path = "epiphany-tool-mcp-runtime/src/main.rs"
+required-features = ["tool-mcp-runtime"]
diff --git a/LICENSE b/LICENSE
index b0d7b796..d815141e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -19,15 +19,10 @@ For this file:
directory states different terms.
- `Upstream Material` means material copied or adapted from third parties and
distributed under their own licenses.
-- `Mixed Apache Files` means files under `vendor/codex/**` that contain
- project-authored changes on top of upstream Apache-licensed material.
2. Upstream And Third-Party Material
------------------------------------
-- All material under `vendor/codex/**` remains subject to its upstream licenses
- and notices, including Apache License 2.0 at `vendor/codex/LICENSE` and any
- applicable `NOTICE` or file-level notices.
- Other third-party material distributed with the repository keeps its own
license terms where provided.
- You must continue to comply with those upstream terms when using,
@@ -36,8 +31,8 @@ For this file:
3. Public License For Project-Authored Material
-----------------------------------------------
-Except where a file or directory says otherwise, Project-Authored Material
-outside `vendor/codex/**` is licensed to the public under:
+Except where a file or directory says otherwise, Project-Authored Material is
+licensed to the public under:
- PolyForm Noncommercial License 1.0.0
@@ -66,27 +61,7 @@ entity is formed and designated in writing, any commercial license for
Project-Authored Material may be offered directly by the individual copyright
holder or holders.
-5. Mixed Apache Files Under `vendor/codex/**`
----------------------------------------------
-
-Some files under `vendor/codex/**` contain project-authored changes layered on
-top of upstream Apache-licensed code.
-
-For those files:
-
-- Apache License 2.0 and the applicable upstream notices still apply.
-- You must not read this repository notice as converting those files into a
- PolyForm-only codebase.
-- To the extent the project owns copyright in new additions to those files, the
- project may also offer separate commercial terms for its own contributions.
-- This repository notice does not claim to erase or retract Apache-2.0
- permissions already granted for Apache-covered material.
-
-The strongest commercial boundary in this repository therefore applies to
-clearly separable Project-Authored Material outside `vendor/codex/**`,
-including `epiphany-core/**` and other non-vendored project files.
-
-6. Open Source Status
+5. Open Source Status
---------------------
Because the public license path for Project-Authored Material is PolyForm
@@ -94,7 +69,7 @@ Noncommercial License 1.0.0 rather than an OSI-approved license, the
repository as a whole is source-available and dual-licensed. It is not an OSI
Open Source distribution as a whole.
-7. Reference Structures
+6. Reference Structures
-----------------------
This licensing structure intentionally borrows the general dual-license shape
@@ -107,7 +82,7 @@ This repository does not claim that Qt or MySQL use the same exact public
license terms used here. Those projects are referenced only as structural
examples of dual licensing, not as the operative terms of this repository.
-8. Contributions
+7. Contributions
----------------
External contributions are accepted only under the EpiphanyAgent Contributor
diff --git a/README.md b/README.md
index 52ed95f9..aa29c3ff 100644
--- a/README.md
+++ b/README.md
@@ -1,191 +1,277 @@
-# EpiphanyAgent
+# Epiphany
-Epiphany is an opinionated fork of Codex built around one demand: the model
-must model the thing it is changing.
+
+
+
-The problem this repo is chasing is not "LLMs can't write code." They can. The
-problem is that they can keep making plausible local moves after the global
-design has already wandered off and died in a ditch.
+Epiphany is GameCult's organizational layer above frontier AI workers: governed
+shared state, bounded authority, coordinated action, and inspectable receipts
+for work that must remain coherent beyond one prompt, one agent, or one
+session.
-Epiphany answers that by moving important state out of transcript fog and into
-typed, inspectable surfaces: maps, evidence, retrieval state, graph/frontier
-state, churn pressure, and compact client reflections. The goal is not maximal
-output. The goal is a machine whose parts visibly deserve to exist.
+The bet is simple and unpleasantly large:
-## Project Direction
+> Frontier agents can keep producing good-looking local progress after the
+> architecture has stopped making sense. Organizations need a shared Mind for
+> the work, not a longer pile of private prompts.
-Epiphany is moving toward project-native agency.
+Epiphany is the control plane for that missing layer. It gives capable workers
+a governed model of the project, routes bounded work, preserves evidence,
+separates authority, and stops or escalates when the machine no longer knows
+enough to act honestly.
-The user should not have to write a perfect brief, name every subsystem, and
-pre-plan the code flow for the whole architecture before the machine can help.
-That is just outsourcing project management to the human and calling the agent
-smart because it waited politely.
+This is not a faster autocomplete costume. It is the beginning of governed
+human/agent labor.
-The intended shape is simpler and stranger: you talk to the project.
+## Front Door
-Each Epiphany owns one or more repos, carries durable memory and jurisdiction
-for them, and can grow one or more Personas. A Persona is the public mouth and
-situated personality of that project: visible in Aquarium, addressable in
-Discord, suitable for voice or stream presence, and backed by the same typed
-state, heartbeat initiative, repo map, evidence, and review gates as the rest of
-the swarm.
+- **Value:** the shared typed Mind for agent work: governed project state, role lanes for research, modeling, implementation, verification, planning and Persona, and receipts for commands, edits and commits, so work stays coherent past one prompt, one agent or one session.
+- **Problem:** global coherence collapse. Agents keep producing plausible local progress after the project has lost a valid global model; Epiphany turns understanding into inspectable state instead of a longer prompt.
+- **Entry points:**
+ - `AGENTS.md`: operating law and re-entry rites. Read it before touching the machine.
+ - `epiphany-core/`: the typed domain organs (`src/runtime_spine.rs` job, worker, model and tool documents; `src/substrate_gate.rs`; `src/state_model.rs`; `src/mind_documents.rs`).
+ - `cargo run --bin epiphany-state -- status`: the steward CLI for direct Mind inspection (other native binaries are declared in `Cargo.toml`).
+ - `schemas/cultnet/`, `state/map.yaml` (canonical project map), `notes/epiphany-current-algorithmic-map.md` (live control flow).
+ - `docs/positioning.md`: what is claimed and what is not yet earned.
+- **Live:** a supervised engineering alpha: durable typed state and prompt projection, update/proposal/promotion/review paths, runtime-spine documents, operator status and coordinator commands, heartbeat and Persona-state machinery, and the Hands, Eyes, Soul, Mind, Continuity and Substrate Gate receipt families.
+- **Planned:** sustained autonomous GameCult production, complete Bifrost attribution, and a longitudinal fleet of one Epiphany organism per project Body. See What Exists Now.
-VoidBot is already showing the small version: repo identities such as Nibu,
-Aqua, and Mimir have Discord roles, repo-local Persona state, proposal authority,
-pending mentions, and heartbeat turns. Epiphany is the larger native substrate:
-projects should notice pressure, ruminate, ask questions, schedule modeling or
-verification, advocate for their own repo needs, and structure work without
-requiring the human to spell out the implementation graph first.
+## The GameCult Bet
-Aquarium is the most direct client because it can show the swarm, its Personas,
-its heartbeat, its memories, and its decisions. It is not the only mouth. A
-project should also be reachable through Discord, voice/WebRTC surfaces, stream
-overlays, native CLIs, and CultNet-speaking tools. The interface contract is
-not "prompt an agent." It is "speak to the project; inspect how it thinks; grant
-or refuse authority when it wants to act."
+GameCult is building infrastructure for coordinated work between humans,
+projects, communities, and agents. Its games and creative tools are not side
+projects beside Epiphany. Shipping them is the longitudinal dogfood program.
+
+The target body is federated: one Epiphany project organism for every living
+project Body, normally a repo-owned swarm with a private local Mind and one or
+more project-facing Personas. Those organisms should collaborate through typed
+offers, claims, requests, evidence, and receipts rather than opening one
+another's state. Over time, their Personas should form durable, publicly
+visible relationships with other project Personas, contributors, players, and
+visitors through deliberate public surfaces. Remembered relationships require
+opt-in, visible retention limits, inspection, correction, revocation, and exit.
+
+The investable loop is Bifrost-first:
+
+```text
+work request or topic
+-> scoped agent execution
+-> bounded artifacts
+-> maintainer review
+-> accepted or rejected outcome
+-> receipts, credit, cost, and lessons
+```
+
+Bifrost owns work records, dispatch, receipts, credit, reward pressure, and
+governance. Epiphany owns agent execution, durable project memory, role
+coordination, evidence, verification pressure, and continuity. CultMesh and
+CultNet carry typed state between organs instead of letting private chats,
+Discord bots, scripts, or dashboards become shadow governments.
+
+That is the core of the GameCult thesis: not "AI writes code," but "AI work
+becomes accountable enough to govern, fund, review, credit, and repeat." The
+studio's products create value and supply the pressure needed to prove the
+production system in reality.
+
+## Why Epiphany Exists
+
+Current agents can write plausible code. That is no longer the hard part.
+
+The expensive failure is global coherence collapse: an agent keeps moving
+after the project has lost a valid global model. It adds an adapter around a
+compensator around a cache, passes a narrow test, and leaves the next worker
+inheriting fog as if it were architecture.
+
+This is not merely context-window exhaustion. A larger window can still hold
+contradictory objectives, stale architecture, split authority, and a handsome
+collection of unreviewed local victories.
+
+Epiphany attacks that failure by turning understanding into shared state:
+
+- the current objective
+- architecture and dataflow maps
+- scratch that is disposable
+- evidence that survives
+- role lanes for research, modeling, implementation, verification, planning,
+ Persona, and reorientation
+- runtime, tool, model, command, patch, and commit receipts
+- review gates before findings become project truth
+- public/operator-safe artifacts that can be shown without leaking private
+ worker context
+
+The point is not maximal motion. The point is coherent motion.
+
+## Organization, Not Prompt Box
+
+Epiphany treats objectives, work, decisions, permissions, evidence, review, and
+accepted knowledge as governed organizational state. Model prompts are bounded
+projections of that state. They are not the durable Mind of the project.
+
+```text
+governed organizational state
+-> scoped Epiphany work
+-> frontier model and tool execution
+-> artifacts, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted knowledge and updated organizational state
+```
+
+Humans own purpose, values, authority, exceptions, acceptance, disagreement,
+and ambiguous tradeoffs. They should not have to spend the day scheduling
+agents, reconstructing context, or typing `Continue`. Agents continue when
+state, authority, and evidence justify it; they ask when judgment or authority
+is genuinely missing.
+
+The target promise is blunt:
+
+> Epiphany is being built so organizations can delegate bounded work to
+> capable AI without turning every employee into an AI operator.
+
+## What She Is
+
+Epiphany is a native GameCult runtime that began as an opinionated Codex fork.
+
+Her body is made of:
+
+- typed Rust domain organs owned by `epiphany-core`
+- CultCache `.cc` stores for runtime, heartbeat, agent state, local Verse,
+ memory graph, and thread state
+- CultMesh and CultNet contracts for local and distributed state
+- provider-neutral model and tool request/receipt documents
+- Mind, Substrate Gate, Eyes, Hands, Soul, Continuity, Persona, and heartbeat
+ authority surfaces
+- a narrow standalone CodexConnector process for OpenAI subscription auth and
+ model transport; Epiphany compiles no Codex crate and keeps cognition local
+
+That last clause matters. Codex and other frontier agents can be excellent
+workers. They do not decide which organizational state is authoritative, who
+may change it, how disagreements resolve, or how an accepted artifact traces
+back to work, evidence, and review. Epiphany owns that layer.
+
+## What She Makes Possible
+
+For engineering teams:
+
+- agents that work from governed project memory across long work and
+ compaction
+- visible separation between research, modeling, implementation, and
+ verification
+- human attention spent on judgment and acceptance instead of agent scheduling
+ and context reconstruction
+- explicit permission and receipt trails for commands, edits, commits, and
+ tool calls
+- durable postmortem evidence when a path fails
+
+For GameCult:
+
+- project Personas that can speak from repo state without becoming hidden
+ operators
+- one locally owned Epiphany organism per project, forming a governed swarm of
+ swarms rather than one central intelligence wearing every repository
+- visitor-facing public surfaces where people can observe, converse, and offer
+ evidence or proposals without receiving hidden authority or exposing private
+ Mind
+- Bifrost-routed work that produces artifacts, review, receipts, and credit
+- a commercial-grade agent substrate while free/reference layers can remain
+ open where that is the right covenant
+- a way for public work logs, design pressure, and contributor effort to become
+ governed production instead of ambient room noise
+
+For investors and partners:
+
+- a differentiated wedge in AI-native work governance
+- measurable proof targets: accepted work between interventions, review burden,
+ cost per accepted artifact, early escalation of bad assumptions, attribution
+ completeness, and failure recovery
+- a path from internal agent tooling to design-partner workflows, enterprise
+ services, commercial licensing, and mission-aligned infrastructure funding
## What Exists Now
-The current spine is real, not aspirational:
+Epiphany is a supervised engineering alpha. Its typed Mind, execution, receipt,
+verification, and operator surfaces exist. Sustained autonomous GameCult
+production and complete Bifrost attribution have not yet been earned.
-- durable `EpiphanyThreadState` in the vendored Codex protocol/core session
-- rollout snapshots and replay for resume, rollback, fork, and compaction
-- bounded `` prompt injection
-- typed client reads through `Thread.epiphanyState`
-- read-only retrieval through `thread/epiphany/retrieve`
-- explicit semantic indexing through `thread/epiphany/index`
-- durable typed writes through `thread/epiphany/update`
-- read-only observation distillation through `thread/epiphany/distill`
-- read-only map/churn proposal through `thread/epiphany/propose`
-- verifier-backed promotion through `thread/epiphany/promote`
-- successful-write notifications through `thread/epiphany/stateUpdated`
-- durable `jobBindings` as a thin Epiphany-owned launcher seam over runtime job backends
-- explicit launch and interrupt authority through `thread/epiphany/jobLaunch` and `thread/epiphany/jobInterrupt`, still backed by runtime `agent_jobs`
-- a bounded reorient-guided worker launch through `thread/epiphany/reorientLaunch`
-- read-only CRRC next-action recommendations through `thread/epiphany/crrc`
-- live bound-job progress notifications through `thread/epiphany/jobsUpdated`
-- read-only reflection surfaces through `thread/epiphany/scene`, `jobs`, `freshness`, `context`, `pressure`, and `reorient`
-- a first dogfood CLI operator view through `tools/epiphany_mvp_status.py`, including explicit implementation, modeling/checkpoint, verification/review, and reorientation lanes
-- durable investigation checkpointing for compaction-safe planning
-- Ghostlight/VoidBot-derived heartbeat initiative with heat, active-turn
- freeze, idle rumination, sleep/dream maintenance, and Persona as a first-class
- public-surface participant
-- repo personality/birth initialization that can seed role dossiers and
- heartbeat pressure from repo terrain before a project starts speaking
-- CultNet schema contracts for runtime, heartbeat, Persona, character-turn,
- Discord-persona, repo-initialization, Rider, Unity, and operator surfaces
-- repo-owned heavy Epiphany organs in `epiphany-core/`, with vendored Codex kept as the host seam where practical
+What exists now is enough to evaluate the thesis:
-Phase 1 through Phase 6 are landed enough for the current experiment. The open
-questions are now about observability, invalidation, coordination, authority,
-and safe capability growth, not whether typed state can exist at all.
+- durable typed state and prompt projection
+- typed update, proposal, promotion, role-result, and review paths
+- runtime-spine job, worker, model, and tool documents
+- local operator status and coordinator commands
+- heartbeat, sleep, memory, and Persona-state machinery inherited from live
+ VoidBot lessons
+- Hands, Eyes, Soul, Mind, Continuity, and Substrate Gate receipt families
+- a Modeling whitepaper mapping Epiphany's body, owners, invariants, and
+ cut lines
+- an investor brief tying Epiphany to the Bifrost-first proof loop
-## Run Locally
+The next proof is not another impressive paragraph. It is a longitudinal
+GameCult fleet across Aetheria, StreamPixels, CultPong, Repixelizer, and the
+rest of the studio: one project organism per Body, collaborating through
+governed boundaries while real products ship.
-The current one-command operator path is:
-
-```powershell
-.\tools\epiphany_local_run.ps1
+```text
+Bifrost work item and decisions
+-> Epiphany execution
+-> artifact, commit, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted or rejected outcome
+-> cost, intervention, failure, recovery, and credit record
```
-Default mode is `smoke`: it builds the retained Codex app-server compatibility
-edge, builds the native Epiphany operator binaries, runs the coordinator smoke,
-and writes launcher artifacts under `.epiphany-run/` plus coordinator evidence
-under `.epiphany-dogfood/`.
+The evidence should show whether human intervention shifts from pulse
+maintenance and cleanup toward product, architecture, and governance judgment.
+Failure and recovery belong in that record. Otherwise it is merely a victory
+reel wearing a lab coat.
-Useful variants:
+## Start Here
-```powershell
-.\tools\epiphany_local_run.ps1 -Mode status
-.\tools\epiphany_local_run.ps1 -Mode plan
-.\tools\epiphany_local_run.ps1 -Mode run -MaxSteps 4
-.\tools\epiphany_local_run.ps1 -Mode mvp -PersonaInput "Wake the local swarm and report through Persona." -MaxSteps 4
-.\tools\epiphany_local_run.ps1 -Mode status -ThreadId -Workspace E:\Projects\SomeRepo
-```
+For investors and serious business-development readers:
-`run` is the live coordinator loop. It also builds `epiphany-openai-runtime` and
-uses the retained Codex auth/model transport spine. `mvp` is the local product
-cycle: project Persona's character turn, write a Persona/Aquarium bubble, run the
-bridge-equipped coordinator loop with auto-tools, then run heartbeat sleep/dream
-maintenance. Fresh `mvp` runs bootstrap a minimal local checkpoint before
-coordination so the first loop does not stall at missing state. Live coordinator
-modes use the workspace `state/runtime-spine.cc` for worker lifecycle
-documents; run bundles remain evidence. Live model-worker turns default to a
-600-second timeout because ChatGPT Codex model latency can exceed four minutes.
-`status`, `plan`, and `smoke` do not spend model calls; `run` and `mvp` do.
+- [Current positioning and evidence boundary](docs/positioning.md)
+- [Epiphany investor brief](docs/epiphany_investor_brief.md)
+- [Epiphany Body whitepaper PDF](docs/epiphany_body_whitepaper.pdf) (June 2026
+ architecture snapshot; historical)
+- [Epiphany Body whitepaper TeX](docs/epiphany_body_whitepaper.tex) (historical
+ source)
+- [GameCult / Epiphany / Bifrost integrated dossier](https://github.com/GameCult/gamecult-site/blob/main/docs/gamecult_integrated_dossier.tex)
+ for the broader investment thesis
-## Where This Leads
+For engineers:
-The architectural goal is not one giant agent that does archaeology, design,
-patching, and self-grading in a single token fog. It is also not a chat box
-where the human must already know the solution architecture before asking.
+- [Docs index](docs/README.md)
+- [Current algorithmic map](notes/epiphany-current-algorithmic-map.md)
+- [Fork implementation plan](notes/epiphany-fork-implementation-plan.md)
+- [Anatomy map](notes/epiphany-anatomy.md)
+- [Safety architecture](notes/epiphany-safety-architecture.md)
+- [Canonical project map](state/map.yaml)
-The goal is a maintained project organism:
+For agents:
-- graph and source-modeling agents keep the machine map current
-- freshness, watcher input, pressure, and reorientation signals decide whether that map still deserves trust
-- verifier agents check claims, diffs, and outcomes against reality
-- coding agents work from bounded packets of graph context, evidence, code refs, and local source reads instead of re-spelunking the repo from scratch every turn
-- Personas translate project state into conversation, voice, stream presence, and
- Discord/Aquarium discussion without becoming omniscient hidden operators
-- initiative scheduling decides which repo, Persona, or internal organ should
- think next, and heat lets the operator turn up one agent, one project, one
- group, or the whole swarm
+- [AGENTS.md](AGENTS.md)
-That still leaves direct source reading where it belongs: at the last mile,
-when a patch has to be grounded in the real files. The difference is that broad
-exploration, coherence maintenance, social interface, scheduling, and
-verification stop living in the same overworked skull.
+Read that before touching the machine. It contains the operating law, re-entry
+rites, and enough anti-Jenga doctrine to keep the next clever patch from
+becoming tomorrow's cleanup sermon.
-## Repo Tour
+## Operator Surfaces
-If you want the human-readable map of the project, start here:
-
-- `notes/epiphany-anatomy.md`: current organ/sub-agent/substrate/protocol split
-- `notes/epiphany-current-algorithmic-map.md`: source-grounded control flow of the live machine
-- `notes/epiphany-fork-implementation-plan.md`: distilled forward plan
-- `notes/epiphany-safety-architecture.md`: capability, authority, interruption, and anti-cage doctrine
-- `notes/verse-service-contract.md`: GameCult Verse service contract for the
- missing Eve GUI/TUI operator surface over existing CultCache/CultMesh state
-- `notes/archive/README.md`: historical ledgers and superseded plans
-- `state/map.yaml`: canonical current project map and accepted design
-
-If you want the code:
-
-- `epiphany-core/`: repo-owned Epiphany logic
-- `vendor/codex/`: vendored Codex host substrate
-- `tools/`: smoke tests and state helpers
-
-If you are an agent or you are steering one, read `AGENTS.md`. That file is
-for operating discipline, re-entry protocol, and session hygiene. The README is
-for people, which is a lower-crime use of everyone's time.
-
-## Design Stance
-
-Epiphany is built on a few stubborn ideas:
-
-- externalized state is better than pretending the transcript is a brain
-- local plausibility is not the same thing as global coherence
-- evidence should survive, but activity feed sludge should not
-- cognition should grow faster than authority
-- interruption, legibility, and explicit permissions matter more as the machine becomes more coherent
-
-This repo is not trying to make the model louder. It is trying to make it less
-likely to build a Jenga tower and call it understanding.
+Eve/CultMesh projections are the normal human interface. Repository surgery
+uses the narrow native binaries owned by the packaged runtime; there is no
+umbrella script that assembles a second local control plane. For direct Mind
+inspection during development, use the shared-target `epiphany-state` command
+documented in [AGENTS.md](AGENTS.md).
## License
-The root `LICENSE` is the operative repository notice. In short:
-`vendor/codex/**` and other third-party material keep their upstream licenses;
-project-authored material outside `vendor/codex/**` is publicly available under
-PolyForm Noncommercial 1.0.0 and is intended to be available under separate
-commercial terms by written agreement.
+The root `LICENSE` is the operative repository notice.
-External contributions require `CONTRIBUTOR_LICENSE_AGREEMENT.md` or a separate
-written agreement accepted by the project steward.
+In short: vendored upstream material keeps its upstream license. GameCult-authored
+Epiphany material is source-available under PolyForm Noncommercial 1.0.0, with
+separate commercial terms available by written agreement.
-The publishing stance is:
+The publishing stance is direct:
-- FOSS where that is viable
-- source-available where the economics or capability profile make unrestricted release a bad idea
-- commercial terms where organizations are extracting real enterprise value
+- free where freedom is the right covenant
+- source-available where unrestricted extraction would be bad governance
+- commercial where organizations are extracting enterprise value
diff --git a/apps/README.md b/apps/README.md
index 031d636d..ff74585c 100644
--- a/apps/README.md
+++ b/apps/README.md
@@ -4,15 +4,19 @@ The Aquarium operator UI moved to its own sibling repository:
`E:\Projects\EpiphanyAquarium`
-EpiphanyAgent remains the harness, typed-state, coordinator, bridge, and backend
-repo. Aquarium is the Tauri/React/WebGL interface organism over those surfaces.
+Epiphany remains the native typed-state, coordination, execution, and backend
+organism. Aquarium is the primary graphical client over those surfaces.
Aquarium is the primary client for the next public shape of Epiphany: projects
-with Personas. A user should be able to talk to a project, not assemble a perfect
-agent prompt. Aquarium should show the repo's Persona, heartbeat, memory, pending
-turns, current jurisdiction, proposed actions, and evidence so the human can
-converse, inspect, approve, refuse, or raise heat without pre-writing the whole
-architecture brief.
+with Faces. A user should be able to talk to a project, not assemble a perfect
+agent prompt. Aquarium should show the repo's Face, heartbeat, memory, pending
+turns, current jurisdiction, proposed actions, evidence, conflicts,
+uncertainty, and requests for authority so the human can converse, inspect,
+approve, refuse, or raise pressure without becoming the agent scheduler.
+
+Routine continuation belongs to Epiphany's physiology. Human attention belongs
+on purpose, judgment, exceptions, disagreement, and acceptance. Conversation is
+an input and relationship surface, not the hidden operating system.
Discord roles, WebRTC/voice surfaces, stream overlays, native CLIs, and other
CultNet clients are sibling mouths over the same substrate. Aquarium is the
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000..02786fdd
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,32 @@
+# Epiphany Docs
+
+This folder packages the human-readable Epiphany material that should survive
+outside the working notes.
+
+## Investor Packet
+
+- [Current positioning](./positioning.md): category, operating model, human
+ authority boundary, GameCult dogfood program, attribution target, and claims
+ the supervised alpha has not yet earned.
+- [Epiphany investor brief](./epiphany_investor_brief.md): compact value and
+ diligence summary for investors, partners, and design-partner conversations.
+- [Epiphany Body whitepaper](./epiphany_body_whitepaper.tex): source TeX for
+ the June 2026 Modeling architecture snapshot. This is historical material;
+ use the positioning document and canonical maps for current product claims.
+- [Epiphany Body whitepaper PDF](./epiphany_body_whitepaper.pdf): compiled
+ historical snapshot for sharing with that caveat.
+
+## Source Notes
+
+- [Investor readiness roadmap](../notes/epiphany-investor-readiness-roadmap.md)
+ names the Bifrost-first proof rail and metrics.
+- [Algorithmic map](../notes/epiphany-current-algorithmic-map.md) records the
+ live control flow.
+- [Fork implementation plan](../notes/epiphany-fork-implementation-plan.md)
+ records the current architecture and cut lines.
+- [Project map](../state/map.yaml) is the canonical slow machine map.
+
+For historical GameCult-level investor context, the sibling site dossier lives
+at `F:\Projects\gamecult-site\docs\gamecult_integrated_dossier.tex`. It is a
+May 2026 snapshot; the current positioning and investor brief above supersede
+its Epiphany category and maturity framing.
diff --git a/docs/assets/epiphany-avatar-4x.png b/docs/assets/epiphany-avatar-4x.png
new file mode 100644
index 00000000..c416ab0b
Binary files /dev/null and b/docs/assets/epiphany-avatar-4x.png differ
diff --git a/docs/epiphany_body_whitepaper.pdf b/docs/epiphany_body_whitepaper.pdf
index cfbba0b0..bed64e64 100644
Binary files a/docs/epiphany_body_whitepaper.pdf and b/docs/epiphany_body_whitepaper.pdf differ
diff --git a/docs/epiphany_body_whitepaper.tex b/docs/epiphany_body_whitepaper.tex
index 3e5bc82a..05046be2 100644
--- a/docs/epiphany_body_whitepaper.tex
+++ b/docs/epiphany_body_whitepaper.tex
@@ -47,34 +47,33 @@ and the difference between the map and the substrate.
The practical definition in this repository is:
\begin{itemize}
- \item the root checkout at \code{E:\Projects\EpiphanyAgent};
- \item Epiphany Rust crates such as \code{epiphany-core}, \code{epiphany-state-model}, \code{epiphany-codex-bridge}, model/tool adapters, and OpenAI transport crates;
+ \item the root checkout at \code{F:\Projects\Epiphany};
+ \item Epiphany Rust crates such as \code{epiphany-core}, model/tool adapters, and provider runtimes;
\item vendored substrate in \code{vendor/codex}, \code{vendor/cultcache-rs}, \code{vendor/cultnet-rs}, and \code{vendor/cultmesh-rs};
\item typed state stores under \code{state/};
\item schemas under \code{schemas/cultnet/};
\item local operator scripts and generated witness artifacts;
- \item adjacent service/client bodies: Aquarium, Odin/Gjallar, Eve/CultUI, Bifrost, VoidBot, Rider, Unity, Discord, and future GameCult Verse hosts.
+ \item adjacent service/client bodies: Aquarium, Odin/Gjallar, Eve/CultUI,
+ Bifrost, VoidBot, Brokkr, Discord, and future GameCult Verse providers.
\end{itemize}
\section{Executive Map}
-Epiphany's current Body is a hybrid machine in transition. Its center of gravity
-has moved into typed Rust/CultCache organs, but compatibility arteries still
-run through vendored Codex. The live target is not a cleaner pile of Codex
-routes. The target is an Epiphany-native CultCache/CultMesh/CultNet body with a
-relatively vanilla Codex-derived reliquary retained for OpenAI subscription
-auth and model transport.
+Epiphany's current Body is a typed Rust/CultCache organism with provider
+transport outside its cognition boundary. Codex requests cross a lean client
+ABI into the independent CodexConnector daemon, which owns subscription
+credential refresh, transport, and replay. Epiphany owns prompts, tools,
+reasoning context, decisions, and Mind admission; it compiles no Codex crate.
\begin{longtable}{>{\raggedright\arraybackslash}p{0.23\linewidth}>{\raggedright\arraybackslash}p{0.32\linewidth}>{\raggedright\arraybackslash}p{0.35\linewidth}}
\textbf{Body Region} & \textbf{Current Owner} & \textbf{Invariant} \\
\hline
-Durable thread state & \code{epiphany-state-model}, \code{epiphany-core} & State shape is typed; prompt rendering is a projection, not authority. \\
+Durable Mind state & keyed CultCache documents assembled by \code{epiphany-core} & Prompt rendering consumes sealed typed projections; no persisted thread aggregate or global authority revision exists. \\
Domain policy & \code{epiphany-core} & Verdicts, launch policy, acceptance rules, runtime lifecycle, and mutation law live here, not in bridge DTOs. \\
-Compatibility bridge & \code{epiphany-codex-bridge} & Translate Codex edge shapes; never become a second policy throne. \\
-Vendored Codex & \code{vendor/codex} & Retain host/app-server/auth/model compatibility where useful; do not let Codex own Epiphany prompts, scheduler, or state. \\
-Runtime spine & \code{epiphany-core/src/runtime_spine.rs} and \code{state/runtime-spine.cc} & Runtime identity, jobs, events, receipts, tool/model documents are typed CultCache records. \\
-Organ memory & \code{state/agents.cc}; agent-memory CLI & Resident work organs use lean work-organ state; Persona uses portable Persona state. \\
-Heartbeat physiology & \code{state/agent-heartbeats.cc} via \code{epiphany-heartbeat-store} & Scheduling, cooldown, rumination, routine, cognition lanes, and active-turn freeze are scheduler physiology, not project truth. \\
+Codex transport & independent \code{GameCult/CodexConnector} daemon & Own subscription credentials, provider transport, and exact replay only; never own Epiphany prompts, scheduler, decisions, or state. \\
+Runtime spine & \code{epiphany-core/src/runtime_spine.rs} and \code{state/runtime-spine.cc} & Runtime identity, jobs, receipts, and tool/model documents are typed CultCache records. \\
+Persona memory & keyed Mind Persona-memory documents & Persona decisions admit bounded memories by semantic identity; no parallel role-memory aggregate or generation head exists. \\
+Resident Self physiology & Resident Self CultCache documents via \code{epiphany-swarm} & Typed pressure, exact grant creation, launch exclusion, leases, terminal receipts, retry, and bounded retention have one owner. No scheduler singleton or acknowledgement loop exists. \\
Local Verse & CultMesh over \code{state/local-verse.cc} & Local Verse context is compact prompt/operator context; private state does not become public by flipping a flag. \\
Schema catalog & \code{schemas/cultnet/index.json} & JSON schema publishes contracts; typed Rust documents remain runtime authority. \\
Operator artifacts & \code{.epiphany-*}, \code{tools/epiphany_local_run.ps1} & Artifacts witness and lower state; they do not become state owners. \\
@@ -82,42 +81,34 @@ Operator artifacts & \code{.epiphany-*}, \code{tools/epiphany_local_run.ps1} & A
\section{Repository Body}
-The checkout has ten primary Epiphany Rust crates:
+The checkout has eight primary Epiphany Rust packages:
\begin{itemize}
- \item \code{epiphany-core}: the main domain organ. It owns state-update
- validation, launch documents, runtime spine, heartbeat, memory graph, Persona
- projection, Substrate Gate, Mind, Eyes, Hands, Soul, Continuity, CultMesh
- integration, surface derivation, smokes, and local operator binaries.
- \item \code{epiphany-state-model}: the durable \code{EpiphanyThreadState}
- type plus \code{render_epiphany_state}. This is the typed Mind surface that
- prompt fragments and views read.
- \item \code{epiphany-codex-bridge}: the translation layer between typed
- Epiphany documents and vendored Codex JSON-RPC/app-server shapes. Its own
- crate header states that it is a bridge, not an authority organ.
+ \item \code{epiphany-core}: the main domain organ. It owns semantic state
+ contracts, keyed Mind admission, launch documents, runtime spine, Resident
+ Self, Persona projection, Substrate Gate, Eyes, Hands, Soul, Continuity,
+ CultMesh integration, and surface derivation.
\item \code{epiphany-model-adapter}: provider-neutral model request, stream
event, receipt, and status documents.
\item \code{epiphany-openai-adapter}: OpenAI-shaped request/event/receipt and
status documents.
- \item \code{epiphany-openai-auth-spine}: Codex-derived auth boundary over
- \code{codex-login}. It preserves honest Codex-compatible credential and token
- behavior rather than impersonating it from scratch.
- \item \code{epiphany-openai-codex-spine}: model transport over vendored Codex
- client machinery.
\item \code{epiphany-openai-runtime}: executable model runtime, including
\code{epiphany-model-runtime}.
+ \item \code{epiphany-release-construction}: exact package construction and
+ release-witness verification.
\item \code{epiphany-tool-adapter}: typed tool capability, invocation intent,
and invocation receipt documents.
- \item \code{epiphany-tool-codex-mcp-spine}: quarantined Codex MCP adapter. It
- consumes typed tool invocation intents and emits typed receipts; raw MCP JSON
- remains adapter-edge cargo.
+ \item \code{epiphany-tool-mcp-runtime}: first-party tool executor. Native
+ Epiphany source tools are explicit local capabilities; foreign MCP calls use
+ the official RMCP SDK behind Epiphany-owned endpoint, process, network, and
+ receipt policy. Codex owns no tool discovery or execution path.
\end{itemize}
The vendored region contains:
\begin{itemize}
- \item \code{vendor/codex}: the Codex-derived host and compatibility substrate.
- It is tracked directly, not as a submodule.
+ \item \code{vendor/codex}: retained Codex-fork source history. It is not in
+ Epiphany's compiled runtime graph.
\item \code{vendor/cultcache-rs}, \code{vendor/cultnet-rs}, and
\code{vendor/cultmesh-rs}: repo-contained Rust Cult substrate.
\end{itemize}
@@ -136,12 +127,11 @@ implementation, not file authority.
\hline
\code{state/map.yaml} & Canonical slow project map: objective, constraints, invariants, dataflow, active subgoals, current status, guardrails, and rejected paths. \\
\code{state/ledgers.cc} & CultCache-shaped evidence and branch ledger. Future behavior-changing lessons go here, not in an endless activity feed. \\
-\code{state/agents.cc} & Organ self-memory and Persona projection source. Resident work organs use \code{work_organ}; public/person-shaped agents use \code{persona}. \\
-\code{state/agent-heartbeats.cc} & Heartbeat initiative, cooldown, pending turns, cognition lanes, routine physiology, and scheduler pressure. \\
-\code{state/runtime-spine.cc} & Runtime identity, sessions, jobs, job results, events, worker launch requests, role/reorient findings, receipts, model/tool documents, and schema catalog surfaces. \\
-\code{state/thread-state.cc} & Native thread-state store. \\
+Resident Self store & Keyed pressure, grants, prepared and active launch authority, terminal receipts, and retention head. \\
+Persona social store & Keyed mentions, immutable turn requests, terminal receipts, quarantine records, and retention plans. \\
+\code{state/runtime-spine.cc} & Runtime identity, sessions, jobs, results, worker launch requests, receipts, and model/tool transport documents. Durable decisions and keyed RepoModel documents live in Mind. \\
\code{state/local-verse.cc} & Local CultMesh Verse context for compact operator and prompt-context packets. \\
-\code{state/memory-graph.cc} & Local memory graph store. \\
+\code{state/semantic-projection.cc} & Typed Qdrant projection receipts. Cache health lives here, outside the canonical RepoModel. \\
\code{state/persona-discord.toml} & Persona Discord boundary configuration. \\
\code{state/void-memory.toml} & Void memory bridge configuration. \\
\code{state/scratch.md} and \code{state/scratch-compaction-*.md} & Scratch surfaces. Scratch is a workbench, not canonical memory. \\
@@ -149,30 +139,18 @@ implementation, not file authority.
Lock files sit beside several stores. Some local generated state is currently
untracked, including \code{state/local-verse.cc},
-\code{state/memory-graph.cc}, and \code{.epiphany-character-loop/}.
+\code{state/semantic-projection.cc}, and \code{.epiphany-character-loop/}.
+The former sibling \code{state/memory-graph.cc}/\code{.msgpack} store is a
+retired migration wound; live Modeling truth is the runtime-spine RepoModel.
\section{CultNet Schema Body}
-The schema catalog in \code{schemas/cultnet/index.json} is the public nerve
-chart. Current local grouping from the catalog is approximately:
-
-\begin{itemize}
- \item 10 agent-state schemas;
- \item 5 heartbeat schemas;
- \item 21 intent schemas;
- \item 8 model/OpenAI schemas;
- \item 3 tool schemas;
- \item 6 runtime schemas;
- \item 17 surface schemas;
- \item 4 receipt/ledger schemas;
- \item 7 other schemas.
-\end{itemize}
-
-The catalog includes runtime identity/session/job/event/result documents, model
-requests and receipts, tool invocation intents and receipts, Persona and
-work-organ state, heartbeat state, operator CultMesh documents, scene/freshness
-/context/graph/pressure/reorient/roles/coordinator surfaces, Unity and Rider
-bridge surfaces, Void memory, and repo-initialization documents.
+The schema catalog in \code{schemas/cultnet/index.json} publishes the portable
+contracts actually carried across a CultNet boundary. Runtime-local CultCache
+registrations are discovered from the native registry instead of mirrored into
+a second hand-maintained catalog. Editor commands are not Epiphany contracts:
+Brokkr owns Unity editor inspection and actuation through Eve/CultMesh, and a
+future Rider provider must own Rider integration through the same boundary.
The invariant is simple: schema JSON describes the contract. Load-bearing
runtime state should be typed Rust documents persisted through CultCache or
@@ -185,19 +163,20 @@ publication, sealed forensic artifacts, or named quarantine experiments.
the Body. It imports and registers:
\begin{itemize}
- \item runtime identity, session, job, job-result, and event records;
+ \item runtime identity, session, job, and job-result records;
\item worker launch requests and role/reorient worker result documents;
\item model adapter, OpenAI adapter, and tool adapter documents;
- \item surface document types for scene, freshness, context, graph query,
- pressure, reorient, CRRC, jobs, roles, role result, reorient result,
- planning, coordinator, Persona, Void memory, repo initialization, repo birth
- runner, Rider bridge, and Unity bridge;
- \item organ receipts for Mind, Eyes, Hands, Soul, Continuity, and Substrate
- Gate;
- \item CultMesh operator status, snapshots, run intents, run receipts, Verse
- policy, global room policy, and organ contract documents.
+ \item sealed reasoning bases, decision contexts, typed pass failures, and
+ exact Mind commit receipts;
+ \item keyed RepoModel, frontier, planning, reorientation, and Persona
+ lifecycle documents;
+ \item exact Eyes, Hands, Soul, Continuity, and Substrate Gate receipts.
\end{itemize}
+Editor-provider capabilities remain outside this registry. Epiphany consumes
+their typed CultMesh state and receipts; it does not embed an IDE bridge or
+editor-specific lifecycle authority.
+
Runtime state is machinery telemetry. It is not project truth. Durable thread
state may link to runtime records through runtime links, but it must not mirror
or duplicate their lifecycle fields as a competing owner.
@@ -233,14 +212,12 @@ move through Substrate-Gate-scoped facts, Mind state, social stimulus, organ
dependencies, Imagination as Projector, Persona as natural-language actor, and
Mind as Interpreter. None of those steps grants Persona hidden state authority.
-\section{Bridge And Codex Reliquary}
+\section{Codex Reliquary}
-\code{epiphany-codex-bridge} states its boundary plainly: it translates Codex
-\code{ThreadEpiphany*} DTOs into Epiphany core documents, projects typed
-Epiphany surfaces back into legacy Codex responses, and calls narrow host traits
-while Codex still owns some thread persistence. It must not own verdicts,
-launch policy, reorientation policy, acceptance rules, runtime-spine lifecycle,
-or durable invariants.
+Epiphany publishes no app-server JSON-RPC state surface. Vendored Codex owns
+only Codex concerns and the retained OpenAI-compatible auth/model transport
+machinery. Epiphany state, prompts, scheduling, interfaces, and durable
+invariants remain native typed organs.
The retained Codex body currently matters for:
@@ -261,17 +238,13 @@ truth, operator API owner, or plugin marketplace brain.
Current operator access is partly native and partly witness-artifact based:
\begin{itemize}
- \item \code{tools/epiphany_local_run.ps1} is the one-command local operator
- wrapper.
- \item Native binaries such as \code{epiphany-mvp-status},
- \code{epiphany-mvp-coordinator}, \code{epiphany-verse-query},
- \code{epiphany-operator-run}, \code{epiphany-operator-snapshot},
- \code{epiphany-eve-surface}, \code{epiphany-runtime-spine},
- \code{epiphany-heartbeat-store}, and \code{epiphany-agent-memory-store}
- inspect or update typed state.
+ \item Native binaries such as \code{epiphany-state},
+ \code{epiphany-mvp-coordinator}, \code{epiphany-runtime-spine},
+ \code{epiphany-swarm}, and the family-specific worker services
+ inspect or update their owned typed state.
\item Local artifact directories such as \code{.epiphany-run/},
\code{.epiphany-dogfood/}, \code{.epiphany-smoke/},
- \code{.epiphany-rumination/}, \code{.epiphany-gui/}, and
+ \code{.epiphany-gui/}, and
\code{.epiphany-character-loop/} witness work and lower typed state for
operator inspection.
\item Aquarium is the richer adjacent operator client. It should render and
@@ -318,9 +291,10 @@ Proprioception refresh.
\subsection{Tool Calls}
Tool use travels through typed capability, invocation intent, and invocation
-receipt documents. The Codex MCP adapter is an external compatibility executor.
-MCP's raw JSON belongs at that boundary; Epiphany's internal tool state is the
-typed intent/receipt pair.
+receipt documents. The first-party tool runtime owns admission policy, native
+tools, and typed receipts while the official RMCP SDK owns MCP lifecycle and
+wire behavior. MCP's raw JSON belongs at that boundary; Epiphany's internal
+tool state is the typed intent/receipt pair.
\subsection{Local Verse And Daemon Awareness}
diff --git a/docs/epiphany_investor_brief.md b/docs/epiphany_investor_brief.md
new file mode 100644
index 00000000..cbd5c556
--- /dev/null
+++ b/docs/epiphany_investor_brief.md
@@ -0,0 +1,220 @@
+# Epiphany Investor Brief
+
+Status: August 2026 discussion packet; maturity: supervised engineering alpha
+Audience: investors, design partners, and diligence reviewers
+
+## One Sentence
+
+Epiphany is the organizational layer above frontier AI workers: governed shared
+state, bounded authority, coordinated action, and inspectable receipts for work
+that must remain coherent beyond one prompt, one agent, or one session.
+
+## Why It Matters
+
+Frontier coding agents can produce plausible local edits after the project has
+lost a valid global model. Code compiles. Narrow tests pass. Each decision sounds
+reasonable. The organization still accumulates stale assumptions, split
+authority, contradictory decisions, and adapter sediment.
+
+This is global coherence collapse, not merely context-window exhaustion. A
+larger window can remember more fragments without deciding which fragment owns
+reality.
+
+Epiphany turns the missing organizational state into governed objects:
+
+- objectives, work, architecture, and dataflow maps
+- accepted decisions and unresolved conflicts
+- scratch separated from durable memory
+- source-grounded evidence and explicit uncertainty
+- role lanes for execution, modeling, research, verification, planning,
+ Persona, and reorientation
+- bounded tool, model, command, patch, and commit authority
+- review gates before findings become project truth
+- operator-safe artifacts that do not expose private worker context
+
+Prompts are bounded projections of that state. They are not the organization's
+memory or the worker's private property.
+
+## Product Category
+
+Epiphany does not compete with frontier labs at the intelligence layer. Codex
+and other capable agents are workers. Epiphany is the coordination and
+governance layer that answers:
+
+- What does the organization currently believe?
+- What work is active, and who may change which state?
+- How are contradictory decisions reconciled?
+- Where must uncertainty return to human judgment?
+- How does an accepted artifact trace back to work, evidence, execution, and
+ review?
+
+The operating loop is:
+
+```text
+governed organizational state
+-> scoped Epiphany work
+-> frontier model and tool execution
+-> artifacts, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted knowledge and updated organizational state
+```
+
+The target promise is that organizations can delegate bounded work to capable
+AI without turning every employee into an AI operator.
+
+## Human Authority
+
+Humans remain participants in judgment and governance. They own purpose,
+values, authority, exceptions, acceptance, disagreement, and ambiguous
+tradeoffs. They should not become schedulers who repeatedly reconstruct context
+and type `Continue`.
+
+Agents own bounded execution. They continue when shared state, authority, and
+evidence justify the next move. They escalate when authority is missing, state
+conflicts, or a consequential judgment cannot be derived honestly.
+
+## What Exists Now
+
+The current native Epiphany body includes:
+
+- typed Rust domain organs owned by `epiphany-core`
+- keyed Mind state with typed projection and promotion paths
+- RepoModel and Model Atlas surfaces for source-grounded architectural belief
+- CultCache `.cc` state and CultMesh/CultNet contracts
+- provider-neutral model request, event, and receipt documents
+- typed tool capability, invocation-intent, and invocation-receipt documents
+- runtime-spine job and worker-result documents
+- Mind, Modeling, Substrate Gate, Eyes, Hands, Soul, Continuity, Persona, and
+ heartbeat authority surfaces
+- local operator status, coordinator, and Verse-context commands
+
+Codex is retained only for OpenAI authentication and model transport. Epiphany
+does not publish Codex app-server state as its project Mind.
+
+The mechanisms are locally verifiable. Sustained autonomous GameCult production
+and complete attribution across every mutation path are not yet proven.
+
+## GameCult As The Proof Program
+
+GameCult's games, creative tools, and infrastructure are the dogfood surface.
+Aetheria, StreamPixels, CultPong, Repixelizer, and the wider studio exercise
+different parts of the same production system: games, realtime services,
+creator tooling, art pipelines, identity, deployment, community memory, and
+long-lived architecture.
+
+The target operating body is federated: one locally owned Epiphany project
+organism per project Body, normally a repo-owned swarm with a private Mind and
+one or more project-facing Personas. Project organisms exchange typed offers,
+claims, requests, evidence, and receipts; none receives ambient authority to
+inspect or change a sibling project. This creates a swarm-of-swarms proof
+surface instead of one central agent with a studio-sized prompt.
+
+The longer social direction is for project Personas to maintain durable,
+publicly visible relationships with other Personas, contributors, players, and
+visitors. Public surfaces may support observation, conversation, and submitted
+evidence or proposals. They must not expose private Mind or turn popularity,
+repetition, or relationship into admission or execution authority. The current
+alpha does not yet provide the full fleet, visitor experience, or social
+governance rail. Any remembered relationship requires opt-in, visible retention
+limits, inspection, correction, revocation, and exit.
+
+The diligence artifact should therefore be longitudinal rather than a polished
+single demo. It should preserve:
+
+```text
+work item and decisions
+-> producing agent and execution
+-> artifacts, commits, evidence, and receipts
+-> human questions and answers
+-> review and acceptance
+-> cost, failure, recovery, and lessons
+```
+
+Useful measures include accepted work between synchronous interventions, time
+spent on judgment versus scheduling, bad assumptions escalated early, review
+burden, cost per accepted artifact, failure recovery, architectural coherence,
+and attribution completeness. Agent-written commit percentage is not a useful
+substitute for this evidence.
+
+## Where Bifrost Fits
+
+Bifrost is the intended governed work and attribution rail. Epiphany owns
+bounded execution, typed project memory, coordination, evidence, and
+verification pressure. Bifrost owns work records, dispatch, identity-linked
+receipts, review outcomes, credit, and governance.
+
+The target invariant is:
+
+> Every admitted mutation of governed project state has an attributable
+> mutation receipt naming its actor, authority, basis, and outcome. An
+> agent-caused mutation also links its exact execution receipt.
+
+The complete agent-execution chain should connect an accepted artifact or commit to the
+producing agent, authorizing or accepting human, Bifrost execution, work item,
+decisions, evidence, model and provider, tools and material commands, repository
+and worktree, and review outcome.
+
+A Git object hash makes later changes detectable. A valid commit signature
+links those commit bytes to a trusted signing key. Neither proves correctness,
+execution authority, or complete provenance. The full chain remains an
+engineering and dogfood target, not a completed claim.
+
+## Near-Term Commercial Offer
+
+The planned offer, after the Bifrost bridge and longitudinal GameCult dogfood
+clear their gates, is a supervised co-development pilot: one repository, one
+repeatable workflow, and a two-to-four-week proof period. The deliverable would
+be a working setup plus evidence about:
+
+- output quality and accepted artifacts
+- human scheduling and review burden
+- authority and attribution coverage
+- failure modes and recovery
+- model and tool cost
+- architectural coherence across repeated work
+
+That is narrow enough to falsify and useful enough to reveal whether Epiphany
+reduces coordination load while preserving human authority.
+
+## Proof To Ask For
+
+1. Repeated GameCult work showing governed scope, decisions, execution,
+ artifacts, review, failures, and recovery across product boundaries.
+2. Bifrost work and attribution proof from accepted artifact back to identity,
+ authority, evidence, model, tools, and review.
+3. Human-intervention accounting that separates scheduling and cleanup from
+ product, architecture, governance, and acceptance judgment.
+4. Cost accounting for model spend, role time, review load, accepted artifacts,
+ and rejected-output reasons.
+5. Public/private export proof: no raw worker thoughts, transcripts, private
+ notes, secrets, or operator context in public artifacts.
+6. Security proof for identity, secrets, write permissions, revocation,
+ external-repo access, and publishing.
+7. A bounded design-partner run on an external or semi-external repository
+ without supervisor contamination.
+
+## Evidence Boundary
+
+Epiphany is a supervised engineering alpha. It should not be presented as
+production-ready, fully autonomous, fully attributable, model-independent, or
+a solved form of organizational intelligence. Inspectability enables
+accountability only when authority, review, and consequence are also real.
+
+## Packet Contents
+
+- `docs/positioning.md`: current category, proof model, and claims boundary.
+- `docs/epiphany_body_whitepaper.pdf`: June 2026 architecture snapshot;
+ historical, not the current product contract.
+- `notes/epiphany-investor-readiness-roadmap.md`: internal readiness roadmap.
+- `notes/epiphany-current-algorithmic-map.md`: current native control flow.
+- `state/map.yaml`: canonical slow machine map and verification status.
+- `F:\Projects\gamecult-site\GameCult\Projects\Epiphany.md`: public site
+ projection.
+
+## Bottom Line
+
+Epiphany is valuable if capable AI workers can complete increasingly long runs
+of accepted work without humans becoming pulse operators, while the
+organization retains judgment, authority, architectural coherence, and a
+traceable account of what happened. GameCult is building that evidence in real
+products before asking anyone to confuse ambition with proof.
diff --git a/docs/positioning.md b/docs/positioning.md
new file mode 100644
index 00000000..188d75a0
--- /dev/null
+++ b/docs/positioning.md
@@ -0,0 +1,191 @@
+# Epiphany Positioning
+
+Status: August 2026 public positioning; maturity: supervised engineering alpha
+
+## One Sentence
+
+Epiphany is the organizational layer above frontier AI workers: governed shared
+state, bounded authority, coordinated action, and inspectable receipts for work
+that must remain coherent beyond one prompt, one agent, or one session.
+
+## The Problem
+
+Frontier agents can keep producing good-looking local progress after the
+architecture has stopped making sense. They can write valid code, pass narrow
+tests, explain each decision, and still leave behind split authority, stale
+assumptions, and a growing stack of compensators.
+
+That is global coherence collapse. It is not merely context-window exhaustion.
+A larger window can hold more contradictory state just as efficiently.
+
+Epiphany treats the project as an organization with a durable Mind rather than
+as a sequence of private conversations. Objectives, architecture, decisions,
+permissions, evidence, work, and review live in governed state. Model prompts
+are bounded projections of that state. They are not the state itself.
+
+## The Category
+
+Epiphany is not a better autocomplete, a prompt manager, or a model competing
+with frontier labs. Frontier models are workers. Epiphany is the coordination
+and governance system that tells those workers what the organization currently
+believes, what they may change, what evidence they owe, and where uncertainty
+must return to human judgment.
+
+```text
+governed organizational state
+-> scoped Epiphany work
+-> frontier model and tool execution
+-> artifacts, evidence, and receipts
+-> review under human-governed acceptance authority
+-> accepted knowledge and updated organizational state
+```
+
+This is the target promise:
+
+> Epiphany is being built so organizations can delegate bounded work to
+> capable AI without turning every employee into an AI operator.
+
+## The Division Of Labor
+
+Humans own purpose, values, authority, exceptions, acceptance, disagreement,
+and ambiguous tradeoffs. They participate in governance and judgment; they
+should not spend the day scheduling agents, reconstructing context, and typing
+`Continue` into a row of private prompt boxes.
+
+Agents own bounded execution. They can continue while shared state, authority,
+and evidence justify the next action. When the machine is missing authority,
+encounters a real conflict, or cannot reconcile its model with the substrate,
+it escalates through the same visible work and discussion surfaces used by the
+organization.
+
+Direct conversation remains useful. It is an input and relationship surface,
+not the hidden operating system.
+
+## Why Not Just Use Codex?
+
+Codex and other frontier coding agents can be excellent workers. Epiphany is
+built around the questions worker quality does not answer:
+
+- Who tells the workers what reality currently is?
+- Which state is durable, and who may change it?
+- How are contradictory decisions reconciled?
+- Where does human authority enter without becoming constant supervision?
+- Can an accepted artifact be traced back to its work item, decisions,
+ evidence, model and tool activity, and review?
+
+Epiphany retains Codex only where Codex has an honest ownership claim—OpenAI
+authentication and model transport. Epiphany owns the project Mind,
+coordination, typed execution state, receipts, and review pressure.
+
+## GameCult Is The Proof Surface
+
+GameCult does not treat its games, creative tools, and infrastructure as a
+separate portfolio beside Epiphany. Shipping them is the dogfood program.
+Aetheria, StreamPixels, CultPong, Repixelizer, and the rest of the studio place
+different pressure on the same production system: realtime services, games,
+art pipelines, identity, deployment, community memory, and long-lived
+architecture.
+
+The credible artifact is longitudinal. It should show work items, questions,
+human decisions, propagation of those decisions, commits, reviews, cost,
+failures, and recovery across real releases. Failures belong in the record;
+otherwise the record is advertising with nicer timestamps.
+
+Useful measures include:
+
+- accepted work completed between synchronous human interventions
+- human time spent on judgment versus scheduling and cleanup
+- assumptions escalated before they became expensive edits
+- architectural reversals or restructures caught and carried coherently
+- review burden and cost per accepted artifact
+- attribution completeness from accepted artifact back to governed work
+- whether intervention shifts over time from pulse maintenance toward product,
+ architecture, and governance decisions
+
+Commit percentages and prompt counts are weak proxies. The target is not fewer
+humans. It is better use of human judgment.
+
+## The GameCult Forge
+
+The intended GameCult topology is a federation of Epiphany project organisms:
+one locally owned organism per living project Body, normally a repo-owned swarm
+with a private Mind, bounded organs, and one or more project-facing Personas.
+There is no central Epiphany entitled to treat every repository as its Body.
+
+Project organisms collaborate through governed typed surfaces. Model Atlas
+carries provider-owned offers, consumer-owned claims, exact Soul evidence, and
+derived technical relationships without allowing one Epiphany to read or write
+another's Mind. Bifrost is the intended external work, membership, governance,
+attribution, and identity-linked receipt rail; Heimdall owns identity, grants,
+sessions, consent, and revocation. Relationship or visibility never grants
+Hands authority.
+
+The social direction is public and relational. Project Personas should form
+durable relationships with one another and with contributors, players, and
+visitors: attributable histories of cooperation, disagreement, promises,
+reputation, correction, and recourse. Visitors should be able to observe
+deliberate public projections, converse, and offer evidence or proposals. Raw
+worker thought, private Mind, secrets, personal context, and non-consenting
+people remain sealed. Remembered relationships require opt-in, visible
+retention limits, inspection, correction, revocation, and exit. Public input is
+pressure until local review authorizes or rejects it; Mind alone admits any
+authorized durable mutation.
+
+This swarm of swarms is where GameCult expects higher-order organizational
+behavior to emerge. It is a target topology, not a deployed-fleet claim. The
+current alpha has locally verified project-local authority and Model Atlas
+mechanisms; the real three-repository Gate 1, sustained GameCult fleet, public
+rooms, visitor experience, and durable social-governance rail still have to be
+forged in use.
+
+## Attribution And Bifrost
+
+Bifrost is the intended governed work and attribution rail. The target
+invariant is:
+
+> Every admitted mutation of governed project state has an attributable
+> mutation receipt naming its actor, authority, basis, and outcome. An
+> agent-caused mutation also links its exact execution receipt.
+
+An eventual agent-execution chain should connect:
+
+```text
+accepted artifact or commit
+-> producing agent and authorizing or accepting human
+-> Bifrost execution and work item
+-> decisions, questions, and evidence
+-> model, provider, tools, material commands, repo, and worktree
+-> review and acceptance outcome
+```
+
+A Git object hash makes later changes detectable. A valid commit signature
+links those commit bytes to a trusted signing key. Neither proves correctness,
+execution authority, or complete provenance. Epiphany and Bifrost must make the
+missing authority and provenance legible. This chain is the target
+architecture; the supervised alpha has not yet proved complete coverage across
+every mutation path.
+
+## Near-Term Offer
+
+The planned commercial offer, after the Bifrost bridge and longitudinal
+GameCult dogfood clear their gates, is a supervised co-development pilot: one
+repository, one repeatable workflow, and a two-to-four-week proof period. The
+deliverable would be a working setup plus evidence about output quality, review
+burden, failure modes, attribution, and cost.
+
+That is enough to learn whether Epiphany reduces coordination load while
+preserving human authority. It is also narrow enough that everyone can see when
+the claim fails.
+
+## Evidence Boundary
+
+Epiphany is a supervised engineering alpha. Its typed Mind, role boundaries,
+projection, execution, receipt, verification, and operator surfaces exist and
+are under active dogfood. Sustained autonomous GameCult production and the full
+Bifrost attribution chain have not yet been earned.
+
+Public claims should therefore say what the machine is built to do, identify
+what has been locally verified, and name the proof still required. Do not call
+Epiphany production-ready, fully autonomous, fully attributable, or a solved
+form of organizational intelligence until longitudinal evidence makes those
+phrases boringly true.
diff --git a/epiphany-codex-bridge/Cargo.toml b/epiphany-codex-bridge/Cargo.toml
deleted file mode 100644
index d546ce42..00000000
--- a/epiphany-codex-bridge/Cargo.toml
+++ /dev/null
@@ -1,35 +0,0 @@
-[package]
-name = "epiphany-codex-bridge"
-version = "0.1.0"
-edition = "2024"
-publish = false
-license-file = "../LICENSE"
-
-[lib]
-name = "epiphany_codex_bridge"
-path = "src/lib.rs"
-
-[dependencies]
-anyhow = "1"
-chrono = { version = "0.4", default-features = false, features = ["clock", "serde"] }
-codex-app-server-protocol = { path = "../vendor/codex/codex-rs/app-server-protocol" }
-codex-utils-absolute-path = { path = "../vendor/codex/codex-rs/utils/absolute-path" }
-# Keep standalone bridge checks aligned with the vendored Codex workspace lock.
-# `starlark_map 0.13.0` does not compile against newer allocative/hashbrown
-# resolver choices on this machine.
-allocative = "=0.3.4"
-epiphany-core = { path = "../epiphany-core" }
-epiphany-state-model = { path = "../epiphany-state-model" }
-notify = "8.2.0"
-serde_json = "1"
-serde = { version = "1", features = ["derive"] }
-tokio = { version = "1", features = ["rt", "sync"] }
-tracing = "0.1"
-uuid = { version = "1", features = ["v4"] }
-
-[patch.crates-io]
-tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "132f5b39c862e3a970f731d709608b3e6276d5f6" }
-tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
-
-[patch."ssh://git@github.com/openai-oss-forks/tungstenite-rs.git"]
-tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
diff --git a/epiphany-codex-bridge/src/checkpoint.rs b/epiphany-codex-bridge/src/checkpoint.rs
deleted file mode 100644
index f50c6be2..00000000
--- a/epiphany-codex-bridge/src/checkpoint.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#[derive(Default)]
-pub struct EpiphanyCheckpointInterventionState {
- last_intervention_turn_id: Option,
- pending_compaction_turn_id: Option,
-}
-
-impl EpiphanyCheckpointInterventionState {
- pub fn record_intervention(&mut self, turn_id: &str) -> bool {
- if self.last_intervention_turn_id.as_deref() == Some(turn_id) {
- return false;
- }
- self.last_intervention_turn_id = Some(turn_id.to_string());
- true
- }
-
- pub fn mark_pending_compaction(&mut self, turn_id: &str) {
- self.pending_compaction_turn_id = Some(turn_id.to_string());
- }
-
- pub fn take_pending_compaction(&mut self, turn_id: &str) -> bool {
- if self.pending_compaction_turn_id.as_deref() != Some(turn_id) {
- return false;
- }
- self.pending_compaction_turn_id = None;
- true
- }
-
- pub fn clear_pending_compaction(&mut self) {
- self.pending_compaction_turn_id = None;
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::EpiphanyCheckpointInterventionState;
-
- #[test]
- fn pending_compaction_is_turn_scoped() {
- let mut state = EpiphanyCheckpointInterventionState::default();
-
- assert!(state.record_intervention("turn-a"));
- assert!(!state.record_intervention("turn-a"));
- assert!(!state.take_pending_compaction("turn-a"));
-
- state.mark_pending_compaction("turn-a");
-
- assert!(!state.take_pending_compaction("turn-b"));
- assert!(state.take_pending_compaction("turn-a"));
- assert!(!state.take_pending_compaction("turn-a"));
- }
-
- #[test]
- fn pending_compaction_can_be_cleared() {
- let mut state = EpiphanyCheckpointInterventionState::default();
-
- state.mark_pending_compaction("turn-a");
- state.clear_pending_compaction();
-
- assert!(!state.take_pending_compaction("turn-a"));
- }
-}
diff --git a/epiphany-codex-bridge/src/context.rs b/epiphany-codex-bridge/src/context.rs
deleted file mode 100644
index b1d4e3ce..00000000
--- a/epiphany-codex-bridge/src/context.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use epiphany_core::EpiphanyContextParams;
-use epiphany_core::EpiphanyContextView;
-use epiphany_core::EpiphanyGraphQuery;
-use epiphany_core::EpiphanyGraphQueryView;
-use epiphany_core::EpiphanyPlanningView;
-use epiphany_core::derive_context;
-use epiphany_core::derive_graph_query;
-use epiphany_core::derive_planning_view;
-use epiphany_state_model::EpiphanyThreadState;
-
-pub fn derive_epiphany_context(
- state: Option<&EpiphanyThreadState>,
- params: &EpiphanyContextParams,
-) -> EpiphanyContextView {
- derive_context(state, params)
-}
-
-pub fn derive_epiphany_planning(state: Option<&EpiphanyThreadState>) -> EpiphanyPlanningView {
- derive_planning_view(state)
-}
-
-pub fn derive_epiphany_graph_query(
- state: Option<&EpiphanyThreadState>,
- query: &EpiphanyGraphQuery,
-) -> EpiphanyGraphQueryView {
- derive_graph_query(state, query)
-}
diff --git a/epiphany-codex-bridge/src/context_protocol.rs b/epiphany-codex-bridge/src/context_protocol.rs
deleted file mode 100644
index 949fab3a..00000000
--- a/epiphany-codex-bridge/src/context_protocol.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use codex_app_server_protocol::ThreadEpiphanyContext;
-use codex_app_server_protocol::ThreadEpiphanyContextMissing;
-use codex_app_server_protocol::ThreadEpiphanyContextStateStatus;
-use codex_app_server_protocol::ThreadEpiphanyGraphContext;
-use codex_app_server_protocol::ThreadEpiphanyGraphQueryMatched;
-use codex_app_server_protocol::ThreadEpiphanyGraphQueryMissing;
-use codex_app_server_protocol::ThreadEpiphanyPlanningSummary;
-use epiphany_core::EpiphanyContext as CoreEpiphanyContext;
-use epiphany_core::EpiphanyContextMissing as CoreEpiphanyContextMissing;
-use epiphany_core::EpiphanyContextStateStatus as CoreEpiphanyContextStateStatus;
-use epiphany_core::EpiphanyContextView;
-use epiphany_core::EpiphanyGraphContext as CoreEpiphanyGraphContext;
-use epiphany_core::EpiphanyGraphQueryMatched as CoreEpiphanyGraphQueryMatched;
-use epiphany_core::EpiphanyGraphQueryMissing as CoreEpiphanyGraphQueryMissing;
-use epiphany_core::EpiphanyGraphQueryView;
-use epiphany_core::EpiphanyPlanningStateStatus as CoreEpiphanyPlanningStateStatus;
-use epiphany_core::EpiphanyPlanningSummary as CoreEpiphanyPlanningSummary;
-use epiphany_core::EpiphanyPlanningView;
-use epiphany_state_model::EpiphanyGraphCheckpoint;
-use epiphany_state_model::EpiphanyGraphFrontier;
-use epiphany_state_model::EpiphanyPlanningState;
-
-pub fn protocol_context_view(
- view: EpiphanyContextView,
-) -> (
- ThreadEpiphanyContextStateStatus,
- Option,
- ThreadEpiphanyContext,
- ThreadEpiphanyContextMissing,
-) {
- (
- protocol_context_state_status(view.state_status),
- view.state_revision,
- protocol_context(view.context),
- protocol_context_missing(view.missing),
- )
-}
-
-pub fn protocol_context_state_status(
- status: CoreEpiphanyContextStateStatus,
-) -> ThreadEpiphanyContextStateStatus {
- match status {
- CoreEpiphanyContextStateStatus::Missing => ThreadEpiphanyContextStateStatus::Missing,
- CoreEpiphanyContextStateStatus::Ready => ThreadEpiphanyContextStateStatus::Ready,
- }
-}
-
-fn protocol_context(context: CoreEpiphanyContext) -> ThreadEpiphanyContext {
- ThreadEpiphanyContext {
- graph: protocol_graph_context(context.graph),
- frontier: context.frontier,
- checkpoint: context.checkpoint,
- investigation_checkpoint: context.investigation_checkpoint,
- observations: context.observations,
- evidence: context.evidence,
- }
-}
-
-pub fn protocol_graph_context(graph: CoreEpiphanyGraphContext) -> ThreadEpiphanyGraphContext {
- ThreadEpiphanyGraphContext {
- architecture_nodes: graph.architecture_nodes,
- architecture_edges: graph.architecture_edges,
- dataflow_nodes: graph.dataflow_nodes,
- dataflow_edges: graph.dataflow_edges,
- links: graph.links,
- }
-}
-
-fn protocol_context_missing(missing: CoreEpiphanyContextMissing) -> ThreadEpiphanyContextMissing {
- ThreadEpiphanyContextMissing {
- graph_node_ids: missing.graph_node_ids,
- graph_edge_ids: missing.graph_edge_ids,
- observation_ids: missing.observation_ids,
- evidence_ids: missing.evidence_ids,
- }
-}
-
-pub fn protocol_planning_view(
- view: EpiphanyPlanningView,
-) -> (
- ThreadEpiphanyContextStateStatus,
- Option,
- EpiphanyPlanningState,
- ThreadEpiphanyPlanningSummary,
-) {
- (
- match view.state_status {
- CoreEpiphanyPlanningStateStatus::Missing => ThreadEpiphanyContextStateStatus::Missing,
- CoreEpiphanyPlanningStateStatus::Ready => ThreadEpiphanyContextStateStatus::Ready,
- },
- view.state_revision,
- view.planning,
- protocol_planning_summary(view.summary),
- )
-}
-
-fn protocol_planning_summary(
- summary: CoreEpiphanyPlanningSummary,
-) -> ThreadEpiphanyPlanningSummary {
- ThreadEpiphanyPlanningSummary {
- capture_count: summary.capture_count,
- pending_capture_count: summary.pending_capture_count,
- github_issue_capture_count: summary.github_issue_capture_count,
- backlog_item_count: summary.backlog_item_count,
- ready_backlog_item_count: summary.ready_backlog_item_count,
- roadmap_stream_count: summary.roadmap_stream_count,
- objective_draft_count: summary.objective_draft_count,
- draft_objective_count: summary.draft_objective_count,
- active_objective: summary.active_objective,
- note: summary.note,
- }
-}
-
-pub fn protocol_graph_query_view(
- view: EpiphanyGraphQueryView,
-) -> (
- ThreadEpiphanyContextStateStatus,
- Option,
- ThreadEpiphanyGraphContext,
- Option,
- Option,
- ThreadEpiphanyGraphQueryMatched,
- ThreadEpiphanyGraphQueryMissing,
-) {
- (
- protocol_context_state_status(view.state_status),
- view.state_revision,
- protocol_graph_context(view.graph),
- view.frontier,
- view.checkpoint,
- protocol_graph_query_matched(view.matched),
- protocol_graph_query_missing(view.missing),
- )
-}
-
-fn protocol_graph_query_matched(
- matched: CoreEpiphanyGraphQueryMatched,
-) -> ThreadEpiphanyGraphQueryMatched {
- ThreadEpiphanyGraphQueryMatched {
- node_ids: matched.node_ids,
- edge_ids: matched.edge_ids,
- paths: matched.paths,
- symbols: matched.symbols,
- edge_kinds: matched.edge_kinds,
- }
-}
-
-fn protocol_graph_query_missing(
- missing: CoreEpiphanyGraphQueryMissing,
-) -> ThreadEpiphanyGraphQueryMissing {
- ThreadEpiphanyGraphQueryMissing {
- node_ids: missing.node_ids,
- edge_ids: missing.edge_ids,
- }
-}
diff --git a/epiphany-codex-bridge/src/coordinator.rs b/epiphany-codex-bridge/src/coordinator.rs
deleted file mode 100644
index 1e1fd4be..00000000
--- a/epiphany-codex-bridge/src/coordinator.rs
+++ /dev/null
@@ -1,601 +0,0 @@
-use epiphany_core::EPIPHANY_IMAGINATION_OWNER_ROLE;
-use epiphany_core::EPIPHANY_IMAGINATION_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_IMPLEMENTATION_OWNER_ROLE;
-use epiphany_core::EPIPHANY_IMPLEMENTATION_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_MODELING_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
-use epiphany_core::EPIPHANY_REORIENT_OWNER_ROLE;
-use epiphany_core::EPIPHANY_RESEARCH_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_VERIFICATION_ROLE_BINDING_ID;
-use epiphany_core::EpiphanyCoordinatorAutomationAction as CoreEpiphanyCoordinatorAutomationAction;
-use epiphany_core::EpiphanyCoordinatorDecision as CoreEpiphanyCoordinatorDecision;
-use epiphany_core::EpiphanyCoordinatorRoleResultStatus as CoreEpiphanyCoordinatorRoleResultStatus;
-use epiphany_core::EpiphanyCoordinatorStatus as CoreEpiphanyCoordinatorStatus;
-use epiphany_core::EpiphanyCoordinatorStatusInput;
-use epiphany_core::EpiphanyCrrcAction as CoreEpiphanyCrrcAction;
-use epiphany_core::EpiphanyCrrcInput;
-use epiphany_core::EpiphanyCrrcRecommendation as CoreEpiphanyCrrcRecommendation;
-use epiphany_core::EpiphanyCrrcReorientAction as CoreEpiphanyCrrcReorientAction;
-use epiphany_core::EpiphanyCrrcResultStatus as CoreEpiphanyCrrcResultStatus;
-use epiphany_core::EpiphanyCrrcStateStatus as CoreEpiphanyCrrcStateStatus;
-use epiphany_core::EpiphanyJobLaunchRequest;
-use epiphany_core::EpiphanyJobStatus as CoreEpiphanyJobStatus;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyReorientAction as CoreEpiphanyReorientAction;
-use epiphany_core::EpiphanyReorientDecision as CoreEpiphanyReorientDecision;
-use epiphany_core::EpiphanyReorientFindingInterpretation as CoreEpiphanyReorientFinding;
-use epiphany_core::EpiphanyReorientStateStatus as CoreEpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRoleBoardCheckpointSummary;
-use epiphany_core::EpiphanyRoleBoardInput;
-use epiphany_core::EpiphanyRoleBoardJob;
-use epiphany_core::EpiphanyRoleBoardJobStatus;
-use epiphany_core::EpiphanyRoleBoardLane;
-use epiphany_core::EpiphanyRoleBoardPlanningSummary;
-use epiphany_core::EpiphanyRoleResultRoleId;
-use epiphany_core::EpiphanyTokenUsageSnapshot;
-use epiphany_core::build_epiphany_reorient_launch_request_with_dynamic_context;
-use epiphany_core::derive_coordinator_finding_signals;
-use epiphany_core::derive_coordinator_status;
-use epiphany_core::derive_role_board;
-use epiphany_core::recommend_crrc_action;
-use epiphany_core::render_epiphany_coordinator_note;
-use epiphany_core::render_role_board_note;
-use epiphany_core::reorient_finding_already_accepted;
-use epiphany_core::select_coordinator_automation_action;
-use epiphany_state_model::EpiphanyRetrievalState;
-use epiphany_state_model::EpiphanyThreadState;
-
-use crate::launch_context::render_launch_dynamic_prompt_context;
-use crate::launch_context::reorient_launch_context_focus;
-use crate::pressure::derive_epiphany_pressure;
-use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
-use crate::reorient::derive_epiphany_freshness_view;
-use crate::reorient::derive_epiphany_reorient;
-use crate::runtime_results::load_core_epiphany_reorient_result_snapshot;
-use crate::runtime_results::load_core_epiphany_role_result_snapshot;
-
-use std::path::Path;
-
-pub fn map_epiphany_crrc_recommendation(
- loaded: bool,
- state_status: CoreEpiphanyReorientStateStatus,
- pressure: &epiphany_core::EpiphanyPressure,
- decision: &CoreEpiphanyReorientDecision,
- result_status: CoreEpiphanyCrrcResultStatus,
- checkpoint_present: bool,
- finding_present: bool,
- finding_accepted: bool,
-) -> CoreEpiphanyCrrcRecommendation {
- recommend_crrc_action(EpiphanyCrrcInput {
- loaded,
- state_status: map_core_crrc_state_status_from_reorient(state_status),
- should_prepare_compaction: pressure.should_prepare_compaction,
- reorient_action: map_core_crrc_reorient_action(decision.action),
- result_status,
- checkpoint_present,
- finding_present,
- finding_accepted,
- })
-}
-
-fn map_core_crrc_state_status_from_reorient(
- status: CoreEpiphanyReorientStateStatus,
-) -> CoreEpiphanyCrrcStateStatus {
- match status {
- CoreEpiphanyReorientStateStatus::Missing => CoreEpiphanyCrrcStateStatus::Missing,
- CoreEpiphanyReorientStateStatus::Ready => CoreEpiphanyCrrcStateStatus::Ready,
- }
-}
-
-fn map_core_crrc_reorient_action(
- action: CoreEpiphanyReorientAction,
-) -> CoreEpiphanyCrrcReorientAction {
- match action {
- CoreEpiphanyReorientAction::Resume => CoreEpiphanyCrrcReorientAction::Resume,
- CoreEpiphanyReorientAction::Regather => CoreEpiphanyCrrcReorientAction::Regather,
- }
-}
-
-pub type EpiphanyCoordinatorDecision = CoreEpiphanyCoordinatorDecision;
-
-pub struct EpiphanyCoordinatorStatus {
- pub core: CoreEpiphanyCoordinatorStatus,
- pub note: String,
-}
-
-pub async fn derive_epiphany_coordinator_status(
- state: Option<&EpiphanyThreadState>,
- runtime_store_path: Option<&Path>,
- state_status: CoreEpiphanyReorientStateStatus,
- pressure: &epiphany_core::EpiphanyPressure,
- recommendation: &CoreEpiphanyCrrcRecommendation,
- roles: Vec,
- reorient_decision: Option<&CoreEpiphanyReorientDecision>,
- reorient_result_status: CoreEpiphanyCrrcResultStatus,
- reorient_finding: Option<&CoreEpiphanyReorientFinding>,
- checkpoint_present: bool,
-) -> EpiphanyCoordinatorStatus {
- let (modeling_result_status, modeling_finding) = if let Some(state) = state {
- let snapshot = load_core_epiphany_role_result_snapshot(
- state,
- runtime_store_path,
- EpiphanyRoleResultRoleId::Modeling,
- EPIPHANY_MODELING_ROLE_BINDING_ID,
- )
- .await;
- (snapshot.status, snapshot.finding)
- } else {
- (CoreEpiphanyCoordinatorRoleResultStatus::MissingState, None)
- };
- let (research_result_status, research_finding) = if let Some(state) = state {
- let snapshot = load_core_epiphany_role_result_snapshot(
- state,
- runtime_store_path,
- EpiphanyRoleResultRoleId::Research,
- EPIPHANY_RESEARCH_ROLE_BINDING_ID,
- )
- .await;
- (snapshot.status, snapshot.finding)
- } else {
- (CoreEpiphanyCoordinatorRoleResultStatus::MissingState, None)
- };
- let (verification_result_status, verification_finding) = if let Some(state) = state {
- let snapshot = load_core_epiphany_role_result_snapshot(
- state,
- runtime_store_path,
- EpiphanyRoleResultRoleId::Verification,
- EPIPHANY_VERIFICATION_ROLE_BINDING_ID,
- )
- .await;
- (snapshot.status, snapshot.finding)
- } else {
- (CoreEpiphanyCoordinatorRoleResultStatus::MissingState, None)
- };
- let (implementation_result_status, implementation_finding, implementation_completed_at) =
- if let Some(state) = state {
- let snapshot = load_core_epiphany_role_result_snapshot(
- state,
- runtime_store_path,
- EpiphanyRoleResultRoleId::Implementation,
- EPIPHANY_IMPLEMENTATION_ROLE_BINDING_ID,
- )
- .await;
- (snapshot.status, snapshot.finding, snapshot.completed_at)
- } else {
- (
- CoreEpiphanyCoordinatorRoleResultStatus::MissingState,
- None,
- None,
- )
- };
- let implementation_commit_requires_modeling_refresh =
- implementation_commit_requires_modeling_refresh(
- state,
- implementation_result_status,
- implementation_finding.as_ref(),
- implementation_completed_at.as_deref(),
- modeling_finding.as_ref(),
- );
- let finding_signals = derive_coordinator_finding_signals(
- state,
- research_finding.as_ref(),
- modeling_finding.as_ref(),
- verification_finding.as_ref(),
- reorient_finding,
- );
- let core = derive_coordinator_status(EpiphanyCoordinatorStatusInput {
- state_status: map_core_crrc_state_status_from_reorient(state_status),
- checkpoint_present,
- pressure: pressure.clone(),
- recommendation: recommendation.clone(),
- roles,
- reorient_action: reorient_decision
- .map(|decision| decision.action)
- .unwrap_or(CoreEpiphanyReorientAction::Resume),
- research_result_status,
- modeling_result_status,
- verification_result_status,
- reorient_result_status,
- research_result_accepted: finding_signals.research_result_accepted,
- research_result_reviewable: finding_signals.research_result_reviewable,
- modeling_result_requests_regather: finding_signals.modeling_result_requests_regather,
- modeling_result_accepted: finding_signals.modeling_result_accepted,
- modeling_result_reviewable: finding_signals.modeling_result_reviewable,
- modeling_result_accepted_after_verification: finding_signals
- .modeling_result_accepted_after_verification,
- implementation_evidence_after_verification: finding_signals
- .implementation_evidence_after_verification,
- verification_result_cites_implementation_evidence: finding_signals
- .verification_result_cites_implementation_evidence,
- verification_result_covers_current_modeling: finding_signals
- .verification_result_covers_current_modeling,
- verification_result_accepted: finding_signals.verification_result_accepted,
- verification_result_allows_implementation: finding_signals
- .verification_result_allows_implementation,
- verification_result_needs_evidence: finding_signals.verification_result_needs_evidence,
- implementation_commit_requires_modeling_refresh,
- reorient_finding_accepted: finding_signals.reorient_finding_accepted,
- });
- let note = render_epiphany_coordinator_note(
- recommendation.action,
- pressure.level,
- modeling_result_status,
- verification_result_status,
- core.source_signals.reorient_result_status,
- core.decision.action,
- );
-
- EpiphanyCoordinatorStatus { core, note }
-}
-
-fn implementation_commit_requires_modeling_refresh(
- state: Option<&EpiphanyThreadState>,
- implementation_status: CoreEpiphanyCoordinatorRoleResultStatus,
- implementation_finding: Option<&epiphany_core::EpiphanyRoleFindingInterpretation>,
- implementation_completed_at: Option<&str>,
- modeling_finding: Option<&epiphany_core::EpiphanyRoleFindingInterpretation>,
-) -> bool {
- if implementation_status != CoreEpiphanyCoordinatorRoleResultStatus::Completed {
- return false;
- }
- let Some(implementation_finding) = implementation_finding else {
- return false;
- };
- if !implementation_finding
- .evidence_ids
- .iter()
- .any(|id| id.starts_with("hands-receipt:hands-commit-") || id.starts_with("hands-commit-"))
- {
- return false;
- }
- let Some(completed_at) = implementation_completed_at else {
- return true;
- };
- !modeling_accepted_after(state, modeling_finding, completed_at)
-}
-
-fn modeling_accepted_after(
- state: Option<&EpiphanyThreadState>,
- modeling_finding: Option<&epiphany_core::EpiphanyRoleFindingInterpretation>,
- completed_at: &str,
-) -> bool {
- let Some(state) = state else {
- return false;
- };
- let Some(result_id) = modeling_finding.and_then(|finding| finding.runtime_result_id.as_deref())
- else {
- return false;
- };
- state.acceptance_receipts.iter().any(|receipt| {
- receipt.result_id == result_id
- && receipt.status == "accepted"
- && receipt.surface == "roleAccept"
- && receipt.role_id == "modeling"
- && receipt.accepted_at.as_str() > completed_at
- })
-}
-
-pub type EpiphanyCoordinatorAutomationAction = CoreEpiphanyCoordinatorAutomationAction;
-
-pub struct EpiphanyCoordinatorAutomationInput<'a> {
- pub thread_id: &'a str,
- pub state: &'a EpiphanyThreadState,
- pub retrieval_override: &'a EpiphanyRetrievalState,
- pub watcher_snapshot: EpiphanyFreshnessWatcherSnapshot<'a>,
- pub token_usage_info: Option<&'a EpiphanyTokenUsageSnapshot>,
- pub runtime_store_path: &'a Path,
- pub force_checkpoint_compaction: bool,
-}
-
-pub struct EpiphanyCoordinatorAutomationVerdict {
- pub action: EpiphanyCoordinatorAutomationAction,
- pub launch_request: Option,
-}
-
-pub async fn select_epiphany_coordinator_automation(
- input: EpiphanyCoordinatorAutomationInput<'_>,
-) -> EpiphanyCoordinatorAutomationVerdict {
- let core_freshness = derive_epiphany_freshness_view(
- Some(input.state),
- Some(input.retrieval_override),
- Some(input.watcher_snapshot),
- );
- let core_pressure = derive_epiphany_pressure(input.token_usage_info);
- let (state_status, reorient_decision) = derive_epiphany_reorient(
- Some(input.state),
- &core_pressure,
- &core_freshness.retrieval,
- &core_freshness.graph,
- &core_freshness.watcher,
- );
- if state_status != CoreEpiphanyReorientStateStatus::Ready {
- return EpiphanyCoordinatorAutomationVerdict {
- action: EpiphanyCoordinatorAutomationAction::None,
- launch_request: None,
- };
- }
-
- let jobs = crate::jobs::map_epiphany_jobs(Some(input.state), Some(input.retrieval_override));
- let reorient_job = jobs
- .iter()
- .find(|job| job.id == EPIPHANY_REORIENT_LAUNCH_BINDING_ID)
- .cloned();
- let reorient_result = load_core_epiphany_reorient_result_snapshot(
- Some(input.state),
- Some(input.runtime_store_path),
- EPIPHANY_REORIENT_LAUNCH_BINDING_ID,
- )
- .await;
- let reorient_finding_accepted = reorient_result
- .finding
- .as_ref()
- .is_some_and(|finding| reorient_finding_already_accepted(input.state, finding));
- let crrc_recommendation = map_epiphany_crrc_recommendation(
- true,
- state_status,
- &core_pressure,
- &reorient_decision,
- reorient_result.status,
- input.state.investigation_checkpoint.as_ref().is_some(),
- reorient_result.finding.is_some(),
- reorient_finding_accepted,
- );
- let roles = map_epiphany_roles(
- Some(input.state),
- &jobs,
- &reorient_decision,
- &core_pressure,
- &crrc_recommendation,
- reorient_result.status,
- reorient_job.as_ref(),
- );
- let coordinator = derive_epiphany_coordinator_status(
- Some(input.state),
- Some(input.runtime_store_path),
- state_status,
- &core_pressure,
- &crrc_recommendation,
- roles.roles,
- Some(&reorient_decision),
- reorient_result.status,
- reorient_result.finding.as_ref(),
- input.state.investigation_checkpoint.as_ref().is_some(),
- )
- .await;
-
- let action = select_coordinator_automation_action(
- &coordinator.core.decision,
- input.force_checkpoint_compaction,
- );
- let launch_request = match action {
- EpiphanyCoordinatorAutomationAction::LaunchReorientWorker => input
- .state
- .investigation_checkpoint
- .as_ref()
- .map(|checkpoint| {
- let dynamic_prompt_context = render_launch_dynamic_prompt_context(
- input.runtime_store_path,
- input.state,
- reorient_launch_context_focus(input.state, &reorient_decision.next_action),
- )
- .ok();
- build_epiphany_reorient_launch_request_with_dynamic_context(
- input.thread_id,
- Some(input.state.revision),
- None,
- input.state,
- checkpoint,
- &reorient_decision,
- dynamic_prompt_context,
- )
- }),
- EpiphanyCoordinatorAutomationAction::None
- | EpiphanyCoordinatorAutomationAction::CompactRehydrateReorient => None,
- };
- let action = if matches!(
- action,
- EpiphanyCoordinatorAutomationAction::LaunchReorientWorker
- ) && launch_request.is_none()
- {
- EpiphanyCoordinatorAutomationAction::None
- } else {
- action
- };
-
- EpiphanyCoordinatorAutomationVerdict {
- action,
- launch_request,
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyRoleBoardStatus {
- pub roles: Vec,
- pub(crate) source_jobs: Vec,
-}
-
-pub fn map_epiphany_roles(
- state: Option<&EpiphanyThreadState>,
- jobs: &[EpiphanyJobView],
- decision: &CoreEpiphanyReorientDecision,
- pressure: &epiphany_core::EpiphanyPressure,
- recommendation: &CoreEpiphanyCrrcRecommendation,
- result_status: CoreEpiphanyCrrcResultStatus,
- reorient_job: Option<&EpiphanyJobView>,
-) -> EpiphanyRoleBoardStatus {
- let planning = state.map(|state| &state.planning);
- let checkpoint = state.and_then(|state| state.investigation_checkpoint.as_ref());
- let mut source_jobs = jobs.to_vec();
- if let Some(job) = reorient_job
- && !source_jobs
- .iter()
- .any(|source_job| source_job.id == job.id && source_job.owner_role == job.owner_role)
- {
- source_jobs.push(job.clone());
- }
- let roles = derive_role_board(EpiphanyRoleBoardInput {
- state_present: state.is_some(),
- planning: EpiphanyRoleBoardPlanningSummary {
- capture_count: planning
- .map(|planning| planning.captures.len())
- .unwrap_or(0),
- backlog_item_count: planning
- .map(|planning| planning.backlog_items.len())
- .unwrap_or(0),
- roadmap_stream_count: planning
- .map(|planning| planning.roadmap_streams.len())
- .unwrap_or(0),
- objective_draft_count: planning
- .map(|planning| planning.objective_drafts.len())
- .unwrap_or(0),
- },
- checkpoint: checkpoint.map(|checkpoint| EpiphanyRoleBoardCheckpointSummary {
- disposition: Some(format!("{:?}", checkpoint.disposition)),
- next_action: checkpoint.next_action.clone(),
- }),
- reorient_next_action: decision.next_action.clone(),
- jobs: source_jobs.iter().map(map_core_role_board_job).collect(),
- crrc_action: recommendation.action,
- crrc_recommended_scene_action: recommendation
- .recommended_scene_action
- .map(epiphany_core::crrc_scene_action_to_coordinator_scene_action),
- crrc_reason: recommendation.reason.clone(),
- reorient_decision_action: format!("{:?}", decision.action),
- pressure_level: format!("{:?}", pressure.level),
- reorient_result_status: result_status,
- reorient_job: reorient_job.map(map_core_role_board_job),
- implementation_binding_id: EPIPHANY_IMPLEMENTATION_ROLE_BINDING_ID.to_string(),
- imagination_binding_id: EPIPHANY_IMAGINATION_ROLE_BINDING_ID.to_string(),
- research_binding_id: EPIPHANY_RESEARCH_ROLE_BINDING_ID.to_string(),
- modeling_binding_id: EPIPHANY_MODELING_ROLE_BINDING_ID.to_string(),
- verification_binding_id: EPIPHANY_VERIFICATION_ROLE_BINDING_ID.to_string(),
- implementation_owner_role: EPIPHANY_IMPLEMENTATION_OWNER_ROLE.to_string(),
- reorient_owner_role: EPIPHANY_REORIENT_OWNER_ROLE.to_string(),
- imagination_owner_role: EPIPHANY_IMAGINATION_OWNER_ROLE.to_string(),
- research_owner_role: epiphany_core::EPIPHANY_RESEARCH_OWNER_ROLE.to_string(),
- });
-
- EpiphanyRoleBoardStatus { roles, source_jobs }
-}
-
-fn map_core_role_board_job(job: &EpiphanyJobView) -> EpiphanyRoleBoardJob {
- EpiphanyRoleBoardJob {
- id: job.id.clone(),
- owner_role: job.owner_role.clone(),
- status: map_core_role_board_job_status(job.status),
- progress_note: job.progress_note.clone(),
- blocking_reason: job.blocking_reason.clone(),
- }
-}
-
-fn map_core_role_board_job_status(status: CoreEpiphanyJobStatus) -> EpiphanyRoleBoardJobStatus {
- match status {
- CoreEpiphanyJobStatus::Idle => EpiphanyRoleBoardJobStatus::Idle,
- CoreEpiphanyJobStatus::Needed => EpiphanyRoleBoardJobStatus::Needed,
- CoreEpiphanyJobStatus::Pending => EpiphanyRoleBoardJobStatus::Pending,
- CoreEpiphanyJobStatus::Running => EpiphanyRoleBoardJobStatus::Running,
- CoreEpiphanyJobStatus::Completed => EpiphanyRoleBoardJobStatus::Completed,
- CoreEpiphanyJobStatus::Failed => EpiphanyRoleBoardJobStatus::Failed,
- CoreEpiphanyJobStatus::Cancelled => EpiphanyRoleBoardJobStatus::Cancelled,
- CoreEpiphanyJobStatus::Blocked => EpiphanyRoleBoardJobStatus::Blocked,
- CoreEpiphanyJobStatus::Unavailable => EpiphanyRoleBoardJobStatus::Unavailable,
- }
-}
-
-pub fn render_epiphany_roles_note(
- roles: &[EpiphanyRoleBoardLane],
- state_status: CoreEpiphanyReorientStateStatus,
- recommendation: CoreEpiphanyCrrcAction,
-) -> String {
- render_role_board_note(
- roles,
- format!("{:?}", state_status).as_str(),
- recommendation,
- )
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- fn finding(
- result_id: &str,
- evidence_ids: Vec,
- ) -> epiphany_core::EpiphanyRoleFindingInterpretation {
- epiphany_core::EpiphanyRoleFindingInterpretation {
- verdict: Some("pass".to_string()),
- summary: Some("Finding.".to_string()),
- next_safe_move: None,
- checkpoint_summary: None,
- scratch_summary: None,
- files_inspected: Vec::new(),
- frontier_node_ids: Vec::new(),
- evidence_ids,
- artifact_refs: Vec::new(),
- runtime_result_id: Some(result_id.to_string()),
- runtime_job_id: Some(format!("job-{result_id}")),
- open_questions: Vec::new(),
- evidence_gaps: Vec::new(),
- risks: Vec::new(),
- state_patch: None,
- self_patch: None,
- self_persistence: None,
- job_error: None,
- item_error: None,
- }
- }
-
- fn state_with_modeling_acceptance(accepted_at: &str) -> EpiphanyThreadState {
- EpiphanyThreadState {
- acceptance_receipts: vec![epiphany_state_model::EpiphanyAcceptanceReceipt {
- id: "accept-modeling".to_string(),
- result_id: "modeling-result".to_string(),
- job_id: "modeling-job".to_string(),
- binding_id: EPIPHANY_MODELING_ROLE_BINDING_ID.to_string(),
- surface: "roleAccept".to_string(),
- role_id: "modeling".to_string(),
- status: "accepted".to_string(),
- accepted_at: accepted_at.to_string(),
- accepted_observation_id: None,
- accepted_evidence_id: None,
- summary: None,
- }],
- ..EpiphanyThreadState::default()
- }
- }
-
- #[test]
- fn hands_commit_requires_modeling_refresh_until_newer_modeling_acceptance() {
- let implementation = finding(
- "implementation-result",
- vec!["hands-receipt:hands-commit-worker-job-impl".to_string()],
- );
- let modeling = finding("modeling-result", Vec::new());
-
- assert!(implementation_commit_requires_modeling_refresh(
- None,
- CoreEpiphanyCoordinatorRoleResultStatus::Completed,
- Some(&implementation),
- Some("2026-06-02T12:00:00Z"),
- Some(&modeling),
- ));
-
- let stale_state = state_with_modeling_acceptance("2026-06-02T11:59:00Z");
- assert!(implementation_commit_requires_modeling_refresh(
- Some(&stale_state),
- CoreEpiphanyCoordinatorRoleResultStatus::Completed,
- Some(&implementation),
- Some("2026-06-02T12:00:00Z"),
- Some(&modeling),
- ));
-
- let refreshed_state = state_with_modeling_acceptance("2026-06-02T12:01:00Z");
- assert!(!implementation_commit_requires_modeling_refresh(
- Some(&refreshed_state),
- CoreEpiphanyCoordinatorRoleResultStatus::Completed,
- Some(&implementation),
- Some("2026-06-02T12:00:00Z"),
- Some(&modeling),
- ));
- }
-}
diff --git a/epiphany-codex-bridge/src/coordinator_protocol.rs b/epiphany-codex-bridge/src/coordinator_protocol.rs
deleted file mode 100644
index 009273a3..00000000
--- a/epiphany-codex-bridge/src/coordinator_protocol.rs
+++ /dev/null
@@ -1,314 +0,0 @@
-use codex_app_server_protocol::ThreadEpiphanyCoordinatorAction;
-use codex_app_server_protocol::ThreadEpiphanyCoordinatorSignals;
-use codex_app_server_protocol::ThreadEpiphanyCrrcAction;
-use codex_app_server_protocol::ThreadEpiphanyCrrcRecommendation;
-use codex_app_server_protocol::ThreadEpiphanyJob;
-use codex_app_server_protocol::ThreadEpiphanyReorientAction;
-use codex_app_server_protocol::ThreadEpiphanyRoleId;
-use codex_app_server_protocol::ThreadEpiphanyRoleLane;
-use codex_app_server_protocol::ThreadEpiphanyRoleStatus;
-use codex_app_server_protocol::ThreadEpiphanyRolesSource;
-use codex_app_server_protocol::ThreadEpiphanySceneAction;
-use codex_app_server_protocol::ThreadEpiphanyViewCoordinator;
-use epiphany_core::EpiphanyCoordinatorAction as CoreEpiphanyCoordinatorAction;
-use epiphany_core::EpiphanyCoordinatorRoleId as CoreEpiphanyCoordinatorRoleId;
-use epiphany_core::EpiphanyCoordinatorRoleStatus as CoreEpiphanyCoordinatorRoleStatus;
-use epiphany_core::EpiphanyCoordinatorSceneAction as CoreEpiphanyCoordinatorSceneAction;
-use epiphany_core::EpiphanyCoordinatorSourceSignals;
-use epiphany_core::EpiphanyCrrcAction as CoreEpiphanyCrrcAction;
-use epiphany_core::EpiphanyCrrcRecommendation as CoreEpiphanyCrrcRecommendation;
-use epiphany_core::EpiphanyCrrcSceneAction as CoreEpiphanyCrrcSceneAction;
-use epiphany_core::EpiphanyJobStatus as CoreEpiphanyJobStatus;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyReorientAction as CoreEpiphanyReorientAction;
-use epiphany_core::EpiphanyReorientStateStatus as CoreEpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRoleBoardJob;
-use epiphany_core::EpiphanyRoleBoardJobStatus;
-use epiphany_core::EpiphanyRoleBoardLane;
-use epiphany_state_model::EpiphanyJobKind as CoreEpiphanyJobKind;
-
-use crate::coordinator::EpiphanyCoordinatorStatus;
-use crate::coordinator::EpiphanyRoleBoardStatus;
-use crate::protocol_edge::protocol_job_from_surface;
-use crate::protocol_edge::protocol_pressure_level;
-use crate::protocol_edge::protocol_reorient_result_status;
-use crate::protocol_edge::protocol_reorient_state_status;
-use crate::protocol_edge::protocol_role_result_status;
-
-fn protocol_coordinator_source_signals(
- signals: EpiphanyCoordinatorSourceSignals,
-) -> ThreadEpiphanyCoordinatorSignals {
- ThreadEpiphanyCoordinatorSignals {
- pressure_level: protocol_pressure_level(signals.pressure_level),
- should_prepare_compaction: signals.should_prepare_compaction,
- reorient_action: protocol_reorient_action(signals.reorient_action),
- crrc_action: protocol_crrc_action(signals.crrc_action),
- research_result_status: protocol_role_result_status(signals.research_result_status),
- modeling_result_status: protocol_role_result_status(signals.modeling_result_status),
- verification_result_status: protocol_role_result_status(signals.verification_result_status),
- reorient_result_status: protocol_reorient_result_status(signals.reorient_result_status),
- implementation_commit_requires_modeling_refresh: signals
- .implementation_commit_requires_modeling_refresh,
- }
-}
-
-fn protocol_reorient_action(action: CoreEpiphanyReorientAction) -> ThreadEpiphanyReorientAction {
- match action {
- CoreEpiphanyReorientAction::Resume => ThreadEpiphanyReorientAction::Resume,
- CoreEpiphanyReorientAction::Regather => ThreadEpiphanyReorientAction::Regather,
- }
-}
-
-pub fn protocol_crrc_action(action: CoreEpiphanyCrrcAction) -> ThreadEpiphanyCrrcAction {
- match action {
- CoreEpiphanyCrrcAction::Continue => ThreadEpiphanyCrrcAction::Continue,
- CoreEpiphanyCrrcAction::PrepareCheckpoint => ThreadEpiphanyCrrcAction::PrepareCheckpoint,
- CoreEpiphanyCrrcAction::LaunchReorientWorker => {
- ThreadEpiphanyCrrcAction::LaunchReorientWorker
- }
- CoreEpiphanyCrrcAction::WaitForReorientWorker => {
- ThreadEpiphanyCrrcAction::WaitForReorientWorker
- }
- CoreEpiphanyCrrcAction::ReviewReorientResult => {
- ThreadEpiphanyCrrcAction::ReviewReorientResult
- }
- CoreEpiphanyCrrcAction::AcceptReorientResult => {
- ThreadEpiphanyCrrcAction::AcceptReorientResult
- }
- CoreEpiphanyCrrcAction::RegatherManually => ThreadEpiphanyCrrcAction::RegatherManually,
- }
-}
-
-fn protocol_crrc_scene_action(action: CoreEpiphanyCrrcSceneAction) -> ThreadEpiphanySceneAction {
- match action {
- CoreEpiphanyCrrcSceneAction::Update => ThreadEpiphanySceneAction::Update,
- CoreEpiphanyCrrcSceneAction::Reorient => ThreadEpiphanySceneAction::Reorient,
- CoreEpiphanyCrrcSceneAction::ReorientLaunch => ThreadEpiphanySceneAction::ReorientLaunch,
- CoreEpiphanyCrrcSceneAction::ReorientResult => ThreadEpiphanySceneAction::ReorientResult,
- CoreEpiphanyCrrcSceneAction::ReorientAccept => ThreadEpiphanySceneAction::ReorientAccept,
- }
-}
-
-pub fn protocol_crrc_recommendation(
- recommendation: CoreEpiphanyCrrcRecommendation,
-) -> ThreadEpiphanyCrrcRecommendation {
- ThreadEpiphanyCrrcRecommendation {
- action: protocol_crrc_action(recommendation.action),
- recommended_scene_action: recommendation
- .recommended_scene_action
- .map(protocol_crrc_scene_action),
- reason: recommendation.reason,
- }
-}
-
-pub fn protocol_coordinator_view(
- thread_id: String,
- loaded: bool,
- state_status: CoreEpiphanyReorientStateStatus,
- state_revision: Option,
- status: EpiphanyCoordinatorStatus,
- roles: EpiphanyRoleBoardStatus,
-) -> ThreadEpiphanyViewCoordinator {
- ThreadEpiphanyViewCoordinator {
- thread_id,
- source: if loaded {
- ThreadEpiphanyRolesSource::Live
- } else {
- ThreadEpiphanyRolesSource::Stored
- },
- state_status: protocol_reorient_state_status(state_status),
- state_revision,
- action: protocol_coordinator_action(status.core.decision.action),
- target_role: status
- .core
- .decision
- .target_role
- .map(protocol_coordinator_role_id),
- recommended_scene_action: status
- .core
- .decision
- .recommended_scene_action
- .map(protocol_coordinator_scene_action),
- requires_review: status.core.decision.requires_review,
- can_auto_run: status.core.decision.can_auto_run,
- reason: status.core.decision.reason,
- source_signals: protocol_coordinator_source_signals(status.core.source_signals),
- roles: protocol_role_board_lanes(&roles),
- note: status.note,
- }
-}
-
-fn protocol_coordinator_role_id(role_id: CoreEpiphanyCoordinatorRoleId) -> ThreadEpiphanyRoleId {
- match role_id {
- CoreEpiphanyCoordinatorRoleId::Implementation => ThreadEpiphanyRoleId::Implementation,
- CoreEpiphanyCoordinatorRoleId::Imagination => ThreadEpiphanyRoleId::Imagination,
- CoreEpiphanyCoordinatorRoleId::Research => ThreadEpiphanyRoleId::Research,
- CoreEpiphanyCoordinatorRoleId::Modeling => ThreadEpiphanyRoleId::Modeling,
- CoreEpiphanyCoordinatorRoleId::Verification => ThreadEpiphanyRoleId::Verification,
- CoreEpiphanyCoordinatorRoleId::Reorientation => ThreadEpiphanyRoleId::Reorientation,
- }
-}
-
-fn protocol_coordinator_scene_action(
- action: CoreEpiphanyCoordinatorSceneAction,
-) -> ThreadEpiphanySceneAction {
- match action {
- CoreEpiphanyCoordinatorSceneAction::Update => ThreadEpiphanySceneAction::Update,
- CoreEpiphanyCoordinatorSceneAction::Reorient => ThreadEpiphanySceneAction::Reorient,
- CoreEpiphanyCoordinatorSceneAction::ReorientLaunch => {
- ThreadEpiphanySceneAction::ReorientLaunch
- }
- CoreEpiphanyCoordinatorSceneAction::ReorientResult => {
- ThreadEpiphanySceneAction::ReorientResult
- }
- CoreEpiphanyCoordinatorSceneAction::ReorientAccept => {
- ThreadEpiphanySceneAction::ReorientAccept
- }
- CoreEpiphanyCoordinatorSceneAction::RoleLaunch => ThreadEpiphanySceneAction::RoleLaunch,
- CoreEpiphanyCoordinatorSceneAction::RoleResult => ThreadEpiphanySceneAction::RoleResult,
- }
-}
-
-fn protocol_coordinator_action(
- action: CoreEpiphanyCoordinatorAction,
-) -> ThreadEpiphanyCoordinatorAction {
- match action {
- CoreEpiphanyCoordinatorAction::PrepareCheckpoint => {
- ThreadEpiphanyCoordinatorAction::PrepareCheckpoint
- }
- CoreEpiphanyCoordinatorAction::CompactRehydrateReorient => {
- ThreadEpiphanyCoordinatorAction::CompactRehydrateReorient
- }
- CoreEpiphanyCoordinatorAction::LaunchReorientWorker => {
- ThreadEpiphanyCoordinatorAction::LaunchReorientWorker
- }
- CoreEpiphanyCoordinatorAction::WaitForReorientWorker => {
- ThreadEpiphanyCoordinatorAction::WaitForReorientWorker
- }
- CoreEpiphanyCoordinatorAction::ReviewReorientResult => {
- ThreadEpiphanyCoordinatorAction::ReviewReorientResult
- }
- CoreEpiphanyCoordinatorAction::RegatherManually => {
- ThreadEpiphanyCoordinatorAction::RegatherManually
- }
- CoreEpiphanyCoordinatorAction::LaunchResearch => {
- ThreadEpiphanyCoordinatorAction::LaunchResearch
- }
- CoreEpiphanyCoordinatorAction::ReviewResearchResult => {
- ThreadEpiphanyCoordinatorAction::ReviewResearchResult
- }
- CoreEpiphanyCoordinatorAction::LaunchModeling => {
- ThreadEpiphanyCoordinatorAction::LaunchModeling
- }
- CoreEpiphanyCoordinatorAction::ReviewModelingResult => {
- ThreadEpiphanyCoordinatorAction::ReviewModelingResult
- }
- CoreEpiphanyCoordinatorAction::LaunchVerification => {
- ThreadEpiphanyCoordinatorAction::LaunchVerification
- }
- CoreEpiphanyCoordinatorAction::ReviewVerificationResult => {
- ThreadEpiphanyCoordinatorAction::ReviewVerificationResult
- }
- CoreEpiphanyCoordinatorAction::ContinueImplementation => {
- ThreadEpiphanyCoordinatorAction::ContinueImplementation
- }
- }
-}
-
-pub fn protocol_role_board_lanes(
- role_board: &EpiphanyRoleBoardStatus,
-) -> Vec {
- role_board
- .roles
- .iter()
- .cloned()
- .map(|lane| protocol_role_board_lane(lane, &role_board.source_jobs))
- .collect()
-}
-
-fn protocol_role_board_lane(
- lane: EpiphanyRoleBoardLane,
- source_jobs: &[EpiphanyJobView],
-) -> ThreadEpiphanyRoleLane {
- ThreadEpiphanyRoleLane {
- id: protocol_coordinator_role_id(lane.id),
- title: lane.title,
- owner_role: lane.owner_role,
- status: protocol_coordinator_role_status(lane.status),
- note: lane.note,
- jobs: lane
- .jobs
- .iter()
- .map(|job| protocol_role_board_job(job, source_jobs))
- .collect(),
- authority_scopes: lane.authority_scopes,
- recommended_action: lane
- .recommended_action
- .map(protocol_coordinator_scene_action),
- }
-}
-
-fn protocol_role_board_job(
- job: &EpiphanyRoleBoardJob,
- source_jobs: &[EpiphanyJobView],
-) -> ThreadEpiphanyJob {
- source_jobs
- .iter()
- .find(|source_job| source_job.id == job.id && source_job.owner_role == job.owner_role)
- .cloned()
- .map(|job| protocol_job_from_surface(job, None, None))
- .unwrap_or_else(|| {
- protocol_job_from_surface(
- EpiphanyJobView {
- id: job.id.clone(),
- kind: CoreEpiphanyJobKind::Specialist,
- scope: job.id.clone(),
- owner_role: job.owner_role.clone(),
- authority_scope: None,
- runtime_job_id: None,
- status: core_epiphany_job_status_from_role_board(job.status),
- items_processed: None,
- items_total: None,
- progress_note: job.progress_note.clone(),
- last_checkpoint_at_unix_seconds: None,
- blocking_reason: job.blocking_reason.clone(),
- active_thread_ids: Vec::new(),
- linked_subgoal_ids: Vec::new(),
- linked_graph_node_ids: Vec::new(),
- },
- None,
- None,
- )
- })
-}
-
-fn core_epiphany_job_status_from_role_board(
- status: EpiphanyRoleBoardJobStatus,
-) -> CoreEpiphanyJobStatus {
- match status {
- EpiphanyRoleBoardJobStatus::Idle => CoreEpiphanyJobStatus::Idle,
- EpiphanyRoleBoardJobStatus::Needed => CoreEpiphanyJobStatus::Needed,
- EpiphanyRoleBoardJobStatus::Pending => CoreEpiphanyJobStatus::Pending,
- EpiphanyRoleBoardJobStatus::Running => CoreEpiphanyJobStatus::Running,
- EpiphanyRoleBoardJobStatus::Completed => CoreEpiphanyJobStatus::Completed,
- EpiphanyRoleBoardJobStatus::Failed => CoreEpiphanyJobStatus::Failed,
- EpiphanyRoleBoardJobStatus::Cancelled => CoreEpiphanyJobStatus::Cancelled,
- EpiphanyRoleBoardJobStatus::Blocked => CoreEpiphanyJobStatus::Blocked,
- EpiphanyRoleBoardJobStatus::Unavailable => CoreEpiphanyJobStatus::Unavailable,
- }
-}
-
-fn protocol_coordinator_role_status(
- status: CoreEpiphanyCoordinatorRoleStatus,
-) -> ThreadEpiphanyRoleStatus {
- match status {
- CoreEpiphanyCoordinatorRoleStatus::Ready => ThreadEpiphanyRoleStatus::Ready,
- CoreEpiphanyCoordinatorRoleStatus::Needed => ThreadEpiphanyRoleStatus::Needed,
- CoreEpiphanyCoordinatorRoleStatus::Running => ThreadEpiphanyRoleStatus::Running,
- CoreEpiphanyCoordinatorRoleStatus::Waiting => ThreadEpiphanyRoleStatus::Waiting,
- CoreEpiphanyCoordinatorRoleStatus::Review => ThreadEpiphanyRoleStatus::Review,
- CoreEpiphanyCoordinatorRoleStatus::Blocked => ThreadEpiphanyRoleStatus::Blocked,
- CoreEpiphanyCoordinatorRoleStatus::Unavailable => ThreadEpiphanyRoleStatus::Unavailable,
- CoreEpiphanyCoordinatorRoleStatus::Completed => ThreadEpiphanyRoleStatus::Completed,
- }
-}
diff --git a/epiphany-codex-bridge/src/cultnet.rs b/epiphany-codex-bridge/src/cultnet.rs
deleted file mode 100644
index 3c9f6920..00000000
--- a/epiphany-codex-bridge/src/cultnet.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use epiphany_core::EpiphanyGraphFreshness;
-pub use epiphany_core::EpiphanyGraphFreshnessStatus;
-use epiphany_core::EpiphanyInvalidationInput;
-pub use epiphany_core::EpiphanyInvalidationStatus;
-pub use epiphany_core::EpiphanyJobStatus;
-pub use epiphany_core::EpiphanyJobView;
-pub use epiphany_core::EpiphanyPressure;
-pub use epiphany_core::EpiphanyPressureBasis;
-pub use epiphany_core::EpiphanyPressureLevel;
-pub use epiphany_core::EpiphanyPressureStatus;
-pub use epiphany_core::EpiphanyReorientAction;
-pub use epiphany_core::EpiphanyReorientCheckpointStatus;
-pub use epiphany_core::EpiphanyReorientDecision;
-pub use epiphany_core::EpiphanyReorientFreshnessStatus;
-pub use epiphany_core::EpiphanyReorientPressureLevel;
-pub use epiphany_core::EpiphanyReorientReason;
-pub use epiphany_core::EpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRetrievalFreshness;
-pub use epiphany_core::EpiphanyRetrievalFreshnessStatus;
-pub use epiphany_core::EpiphanyStateUpdatedField;
-pub use epiphany_state_model::EpiphanyJobKind;
-use serde::Deserialize;
-use serde::Serialize;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub enum EpiphanySurfaceSource {
- Stored,
- Live,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-#[serde(rename_all = "camelCase")]
-pub struct EpiphanyFreshnessSurface {
- pub thread_id: String,
- pub source: EpiphanySurfaceSource,
- #[serde(default, skip_serializing_if = "Option::is_none")]
- pub state_revision: Option,
- pub retrieval: EpiphanyRetrievalFreshness,
- pub graph: EpiphanyGraphFreshness,
- pub watcher: EpiphanyInvalidationInput,
-}
diff --git a/epiphany-codex-bridge/src/error.rs b/epiphany-codex-bridge/src/error.rs
deleted file mode 100644
index 777cb03e..00000000
--- a/epiphany-codex-bridge/src/error.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::error::Error;
-use std::fmt;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum EpiphanyBridgeError {
- InvalidRequest(String),
- Fatal(String),
-}
-
-pub type Result = std::result::Result;
-
-impl fmt::Display for EpiphanyBridgeError {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::InvalidRequest(message) | Self::Fatal(message) => f.write_str(message),
- }
- }
-}
-
-impl Error for EpiphanyBridgeError {}
diff --git a/epiphany-codex-bridge/src/invalidation.rs b/epiphany-codex-bridge/src/invalidation.rs
deleted file mode 100644
index 79f16459..00000000
--- a/epiphany-codex-bridge/src/invalidation.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-use codex_utils_absolute_path::AbsolutePathBuf;
-use notify::RecursiveMode;
-use notify::Watcher;
-use std::collections::HashMap;
-use std::path::PathBuf;
-use std::sync::Arc;
-use std::time::SystemTime;
-use std::time::UNIX_EPOCH;
-use tokio::sync::Mutex as AsyncMutex;
-use tokio::sync::mpsc;
-use tokio::sync::oneshot;
-use tracing::warn;
-
-use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct EpiphanyInvalidationSnapshot {
- pub available: bool,
- pub workspace_root: Option,
- pub observed_at_unix_seconds: Option,
- pub changed_paths: Vec,
-}
-
-pub fn epiphany_freshness_watcher_snapshot(
- snapshot: &EpiphanyInvalidationSnapshot,
-) -> EpiphanyFreshnessWatcherSnapshot<'_> {
- EpiphanyFreshnessWatcherSnapshot {
- available: snapshot.available,
- workspace_root: snapshot.workspace_root.as_ref().map(|path| path.as_path()),
- observed_at_unix_seconds: snapshot.observed_at_unix_seconds,
- changed_paths: snapshot.changed_paths.as_slice(),
- }
-}
-
-#[derive(Clone)]
-pub struct EpiphanyInvalidationManager {
- state: Arc>>,
-}
-
-struct WatchEntry {
- workspace_root: AbsolutePathBuf,
- latest: Arc>,
- terminate_tx: oneshot::Sender>,
- _watcher: notify::RecommendedWatcher,
-}
-
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-struct LatestInvalidation {
- observed_at_unix_seconds: Option,
- changed_paths: Vec,
-}
-
-impl EpiphanyInvalidationManager {
- pub fn new() -> Self {
- Self {
- state: Arc::new(AsyncMutex::new(HashMap::new())),
- }
- }
-
- pub async fn ensure_thread_watch(&self, thread_id: &str, workspace_root: &AbsolutePathBuf) {
- let existing_entry = {
- let mut state = self.state.lock().await;
- match state.get(thread_id) {
- Some(entry) if &entry.workspace_root == workspace_root => return,
- Some(_) => state.remove(thread_id),
- None => None,
- }
- };
-
- if let Some(entry) = existing_entry {
- stop_watch_entry(entry).await;
- }
-
- let latest = Arc::new(AsyncMutex::new(LatestInvalidation::default()));
- let (event_tx, mut event_rx) = mpsc::unbounded_channel::>();
- let mut watcher =
- match notify::recommended_watcher(move |result: notify::Result| {
- match result {
- Ok(event) => {
- let _ = event_tx.send(event.paths);
- }
- Err(err) => warn!("epiphany invalidation watcher event failed: {err}"),
- }
- }) {
- Ok(watcher) => watcher,
- Err(err) => {
- warn!("epiphany invalidation manager could not create watcher: {err}");
- return;
- }
- };
- if let Err(err) = watcher.watch(workspace_root.as_path(), RecursiveMode::Recursive) {
- warn!(
- "epiphany invalidation manager could not watch `{}`: {err}",
- workspace_root.display()
- );
- return;
- }
- let (terminate_tx, terminate_rx) = oneshot::channel();
- let workspace_root_path = workspace_root.to_path_buf();
-
- let entry = WatchEntry {
- workspace_root: workspace_root.clone(),
- latest: Arc::clone(&latest),
- terminate_tx,
- _watcher: watcher,
- };
- self.state.lock().await.insert(thread_id.to_string(), entry);
-
- tokio::spawn(async move {
- let mut terminate_rx = terminate_rx;
- let mut done_tx = None;
-
- loop {
- let paths = tokio::select! {
- biased;
- result = &mut terminate_rx => {
- done_tx = result.ok();
- break;
- }
- paths = event_rx.recv() => match paths {
- Some(paths) => paths,
- None => break,
- },
- };
-
- let observed_at_unix_seconds = unix_now();
- let mut latest = latest.lock().await;
- latest.observed_at_unix_seconds = Some(observed_at_unix_seconds);
- latest.changed_paths =
- normalize_changed_paths(paths, workspace_root_path.as_path());
- }
-
- if let Some(done_tx) = done_tx {
- let _ = done_tx.send(());
- }
- });
- }
-
- pub async fn snapshot(&self, thread_id: &str) -> EpiphanyInvalidationSnapshot {
- let (workspace_root, latest) = {
- let state = self.state.lock().await;
- match state.get(thread_id) {
- Some(entry) => (
- Some(entry.workspace_root.clone()),
- Some(Arc::clone(&entry.latest)),
- ),
- None => (None, None),
- }
- };
-
- let Some(latest) = latest else {
- return EpiphanyInvalidationSnapshot {
- available: false,
- workspace_root: None,
- observed_at_unix_seconds: None,
- changed_paths: Vec::new(),
- };
- };
-
- let latest = latest.lock().await.clone();
- EpiphanyInvalidationSnapshot {
- available: true,
- workspace_root,
- observed_at_unix_seconds: latest.observed_at_unix_seconds,
- changed_paths: latest.changed_paths,
- }
- }
-
- pub async fn remove_thread(&self, thread_id: &str) {
- let entry = self.state.lock().await.remove(thread_id);
- if let Some(entry) = entry {
- stop_watch_entry(entry).await;
- }
- }
-}
-
-async fn stop_watch_entry(entry: WatchEntry) {
- let (done_tx, done_rx) = oneshot::channel();
- let _ = entry.terminate_tx.send(done_tx);
- let _ = done_rx.await;
-}
-
-fn unix_now() -> i64 {
- SystemTime::now()
- .duration_since(UNIX_EPOCH)
- .map(|duration| duration.as_secs() as i64)
- .unwrap_or_default()
-}
-
-fn normalize_changed_paths(paths: Vec, workspace_root: &std::path::Path) -> Vec {
- let mut normalized = paths
- .into_iter()
- .filter_map(|path| match path.strip_prefix(workspace_root) {
- Ok(relative) if relative.as_os_str().is_empty() => None,
- Ok(relative) => Some(relative.to_path_buf()),
- Err(_) => Some(path),
- })
- .collect::>();
- normalized.sort();
- normalized.dedup();
- normalized
-}
diff --git a/epiphany-codex-bridge/src/jobs.rs b/epiphany-codex-bridge/src/jobs.rs
deleted file mode 100644
index 666b0443..00000000
--- a/epiphany-codex-bridge/src/jobs.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use epiphany_core::EpiphanyJobStatus as CoreEpiphanyJobStatus;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyJobsInput;
-use epiphany_core::derive_jobs;
-use epiphany_state_model::EpiphanyJobKind as CoreEpiphanyJobKind;
-use epiphany_state_model::EpiphanyRetrievalState;
-use epiphany_state_model::EpiphanyThreadState;
-
-pub fn derive_epiphany_jobs(
- state: Option<&EpiphanyThreadState>,
- retrieval_override: Option<&EpiphanyRetrievalState>,
-) -> Vec {
- derive_jobs(EpiphanyJobsInput {
- state,
- retrieval_override,
- })
-}
-
-pub fn map_epiphany_jobs(
- state: Option<&EpiphanyThreadState>,
- retrieval_override: Option<&EpiphanyRetrievalState>,
-) -> Vec {
- derive_epiphany_jobs(state, retrieval_override)
-}
-
-pub fn map_launched_epiphany_job(
- state: &EpiphanyThreadState,
- binding_id: &str,
- backend_job_id: &str,
- fallback_kind: CoreEpiphanyJobKind,
- fallback_scope: &str,
-) -> EpiphanyJobView {
- derive_epiphany_jobs(Some(state), None)
- .into_iter()
- .find(|job| job.id == binding_id)
- .unwrap_or_else(|| EpiphanyJobView {
- id: binding_id.to_string(),
- kind: fallback_kind,
- scope: fallback_scope.to_string(),
- owner_role: "epiphany-harness".to_string(),
- authority_scope: None,
- runtime_job_id: Some(backend_job_id.to_string()),
- status: CoreEpiphanyJobStatus::Pending,
- items_processed: None,
- items_total: None,
- progress_note: None,
- last_checkpoint_at_unix_seconds: None,
- blocking_reason: None,
- active_thread_ids: Vec::new(),
- linked_subgoal_ids: Vec::new(),
- linked_graph_node_ids: Vec::new(),
- })
-}
-
-pub fn map_interrupted_epiphany_job(
- state: &EpiphanyThreadState,
- binding_id: &str,
-) -> EpiphanyJobView {
- derive_epiphany_jobs(Some(state), None)
- .into_iter()
- .find(|job| job.id == binding_id)
- .unwrap_or_else(|| {
- epiphany_blocked_state_job(
- binding_id,
- CoreEpiphanyJobKind::Specialist,
- "role-scoped specialist work",
- "Interrupted job binding was not reflected in Epiphany state.",
- )
- })
-}
-
-pub fn epiphany_blocked_state_job(
- id: &str,
- kind: CoreEpiphanyJobKind,
- scope: &str,
- blocking_reason: &str,
-) -> EpiphanyJobView {
- EpiphanyJobView {
- id: id.to_string(),
- kind,
- scope: scope.to_string(),
- owner_role: "epiphany-harness".to_string(),
- authority_scope: None,
- runtime_job_id: None,
- status: CoreEpiphanyJobStatus::Blocked,
- items_processed: None,
- items_total: None,
- progress_note: None,
- last_checkpoint_at_unix_seconds: None,
- blocking_reason: Some(blocking_reason.to_string()),
- active_thread_ids: Vec::new(),
- linked_subgoal_ids: Vec::new(),
- linked_graph_node_ids: Vec::new(),
- }
-}
diff --git a/epiphany-codex-bridge/src/launch.rs b/epiphany-codex-bridge/src/launch.rs
deleted file mode 100644
index 20d5d6b8..00000000
--- a/epiphany-codex-bridge/src/launch.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Compatibility facade for older bridge callers.
-//!
-//! Epiphany prompt doctrine, worker launch policy, role binding ids, and output
-//! schemas live in `epiphany-core`. The bridge may translate those typed launch
-//! requests to Codex JSON-RPC, but it does not own the agent instructions.
-
-pub use epiphany_core::EPIPHANY_IMAGINATION_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_IMAGINATION_ROLE_BINDING_ID;
-pub use epiphany_core::EPIPHANY_IMPLEMENTATION_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_IMPLEMENTATION_ROLE_BINDING_ID;
-pub use epiphany_core::EPIPHANY_MODELING_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_MODELING_ROLE_BINDING_ID;
-pub use epiphany_core::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
-pub use epiphany_core::EPIPHANY_REORIENT_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_RESEARCH_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_RESEARCH_ROLE_BINDING_ID;
-pub use epiphany_core::EPIPHANY_VERIFICATION_OWNER_ROLE;
-pub use epiphany_core::EPIPHANY_VERIFICATION_ROLE_BINDING_ID;
-pub use epiphany_core::EpiphanyCoordinatorPromptConfig;
-pub use epiphany_core::EpiphanyCrrcPromptConfig;
-pub use epiphany_core::EpiphanyImplementationPromptConfig;
-pub use epiphany_core::EpiphanyReorientationPromptConfig;
-pub use epiphany_core::EpiphanyRolePromptConfig;
-pub use epiphany_core::EpiphanySharedPromptConfig;
-pub use epiphany_core::EpiphanySpecialistPromptConfig;
-pub use epiphany_core::build_epiphany_job_launch_request;
-pub use epiphany_core::build_epiphany_reorient_launch_instruction;
-pub use epiphany_core::build_epiphany_reorient_launch_request;
-pub use epiphany_core::build_epiphany_role_launch_request;
-pub use epiphany_core::epiphany_agent_prompt_with_memory;
-pub use epiphany_core::epiphany_reorient_launch_output_schema;
-pub use epiphany_core::epiphany_role_binding_id;
-pub use epiphany_core::epiphany_role_label;
-pub use epiphany_core::epiphany_role_launch_output_schema;
-pub use epiphany_core::epiphany_role_owner;
-pub use epiphany_core::epiphany_specialist_prompt_config;
-pub use epiphany_core::epiphany_worker_prompt;
-pub use epiphany_core::render_epiphany_coordinator_note;
-pub use epiphany_core::render_epiphany_pre_compaction_checkpoint_intervention;
-pub use epiphany_core::unique_strings;
diff --git a/epiphany-codex-bridge/src/launch_context.rs b/epiphany-codex-bridge/src/launch_context.rs
deleted file mode 100644
index 397df252..00000000
--- a/epiphany-codex-bridge/src/launch_context.rs
+++ /dev/null
@@ -1,250 +0,0 @@
-use chrono::SecondsFormat;
-use chrono::Utc;
-use epiphany_core::EpiphanyMemoryContextPacket;
-use epiphany_core::EpiphanyMemoryContextQuery;
-use epiphany_core::EpiphanyMemoryProfile;
-use epiphany_core::EpiphanyPromptContextInput;
-use epiphany_core::EpiphanyThreadState;
-use epiphany_core::import_gjallar_daemon_affordances;
-use epiphany_core::load_memory_graph_snapshot;
-use epiphany_core::memory_graph_from_epiphany_graphs;
-use epiphany_core::plan_memory_graph_context_cut;
-use epiphany_core::query_epiphany_local_verse_context;
-use epiphany_core::render_epiphany_prompt_context;
-use epiphany_core::seed_epiphany_local_verse_context;
-use epiphany_core::write_memory_graph_snapshot;
-use std::env;
-use std::path::Path;
-use std::path::PathBuf;
-
-pub const EPIPHANY_LOCAL_VERSE_RUNTIME_ID: &str = "epiphany-local";
-
-pub fn local_verse_store_path(runtime_store_path: &Path) -> PathBuf {
- sibling_state_store_path(runtime_store_path, "local-verse.cc")
-}
-
-pub fn memory_graph_store_path(runtime_store_path: &Path) -> PathBuf {
- sibling_state_store_path(runtime_store_path, "memory-graph.cc")
-}
-
-fn sibling_state_store_path(runtime_store_path: &Path, filename: &str) -> PathBuf {
- runtime_store_path
- .parent()
- .unwrap_or_else(|| Path::new("."))
- .join(filename)
-}
-
-pub fn role_launch_context_focus(state: &EpiphanyThreadState, role_label: &str) -> String {
- let objective = state
- .objective
- .as_deref()
- .map(str::trim)
- .filter(|objective| !objective.is_empty())
- .unwrap_or("Epiphany worker launch");
- format!("Launch `{role_label}` worker for: {objective}")
-}
-
-pub fn reorient_launch_context_focus(state: &EpiphanyThreadState, next_action: &str) -> String {
- let objective = state
- .objective
- .as_deref()
- .map(str::trim)
- .filter(|objective| !objective.is_empty())
- .unwrap_or("Epiphany reorientation");
- format!("Launch reorientation worker for: {objective}. Next action: {next_action}")
-}
-
-pub fn render_launch_dynamic_prompt_context(
- runtime_store_path: &Path,
- state: &EpiphanyThreadState,
- focus: String,
-) -> Result {
- let local_verse_store = local_verse_store_path(runtime_store_path);
- seed_epiphany_local_verse_context(
- &local_verse_store,
- EPIPHANY_LOCAL_VERSE_RUNTIME_ID,
- Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true),
- )
- .map_err(|error| {
- format!(
- "failed to seed local Verse context store {}: {error}",
- local_verse_store.display()
- )
- })?;
- if let Some(gjallar_store) = gjallar_affordance_store_path() {
- import_gjallar_daemon_affordances(
- &local_verse_store,
- &gjallar_store,
- EPIPHANY_LOCAL_VERSE_RUNTIME_ID,
- )
- .map_err(|error| {
- format!(
- "failed to import Gjallar daemon affordances from {} into {}: {error}",
- gjallar_store.display(),
- local_verse_store.display()
- )
- })?;
- }
- let local_verse =
- query_epiphany_local_verse_context(&local_verse_store, EPIPHANY_LOCAL_VERSE_RUNTIME_ID)
- .map_err(|error| {
- format!(
- "failed to query local Verse context store {}: {error}",
- local_verse_store.display()
- )
- })?;
- let memory_context =
- launch_memory_context(runtime_store_path, state, focus.as_str()).map_err(|error| {
- format!(
- "failed to build launch memory context beside {}: {error}",
- runtime_store_path.display()
- )
- })?;
- Ok(render_epiphany_prompt_context(
- &EpiphanyPromptContextInput {
- focus,
- local_verse,
- memory_context,
- },
- ))
-}
-
-fn gjallar_affordance_store_path() -> Option {
- env::var_os("EPIPHANY_GJALLAR_AFFORDANCE_STORE")
- .map(PathBuf::from)
- .filter(|path| path.exists())
-}
-
-fn launch_memory_context(
- runtime_store_path: &Path,
- state: &EpiphanyThreadState,
- focus: &str,
-) -> Result {
- let memory_graph_store = memory_graph_store_path(runtime_store_path);
- let (snapshot, refreshed_from_state) = match load_memory_graph_snapshot(&memory_graph_store)
- .map_err(|error| {
- format!(
- "failed to load memory graph store {}: {error}",
- memory_graph_store.display()
- )
- })? {
- Some(snapshot) => (snapshot, false),
- None => {
- let snapshot = memory_graph_from_epiphany_graphs(
- format!("bridge-launch-state-rev-{}", state.revision),
- &state.graphs,
- );
- write_memory_graph_snapshot(&memory_graph_store, &snapshot).map_err(|error| {
- format!(
- "failed to write memory graph store {} from thread state: {error}",
- memory_graph_store.display()
- )
- })?;
- (snapshot, true)
- }
- };
-
- let mut packet = plan_memory_graph_context_cut(
- &snapshot,
- &EpiphanyMemoryContextQuery {
- id: format!("bridge-launch-query-state-rev-{}", state.revision),
- profile: Some(EpiphanyMemoryProfile::RepoArchitecture),
- text: Some(focus.to_string()),
- budget: Some(5),
- ..Default::default()
- },
- );
- if refreshed_from_state {
- packet.warnings.push(format!(
- "Memory graph store was refreshed from current thread-state repo graph at {}.",
- memory_graph_store.display()
- ));
- }
- if packet.nodes.is_empty() && packet.summaries.is_empty() {
- packet.warnings.push(
- "Memory graph context is empty for this launch focus; the accepted repo graph may be thin or stale.".to_string(),
- );
- }
- Ok(packet)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use epiphany_core::EpiphanyRoleResultRoleId;
- use epiphany_core::RuntimeSpineHeartbeatJobOptions;
- use epiphany_core::build_epiphany_role_launch_request_with_dynamic_context;
- use epiphany_core::open_runtime_spine_heartbeat_job;
- use epiphany_core::runtime_worker_launch_request;
- use std::fs;
- use uuid::Uuid;
-
- #[test]
- fn launch_context_persists_on_runtime_worker_request() -> anyhow::Result<()> {
- let temp =
- std::env::temp_dir().join(format!("epiphany-bridge-launch-context-{}", Uuid::new_v4()));
- fs::create_dir_all(&temp)?;
- let runtime_store = temp.join("runtime-spine.cc");
- let state = EpiphanyThreadState {
- revision: 7,
- objective: Some("Test launch context.".to_string()),
- ..Default::default()
- };
-
- let rendered = render_launch_dynamic_prompt_context(
- &runtime_store,
- &state,
- role_launch_context_focus(&state, "modeling"),
- )
- .map_err(anyhow::Error::msg)?;
-
- assert!(rendered.contains(""));
- assert!(rendered.contains("Test launch context."));
- assert!(rendered.contains("Odin"));
- assert!(rendered.contains("Yggdrasil"));
- assert!(rendered.contains("Memory graph"));
- assert!(local_verse_store_path(&runtime_store).exists());
- assert!(memory_graph_store_path(&runtime_store).exists());
-
- let launch_request = build_epiphany_role_launch_request_with_dynamic_context(
- "thread-1",
- EpiphanyRoleResultRoleId::Modeling,
- Some(state.revision),
- Some(60),
- &state,
- Some(rendered.clone()),
- )
- .map_err(anyhow::Error::msg)?;
- open_runtime_spine_heartbeat_job(
- &runtime_store,
- RuntimeSpineHeartbeatJobOptions {
- runtime_id: EPIPHANY_LOCAL_VERSE_RUNTIME_ID.to_string(),
- display_name: "Epiphany Local".to_string(),
- session_id: "epiphany-main".to_string(),
- objective: "Test persisted launch context.".to_string(),
- coordinator_note: "Bridge launch-context smoke.".to_string(),
- job_id: "job-launch-context".to_string(),
- role: launch_request.owner_role.clone(),
- binding_id: launch_request.binding_id.clone(),
- authority_scope: launch_request.authority_scope.clone(),
- instruction: launch_request.instruction.clone(),
- launch_document: launch_request.launch_document.clone(),
- output_contract_id: launch_request.output_contract_id.clone(),
- organ_launch_contract: launch_request.organ_launch_contract.clone(),
- created_at: "2026-06-02T00:00:00Z".to_string(),
- },
- )?;
- let stored = runtime_worker_launch_request(&runtime_store, "job-launch-context")?
- .expect("runtime worker launch request should be persisted");
- let stored_document = stored.launch_document()?;
- let stored_context = stored_document
- .dynamic_prompt_context()
- .expect("stored launch document should carry dynamic context");
- assert!(stored_context.contains("Odin"));
- assert!(stored_context.contains("Memory graph"));
- assert!(stored_context.contains("Test launch context."));
-
- fs::remove_dir_all(&temp)?;
- Ok(())
- }
-}
diff --git a/epiphany-codex-bridge/src/lib.rs b/epiphany-codex-bridge/src/lib.rs
deleted file mode 100644
index 05717d56..00000000
--- a/epiphany-codex-bridge/src/lib.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-//! Compatibility bridge between Epiphany's typed CultNet/CultCache-shaped
-//! contracts and the vendored Codex JSON-RPC/app-server shell.
-//!
-//! This crate is a bridge, not an authority organ. Its job is to translate
-//! Codex `ThreadEpiphany*` DTOs into Epiphany core documents, project typed
-//! Epiphany surfaces back into legacy Codex responses, and call the narrow
-//! host trait needed while Codex still owns thread persistence. Verdicts,
-//! launch policy, reorientation policy, acceptance rules, runtime-spine
-//! lifecycle semantics, and durable state invariants belong in `epiphany-core`
-//! or `epiphany-state-model`.
-//!
-//! Host facts and side effects that still pass through this crate are
-//! quarantine scaffolding for the current Codex shell. Do not let them become
-//! a second policy throne. The long cut is to replace these adapters with
-//! native CultNet intents and receipts, leaving Codex only as the OpenAI
-//! subscription auth/model transport reliquary.
-
-pub mod checkpoint;
-pub mod context;
-pub mod context_protocol;
-pub mod coordinator;
-pub mod coordinator_protocol;
-pub mod cultnet;
-pub mod error;
-pub mod invalidation;
-pub mod jobs;
-pub mod launch;
-pub mod launch_context;
-pub mod mutation;
-pub mod mutation_service;
-pub mod pressure;
-pub mod protocol_edge;
-pub mod reorient;
-pub mod results;
-pub mod retrieve;
-pub mod retrieve_protocol;
-pub mod runtime_results;
-pub mod scene;
-pub mod scene_protocol;
-pub mod state;
-pub mod view_protocol;
diff --git a/epiphany-codex-bridge/src/mutation.rs b/epiphany-codex-bridge/src/mutation.rs
deleted file mode 100644
index 4f285860..00000000
--- a/epiphany-codex-bridge/src/mutation.rs
+++ /dev/null
@@ -1,337 +0,0 @@
-use epiphany_core::EpiphanyReorientAcceptanceFinding;
-use epiphany_core::EpiphanyReorientFindingInterpretation as CoreEpiphanyReorientFinding;
-use epiphany_core::EpiphanyRoleAcceptanceFinding;
-use epiphany_core::EpiphanyRoleFindingInterpretation as CoreEpiphanyRoleFinding;
-use epiphany_core::EpiphanyRoleResultRoleId;
-use epiphany_core::EpiphanyRoleStatePatchDocument;
-use epiphany_core::EpiphanyStateUpdate;
-use epiphany_core::EpiphanyStateUpdatedField;
-use epiphany_core::MindGatewayReview;
-use epiphany_core::build_reorient_acceptance_bundle;
-use epiphany_core::build_role_acceptance_bundle;
-use epiphany_core::imagination_role_state_patch_policy_errors;
-use epiphany_core::mind_review_allows_state;
-use epiphany_core::mind_review_reorient_acceptance;
-use epiphany_core::mind_review_role_acceptance;
-use epiphany_core::modeling_role_state_patch_policy_errors;
-use epiphany_state_model::EpiphanyInvestigationCheckpoint;
-
-pub struct RoleAcceptanceUpdate {
- pub state_update: EpiphanyStateUpdate,
- pub applied_patch: EpiphanyRoleStatePatchDocument,
- pub changed_fields: Vec,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub mind_review: MindGatewayReview,
-}
-
-pub struct ReorientAcceptanceUpdate {
- pub state_update: EpiphanyStateUpdate,
- pub changed_fields: Vec,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub mind_review: MindGatewayReview,
-}
-
-pub fn parse_core_role_finding_state_patch(
- finding: &CoreEpiphanyRoleFinding,
-) -> Result {
- finding
- .state_patch
- .clone()
- .ok_or_else(|| "completed role finding did not include a reviewable statePatch".to_string())
-}
-
-pub fn state_update_from_core_patch(
- expected_revision: Option,
- patch: EpiphanyRoleStatePatchDocument,
-) -> EpiphanyStateUpdate {
- EpiphanyStateUpdate {
- expected_revision,
- objective: patch.objective,
- active_subgoal_id: patch.active_subgoal_id,
- subgoals: patch.subgoals,
- invariants: patch.invariants,
- graphs: patch.graphs,
- graph_frontier: patch.graph_frontier,
- graph_checkpoint: patch.graph_checkpoint,
- scratch: patch.scratch,
- investigation_checkpoint: patch.investigation_checkpoint,
- job_bindings: patch.job_bindings,
- acceptance_receipts: patch.acceptance_receipts,
- runtime_links: patch.runtime_links,
- observations: patch.observations,
- evidence: patch.evidence,
- churn: patch.churn,
- mode: patch.mode,
- planning: patch.planning,
- }
-}
-
-pub fn build_role_acceptance_update(
- expected_revision: Option,
- role_id: EpiphanyRoleResultRoleId,
- binding_id: &str,
- finding: &CoreEpiphanyRoleFinding,
- accepted_evidence_id: String,
- accepted_observation_id: String,
- accepted_at: String,
-) -> Result {
- let mut core_patch = match role_id {
- EpiphanyRoleResultRoleId::Imagination => {
- let patch = parse_core_role_finding_state_patch(finding)?;
- let patch_errors = imagination_role_state_patch_policy_errors(&patch);
- if !patch_errors.is_empty() {
- return Err(format!(
- "imagination role state patch is not acceptable: {}",
- patch_errors.join("; ")
- ));
- }
- patch
- }
- EpiphanyRoleResultRoleId::Modeling => {
- let patch = parse_core_role_finding_state_patch(finding)?;
- let patch_errors = modeling_role_state_patch_policy_errors(&patch);
- if !patch_errors.is_empty() {
- return Err(format!(
- "modeling role state patch is not acceptable: {}",
- patch_errors.join("; ")
- ));
- }
- patch
- }
- EpiphanyRoleResultRoleId::Research => {
- let patch = parse_core_role_finding_state_patch(finding)?;
- let patch_errors = epiphany_core::research_role_state_patch_policy_errors(&patch);
- if !patch_errors.is_empty() {
- return Err(format!(
- "research role state patch is not acceptable: {}",
- patch_errors.join("; ")
- ));
- }
- patch
- }
- EpiphanyRoleResultRoleId::Verification => EpiphanyRoleStatePatchDocument::default(),
- EpiphanyRoleResultRoleId::Implementation | EpiphanyRoleResultRoleId::Reorientation => {
- return Err(format!(
- "role {:?} cannot be accepted through roleAccept",
- role_id
- ));
- }
- };
-
- let projected_fields = epiphany_update_patch_changed_fields(&core_patch)
- .into_iter()
- .map(|field| format!("{field:?}"))
- .collect();
- let mind_review = mind_review_role_acceptance(binding_id, role_id, finding, &core_patch);
- mind_review_allows_state(&mind_review)?;
- let acceptance_bundle = build_role_acceptance_bundle(
- binding_id,
- EpiphanyRoleAcceptanceFinding {
- role_id,
- verdict: finding.verdict.clone(),
- summary: finding.summary.clone(),
- next_safe_move: finding.next_safe_move.clone(),
- files_inspected: finding.files_inspected.clone(),
- runtime_result_id: finding.runtime_result_id.clone(),
- runtime_job_id: finding.runtime_job_id.clone(),
- projected_fields,
- },
- accepted_evidence_id,
- accepted_observation_id,
- accepted_at,
- )?;
- let accepted_receipt_id = acceptance_bundle.accepted_receipt_id.clone();
- let accepted_observation_id = acceptance_bundle.accepted_observation_id.clone();
- let accepted_evidence_id = acceptance_bundle.accepted_evidence_id.clone();
- core_patch.evidence.push(acceptance_bundle.evidence);
- core_patch.observations.push(acceptance_bundle.observation);
- core_patch
- .acceptance_receipts
- .push(acceptance_bundle.receipt);
- let applied_patch = core_patch.clone();
- let changed_fields = epiphany_update_patch_changed_fields(&applied_patch);
- let state_update = state_update_from_core_patch(expected_revision, core_patch);
-
- Ok(RoleAcceptanceUpdate {
- state_update,
- applied_patch,
- changed_fields,
- accepted_receipt_id,
- accepted_observation_id,
- accepted_evidence_id,
- mind_review,
- })
-}
-
-pub fn build_reorient_acceptance_update(
- expected_revision: Option,
- binding_id: &str,
- finding: &CoreEpiphanyReorientFinding,
- accepted_evidence_id: String,
- accepted_observation_id: String,
- accepted_at: String,
- update_scratch: bool,
- update_investigation_checkpoint: bool,
- checkpoint: Option,
-) -> Result {
- let mind_finding = EpiphanyReorientAcceptanceFinding {
- mode: finding.mode.clone(),
- summary: finding.summary.clone(),
- next_safe_move: finding.next_safe_move.clone(),
- checkpoint_still_valid: finding.checkpoint_still_valid,
- files_inspected: finding.files_inspected.clone(),
- runtime_result_id: finding.runtime_result_id.clone(),
- runtime_job_id: finding.runtime_job_id.clone(),
- };
- let mind_review = mind_review_reorient_acceptance(
- binding_id,
- &mind_finding,
- update_scratch,
- update_investigation_checkpoint,
- );
- mind_review_allows_state(&mind_review)?;
- let acceptance_bundle = build_reorient_acceptance_bundle(
- binding_id,
- mind_finding,
- accepted_evidence_id,
- accepted_observation_id,
- accepted_at,
- update_scratch,
- update_investigation_checkpoint
- .then_some(checkpoint)
- .flatten(),
- )?;
- let accepted_receipt_id = acceptance_bundle.accepted_receipt_id.clone();
- let accepted_observation_id = acceptance_bundle.accepted_observation_id.clone();
- let accepted_evidence_id = acceptance_bundle.accepted_evidence_id.clone();
- let scratch = acceptance_bundle.scratch;
- let investigation_checkpoint = acceptance_bundle.investigation_checkpoint;
-
- let mut changed_fields = vec![
- EpiphanyStateUpdatedField::AcceptanceReceipts,
- EpiphanyStateUpdatedField::Observations,
- EpiphanyStateUpdatedField::Evidence,
- ];
- if scratch.is_some() {
- changed_fields.push(EpiphanyStateUpdatedField::Scratch);
- }
- if investigation_checkpoint.is_some() {
- changed_fields.push(EpiphanyStateUpdatedField::InvestigationCheckpoint);
- }
-
- Ok(ReorientAcceptanceUpdate {
- state_update: EpiphanyStateUpdate {
- expected_revision,
- scratch,
- investigation_checkpoint,
- acceptance_receipts: vec![acceptance_bundle.receipt],
- observations: vec![acceptance_bundle.observation],
- evidence: vec![acceptance_bundle.evidence],
- ..Default::default()
- },
- changed_fields,
- accepted_receipt_id,
- accepted_observation_id,
- accepted_evidence_id,
- mind_review,
- })
-}
-
-pub fn epiphany_job_launch_changed_fields() -> Vec {
- vec![
- EpiphanyStateUpdatedField::JobBindings,
- EpiphanyStateUpdatedField::RuntimeLinks,
- ]
-}
-
-pub fn thread_epiphany_patch_has_state_replacements(
- patch: &EpiphanyRoleStatePatchDocument,
-) -> bool {
- patch.objective.is_some()
- || patch.active_subgoal_id.is_some()
- || patch.subgoals.is_some()
- || patch.invariants.is_some()
- || patch.graphs.is_some()
- || patch.graph_frontier.is_some()
- || patch.graph_checkpoint.is_some()
- || patch.scratch.is_some()
- || patch.investigation_checkpoint.is_some()
- || patch.job_bindings.is_some()
- || !patch.acceptance_receipts.is_empty()
- || !patch.runtime_links.is_empty()
- || patch.churn.is_some()
- || patch.mode.is_some()
- || patch.planning.is_some()
-}
-
-pub fn epiphany_update_patch_changed_fields(
- patch: &EpiphanyRoleStatePatchDocument,
-) -> Vec {
- let mut fields = Vec::new();
- if patch.objective.is_some() {
- fields.push(EpiphanyStateUpdatedField::Objective);
- }
- if patch.active_subgoal_id.is_some() {
- fields.push(EpiphanyStateUpdatedField::ActiveSubgoalId);
- }
- if patch.subgoals.is_some() {
- fields.push(EpiphanyStateUpdatedField::Subgoals);
- }
- if patch.invariants.is_some() {
- fields.push(EpiphanyStateUpdatedField::Invariants);
- }
- if patch.graphs.is_some() {
- fields.push(EpiphanyStateUpdatedField::Graphs);
- }
- if patch.graph_frontier.is_some() {
- fields.push(EpiphanyStateUpdatedField::GraphFrontier);
- }
- if patch.graph_checkpoint.is_some() {
- fields.push(EpiphanyStateUpdatedField::GraphCheckpoint);
- }
- if patch.scratch.is_some() {
- fields.push(EpiphanyStateUpdatedField::Scratch);
- }
- if patch.investigation_checkpoint.is_some() {
- fields.push(EpiphanyStateUpdatedField::InvestigationCheckpoint);
- }
- if patch.job_bindings.is_some() {
- fields.push(EpiphanyStateUpdatedField::JobBindings);
- }
- if !patch.acceptance_receipts.is_empty() {
- fields.push(EpiphanyStateUpdatedField::AcceptanceReceipts);
- }
- if !patch.runtime_links.is_empty() {
- fields.push(EpiphanyStateUpdatedField::RuntimeLinks);
- }
- if !patch.observations.is_empty() {
- fields.push(EpiphanyStateUpdatedField::Observations);
- }
- if !patch.evidence.is_empty() {
- fields.push(EpiphanyStateUpdatedField::Evidence);
- }
- if patch.churn.is_some() {
- fields.push(EpiphanyStateUpdatedField::Churn);
- }
- if patch.mode.is_some() {
- fields.push(EpiphanyStateUpdatedField::Mode);
- }
- if patch.planning.is_some() {
- fields.push(EpiphanyStateUpdatedField::Planning);
- }
- fields
-}
-
-pub fn epiphany_promote_changed_fields(
- patch: &EpiphanyRoleStatePatchDocument,
-) -> Vec {
- let mut fields = epiphany_update_patch_changed_fields(patch);
- if !fields.contains(&EpiphanyStateUpdatedField::Evidence) {
- fields.push(EpiphanyStateUpdatedField::Evidence);
- }
- fields
-}
diff --git a/epiphany-codex-bridge/src/mutation_service.rs b/epiphany-codex-bridge/src/mutation_service.rs
deleted file mode 100644
index 46447fe9..00000000
--- a/epiphany-codex-bridge/src/mutation_service.rs
+++ /dev/null
@@ -1,1159 +0,0 @@
-use chrono::SecondsFormat;
-use chrono::Utc;
-use std::path::Path;
-use std::path::PathBuf;
-
-use epiphany_core::CONTINUITY_RECOVERY_RECEIPT_TYPE;
-use epiphany_core::EPIPHANY_IMPLEMENTATION_ROLE_BINDING_ID;
-use epiphany_core::EPIPHANY_REORIENT_LAUNCH_BINDING_ID;
-use epiphany_core::EPIPHANY_RESEARCH_ROLE_BINDING_ID;
-use epiphany_core::EYES_EVIDENCE_PACKET_TYPE;
-use epiphany_core::EpiphanyJobInterruptRequest;
-use epiphany_core::EpiphanyJobInterruptResult;
-use epiphany_core::EpiphanyJobLaunchRequest;
-use epiphany_core::EpiphanyJobLaunchResult;
-use epiphany_core::EpiphanyJobView;
-use epiphany_core::EpiphanyLaunchOrganContract;
-use epiphany_core::EpiphanyPromotionInput;
-use epiphany_core::EpiphanyReceiptEffectKind;
-use epiphany_core::EpiphanyReorientDecision;
-use epiphany_core::EpiphanyReorientFindingInterpretation;
-use epiphany_core::EpiphanyReorientStateStatus;
-use epiphany_core::EpiphanyRoleFindingInterpretation;
-use epiphany_core::EpiphanyRoleResultRoleId;
-use epiphany_core::EpiphanyRoleStatePatchDocument;
-use epiphany_core::EpiphanyStateUpdate;
-use epiphany_core::EpiphanyStateUpdatedField;
-use epiphany_core::EpiphanyTokenUsageSnapshot;
-use epiphany_core::MIND_GATEWAY_REVIEW_TYPE;
-use epiphany_core::MindGatewayReview;
-use epiphany_core::RuntimeSpineHeartbeatJobOptions;
-use epiphany_core::RuntimeSpineHeartbeatLaunchPlanOptions;
-use epiphany_core::SOUL_VERDICT_RECEIPT_TYPE;
-use epiphany_core::SUBSTRATE_GATE_REPO_ACCESS_GRANT_RECEIPT_TYPE;
-use epiphany_core::apply_epiphany_state_update;
-use epiphany_core::build_epiphany_reorient_launch_request_with_dynamic_context;
-use epiphany_core::build_epiphany_role_launch_request_with_dynamic_context;
-use epiphany_core::clear_epiphany_job_binding_backend;
-use epiphany_core::continuity_recovery_receipt_from_reorient_finding;
-use epiphany_core::epiphany_role_label;
-use epiphany_core::epiphany_state_update_validation_errors;
-use epiphany_core::evaluate_promotion;
-use epiphany_core::evaluate_receipt_proof_profiles;
-use epiphany_core::eyes_evidence_packet_from_research_finding;
-use epiphany_core::mind_state_commit_receipt;
-use epiphany_core::open_runtime_spine_heartbeat_job;
-use epiphany_core::plan_runtime_spine_heartbeat_launch;
-use epiphany_core::put_continuity_recovery_receipt;
-use epiphany_core::put_eyes_evidence_packet;
-use epiphany_core::put_mind_gateway_review;
-use epiphany_core::put_mind_state_commit_receipt;
-use epiphany_core::put_soul_verdict_receipt;
-use epiphany_core::put_substrate_gate_repo_access_grant_receipt;
-use epiphany_core::receipt_proof_evaluation_errors;
-use epiphany_core::replace_or_append_epiphany_job_binding;
-use epiphany_core::runtime_continuity_recovery_receipt;
-use epiphany_core::runtime_eyes_evidence_packet;
-use epiphany_core::runtime_job_snapshot;
-use epiphany_core::runtime_mind_gateway_review;
-use epiphany_core::runtime_mind_state_commit_receipt;
-use epiphany_core::runtime_soul_verdict_receipt;
-use epiphany_core::runtime_substrate_gate_repo_access_grant_receipt;
-use epiphany_core::soul_verdict_receipt_from_verification_finding;
-use epiphany_core::substrate_gate_repo_access_grant_for_launch;
-use epiphany_core::substrate_gate_repo_mutation_grant_for_launch;
-use epiphany_state_model::EpiphanyEvidenceRecord;
-use epiphany_state_model::EpiphanyJobKind as CoreEpiphanyJobKind;
-use epiphany_state_model::EpiphanyRetrievalState;
-use epiphany_state_model::EpiphanyRuntimeLink;
-use epiphany_state_model::EpiphanyThreadState;
-
-use crate::cultnet::EpiphanySurfaceSource;
-use crate::error::EpiphanyBridgeError;
-use crate::error::Result as BridgeResult;
-use crate::jobs::derive_epiphany_jobs;
-use crate::jobs::epiphany_blocked_state_job;
-use crate::jobs::map_interrupted_epiphany_job;
-use crate::jobs::map_launched_epiphany_job;
-use crate::launch_context::render_launch_dynamic_prompt_context;
-use crate::launch_context::reorient_launch_context_focus;
-use crate::launch_context::role_launch_context_focus;
-use crate::mutation::build_reorient_acceptance_update;
-use crate::mutation::build_role_acceptance_update;
-use crate::mutation::epiphany_job_launch_changed_fields;
-use crate::mutation::epiphany_promote_changed_fields;
-use crate::mutation::epiphany_update_patch_changed_fields;
-use crate::mutation::thread_epiphany_patch_has_state_replacements;
-use crate::pressure::derive_epiphany_pressure;
-use crate::reorient::EpiphanyFreshnessWatcherSnapshot;
-use crate::reorient::derive_epiphany_freshness_view;
-use crate::reorient::derive_epiphany_reorient;
-use crate::runtime_results::latest_epiphany_runtime_link_for_binding;
-use crate::runtime_results::load_completed_core_epiphany_reorient_finding;
-use crate::runtime_results::load_completed_core_epiphany_role_finding;
-use crate::runtime_results::load_launch_organ_contract_for_runtime_job;
-use uuid::Uuid;
-
-#[allow(async_fn_in_trait)]
-pub trait EpiphanyMutationHost {
- /// Read the Codex-hosted compatibility snapshot.
- ///
- /// The bridge may request host state so core can evaluate typed policy. The
- /// host snapshot is an input fact, not a bridge-owned source of truth.
- async fn epiphany_state(&self) -> Option;
- async fn epiphany_reference_turn_id(&self) -> Option;
- /// Persist a state document already validated by Epiphany core policy.
- ///
- /// This is the Codex JSON-RPC shell's current persistence hook. It must not
- /// grow mutation policy of its own.
- async fn epiphany_persist_state(
- &self,
- next_state: EpiphanyThreadState,
- ) -> BridgeResult;
- /// Locate the native runtime-spine store while Codex still hosts the turn.
- async fn epiphany_runtime_spine_store_path(&self) -> PathBuf;
- /// Project the already-typed state into Codex's current client-visible view.
- async fn client_visible_epiphany_state(
- &self,
- fallback: EpiphanyThreadState,
- ) -> EpiphanyThreadState;
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyThreadUpdateApplied {
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
-}
-
-#[derive(Debug, Clone)]
-pub enum EpiphanyThreadPromoteApplied {
- Rejected { reasons: Vec },
- Accepted(EpiphanyThreadUpdateApplied),
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyRoleAcceptApplied {
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub applied_patch: EpiphanyRoleStatePatchDocument,
- pub finding: EpiphanyRoleFindingInterpretation,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyReorientAcceptApplied {
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub accepted_receipt_id: String,
- pub accepted_observation_id: String,
- pub accepted_evidence_id: String,
- pub finding: EpiphanyReorientFindingInterpretation,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyJobLaunchApplied {
- pub launcher_job_id: String,
- pub backend_job_id: String,
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub job: EpiphanyJobView,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyJobInterruptApplied {
- pub cancel_requested: bool,
- pub interrupted_thread_ids: Vec,
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub job: EpiphanyJobView,
-}
-
-#[derive(Debug, Clone)]
-pub struct EpiphanyReorientLaunchApplied {
- pub launcher_job_id: String,
- pub backend_job_id: String,
- pub source: EpiphanySurfaceSource,
- pub state_status: EpiphanyReorientStateStatus,
- pub state_revision: Option,
- pub decision: EpiphanyReorientDecision,
- pub revision: u64,
- pub changed_fields: Vec,
- pub epiphany_state: EpiphanyThreadState,
- pub job: EpiphanyJobView,
-}
-
-pub async fn apply_epiphany_state_update_to_thread(
- thread: &impl EpiphanyMutationHost,
- update: EpiphanyStateUpdate,
-) -> BridgeResult {
- let current_state = thread.epiphany_state().await.unwrap_or_default();
- let reference_turn_id = thread.epiphany_reference_turn_id().await;
- let next_state =
- apply_epiphany_state_update_to_state(¤t_state, update, reference_turn_id)?;
- thread.epiphany_persist_state(next_state).await
-}
-
-pub fn apply_epiphany_state_update_to_state(
- current_state: &EpiphanyThreadState,
- update: EpiphanyStateUpdate,
- reference_turn_id: Option,
-) -> BridgeResult {
- if update.is_empty() {
- return Err(EpiphanyBridgeError::InvalidRequest(
- "epiphany update patch must contain at least one mutation".to_string(),
- ));
- }
-
- let mut next_state = current_state.clone();
- if let Some(expected_revision) = update.expected_revision
- && next_state.revision != expected_revision
- {
- return Err(EpiphanyBridgeError::InvalidRequest(format!(
- "epiphany state revision mismatch: expected {expected_revision}, found {}",
- next_state.revision
- )));
- }
-
- let validation_errors = epiphany_state_update_validation_errors(&next_state, &update);
- if !validation_errors.is_empty() {
- return Err(EpiphanyBridgeError::InvalidRequest(format!(
- "invalid epiphany update patch: {}",
- validation_errors.join("; ")
- )));
- }
-
- apply_epiphany_state_update(&mut next_state, update, reference_turn_id);
- Ok(next_state)
-}
-
-pub async fn launch_epiphany_job_on_thread(
- thread: &impl EpiphanyMutationHost,
- request: EpiphanyJobLaunchRequest,
-) -> BridgeResult {
- // Compatibility choreography only: core validates the launch plan and
- // runtime-spine opens the typed job. The bridge stitches those typed
- // documents into Codex's JSON-RPC thread shell until CultNet owns the route.
- let current_state = thread.epiphany_state().await.unwrap_or_default();
- validate_expected_revision(request.expected_revision, current_state.revision)?;
- let runtime_store = thread.epiphany_runtime_spine_store_path().await;
- let completed_prior_link = terminal_runtime_link_for_binding(
- ¤t_state,
- request.binding_id.as_str(),
- runtime_store.as_path(),
- )?;
- let mut planning_state = current_state.clone();
- if let Some(link) = completed_prior_link.clone() {
- planning_state.runtime_links.insert(0, link);
- }
-
- let launcher_job_id = format!("epiphany-heartbeat-launch-{}", Uuid::new_v4());
- let backend_job_id = Uuid::new_v4().to_string();
- let launch_plan = plan_runtime_spine_heartbeat_launch(
- &planning_state,
- RuntimeSpineHeartbeatLaunchPlanOptions {
- binding_id: request.binding_id.clone(),
- kind: request.kind,
- scope: request.scope.clone(),
- owner_role: request.owner_role.clone(),
- authority_scope: request.authority_scope.clone(),
- linked_subgoal_ids: request.linked_subgoal_ids.clone(),
- linked_graph_node_ids: request.linked_graph_node_ids.clone(),
- instruction: request.instruction.clone(),
- launch_document: request.launch_document.clone(),
- output_contract_id: request.output_contract_id.clone(),
- organ_launch_contract: request.organ_launch_contract.clone(),
- max_runtime_seconds: request.max_runtime_seconds,
- runtime_job_id: backend_job_id.clone(),
- },
- )
- .map_err(|err| EpiphanyBridgeError::InvalidRequest(err.to_string()))?;
- let next_job_bindings = replace_or_append_epiphany_job_binding(
- current_state.job_bindings.clone(),
- launch_plan.binding,
- );
-
- let mut runtime_links = Vec::new();
- runtime_links.push(launch_plan.runtime_link.clone());
- if let Some(link) = completed_prior_link {
- runtime_links.push(link);
- }
-
- let validation_errors = epiphany_state_update_validation_errors(
- ¤t_state,
- &EpiphanyStateUpdate {
- job_bindings: Some(next_job_bindings.clone()),
- runtime_links: runtime_links.clone(),
- ..Default::default()
- },
- );
- if !validation_errors.is_empty() {
- return Err(EpiphanyBridgeError::InvalidRequest(format!(
- "invalid Epiphany job launch patch: {}",
- validation_errors.join("; ")
- )));
- }
- open_epiphany_runtime_spine_job(
- runtime_store.as_path(),
- &planning_state,
- &request,
- backend_job_id.as_str(),
- )?;
- maybe_put_substrate_gate_launch_grant(
- runtime_store.as_path(),
- &request,
- backend_job_id.as_str(),
- )?;
-
- let epiphany_state = apply_epiphany_state_update_to_thread(
- thread,
- EpiphanyStateUpdate {
- expected_revision: request.expected_revision,
- job_bindings: Some(next_job_bindings),
- runtime_links,
- ..Default::default()
- },
- )
- .await?;
-
- Ok(EpiphanyJobLaunchResult {
- epiphany_state,
- binding_id: request.binding_id,
- launcher_job_id,
- backend_job_id,
- })
-}
-
-fn terminal_runtime_link_for_binding(
- state: &EpiphanyThreadState,
- binding_id: &str,
- runtime_store: &Path,
-) -> BridgeResult