Tree Ring Memory
Tree Ring Memory 3.4.2 integrates Agent Zero with bundled Tree Ring 0.15.12, native receipt-backed cross-session lifecycle recall, bounded agent-mediated automatic capture, persistent project-level writer identity, and shared multi-agent memory.
README
Tree Ring Memory for Agent Zero
Plugin 3.4.2 targets the Tree Ring 0.15 activation and automatic-capture
protocol and requires Tree Ring 0.15.12 or a newer 0.15.x patch. Core
0.15.12 recognizes this plugin's activation capability and retains the atomic
DOX source-collision guards introduced in 0.15.11. It also retains strict
automatic capture and the existing receipt-backed lifecycle hooks.
The checked-in Linux executables are verified 0.15.12 artifacts built from the
immutable core release on native x86-64 and ARM64 GitHub runners. Their matching
checksums and provenance are part of the plugin release surface.
This plugin is an Agent Zero bridge to the Rust-native Tree Ring Memory CLI. It does not maintain a second Python memory engine.
The Rust CLI owns validation, sensitivity classification, SQLite/FTS storage, recall ranking, import/export, audit, consolidation, maintenance, DOX/Revolve adapters, coordinated write authorization, and integration discovery. The plugin owns Agent Zero context mapping, tools, API envelopes, Web UI shaping, safe host paths, runtime status, and guarded migration.
Release and update boundary
- Plugin
3.4.2supportstree-ring0.15.12through0.15.xand fails closed on older or different-minor executables. - The activation capability also declares
0.15.12as its minimum, so a core without this plugin's activation contract cannot validate it as active. Saved settings cannot lower the runtime minimum. - The current
bin/executables, provenance, and checksums are pinned to immutable core tagv0.15.12, commite9433e281c9743988a194f5af36a8258f2b9cc68. - The manual Prepare Tree Ring 0.15.12 bundled binaries workflow and
scripts/stage-v01512-bundled-binaries.shfail closed on non-0.15.12 or mismatched artifacts. The checked-in pair came from successful native workflow run35026514548.
Install and update
In Agent Zero open Plugins → Install, choose the Git repository option, and use:
https://github.com/TerminallyLazy/tree-ring-memory-agent-zero
The installer places the plugin under usr/plugins/tree_ring_memory. To update,
use the installed plugin's update action in Agent Zero, then restart the Agent
Zero runtime. The updated hooks validate the bundled CLI before opening the
configured Rust-owned store. Existing memory under
usr/memory/tree_ring_memory is preserved across updates and uninstall.
An unversioned v0.12 or versioned schema-v1/v2 Rust store waits for the explicit
offline schema-v3 workflow below.
A fresh install without a selected Agent Zero project waits for project
activation and does not initialize the legacy global memory root. Selecting a
project and choosing Activate this project creates or opens only that
project's .tree-ring store.
Requirements
- Agent Zero with this directory mounted at
/a0/usr/plugins/tree_ring_memory/. - An executable
tree-ring0.15.xbinary. The plugin requires at least0.15.12and fails closed on older patches or other minor versions. A release build bundles compatible Linux binaries for Agent Zero'sx86_64andaarch64Docker runtimes. - Python 3.12+ in the Agent Zero framework runtime.
Binary discovery order is:
TREE_RING_MEMORY_CLIorcli.binary./a0/usr/plugins/tree_ring_memory/bin/linux-<architecture>/tree-ring./a0/usr/plugins/tree_ring_memory/bin/tree-ringfor an operator-supplied generic fallback.<memory-root>/bin/tree-ring.tree-ringon the framework runtimePATH.
The install hook selects only the executable already packaged for the running Docker architecture; it does not download or build executable code. Any replacement binary remains an explicit operator action.
Project activation protocol
Project activation is a proof flow, not a marker-file claim. Mount the project
read/write at Agent Zero's standard /a0/usr/projects/<project> path, choose
that project in Plugin Settings, and select Activate this project. The
plugin derives activation.project_root and the matching project-local
storage.root, saves the project-scoped configuration, and immediately runs
the existing core bootstrap command from the mounted project:
tree-ring init --root .tree-ring --json
The plugin passes its fixed, installed, non-project
activation-capability.json only in that child process environment. Users do
not set its path, pass an environment variable, hand-write a binding, or use a
generic .a0 marker. Core validates the descriptor and its sibling plugin
manifest; the plugin never writes the project binding itself.
Core creation-publishes an Agent Zero binding whose persisted state remains
needs-plugin, even while the installed plugin is present. Descriptor-scoped
runtime status may derive configured-awaiting-proof without changing that
passive record. When the selected project has a matching chat or task, the
activation action also runs preflight with that session-specific identity. If
no matching context exists yet, start or open a project chat to produce the
fresh project-local receipt that can make runtime status active.
The writer-context selector remains session-specific because attribution, idempotency, coordinated writes, and activation receipts require a real chat or task identity. The UI filters choices to the active project, displays compact task/chat labels, and preserves the explicit selection across panel reopen and page reload for the current browser session.
If the plugin is removed, a host CLI runs without the descriptor, or a second
agent points at a different store, status remains needs-plugin or
active-isolated as appropriate. Multiple Agent Zero workers can share the
same mounted .tree-ring root, but each receives its own receipt-backed proof;
the core store fingerprint and project binding prevent an arbitrary mount from
claiming that shared activation.
Installation alone is not activation proof. Only a fresh receipt-backed
preflight against the mounted project and matching store can report active.
Native agent lifecycle
The plugin registers two Agent Zero lifecycle extensions. Before the main model
prompt is assembled, message_loop_prompts_after delegates to the shared
runtime adapter. That adapter derives the active agent, project, workflow, and
session identity from Agent Zero-owned context; runs one bounded, receipt-backed
preflight for the context; and adds only accepted, size-bounded recall output to
the tree_ring_memory prompt extra. It does not pass a raw user prompt or chat
transcript to Tree Ring.
The injected context also includes a fresh automatic-capture checkpoint. Before
finalizing the task, the agent selects zero to three concise, normal-sensitivity
durable candidates and calls only the strict capture tool for each accepted
candidate. Zero is the expected result when the turn has no reusable learning.
The agent must not create filler, transient status, unsupported claims,
duplicate knowledge, or transcript summaries merely to produce a memory. Each
candidate uses its own checkpoint-provided indexed operation_id and matching
source_ref; retries reuse that candidate's slot, while different candidates
never share one. Agent Zero derives identity and routing, and core tree-ring capture enforces the allowed event/ring pairs and rejects non-normal
sensitivity. Manual remember and evidence remain available outside this
automatic checkpoint.
At monologue_end, the second extension removes only ephemeral lifecycle state
and the injected prompt extra. It does not inspect history or persist anything.
Lifecycle failure never marks the integration active and never blocks the normal
Agent Zero prompt flow. Automatic capture is agent-mediated: the lifecycle
adapter never scrapes raw prompts, transcripts, history, or scratchpads, never
starts a background recorder, and never writes durable memory directly. A
candidate is durable only after its explicit tool call succeeds.
Storage
The default memory root remains:
/a0/usr/memory/tree_ring_memory/
The current Rust-owned database is:
/a0/usr/memory/tree_ring_memory/memory.sqlite
The Python-v1 database is preserved as read-only migration input:
/a0/usr/memory/tree_ring_memory/indexes/memory.sqlite
Uninstall preserves both stores. Removing the memory root remains a deliberate operator action outside automatic plugin lifecycle handling.
Schema-v3 upgrade introduced in v0.13
The 0.15 bridge never auto-opens an existing unversioned v0.12 or versioned
schema-v1/v2 store. The dashboard and settings report upgrade_required while
normal store operations remain blocked. The pre-v0.13 wording in backup
filenames and markers is historical schema provenance, not a claim that a
v0.13 runtime is supported by plugin 3.4.2.
Treat the upgrade as an offline, one-way operation:
- Stop every Tree Ring CLI, plugin, TUI, and worker using the memory root.
- In plugin settings, choose Create verified upgrade backup and attest that the root is offline.
- The helper checkpoints and truncates SQLite WAL, acquires the database lock, verifies
PRAGMA integrity_check, creates an exact mode-0600database backup under<memory-root>/migrations/, verifies SHA-256 and record count, and writes a mode-0600marker. - Choose Apply schema v3 while every other process remains stopped. The plugin rechecks the source and backup checksums before allowing
tree-ring initto migrate. - Upgrade every other CLI, plugin, and bundled worker before reopening the shared root.
If the source changes after backup, application fails closed and requires a fresh backup. Do not run v0.12 against an upgraded root. Schema v3 fences old memory inserts, updates, and deletes, but all mixed-version use—including reads and maintenance—is unsupported. Rollback means stopping every process and restoring the recorded complete backup; it is not a down-migration.
Legacy Migration
Legacy Python-v1 migration never edits or deletes the old SQLite database. The migrator reads raw_json, normalizes Python-v1 null/string and chat-scope differences, writes a mode-0600 temporary JSONL file, validates that file with tree-ring import --dry-run, and only then imports it through the Rust CLI. The temporary file is removed after the attempt.
Migration is idempotent. A marker under <memory-root>/migrations/ prevents accidental repeats, while the Rust importer skips duplicate IDs by default. The original legacy database remains available as read-only recovery input. Automatic durable import occurs only while the Rust store policy is open; in coordinated mode the bridge performs only the dry-run preview until an authorized coordinator profile explicitly confirms migration.
Multi-Agent and Coordinator Mapping
Every Agent Zero tool invocation derives its Tree Ring identity from the live server-side Agent Zero context:
agent_profilecomes from the active Agent Zero profile, with the Agent Zero name as a fallback.projectcomes from the active Agent Zero project.session_idis the current chat or worker context.workflow_idis the parent context for parallel fan-out workers and otherwise the current context.operation_idandsource_refare explicit tool inputs and are forwarded unchanged so a retry can reuse the same logical write identity and provenance.
The caller cannot set write identity through API payload fields. Recall can intentionally request a wider fan-in view with include_all_agents=true; that suppresses the current context's default agent/session filters while preserving any explicit agent, workflow, session, or scope filters.
Every subprocess starts from a copy of the host environment with TREE_RING_COORDINATOR_TOKEN and all Tree Ring identity environment variables removed. A coordinator capability is reinserted only when both conditions hold:
- the operation is a protected mutation; and
- the server-derived Agent Zero profile appears in
coordination.coordinator_profiles.
The capability remains host-environment-only. It is not accepted by tools or API payloads, stored in plugin configuration, logged, returned, or rendered in the Web UI. Policy enable/rotate/disable and the one-time capability stay operator-only CLI actions. The plugin exposes only read-only policy_status and policy_audit.
Ordinary memories default to scope=agent, carry the derived identity, and do not receive the capability. In coordinated mode, shared/global/project/workflow writes, heartwood creation, evidence publication, persisted consolidation or adapter sync, imports, replacements, ring changes, delete/redact, and applied maintenance require coordinator authorization.
This is operational write authorization for cooperative official processes sharing one local SQLite store on one host. It is not a read ACL, an operating-system boundary, distributed coordination, or a cross-host/network-filesystem guarantee.
Agent Tools
capture: strict automatic-checkpoint writes bound to the active lifecycle checkpoint, server-derived identity, and one of three indexed slots.remember: manual concise agent-scoped memory with server-derived identity plus optionaloperation_idandsource_ref.evidence: manual evaluated outcomes with a required evidence reference.recall: Rust-ranked recall with native project/agent/workflow/session/scope filters and optional Agent Zero ring/event post-filters.forget: explicit-ID delete or redact.consolidate: daily, weekly, monthly, yearly, or manual consolidation.audit_memory: non-mutating quality, privacy, and integrity audit.maintain_memory: dry-run maintenance or explicit expiry/redaction/FTS repair.sync_dox: DOX source adapter; dry-run by default.sync_revolve: Revolve evidence adapter; dry-run by default.import_memory: dry-run by default, with optional duplicate replacement.export_memory: canonical JSONL export.preflight: explicit diagnostic or fallback for the project-local, receipt-backed Agent Zero activation proof; native lifecycle recall normally runs it automatically.policy_status: read-only coordinated-policy status.policy_audit: read-only protected-write authorization decisions.
The 0.15 CLI does not expose query-wide forget, selected-memory export,
Markdown/SQLite export, expiry, or supersession as scriptable commands. The
plugin returns an explicit unsupported-operation error for those former
Python-v1 surfaces.
Web UI
The panel provides runtime/schema readiness, one-action project activation, write-policy status, search, ring/event filters, memory detail, ring-derived copies, delete/redact, consolidation, safe DOX/Revolve previews, memory and policy audit, and canonical JSONL export. Its concentric Tree Ring visual illuminates each ring relative to the busiest ring, while the adjacent ledger shows exact record counts and share of the store; selecting a ring filters the live results. A visible writer-context selector attributes protected actions to an existing Agent Zero chat or task without weakening the server-side identity gate. The settings view owns the explicit two-step schema upgrade, the non-secret coordinator-profile allowlist, the selected-project configuration, and compatibility hydration for partial configuration saved by older releases.
When the CLI is missing or incompatible, the panel stays available and shows the concrete readiness error instead of initializing a second store.
Lifecycle and Maintenance
hooks.py owns install and update setup, while native extensions own agent
lifecycle recall and cleanup. The install hook is idempotent, and Agent Zero
runs it after both fresh installs and updates. For a configured canonical
mounted project root, it asks the released core to create the passive binding
through the installed descriptor, then reloads that core-generated contract;
it never hand-writes or upgrades an activation binding. The configuration hook
provides a second idempotent bootstrap path after an update so older
installations cannot remain dependent on the removed execute.py script. An
unversioned v0.12 or versioned schema-v1/v2 preflight returns without opening
the database. Before later updates, the hook exports an initialized compatible
store as a recovery snapshot.
Interactive audit, consolidation, FTS repair, DOX/Revolve previews, import preview, and export remain available through the Web UI and Agent Zero tools. Sensitive recall and export remain opt-in. DOX AGENTS.md, Revolve evidence, current source, tests, and explicit user instructions remain authoritative over recalled memory.
Verification
Focused package-layout tests use temporary roots and make no network calls:
PYTHONDONTWRITEBYTECODE=1 \
python3 -m pytest -q -p no:cacheprovider \
tests/test_manifest.py tests/test_lifecycle_extensions.py \
tests/test_webui.py tests/test_activation_package_layout.py
node --check webui/memory-store.js
Before tagging either a core release or a plugin release, exercise the current
checkout's actual plugin.yaml and activation-capability.json against the
candidate core executable:
python3 scripts/verify-activation-pair.py /absolute/path/to/candidate/tree-ring
This uses a temporary project to verify initialization, preflight, a matching receipt, and persisted active status. A version string alone is insufficient. Keep the core's capability allowlist exact; add and test the intended plugin/minimum pair instead of weakening the contract or substituting an older descriptor. Rerun the bridge's real-CLI tests against each finished bundle before publication.
Upstream certification uses the exact released CLI in a real Agent Zero package
layout. Package tests verify both checked-in 0.15.12 binaries, their immutable
source provenance and checksums, activation envelopes, lifecycle capture, and
the source-only bridge contract. CI also runs the bridge against the bundled
x86-64 executable, including repeated DOX sync and atomic source-collision
rejection; release validation runs that same proof on native ARM64.
Contribution Boundary
Keep implementation under usr/plugins/tree_ring_memory/ and the companion guidance under usr/skills/tree-ring-memory/. Do not modify Agent Zero core code for this integration. If upstream changes its CLI or JSON schema, update the adapter and version gate together, then rerun the real CLI and legacy-copy proofs before changing the supported series.
Cross-session recall in 3.4.1
The bundled CLI 0.15.7 fixes lifecycle visibility: project guidance and this agent profile survive new sessions; workflow and session memories stay confined to their matching identities. Keywordless startup loads a bounded ranked brief. The native prompt extension continues to inject receipt-backed context and the monologue-end extension clears per-turn state. No additional pre-tool hook is needed. Re-run project activation if status reports an older managed adapter.
Guarded DOX sync in 3.4.2
DOX sync still uses the public Rust CLI and the existing preview/apply tools.
Repeated sync of the same source updates its stable IDs. A collision with another
project, source root, or unrelated memory rejects the whole batch. Legacy DOX
entries without root provenance can only be adopted in that source project's
local .tree-ring store; shared or custom stores require provenance reconciliation
or a separate project store. Coordinated writes still require an authorized
coordinator. These checks run in the core; the bridge cannot bypass them.
Recovering legacy DOX from a shared or global store
A rejected legacy DOX sync means the old entries do not identify their source root well enough for a safe update. Preserve the old memory root. If you make a backup copy, stop its writers first. Do not add guessed provenance, copy its SQLite database into a new store, or import its ambiguous DOX IDs to bypass the guard. Rebuild DOX memories from the authoritative project files instead:
Mount the source project at its Agent Zero path, for example
/a0/usr/projects/my-project. Use a fresh project-local.tree-ringstore; if that path already contains a store, preserve and inspect it rather than replacing it. A separate clean project checkout can provide a fresh store.In Plugin Settings, select that project's scope. Before activating, set Legacy Python-v1 SQLite to
/a0/usr/projects/my-project/.tree-ring/indexes/memory.sqlite, which is absent in the fresh store. This avoids importing an old Python-v1 database while rebuilding DOX. Activate this project changes the memory and source roots together, but retains the configured legacy migration path. If the host setsTREE_RING_MEMORY_ROOTorTREE_RING_MEMORY_DATA_DIRto the old shared root, the operator must remove or update that override first; it takes precedence over the project setting.Choose Activate this project and open a chat for that project. Verify the reported memory root is
/a0/usr/projects/my-project/.tree-ringand select that project's writer context. Check that the new store contains zero memories before DOX import. If it is not empty, inspect why before proceeding; do not clear it. Keep the old shared/global root available for separate review; this procedure does not migrate its other memories.Ask the agent to call
sync_doxwith explicit source and project arguments:{"source_root":"/a0/usr/projects/my-project","project":"my-project","dry_run":true}Replace both examples with the selected project's actual path and name. Review the candidates, source references, rings, and warnings. The panel's Preview DOX button also previews, but does not persist the result.
With the source files unchanged, call
sync_doxagain with the same source and project anddry_run:false. Use an authorized project context. If the target store is coordinated, the context's profile must be incoordination.coordinator_profilesand the runtime must already hold its coordinator capability in the host environment. Never put a capability in the tool arguments or plugin settings. Recheck the target store and recall after the write; the original store remains preserved.
The tool collects the source again when applying; if the files changed after preview, preview them again before applying. There is no automatic adoption of ambiguous legacy identities in a shared or global store.