Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ The installer builds the Rust CLI with `cargo`, installs `tree-ring`, then shows
a short terminal onboarding screen with ASCII rings and the next useful
commands. It does not initialize memory unless `--init` is passed.

Initialization creates the SQLite store and non-destructive agent-awareness
files in the memory root:

- `.tree-ring/AGENTS.md`: DOX-style Tree Ring Memory guidance and root
`AGENTS.md` merge notes.
- `.tree-ring/SKILL.md`: portable skill instructions for agent runtimes.
- `.tree-ring/CLI.md`: quick command reference for recall, remember, forget,
maintain, and TUI usage.

Existing awareness files are left untouched. Tree Ring Memory does not modify a
project's root `AGENTS.md`; merge the generated guidance manually when you want
DOX-aware agents to see it before entering `.tree-ring/`.

Useful installer options:

```bash
Expand Down Expand Up @@ -106,6 +119,7 @@ The `tree-ring` command is the Rust CLI.
```bash
tree-ring init
tree-ring remember "Use protocol-first design." --event-type decision --tag architecture
tree-ring evidence "Snapshot invalidation fixed stale unread chat state." --outcome promoted --evidence-ref evals/chat-state/run-042 --score 0.91
tree-ring recall "protocol design"
tree-ring forget mem_example --mode delete --reason "example cleanup"
tree-ring export --output memories.jsonl
Expand All @@ -119,6 +133,35 @@ tree-ring maintain --apply-expired --repair-fts

The CLI stores memory in `.tree-ring/` by default.

## Evidence Loop

The Revolve-inspired loop is exposed through `tree-ring evidence`. It records
evaluated outcomes as memory with an evidence reference instead of treating
claims as durable truth without support.

```bash
tree-ring evidence "Snapshot invalidation fixed stale unread chat state." \
--outcome promoted \
--evidence-ref evals/chat-state/run-042 \
--project agent-ui \
--score 0.91

tree-ring evidence "Aggressive caching caused stale multi-chat state." \
--outcome rejected \
--evidence-ref evals/cache-branch/run-013 \
--project agent-ui
```

Outcome mapping:

- `promoted` -> `heartwood`, durable `evaluation_promotion`
- `rejected` -> `scar`, durable `evaluation_rejection`
- `deferred` -> `seed`, `evaluation_hypothesis`
- `observed` -> `outer`, `evaluation_result`

This is not a replacement for Revolve records. Use source refs that point back
to real evaluations, checkpoints, PRs, issues, logs, or run artifacts.

`tree-ring export` writes newline-delimited JSON. The first line is a
`tree_ring_memory_export` header with schema and plugin version metadata; each
remaining line is a `memory_event` envelope. The command excludes sensitive and
Expand Down Expand Up @@ -252,6 +295,11 @@ for the synthetic workload.
- `skills/tree-ring-memory/SKILL.md` gives agents portable guidance for when to recall, remember, redact, forget, or avoid memory capture.
- `templates/dox/AGENTS.md` is a DOX-style project contract template for repos that want Tree Ring Memory rules alongside source code.
- `docs/integrations/agent-skill.md` explains how to use both without making memory more authoritative than local project docs.
- `tree-ring init` and `tree-ring welcome --init` copy local guidance into `.tree-ring/AGENTS.md`, `.tree-ring/SKILL.md`, and `.tree-ring/CLI.md` without overwriting existing files.

For DOX-style project awareness, merge the relevant generated `.tree-ring/AGENTS.md`
sections into the project root `AGENTS.md`. The CLI intentionally does not
rewrite root project contracts automatically.

## Brand Assets

Expand Down
166 changes: 166 additions & 0 deletions crates/tree-ring-memory-cli/src/agent_awareness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use serde::Serialize;
use std::fs;
use std::path::{Path, PathBuf};

const SKILL_TEMPLATE: &str = include_str!("../../../skills/tree-ring-memory/SKILL.md");
const DOX_TEMPLATE: &str = include_str!("../../../templates/dox/AGENTS.md");
const CLI_REFERENCE: &str = r#"# Tree Ring Memory CLI Quick Reference

Tree Ring Memory is a local-first memory lifecycle layer for AI agents.

Use memory deliberately:

- recall before substantial project work
- remember durable decisions, lessons, warnings, and user preferences
- use scars for failures that should not be repeated
- use seeds for future work and hypotheses
- forget, redact, or supersede stale or sensitive memory

Core commands:

```bash
tree-ring init
tree-ring recall "project startup warnings"
tree-ring remember "Use project-scoped recall before risky changes." --event-type lesson --scope project
tree-ring evidence "Snapshot invalidation fixed stale unread chat state." --outcome promoted --evidence-ref evals/chat-state/run-042 --score 0.91
tree-ring evidence "Aggressive caching caused stale multi-chat state." --outcome rejected --evidence-ref evals/cache-branch/run-013
tree-ring forget mem_example --mode redact --reason "remove sensitive detail"
tree-ring consolidate --period-type manual --dry-run
tree-ring maintain
tree-ring tui
```

Safety rules:

- Do not store secrets, credentials, private keys, or raw chain-of-thought.
- Prefer concise, source-linked summaries over transcript capture.
- Treat local source files, tests, explicit user instructions, and root `AGENTS.md` files as authoritative.
- When memory and source docs disagree, re-read source docs and update or forget stale memory.
"#;

#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub struct AgentAwarenessReport {
pub created: Vec<PathBuf>,
pub existing: Vec<PathBuf>,
}

pub fn ensure_agent_awareness(root: &Path) -> Result<AgentAwarenessReport, String> {
fs::create_dir_all(root).map_err(|err| err.to_string())?;
let mut report = AgentAwarenessReport {
created: Vec::new(),
existing: Vec::new(),
};

write_if_missing(&root.join("AGENTS.md"), &agent_contract(root), &mut report)?;
write_if_missing(&root.join("SKILL.md"), SKILL_TEMPLATE, &mut report)?;
write_if_missing(&root.join("CLI.md"), CLI_REFERENCE, &mut report)?;

Ok(report)
}

fn write_if_missing(
path: &Path,
content: &str,
report: &mut AgentAwarenessReport,
) -> Result<(), String> {
if path.exists() {
report.existing.push(path.to_path_buf());
return Ok(());
}
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).map_err(|err| err.to_string())?;
}
fs::write(path, content).map_err(|err| err.to_string())?;
report.created.push(path.to_path_buf());
Ok(())
}

fn agent_contract(root: &Path) -> String {
format!(
r#"# Tree Ring Memory Agent Instructions

This directory contains Tree Ring Memory's local project memory store.

Memory is a recall aid. It does not replace project source files, tests, root
`AGENTS.md` files, explicit user instructions, DOX contracts, or other local
project documentation.

## Memory Root

```text
{root}
```

Do not commit local memory databases or exports unless the project explicitly
requires sanitized fixtures.

## Agent Skill

Read `SKILL.md` before using Tree Ring Memory. It explains when to recall,
remember, redact, forget, consolidate, and avoid memory capture.

## CLI Reference

Read `CLI.md` for local commands. Common commands:

```bash
tree-ring --root {root} recall "project startup warnings"
tree-ring --root {root} remember "Use project-scoped recall before risky changes." --event-type lesson --scope project
tree-ring --root {root} forget mem_example --mode redact --reason "remove sensitive detail"
tree-ring --root {root} tui
```

## DOX Integration

If this project uses DOX-style `AGENTS.md` traversal, merge the relevant
sections from the template below into the project root `AGENTS.md`. Tree Ring
Memory does not overwrite root project contracts automatically.

---

{DOX_TEMPLATE}
"#,
root = shell_path(root)
)
}

fn shell_path(path: &Path) -> String {
path.display().to_string()
}
Comment on lines +127 to +129

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The shell_path function in agent_awareness.rs does not handle paths containing spaces, unlike the implementation in welcome.rs. If the project path contains spaces, the generated shell commands in AGENTS.md will be malformed and broken when copy-pasted or executed by an agent. Update this function to wrap paths containing spaces in single quotes.

fn shell_path(path: &Path) -> String {
    let value = path.display().to_string();
    if value.contains(' ') {
        format!("'{value}'")
    } else {
        value
    }
}


#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;

#[test]
fn init_writes_agent_awareness_files_without_overwriting() {
let dir = tempdir().unwrap();
let root = dir.path().join(".tree-ring");

let first = ensure_agent_awareness(&root).unwrap();
assert_eq!(first.created.len(), 3);
assert!(root.join("AGENTS.md").exists());
assert!(root.join("SKILL.md").exists());
assert!(root.join("CLI.md").exists());

fs::write(root.join("CLI.md"), "custom").unwrap();
let second = ensure_agent_awareness(&root).unwrap();
assert!(second.existing.iter().any(|path| path.ends_with("CLI.md")));
assert_eq!(fs::read_to_string(root.join("CLI.md")).unwrap(), "custom");
}

#[test]
fn generated_agents_file_mentions_skill_cli_and_dox() {
let dir = tempdir().unwrap();
let root = dir.path().join(".tree-ring");

ensure_agent_awareness(&root).unwrap();
let agents = fs::read_to_string(root.join("AGENTS.md")).unwrap();

assert!(agents.contains("SKILL.md"));
assert!(agents.contains("CLI.md"));
assert!(agents.contains("DOX Integration"));
assert!(agents.contains("Tree Ring Memory Project Contract"));
}
}
Loading