Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6d166b3
docs: plan agent workflow proof runner
TerminallyLazy Jul 12, 2026
3ec1261
docs: correct workflow proof plan test
TerminallyLazy Jul 12, 2026
5906dd2
docs: define workflow agent response contract
TerminallyLazy Jul 12, 2026
d7337a3
feat: add workflow proof scenario contract
TerminallyLazy Jul 12, 2026
6305e48
fix: harden workflow fixture parsing
TerminallyLazy Jul 12, 2026
ce038d8
fix: enforce portable workflow paths
TerminallyLazy Jul 12, 2026
1f4369a
feat: add paired agent workflow proof runner
TerminallyLazy Jul 13, 2026
a4ba2c9
fix: preserve workflow proof failure evidence
TerminallyLazy Jul 13, 2026
ffbb0c6
docs: clarify workflow proof help coverage
TerminallyLazy Jul 13, 2026
8fa8152
docs: add agent workflow proof fixtures
TerminallyLazy Jul 13, 2026
c1fd973
docs: require workflow proof model identity
TerminallyLazy Jul 13, 2026
df110a2
fix: require workflow proof model identity
TerminallyLazy Jul 13, 2026
8363b88
docs: require model identity at codex boundary
TerminallyLazy Jul 13, 2026
331c88b
fix: require model at workflow adapter boundary
TerminallyLazy Jul 13, 2026
a10abc5
docs: align workflow proof plan with model boundary
TerminallyLazy Jul 13, 2026
fc92aa8
fix: resolve workflow codex binary
TerminallyLazy Jul 13, 2026
fb8354a
fix: align stale workflow retrieval fixture
TerminallyLazy Jul 13, 2026
de18a56
feat: add structured workflow file checks
TerminallyLazy Jul 13, 2026
8fce211
fix: reject symlinked workflow outputs
TerminallyLazy Jul 13, 2026
31725dc
feat: harden structured workflow proof evidence
TerminallyLazy Jul 13, 2026
7a79f12
docs: prepare v0.12.0 release
TerminallyLazy Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ members = [
resolver = "2"

[workspace.package]
version = "0.11.0"
version = "0.12.0"
edition = "2021"
license = "MIT"
authors = ["TerminallyLazy"]
Expand All @@ -16,6 +16,7 @@ repository = "https://github.com/TerminallyLazy/Tree-Ring-Memory"
[workspace.dependencies]
chrono = { version = "0.4", features = ["serde", "clock"] }
clap = { version = "4", features = ["derive"] }
libc = "0.2"
once_cell = "1"
regex = "1"
rusqlite = { version = "0.32", features = ["bundled"] }
Expand Down
38 changes: 27 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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: <https://terminallylazy.github.io/Tree-Ring-Memory/>
- Launch release: <https://github.com/TerminallyLazy/Tree-Ring-Memory/releases/tag/v0.11.0>
- Launch release: <https://github.com/TerminallyLazy/Tree-Ring-Memory/releases/tag/v0.12.0>
- Launch discussion: <https://github.com/TerminallyLazy/Tree-Ring-Memory/discussions/27>
- Rust-native CLI article: <https://terminallylazy.github.io/Tree-Ring-Memory/launch/rust-native-agent-memory-cli.md>
- Feedback issue: <https://github.com/TerminallyLazy/Tree-Ring-Memory/issues/26>
Expand All @@ -37,6 +37,7 @@ Tree Ring Memory is in protocol-preview status. Current launch links:
- v0.9 removed tracked Python source, tests, smoke scripts, and the optional CPython extension from the canonical repo.
- v0.10 added a one-line installer plus Rust-native terminal onboarding with animated terminal tree rings.
- v0.11 made the repo fully Rust-native, wired TUI export/consolidation actions, added DOX/Revolve sync adapters, and added agent-framework discovery.
- v0.12 adds a controlled, retained agent-workflow proof with explicit model identity and exact structured-output checks; it reports observed outcomes without claiming a universal memory advantage.

</details>

Expand Down Expand Up @@ -164,7 +165,7 @@ sh install.sh --project --init
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 --archive-url https://example/tree-ring-memory-0.11.0-macos-arm64.tar.gz --archive-sha256 <sha256>
sh install.sh --archive-url https://example/tree-ring-memory-0.12.0-darwin-arm64.tar.gz --archive-sha256 <sha256>
```

After install, rerun onboarding anytime:
Expand Down Expand Up @@ -441,19 +442,19 @@ harness checks, import throughput, and 10k/30k recall timing. It writes
`target/tree-ring-certification/evidence-index.json`.

Most recent branch-local certification run, generated at
`2026-07-09T15:34:52Z`:

- Release binary: 6,352,528 bytes.
- Project install with init: 6,272 KB.
- Global install: 6,228 KB.
- CLI import: 10,000 memories in 5 seconds, about 2,000/sec.
- 10k recall: 3.643 ms average, 6.499 ms max.
- 30k recall: 7.608 ms average, 13.634 ms max.
`2026-07-15T22:02:33Z`:

- Release binary: 6,366,432 bytes.
- Project install with init: 6,292 KB.
- Global install: 6,244 KB.
- CLI import: 10,000 memories in 4 seconds, about 2,500/sec.
- 10k recall: 3.451 ms average, 6.197 ms max.
- 30k recall: 7.538 ms average, 13.495 ms max.
- Harness matrix: 5 pass, 1 skip. Codex, Claude Code, OpenCode, Goose, and
Agent Zero/A0 passed; Pi was skipped because only a user-home marker was
present in the fixture.
- Recall quality: 4 queries, 4 pass, 0 fail, 0 needs review; average latency
0.118 ms, max latency 0.370 ms.
0.137 ms, max latency 0.418 ms.
- Agent Zero plugin smoke: skipped because `TREE_RING_AGENT_ZERO_ROOT` was not
set.

Expand All @@ -464,6 +465,21 @@ The quality report is written to
`target/tree-ring-certification/quality/quality-report.json` with a readable
summary at `target/tree-ring-certification/quality/quality-summary.md`.

An explicit agent workflow evaluation keeps paired trial workspaces and an
observed evidence report separate from normal certification and CI. It requires
a validated explicit model ID and records `codex:<model-id>` in the paired
reports:

```bash
cargo run --locked -p tree-ring-memory-cli --example workflow_proof -- \
fixtures/workflow-proof target/tree-ring-certification/workflow-proof \
--model <model-id>
```

See [agent workflow proof](docs/integrations/agent-workflow-proof.md) for the
controlled command, retained artifacts, exact structured-outcome checks, and
interpretation limits.

`scripts/package-release.sh` builds the Rust CLI in release mode, creates a
platform tarball under `dist/`, and writes a SHA-256 checksum file. Tag pushes
run the release artifact workflow for Linux and macOS.
Expand Down
4 changes: 2 additions & 2 deletions crates/tree-ring-memory-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ clap.workspace = true
ratatui.workspace = true
serde.workspace = true
serde_json.workspace = true
tree-ring-memory-core = { path = "../tree-ring-memory-core", version = "0.11.0" }
tree-ring-memory-sqlite = { path = "../tree-ring-memory-sqlite", version = "0.11.0" }
tree-ring-memory-core = { path = "../tree-ring-memory-core", version = "0.12.0" }
tree-ring-memory-sqlite = { path = "../tree-ring-memory-sqlite", version = "0.12.0" }

[dev-dependencies]
tempfile.workspace = true
171 changes: 171 additions & 0 deletions crates/tree-ring-memory-cli/examples/workflow_proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
use std::{ffi::OsString, path::PathBuf};

use tree_ring_memory_cli::workflow_proof::{
run_workflow_proof, CodexWorkflowAgent, WorkflowProofReport,
};

const USAGE: &str =
"usage: workflow_proof <fixture-dir> <output-dir> --model <model-id> [--codex-bin <path>]";

enum WorkflowProofCliArgs {
Help,
Run {
fixture_dir: PathBuf,
output_dir: PathBuf,
codex_binary: PathBuf,
model: String,
},
}

fn main() {
if let Err(error) = run() {
eprintln!("workflow proof failed: {error}");
std::process::exit(1);
}
}

fn run() -> Result<(), String> {
let args = match parse_cli_args(std::env::args_os().skip(1))? {
WorkflowProofCliArgs::Help => {
println!("{USAGE}");
return Ok(());
}
WorkflowProofCliArgs::Run {
fixture_dir,
output_dir,
codex_binary,
model,
} => (fixture_dir, output_dir, codex_binary, model),
};

let (fixture_dir, output_dir, codex_binary, model) = args;
let agent = CodexWorkflowAgent::new(codex_binary, model)?;
let report = run_workflow_proof(&fixture_dir, &output_dir, &agent)?;
print_summary(&report);
if !report.tree_ring_complete {
return Err(format!(
"Tree Ring trials were incomplete after reports were written: {} failed or errored trial(s)",
tree_ring_non_passes(&report)
));
}
Ok(())
}

fn parse_cli_args(
arguments: impl IntoIterator<Item = OsString>,
) -> Result<WorkflowProofCliArgs, String> {
let mut args = arguments.into_iter();
let Some(first_argument) = args.next() else {
return Err(USAGE.to_string());
};
if first_argument == "--help" {
return Ok(WorkflowProofCliArgs::Help);
}

let fixture_dir = PathBuf::from(first_argument);
let output_dir = args
.next()
.map(PathBuf::from)
.ok_or_else(|| USAGE.to_string())?;
let mut codex_binary = PathBuf::from("codex");
let mut codex_binary_supplied = false;
let mut model = None;

while let Some(argument) = args.next() {
if argument == "--codex-bin" {
if codex_binary_supplied {
return Err(USAGE.to_string());
}
codex_binary = args
.next()
.map(PathBuf::from)
.ok_or_else(|| USAGE.to_string())?;
codex_binary_supplied = true;
} else if argument == "--model" {
if model.is_some() {
return Err(USAGE.to_string());
}
let value = args.next().ok_or_else(|| USAGE.to_string())?;
model = Some(
value
.into_string()
.map_err(|_| "model must be valid UTF-8".to_string())?,
);
} else {
return Err(USAGE.to_string());
}
}

let model = model
.map(|model| model.trim().to_string())
.filter(|model| !model.is_empty())
.ok_or_else(|| USAGE.to_string())?;

Ok(WorkflowProofCliArgs::Run {
fixture_dir,
output_dir,
codex_binary,
model,
})
}

fn print_summary(report: &WorkflowProofReport) {
println!(
"workflow proof evaluated: {} scenario(s), {} trial(s), observed Tree Ring wins over no-memory: {}, observed Tree Ring wins over raw-memory: {}",
report.scenario_count,
report.trial_count,
report.tree_ring_wins_over_no_memory,
report.tree_ring_wins_over_raw_memory
);
}

fn tree_ring_non_passes(report: &WorkflowProofReport) -> usize {
report
.arm_summaries
.iter()
.find(|summary| summary.arm == tree_ring_memory_core::WorkflowArm::TreeRing)
.map(|summary| summary.fail_count + summary.error_count)
.unwrap_or(report.scenario_count)
}

#[cfg(test)]
mod tests {
use std::ffi::OsString;

use super::{parse_cli_args, WorkflowProofCliArgs, USAGE};

#[test]
fn parse_cli_args_recognizes_help() {
assert!(matches!(
parse_cli_args([OsString::from("--help")]),
Ok(WorkflowProofCliArgs::Help)
));
}

#[test]
fn parse_cli_args_rejects_missing_model() {
assert_eq!(
parse_cli_args([OsString::from("fixtures"), OsString::from("output")])
.err()
.as_deref(),
Some(USAGE)
);
}

#[test]
fn parse_cli_args_rejects_blank_model() {
for model in ["", " "] {
assert_eq!(
parse_cli_args([
OsString::from("fixtures"),
OsString::from("output"),
OsString::from("--model"),
OsString::from(model),
])
.err()
.as_deref(),
Some(USAGE)
);
}
}
}
1 change: 1 addition & 0 deletions crates/tree-ring-memory-cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod workflow_proof;
Loading
Loading