Add typed tool invocation contracts

This commit is contained in:
Meta Vens 2026-05-27 22:51:13 +01:00
commit 65a65c19e7
12 changed files with 1097 additions and 1 deletions

View file

@ -18,6 +18,7 @@ cultmesh-rs = { path = "../vendor/cultmesh-rs" }
cultnet-rs = { path = "../vendor/cultnet-rs" }
epiphany-openai-adapter = { path = "../epiphany-openai-adapter" }
epiphany-model-adapter = { path = "../epiphany-model-adapter" }
epiphany-tool-adapter = { path = "../epiphany-tool-adapter" }
epiphany-state-model = { path = "../epiphany-state-model" }
ignore = "0.4.23"
postgres = "0.19"

View file

@ -83,6 +83,9 @@ use epiphany_state_model::EpiphanyJobBinding;
use epiphany_state_model::EpiphanyJobKind;
use epiphany_state_model::EpiphanyRuntimeLink;
use epiphany_state_model::EpiphanyThreadState;
use epiphany_tool_adapter::EpiphanyToolCapability;
use epiphany_tool_adapter::EpiphanyToolInvocationIntent;
use epiphany_tool_adapter::EpiphanyToolInvocationReceipt;
use serde::Deserialize;
use serde::Serialize;
use std::collections::BTreeMap;
@ -107,6 +110,9 @@ pub const MODEL_ADAPTER_STATUS_TYPE: &str = "epiphany.model_adapter_status.v0";
pub const MODEL_REQUEST_TYPE: &str = "epiphany.model_request.v0";
pub const MODEL_STREAM_EVENT_TYPE: &str = "epiphany.model_stream_event.v0";
pub const MODEL_RECEIPT_TYPE: &str = "epiphany.model_receipt.v0";
pub const TOOL_CAPABILITY_TYPE: &str = "epiphany.tool_capability.v0";
pub const TOOL_INVOCATION_INTENT_TYPE: &str = "epiphany.tool_invocation_intent.v0";
pub const TOOL_INVOCATION_RECEIPT_TYPE: &str = "epiphany.tool_invocation_receipt.v0";
pub const SURFACE_SCENE_TYPE: &str = "epiphany.surface.scene";
pub const SURFACE_FRESHNESS_TYPE: &str = "epiphany.surface.freshness";
pub const SURFACE_CONTEXT_TYPE: &str = "epiphany.surface.context";
@ -141,6 +147,9 @@ pub const MODEL_ADAPTER_STATUS_SCHEMA_VERSION: &str = "epiphany.model_adapter_st
pub const MODEL_REQUEST_SCHEMA_VERSION: &str = "epiphany.model_request.v0";
pub const MODEL_STREAM_EVENT_SCHEMA_VERSION: &str = "epiphany.model_stream_event.v0";
pub const MODEL_RECEIPT_SCHEMA_VERSION: &str = "epiphany.model_receipt.v0";
pub const TOOL_CAPABILITY_SCHEMA_VERSION: &str = "epiphany.tool_capability.v0";
pub const TOOL_INVOCATION_INTENT_SCHEMA_VERSION: &str = "epiphany.tool_invocation_intent.v0";
pub const TOOL_INVOCATION_RECEIPT_SCHEMA_VERSION: &str = "epiphany.tool_invocation_receipt.v0";
pub const SCENE_SURFACE_SCHEMA_VERSION: &str = "epiphany.scene_surface.v0";
pub const FRESHNESS_SURFACE_SCHEMA_VERSION: &str = "epiphany.freshness_surface.v0";
pub const CONTEXT_SURFACE_SCHEMA_VERSION: &str = "epiphany.context_surface.v0";
@ -684,6 +693,9 @@ pub fn runtime_spine_cache(store_path: impl AsRef<Path>) -> Result<CultCache> {
cache.register_entry_type::<EpiphanyModelRequest>()?;
cache.register_entry_type::<EpiphanyModelStreamEvent>()?;
cache.register_entry_type::<EpiphanyModelReceipt>()?;
cache.register_entry_type::<EpiphanyToolCapability>()?;
cache.register_entry_type::<EpiphanyToolInvocationIntent>()?;
cache.register_entry_type::<EpiphanyToolInvocationReceipt>()?;
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(
store_path.to_path_buf(),
));
@ -2165,6 +2177,42 @@ fn epiphany_mutation_contracts() -> Vec<CultNetDocumentMutationContract> {
"Terminal model receipts carry provider response id, usage, and transport evidence.",
],
),
mutation_contract(
TOOL_CAPABILITY_TYPE,
TOOL_CAPABILITY_SCHEMA_VERSION,
vec![CultNetDocumentOperation::Snapshot],
CultNetMutationAuthority::ReadOnly,
vec![],
vec![],
vec![
"Tool capability documents describe adapter-discovered tools without making raw MCP discovery JSON authoritative.",
],
),
mutation_contract(
TOOL_INVOCATION_INTENT_TYPE,
TOOL_INVOCATION_INTENT_SCHEMA_VERSION,
vec![
CultNetDocumentOperation::IntentSubmit,
CultNetDocumentOperation::ReceiptWatch,
],
CultNetMutationAuthority::Coordinator,
vec![TOOL_INVOCATION_INTENT_TYPE],
vec![TOOL_INVOCATION_RECEIPT_TYPE],
vec![
"Tool calls enter Epiphany as typed invocation intents; MCP JSON remains protocol-edge cargo.",
],
),
mutation_contract(
TOOL_INVOCATION_RECEIPT_TYPE,
TOOL_INVOCATION_RECEIPT_SCHEMA_VERSION,
vec![CultNetDocumentOperation::ReceiptWatch],
CultNetMutationAuthority::ReadOnly,
vec![],
vec![],
vec![
"Tool invocation receipts seal parsed results, errors, and raw-result artifact refs before scheduler or state admission.",
],
),
mutation_contract(
OPENAI_ADAPTER_STATUS_TYPE,
OPENAI_ADAPTER_STATUS_SCHEMA_VERSION,
@ -3229,6 +3277,22 @@ mod tests {
assert!(openai_contract.notes.as_ref().is_some_and(|notes| {
notes.iter().any(|note| note.contains("adapter projection"))
}));
let tool_intent_contract = contracts
.iter()
.find(|contract| contract.document_type == TOOL_INVOCATION_INTENT_TYPE)
.expect("tool invocation intent should advertise typed adapter contract");
assert_eq!(
tool_intent_contract.authority,
CultNetMutationAuthority::Coordinator
);
assert!(
tool_intent_contract
.receipt_document_types
.as_ref()
.is_some_and(|items| items
.iter()
.any(|item| item == TOOL_INVOCATION_RECEIPT_TYPE))
);
let memory_graph_contract = contracts
.iter()
.find(|contract| contract.document_type == MEMORY_GRAPH_TYPE)
@ -3295,6 +3359,14 @@ mod tests {
schema.document_type.as_deref() == Some(MODEL_RECEIPT_TYPE)
&& schema.schema_version.as_deref() == Some(MODEL_RECEIPT_SCHEMA_VERSION)
}));
assert!(schemas.iter().any(|schema| {
schema.document_type.as_deref() == Some(TOOL_INVOCATION_INTENT_TYPE)
&& schema.schema_version.as_deref() == Some(TOOL_INVOCATION_INTENT_SCHEMA_VERSION)
}));
assert!(schemas.iter().any(|schema| {
schema.document_type.as_deref() == Some(TOOL_INVOCATION_RECEIPT_TYPE)
&& schema.schema_version.as_deref() == Some(TOOL_INVOCATION_RECEIPT_SCHEMA_VERSION)
}));
let receipt_schema_path =
epiphany_schema_root().join("epiphany.swarm-control-receipt.schema.json");
let receipt_schema: serde_json::Value =

