From 7656ae09587698a9b14e9bfbbeeaadb4df7c2eed Mon Sep 17 00:00:00 2001 From: TerminallyLazy Date: Tue, 25 Aug 2026 19:08:12 -0400 Subject: [PATCH] feat: trust Agent Zero plugin 3.2 capability --- Cargo.lock | 6 +- Cargo.toml | 2 +- README.md | 6 +- crates/tree-ring-memory-cli/Cargo.toml | 4 +- .../src/activation/adapters.rs | 66 +++++++++++++++---- .../tests/harness_activation_acceptance.rs | 6 +- crates/tree-ring-memory-sqlite/Cargo.toml | 2 +- docs/press-kit.md | 4 +- marketing/README.md | 2 +- 9 files changed, 68 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad03715..f76ff73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1690,7 +1690,7 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "tree-ring-memory-cli" -version = "0.15.2" +version = "0.15.3" dependencies = [ "chrono", "clap", @@ -1709,7 +1709,7 @@ dependencies = [ [[package]] name = "tree-ring-memory-core" -version = "0.15.2" +version = "0.15.3" dependencies = [ "chrono", "libc", @@ -1725,7 +1725,7 @@ dependencies = [ [[package]] name = "tree-ring-memory-sqlite" -version = "0.15.2" +version = "0.15.3" dependencies = [ "rusqlite", "serde", diff --git a/Cargo.toml b/Cargo.toml index e3e6b04..8de24e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.15.2" +version = "0.15.3" edition = "2021" license = "MIT" authors = ["TerminallyLazy"] diff --git a/README.md b/README.md index 9204288..6632517 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ framework-agnostic and does not replace either protocol. Tree Ring Memory is in protocol-preview status. Current launch links: - Launch page: -- Launch release: +- Launch release: - Launch discussion: - Rust-native CLI article: - Feedback issue: @@ -259,8 +259,8 @@ sh install.sh --project --init --release latest sh install.sh --global --install-dir "$HOME/.local" sh install.sh --no-animation # stable output; kept for explicit script usage sh install.sh --no-path-update -sh install.sh --release 0.15.2 -sh install.sh --archive-url https://example/tree-ring-memory-0.15.2-darwin-arm64.tar.gz --archive-sha256 +sh install.sh --release 0.15.3 +sh install.sh --archive-url https://example/tree-ring-memory-0.15.3-darwin-arm64.tar.gz --archive-sha256 ``` After install, rerun onboarding anytime: diff --git a/crates/tree-ring-memory-cli/Cargo.toml b/crates/tree-ring-memory-cli/Cargo.toml index 3105496..aaef226 100644 --- a/crates/tree-ring-memory-cli/Cargo.toml +++ b/crates/tree-ring-memory-cli/Cargo.toml @@ -26,8 +26,8 @@ semver.workspace = true sha2.workspace = true tempfile.workspace = true uuid.workspace = true -tree-ring-memory-core = { path = "../tree-ring-memory-core", version = "0.15.2" } -tree-ring-memory-sqlite = { path = "../tree-ring-memory-sqlite", version = "0.15.2" } +tree-ring-memory-core = { path = "../tree-ring-memory-core", version = "0.15.3" } +tree-ring-memory-sqlite = { path = "../tree-ring-memory-sqlite", version = "0.15.3" } [dev-dependencies] rusqlite.workspace = true diff --git a/crates/tree-ring-memory-cli/src/activation/adapters.rs b/crates/tree-ring-memory-cli/src/activation/adapters.rs index bba9c2c..0687a6d 100644 --- a/crates/tree-ring-memory-cli/src/activation/adapters.rs +++ b/crates/tree-ring-memory-cli/src/activation/adapters.rs @@ -15,9 +15,8 @@ pub const AGENT_ZERO_PLUGIN_MANIFEST_ENV: &str = "TREE_RING_AGENT_ZERO_PLUGIN_MA const AGENT_ZERO_CAPABILITY_FILE: &str = "activation-capability.json"; const AGENT_ZERO_CAPABILITY_KIND: &str = "tree-ring-agent-zero-plugin-capability"; -const AGENT_ZERO_PLUGIN_VERSION: &str = "3.1.0"; -const AGENT_ZERO_TREE_RING_MIN_VERSION: &str = "0.14.0"; -const AGENT_ZERO_TREE_RING_MINOR_VERSION: &str = "0.14"; +const AGENT_ZERO_CAPABILITY_CONTRACTS: &[(&str, &str, &str)] = + &[("3.1.0", "0.14.0", "0.14"), ("3.2.0", "0.15.3", "0.15")]; const MAX_AGENT_ZERO_CAPABILITY_BYTES: u64 = 16 * 1024; /// Project paths used by activation. Adapter plans always target this root. @@ -163,13 +162,18 @@ fn read_agent_zero_plugin_manifest( &read_regular_file_no_follow(&descriptor)?, ) .ok()?; + let trusted_contract = AGENT_ZERO_CAPABILITY_CONTRACTS.iter().any( + |(plugin_version, minimum_version, minor_version)| { + capability.plugin_version == *plugin_version + && capability.tree_ring_version.min == *minimum_version + && capability.tree_ring_version.minor == *minor_version + }, + ); if capability.schema_version != 1 || capability.kind != AGENT_ZERO_CAPABILITY_KIND || capability.plugin_id != AGENT_ZERO_PLUGIN_ID - || capability.plugin_version != AGENT_ZERO_PLUGIN_VERSION || capability.activation_protocol_version != ACTIVATION_PROTOCOL_VERSION - || capability.tree_ring_version.min != AGENT_ZERO_TREE_RING_MIN_VERSION - || capability.tree_ring_version.minor != AGENT_ZERO_TREE_RING_MINOR_VERSION + || !trusted_contract || !capability.enabled { return None; @@ -177,8 +181,11 @@ fn read_agent_zero_plugin_manifest( let plugin_yaml = descriptor.parent()?.join("plugin.yaml"); let plugin_yaml = read_regular_file_no_follow(&plugin_yaml)?; - plugin_yaml_matches_capability(std::str::from_utf8(&plugin_yaml).ok()?) - .then_some(AgentZeroPluginManifest::compatible()) + plugin_yaml_matches_capability( + std::str::from_utf8(&plugin_yaml).ok()?, + &capability.plugin_version, + ) + .then_some(AgentZeroPluginManifest::compatible()) } /// Opens one regular capability file without following its final path entry. @@ -215,7 +222,7 @@ fn read_regular_file_no_follow(_path: &Path) -> Option> { None } -fn plugin_yaml_matches_capability(plugin_yaml: &str) -> bool { +fn plugin_yaml_matches_capability(plugin_yaml: &str, expected_version: &str) -> bool { let mut name = None; let mut version = None; for line in plugin_yaml.lines() { @@ -237,7 +244,7 @@ fn plugin_yaml_matches_capability(plugin_yaml: &str) -> bool { _ => {} } } - name == Some(AGENT_ZERO_PLUGIN_ID) && version == Some(AGENT_ZERO_PLUGIN_VERSION) + name == Some(AGENT_ZERO_PLUGIN_ID) && version == Some(expected_version) } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize)] @@ -1106,6 +1113,37 @@ mod tests { Some(AgentZeroPluginManifest::compatible()) ); + fs::write( + plugin.join("plugin.yaml"), + "name: tree_ring_memory\nversion: 3.1.0\n", + ) + .unwrap(); + fs::write( + &descriptor, + r#"{"schema_version":1,"kind":"tree-ring-agent-zero-plugin-capability","plugin_id":"tree_ring_memory","plugin_version":"3.1.0","activation_protocol_version":1,"tree_ring_version":{"min":"0.14.0","minor":"0.14"},"enabled":true}"#, + ) + .unwrap(); + assert_eq!( + read_agent_zero_plugin_manifest(&project, &descriptor), + Some(AgentZeroPluginManifest::compatible()) + ); + + fs::write(&descriptor, capability_document(true)).unwrap(); + fs::write( + plugin.join("plugin.yaml"), + "name: tree_ring_memory\nversion: 3.2.0\n", + ) + .unwrap(); + fs::write( + &descriptor, + capability_document(true).replace( + "\"min\":\"0.15.3\",\"minor\":\"0.15\"", + "\"min\":\"0.14.0\",\"minor\":\"0.14\"", + ), + ) + .unwrap(); + assert!(read_agent_zero_plugin_manifest(&project, &descriptor).is_none()); + fs::write(&descriptor, capability_document(false)).unwrap(); assert!(read_agent_zero_plugin_manifest(&project, &descriptor).is_none()); @@ -1125,7 +1163,7 @@ mod tests { assert!(read_agent_zero_plugin_manifest(&project, &descriptor).is_none()); fs::write( plugin.join("plugin.yaml"), - "name: tree_ring_memory\nversion: 3.1.0\n", + "name: tree_ring_memory\nversion: 3.2.0\n", ) .unwrap(); assert!( @@ -1145,7 +1183,7 @@ mod tests { fs::create_dir_all(&symlink_parent).unwrap(); fs::write( symlink_parent.join("plugin.yaml"), - "name: tree_ring_memory\nversion: 3.1.0\n", + "name: tree_ring_memory\nversion: 3.2.0\n", ) .unwrap(); let symlink_descriptor = symlink_parent.join(AGENT_ZERO_CAPABILITY_FILE); @@ -1157,7 +1195,7 @@ mod tests { fn write_capability_descriptor(plugin: &Path, enabled: bool) -> PathBuf { fs::write( plugin.join("plugin.yaml"), - "name: tree_ring_memory\nversion: 3.1.0\n", + "name: tree_ring_memory\nversion: 3.2.0\n", ) .unwrap(); let descriptor = plugin.join(AGENT_ZERO_CAPABILITY_FILE); @@ -1167,7 +1205,7 @@ mod tests { fn capability_document(enabled: bool) -> String { format!( - r#"{{"schema_version":1,"kind":"tree-ring-agent-zero-plugin-capability","plugin_id":"tree_ring_memory","plugin_version":"3.1.0","activation_protocol_version":1,"tree_ring_version":{{"min":"0.14.0","minor":"0.14"}},"enabled":{enabled}}}"# + r#"{{"schema_version":1,"kind":"tree-ring-agent-zero-plugin-capability","plugin_id":"tree_ring_memory","plugin_version":"3.2.0","activation_protocol_version":1,"tree_ring_version":{{"min":"0.15.3","minor":"0.15"}},"enabled":{enabled}}}"# ) } } diff --git a/crates/tree-ring-memory-cli/tests/harness_activation_acceptance.rs b/crates/tree-ring-memory-cli/tests/harness_activation_acceptance.rs index c1e572f..0a8606e 100644 --- a/crates/tree-ring-memory-cli/tests/harness_activation_acceptance.rs +++ b/crates/tree-ring-memory-cli/tests/harness_activation_acceptance.rs @@ -500,7 +500,7 @@ fn agent_zero_plugin_descriptor_bootstraps_passive_binding_then_receipt_backed_a // state until a live compatible descriptor is available again. fs::write( &descriptor, - r#"{"schema_version":1,"kind":"tree-ring-agent-zero-plugin-capability","plugin_id":"tree_ring_memory","plugin_version":"3.1.0","activation_protocol_version":1,"tree_ring_version":{"min":"0.14.0","minor":"0.14"},"enabled":false}"#, + r#"{"schema_version":1,"kind":"tree-ring-agent-zero-plugin-capability","plugin_id":"tree_ring_memory","plugin_version":"3.2.0","activation_protocol_version":1,"tree_ring_version":{"min":"0.15.3","minor":"0.15"},"enabled":false}"#, ) .unwrap(); let disabled = @@ -918,13 +918,13 @@ fn install_agent_zero_plugin(base: &Path) -> PathBuf { fs::create_dir_all(&plugin).unwrap(); fs::write( plugin.join("plugin.yaml"), - "name: tree_ring_memory\nversion: 3.1.0\n", + "name: tree_ring_memory\nversion: 3.2.0\n", ) .unwrap(); let descriptor = plugin.join("activation-capability.json"); fs::write( &descriptor, - r#"{"schema_version":1,"kind":"tree-ring-agent-zero-plugin-capability","plugin_id":"tree_ring_memory","plugin_version":"3.1.0","activation_protocol_version":1,"tree_ring_version":{"min":"0.14.0","minor":"0.14"},"enabled":true}"#, + r#"{"schema_version":1,"kind":"tree-ring-agent-zero-plugin-capability","plugin_id":"tree_ring_memory","plugin_version":"3.2.0","activation_protocol_version":1,"tree_ring_version":{"min":"0.15.3","minor":"0.15"},"enabled":true}"#, ) .unwrap(); descriptor diff --git a/crates/tree-ring-memory-sqlite/Cargo.toml b/crates/tree-ring-memory-sqlite/Cargo.toml index 64911c9..690a3aa 100644 --- a/crates/tree-ring-memory-sqlite/Cargo.toml +++ b/crates/tree-ring-memory-sqlite/Cargo.toml @@ -16,7 +16,7 @@ rusqlite.workspace = true serde.workspace = true serde_json.workspace = true sha2.workspace = true -tree-ring-memory-core = { path = "../tree-ring-memory-core", version = "0.15.2" } +tree-ring-memory-core = { path = "../tree-ring-memory-core", version = "0.15.3" } uuid.workspace = true [dev-dependencies] diff --git a/docs/press-kit.md b/docs/press-kit.md index eb73ff7..9280d21 100644 --- a/docs/press-kit.md +++ b/docs/press-kit.md @@ -23,10 +23,10 @@ DOX/Revolve adapters, framework discovery, and a terminal TUI. - Category: AI agents, developer tools, local-first software, Rust CLI - License: MIT - Status: protocol-preview -- Current version: 0.15.2 +- Current version: 0.15.3 - Website: - Repository: -- Launch release: +- Launch release: - Launch discussion: - Homebrew tap: - Feedback: diff --git a/marketing/README.md b/marketing/README.md index eca106c..6fd66b3 100644 --- a/marketing/README.md +++ b/marketing/README.md @@ -309,7 +309,7 @@ python3 marketing/scripts/build-campaign-cards.py - Repository: `https://github.com/TerminallyLazy/Tree-Ring-Memory` - Launch page: `https://terminallylazy.github.io/Tree-Ring-Memory/` -- Launch release: `https://github.com/TerminallyLazy/Tree-Ring-Memory/releases/tag/v0.15.2` +- Launch release: `https://github.com/TerminallyLazy/Tree-Ring-Memory/releases/tag/v0.15.3` - Launch discussion: `https://github.com/TerminallyLazy/Tree-Ring-Memory/discussions/27` - Homebrew tap: `https://github.com/TerminallyLazy/homebrew-tree-ring` - Agent-Skills.md main repo listing: