claude-skills/engineering/agent-memory/README.md
Claude a3b6a195cb
feat(agent-memory): implement the four-tier memory ladder
Turns DESIGN.md from a spec into a working plugin. Five stdlib scripts, three
hooks, agent, command, three references, plugin manifests.

The gates are the design:
  L1 -> L2  >= 3 distinct sessions spanning >= 2 distinct calendar days
            (`stated` = 2 sessions, day rule still applies; `verified` = 1
            observation and is the only day-exempt path)
  L2 -> L3  >= 2 distinct projects, >= 30 days, uncontested

Two gates refuse rather than guess. `redacted: true` blocks promotion on any
volume of evidence -- a durability-independent barrier, since a secret restated
across five sessions passes every recurrence gate; the flag firing means the
text was altered, a lexical filter finding one secret is not proof it found all
of them, and L2/L3 are committed to git. An open contradiction freezes both
claims, found by reverse join because the newer atom carries no flag.

All three hooks fail open: a broken memory system costs memory, never a session.
SessionEnd stages promotions to .memory/staged/ and never touches a CLAUDE.md;
only an explicit human adopt does, after backing both files up.

Verified, not asserted:
  - all three pinned atom ids from DESIGN.md reproduce exactly
  - both blocking gates demonstrated on sample input, named in the output
  - end-to-end: two transcripts across two calendar days -> merged L1 atom ->
    staged L2 promotion with the path prefix stripped
  - reverse join blocks the unflagged newer atom
  - cross-tier L2/L3 collision marked at injection time
  - recall p50 29ms / p95 31ms / max 35ms spawn-to-exit, scoring itself 2-3ms
    over 500 atoms -- interpreter cold start is the entire cost
  - validate_examples.py 69 checks 0 failures; SKILL.md 6/6 PASS
  - derive_counters --check, check_plugin_json --all, check_paths all clean

DESIGN.md 10.1's "+6" tool estimate corrected to +8 -- the delivered surface is
5 scripts + 3 hooks. README.md's deviations list is authoritative for that and
five other divergences from the pre-implementation spec.

Concept from TencentCloud/TencentDB-Agent-Memory (MIT). No upstream code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EM5xmJ7AmTMg31rq68BCym
2026-08-24 18:23:01 +00:00