737
epiphany-tool-adapter/Cargo.lock generated Normal file
View file

@ -0,0 +1,737 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anyhow"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "autocfg"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "bitflags"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]]
name = "bumpalo"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "cc"
version = "1.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chrono"
version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"serde",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "cultcache-rs"
version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"cultcache-rs-derive",
"fs2",
"rmp-serde",
"serde",
"serde_bytes",
"serde_json",
"uuid",
]
[[package]]
name = "cultcache-rs-derive"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "epiphany-tool-adapter"
version = "0.1.0"
dependencies = [
"cultcache-rs",
"serde",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "foldhash"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "fs2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "futures-core"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-task"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"slab",
]
[[package]]
name = "getrandom"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasip2",
"wasip3",
]
[[package]]
name = "hashbrown"
version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
]
[[package]]
name = "hashbrown"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[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 = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "indexmap"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"serde",
"serde_core",
]
[[package]]
name = "itoa"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
dependencies = [
"cfg-if",
"futures-util",
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "libc"
version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]]
name = "log"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616ec5685824bcc94416c6d4a7a446eea774a31efd7062c8480ba6fd06d7a6e5"
[[package]]
name = "memchr"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "pin-project-lite"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
[[package]]
name = "r-efi"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[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 = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
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.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "slab"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "uuid"
version = "1.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
dependencies = [
"getrandom",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "wasip2"
version = "1.0.3+wasi-0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
dependencies = [
"wit-bindgen 0.57.1",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen 0.51.0",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.122"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags",
"hashbrown 0.15.5",
"indexmap",
"semver",
]
[[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-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[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-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[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",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[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 = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen"
version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap",
"prettyplease",
"syn",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"

View file

@ -0,0 +1,12 @@
[package]
name = "epiphany-tool-adapter"
version = "0.1.0"
edition = "2024"
[lib]
name = "epiphany_tool_adapter"
path = "src/lib.rs"
[dependencies]
cultcache-rs = { path = "../vendor/cultcache-rs" }
serde = { version = "1", features = ["derive"] }

View file

@ -0,0 +1,153 @@
use cultcache_rs::DatabaseEntry;
pub const TOOL_ADAPTER_CAPABILITY_SCHEMA_ID: &str = "epiphany.tool_capability.v0";
pub const TOOL_ADAPTER_INVOCATION_INTENT_SCHEMA_ID: &str = "epiphany.tool_invocation_intent.v0";
pub const TOOL_ADAPTER_INVOCATION_RECEIPT_SCHEMA_ID: &str = "epiphany.tool_invocation_receipt.v0";
#[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)]
#[cultcache(
type = "epiphany.tool_capability.v0",
schema = "EpiphanyToolCapability"
)]
pub struct EpiphanyToolCapability {
#[cultcache(key = 0)]
pub schema_id: String,
#[cultcache(key = 1)]
pub capability_id: String,
#[cultcache(key = 2)]
pub adapter: String,
#[cultcache(key = 3)]
pub server: String,
#[cultcache(key = 4)]
pub tool_name: String,
#[cultcache(key = 5, default)]
pub description: Option<String>,
#[cultcache(key = 6, default)]
pub input_schema_json: Option<String>,
}
impl EpiphanyToolCapability {
pub fn new(
capability_id: impl Into<String>,
adapter: impl Into<String>,
server: impl Into<String>,
tool_name: impl Into<String>,
) -> Self {
Self {
schema_id: TOOL_ADAPTER_CAPABILITY_SCHEMA_ID.to_string(),
capability_id: capability_id.into(),
adapter: adapter.into(),
server: server.into(),
tool_name: tool_name.into(),
description: None,
input_schema_json: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)]
#[cultcache(
type = "epiphany.tool_invocation_intent.v0",
schema = "EpiphanyToolInvocationIntent"
)]
pub struct EpiphanyToolInvocationIntent {
#[cultcache(key = 0)]
pub schema_id: String,
#[cultcache(key = 1)]
pub intent_id: String,
#[cultcache(key = 2)]
pub adapter: String,
#[cultcache(key = 3)]
pub server: String,
#[cultcache(key = 4)]
pub tool_name: String,
#[cultcache(key = 5)]
pub arguments_json: String,
#[cultcache(key = 6)]
pub caller: String,
#[cultcache(key = 7)]
pub reason: String,
#[cultcache(key = 8)]
pub created_at: String,
}
impl EpiphanyToolInvocationIntent {
pub fn new(
intent_id: impl Into<String>,
adapter: impl Into<String>,
server: impl Into<String>,
tool_name: impl Into<String>,
arguments_json: impl Into<String>,
caller: impl Into<String>,
reason: impl Into<String>,
created_at: impl Into<String>,
) -> Self {
Self {
schema_id: TOOL_ADAPTER_INVOCATION_INTENT_SCHEMA_ID.to_string(),
intent_id: intent_id.into(),
adapter: adapter.into(),
server: server.into(),
tool_name: tool_name.into(),
arguments_json: arguments_json.into(),
caller: caller.into(),
reason: reason.into(),
created_at: created_at.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, DatabaseEntry)]
#[cultcache(
type = "epiphany.tool_invocation_receipt.v0",
schema = "EpiphanyToolInvocationReceipt"
)]
pub struct EpiphanyToolInvocationReceipt {
#[cultcache(key = 0)]
pub schema_id: String,
#[cultcache(key = 1)]
pub receipt_id: String,
#[cultcache(key = 2)]
pub intent_id: String,
#[cultcache(key = 3)]
pub adapter: String,
#[cultcache(key = 4)]
pub server: String,
#[cultcache(key = 5)]
pub tool_name: String,
#[cultcache(key = 6)]
pub status: String,
#[cultcache(key = 7)]
pub completed_at: String,
#[cultcache(key = 8, default)]
pub result_json: Option<String>,
#[cultcache(key = 9, default)]
pub error: Option<String>,
#[cultcache(key = 10, default)]
pub sealed_raw_result_ref: Option<String>,
}
impl EpiphanyToolInvocationReceipt {
pub fn new(
receipt_id: impl Into<String>,
intent_id: impl Into<String>,
adapter: impl Into<String>,
server: impl Into<String>,
tool_name: impl Into<String>,
status: impl Into<String>,
completed_at: impl Into<String>,
) -> Self {
Self {
schema_id: TOOL_ADAPTER_INVOCATION_RECEIPT_SCHEMA_ID.to_string(),
receipt_id: receipt_id.into(),
intent_id: intent_id.into(),
adapter: adapter.into(),
server: server.into(),
tool_name: tool_name.into(),
status: status.into(),
completed_at: completed_at.into(),
result_json: None,
error: None,
sealed_raw_result_ref: None,
}
}
}

View file

@ -39,6 +39,7 @@ remembers doctrine; the branch remembers the blade.
- `epiphany-mvp-status --source native` is the current provider-neutral status boundary. It projects scene, pressure, jobs, roles, planning, reorient, CRRC, and coordinator status from native core surfaces and returns provider/runtime worker results as `backendMissing` placeholders instead of asking Codex for model-worker state. Keep future pluggable model-provider work behind launch/result/runtime documents; do not let provider choice leak into status, prompt authority, scheduler policy, or durable `EpiphanyThreadState`.
- `epiphany-model-runtime` is the current provider-neutral executable boundary. It is built by the `epiphany-openai-runtime` crate for now and accepts `--provider openai-codex`; the old `epiphany-openai-runtime` binary, `--openai-runtime-bin`, and `openai-runtime` executor name survive only as compatibility aliases. Coordinator run mode, local wrapper run mode, and repo birth runner should call `--model-runtime-bin` plus `--model-provider`. The typed request/event/receipt contract is now provider-neutral in `epiphany-model-adapter` as `epiphany.model_request.v0`, `epiphany.model_stream_event.v0`, `epiphany.model_receipt.v0`, and `epiphany.model_adapter_status.v0`; OpenAI/Codex documents are adapter evidence behind that boundary, not scheduler/status/state authority.
- Coordinator plan/run passes now emit `epiphany.coordinator_run_receipt.v0` into runtime-spine. `coordinator-summary.json` and `coordinator-steps.jsonl` remain useful operator artifacts, but the durable receipt of what the coordinator decided is typed CultCache/CultNet state.
- The first tool/MCP contract surface exists in `epiphany-tool-adapter`: `epiphany.tool_capability.v0`, `epiphany.tool_invocation_intent.v0`, and `epiphany.tool_invocation_receipt.v0`. Runtime-spine advertises these as the Epiphany-facing tool boundary. Raw MCP JSON is still an execution-edge concern until a real adapter consumes the intents and emits the receipts.
- The active foundation directive is now `notes/codex-starvation-and-cultnet-liberation-plan.md`. The previous Codex app-server control-plane rebuild made Epiphany less rotten inside Codex, but that is not the destination. Epiphany must become a native CultCache/CultMesh/CultNet runtime while remaining an honest modified Codex-derived backend for subscription auth/model use. Codex should remain relatively vanilla and keep doing Codex things, including useful app-server and streaming bridge affordances, but it must not own Epiphany state, processes, prompts, scheduler decisions, or policy. The bridge handles interop; Codex and Epiphany do not get to rummage around in each other's organs.
- `notes/epiphany-cultmesh-dreaming-roadmap.md` is the new concrete design for distributed Epiphany dreaming. The invariant is hard: private state stays local; public dreams are separately authored typed documents distributed through CultMesh/CultNet; foreign dreams are thought weather until a reviewed local adoption receipt digests them. The first code slice should be dream schemas plus a local CultMesh-backed store, not public fanout.
- CultMesh is now the preferred Rust abstraction for that local store work. The compile-time Rust substrate is repo-contained: `vendor/cultcache-rs`, `vendor/cultnet-rs`, and `vendor/cultmesh-rs`. The old `E:\Projects\CultLib\crates\*` dependency body is dead in this checkout and must not be revived by accident. Vendored CultCache reads/writes `cultcache.store.v1`, so `state/ledgers.msgpack` and `epiphany-state status` are aligned again. The first integrations are deliberately small: status, Verse policy, global room policy, organ contract policy, native operator status, native operator snapshots, and local operator run intent/receipt round-trip through CultMesh. Use `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-cultmesh-smoke`, `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-cultmesh-status -- smoke --store .\.epiphany-smoke\cultmesh\operator-status.ccmp --runtime-id epiphany-cultmesh-status-smoke`, `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-operator-snapshot -- smoke --store .\.epiphany-smoke\cultmesh\operator-snapshots.ccmp --runtime-id epiphany-operator-snapshot-smoke --snapshot-id smoke-status`, and `cargo run --manifest-path .\epiphany-core\Cargo.toml --bin epiphany-operator-run -- smoke --store .\.epiphany-smoke\cultmesh\operator-runs.ccmp --runtime-id epiphany-operator-run-smoke --run-id smoke-run` for the focused proofs. Future local dream/status/Verse work should start from CultMesh, not raw CultNet, unless the task is polishing the CultMesh internals themselves. Preserve the three Verse tiers: `epiphany-internal` for private sub-agent typed state, `gamecult-local` for trusted LAN/Yggdrasil-tunnel GameCult sharing, and `epiphany-global` for untrusted public dreams plus topic-specific threaded public rooms for Face posts.

View file

@ -0,0 +1,18 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.tool-capability.schema.json",
"title": "Epiphany Tool Capability",
"description": "Typed capability advertised by an Epiphany tool adapter. MCP discovery JSON may be the source, but this document is the inspectable Epiphany-facing capability record.",
"type": "object",
"required": ["schema_id", "capability_id", "adapter", "server", "tool_name"],
"properties": {
"schema_id": { "const": "epiphany.tool_capability.v0" },
"capability_id": { "type": "string" },
"adapter": { "type": "string" },
"server": { "type": "string" },
"tool_name": { "type": "string" },
"description": { "type": ["string", "null"] },
"input_schema_json": { "type": ["string", "null"] }
},
"additionalProperties": false
}

View file

@ -0,0 +1,30 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.tool-invocation-intent.schema.json",
"title": "Epiphany Tool Invocation Intent",
"description": "Coordinator-owned typed request to call a tool through an adapter. Raw MCP arguments remain string cargo until the adapter validates them.",
"type": "object",
"required": [
"schema_id",
"intent_id",
"adapter",
"server",
"tool_name",
"arguments_json",
"caller",
"reason",
"created_at"
],
"properties": {
"schema_id": { "const": "epiphany.tool_invocation_intent.v0" },
"intent_id": { "type": "string" },
"adapter": { "type": "string" },
"server": { "type": "string" },
"tool_name": { "type": "string" },
"arguments_json": { "type": "string" },
"caller": { "type": "string" },
"reason": { "type": "string" },
"created_at": { "type": "string" }
},
"additionalProperties": false
}