126 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# agent-memory
A four-tier memory ladder for Claude Code. **Promotion is earned by recurrence,
never asserted by confidence**, and nothing reaches a committed file without a
human adopting it.
Concept derived from [TencentCloud/TencentDB-Agent-Memory][tencent] (MIT). No
upstream code is included — see
[`.claude-plugin/authoring-notes.json`](.claude-plugin/authoring-notes.json) for
what was taken and what was deliberately rejected.
[tencent]: https://github.com/TencentCloud/TencentDB-Agent-Memory
---
## What it does
| Tier | Holds | Injected | Committed |
|---|---|---|---|
| **L0** | raw session transcripts | never | already on disk |
| **L1** | candidate atoms | on relevance, per prompt | no (gitignored) |
| **L2** | this project's context | every session start | yes, after adopt |
| **L3** | stable cross-project persona | always | yes, after adopt |
**L1 → L2** needs ≥ 3 distinct sessions spanning ≥ 2 distinct calendar days. A
claim stated outright needs 2 sessions — the day rule still applies. A
deterministically verified claim promotes on one observation and is the only
day-exempt path. **L2 → L3** needs ≥ 2 distinct projects and ≥ 30 days.
Two gates refuse rather than guess: a **redacted** claim never promotes on
evidence alone, and a claim with an **open contradiction** freezes until a human
resolves it.
## Install and use
The three hooks in [`hooks/hooks.json`](hooks/hooks.json) run the loop
unattended. Each is disabled independently:
```bash
AGENT_MEMORY_SESSIONSTART=0 # stop injecting L2 + L3
AGENT_MEMORY_USERPROMPTSUBMIT=0 # stop L1 recall
AGENT_MEMORY_SESSIONEND=0 # stop capture
```
```bash
cd skills/agent-memory/scripts
python3 memory_inspect.py --tier L1 # what's stuck, and why
python3 memory_inspect.py --why "<claim>" # full provenance + source line
python3 memory_inspect.py --contested # disputed claims, both directions
python3 memory_promote.py # dry-run the gates; writes nothing
python3 validate_examples.py # 69 checks over the spec + schema
```
Every script takes `--sample` and `--output json`. `/cs:memory` wraps all of it;
`/cs:memory adopt` is the only path that writes to a `CLAUDE.md`, and it backs
both files up first.
## Contents
```
DESIGN.md the spec: schema, gates, hook contracts, open decisions
hooks/hooks.json three hook contracts
hooks/session_start.py inject L3 + L2, mark cross-tier conflicts
hooks/user_prompt_submit.py recall L1 on a 100 ms internal budget
hooks/session_end.py capture, redact, detect, merge, stage
skills/agent-memory/SKILL.md 6/6 PASS on the write-a-skill checklist
scripts/memory_core.py shared: ids, redaction, locking, contradictions
scripts/memory_extract.py L0 → L1, rule-based, no LLM
scripts/memory_promote.py L1 → L2 → L3, stages proposals
scripts/memory_inspect.py read-only: --tier / --contested / --why
scripts/validate_examples.py 69 checks in seven families
assets/memory_schema.json 13 required fields, five conditionals
references/ three references, 67 sources each
agents/cs-memory-curator.md refuses to adopt what it cannot cite
commands/cs-memory.md status | why | contested | adopt | forget
```
## Deviations from `DESIGN.md`
`DESIGN.md` was written before the implementation and reviewed at length. Where
the built thing differs from the planned thing, **this list is authoritative**.
1. **`memory_core.py` exists.** §10's planned tree lists four scripts and no
shared module. Building it that way would have duplicated the redaction
patterns, the id algorithm and the lock protocol across seven files — which
is precisely the drift class the spec exists to prevent. The module has no
CLI and is not a plugin-facing tool.
2. **The tool count in §10.1 is wrong.** It says `+6` (3 scripts + 3 hooks).
The delivered surface is 5 scripts + 3 hooks = **8**. Corrected in the
counters; §10.1's text is left as the historical record of the estimate.
3. **`mark_contradictions()` was added to the core.** §4.2.1 specifies detection
running at merge time in `SessionEnd` but assigns it to no file. It lives in
the core so the promoter and the inspector share one definition of "open
contradiction" rather than three.
4. **Cross-tier conflict marking marks both sides.** §5.1 requires that an L2
and an L3 claim colliding must not both appear as plain assertions, and says
all three candidate policies satisfy it. The implementation marks both and
picks no winner — the least committal option, and the one that does not have
to be undone if the open decision lands on specificity-wins.
5. **The 100 ms recall budget is met, on this machine.** §9.5 asserted the
budget without measurement and offered dropping the hook as option (c).
Measured: spawn-plus-recall p50 ≈ 29 ms, p95 ≈ 31 ms, max ≈ 35 ms against a
populated store; the scoring pass itself 23 ms over 500 atoms. Interpreter
start-up is the whole cost. **This does not close §9.5** — one machine is not
a portability claim, and a slower host may still force option (c).
6. **`--why` quotes the source line.** Not specified anywhere; added because
"cite, don't invent" is unfalsifiable if a human cannot see the cited line.
It prints nothing when the back-pointer resolves `ambiguous`.
## What would make this worth deleting
Stated plainly because §9.3 permits it and the trial is the point:
- **Recall is too low to matter.** Rule-based extraction is deliberately
high-precision. If a two-week trial produces a handful of atoms and none
reach L2, the honest response is to remove the folder — not to loosen gates
until something passes.
- **Nobody reviews the staged promotions.** The entire security argument rests
on a human at the `adopt` gate. If staged items are accepted unread, the gate
is theatre.
- **`--why` is never run.** Provenance nobody checks is provenance nobody needs.
## License
MIT. Concept attribution: TencentDB-Agent-Memory (MIT, © Tencent). See
[`../../LICENSE`](../../LICENSE).