View file

@ -0,0 +1,31 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://gamecult.dev/epiphany/cultnet/epiphany.tool-invocation-receipt.schema.json",
"title": "Epiphany Tool Invocation Receipt",
"description": "Typed receipt from a tool adapter after it executes or refuses a tool invocation.",
"type": "object",
"required": [
"schema_id",
"receipt_id",
"intent_id",
"adapter",
"server",
"tool_name",
"status",
"completed_at"
],
"properties": {
"schema_id": { "const": "epiphany.tool_invocation_receipt.v0" },
"receipt_id": { "type": "string" },
"intent_id": { "type": "string" },
"adapter": { "type": "string" },
"server": { "type": "string" },
"tool_name": { "type": "string" },
"status": { "type": "string" },
"completed_at": { "type": "string" },
"result_json": { "type": ["string", "null"] },
"error": { "type": ["string", "null"] },
"sealed_raw_result_ref": { "type": ["string", "null"] }
},
"additionalProperties": false
}

View file

@ -111,6 +111,39 @@
"title": "Epiphany Model Receipt",
"path": "epiphany.model-receipt.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.tool-capability.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.tool_capability.v0",
"documentType": "epiphany.tool_capability.v0",
"title": "Epiphany Tool Capability",
"path": "epiphany.tool-capability.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.tool-invocation-intent.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.tool_invocation_intent.v0",
"documentType": "epiphany.tool_invocation_intent.v0",
"title": "Epiphany Tool Invocation Intent",
"path": "epiphany.tool-invocation-intent.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.tool-invocation-receipt.schema.json",
"kind": "document_payload",
"wireContracts": [
"cultnet.schema.v0"
],
"schemaVersion": "epiphany.tool_invocation_receipt.v0",
"documentType": "epiphany.tool_invocation_receipt.v0",
"title": "Epiphany Tool Invocation Receipt",
"path": "epiphany.tool-invocation-receipt.schema.json"
},
{
"schemaId": "https://gamecult.dev/epiphany/cultnet/epiphany.openai-adapter-status.schema.json",
"kind": "document_payload",

Binary file not shown.

View file

@ -532,4 +532,12 @@ current_status:
existing coordinator artifact JSON remains operator display and sealed
audit evidence, but it is no longer the only durable account of what the
coordinator decided.
next_action: Continue Codex starvation and CultNet liberation by wrapping remaining unavoidable JSON protocol edges, especially MCP/tool execution, in typed Epiphany intent/result/receipt documents before letting them influence scheduler, state, or acceptance authority.
The first tool/MCP boundary contract is also named:
`epiphany-tool-adapter` owns typed `epiphany.tool_capability.v0`,
`epiphany.tool_invocation_intent.v0`, and
`epiphany.tool_invocation_receipt.v0` documents. Runtime-spine advertises
them as the Epiphany-facing tool contract so MCP discovery/call JSON can
remain protocol-edge cargo instead of scheduler, state, or acceptance
authority. This is a contract surface only; the executing MCP adapter still
needs to be built before Codex MCP routes can be demoted.
next_action: Continue Codex starvation and CultNet liberation by building the executing tool/MCP adapter that consumes `epiphany.tool_invocation_intent.v0`, emits `epiphany.tool_invocation_receipt.v0`, and keeps raw MCP JSON sealed at the adapter boundary.