ai-memory-system
CLAUDE.md2 starsChanged 21 days agoMITView on GitHub
This repo holds the source of a cross-project memory system for Claude Code. The system is described in README.md; this file is about working on it. An instruction in a prompt is not a guarantee. Every safety property here is enforced by code that verifies and reverts, never by asking a model nicely: - scripts/memory_core.py — validates revisions and preservation, journals full originals, and recovers interrupted writes. - cron/curate.sh — relocates overflowing indexes verbatim; it does not perform model rewrites.…
In this repositoryOne other file it gives its agents.
- memory-writeSkill
The file
We split this CLAUDE.md into the rules it gives an agent
5 rules. About 0 are common, 4 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
When you add a guarantee, add the check that fails when it breaks.
- Distinctive: line 88
Do not hand-edit them here — edit the install, then run:
- Distinctive: line 101
Every non-trivial guard has one.
- Distinctive: line 115
Prefer mutation-testing a new case: break the guard on purpose and confirm the test fails.
- Very specific: line 145
Commit messages in pt-BR, semantic emoji prefix (✨ feat:, 🐛 fix:, 🔒 security:, 📚 docs:).
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
ai-memory-system — working in this repo
This repo holds the source of a cross-project memory system for Claude Code.
The system is described in README.md; this file is about working on it.
The one rule that explains most of the design
An instruction in a prompt is not a guarantee. Every safety property here is enforced by code that verifies and reverts, never by asking a model nicely:
scripts/memory_core.py— validates revisions and preservation, journals full originals, and recovers interrupted writes.cron/curate.sh— relocates overflowing indexes verbatim; it does not perform model rewrites.sync-release.sh— refuses to copy anything carrying an absolute home path, and scans itself while doing it.
When you add a guarantee, add the check that fails when it breaks. Prose in a prompt does not count.
What ships and what doesn't: mechanism vs policy
A live ~/.claude holds two things. Only one of them is this product.
- Mechanism (ships) — code that works on anyone's machine:
hooks/,cron/,scripts/,docs/,install.sh. It operates oncontext/,projects/anddata/: the paths are mechanism, the contents are the user's. - Policy (never ships) — what one machine decides:
CLAUDE.md,commands/,skills/,agents/,settings.json.
The boundary is the MANIFEST — an allowlist, so anything unlisted is private by
default. Note that shape is not membership: a hook with tests can still be pure
policy (a push-approval gate is a hook, and it is nobody else's business).
The rule inside a shipped file: shipped code (hooks/, cron/, scripts/)
may not name the config surface at all, in any syntax. The few files that
genuinely operate on it are listed by name in CONFIG_OK in sync-release.sh,
where a reviewer sees them — currently just cron/check-hooks.sh, which reads the
settings file to verify the hooks are installed. docs/ and README.md are out
of scope: telling the reader to edit their own instructions file is what they are
for.
Deny-by-default, and it took three tries to get there because each earlier version modelled a form instead of suspecting the reference:
| attempt | modelled | what walked through |
| syntax | "config may appear in code, never in a comment" | trailing comments (anchored to line start), the docstrings in four shipped .py files |
| path shape | (~|$HOME)/.claude/<config> | ${HOME}/…, "$HOME"/…, and path.join(home, '.claude', …) — which is how all eight shipped .js files build paths, so half the release |
| co-occurrence | a line naming the store AND something on the config surface | (current) spelling, quoting and separators stop mattering |
Same lesson as the shell-parsing one: an enumerator has to recognise every form, and there is always one more. Match on what the leak is about, not how it is written, and let the few legitimate files prove themselves by name.
The current rule has two deliberate limits, both pinned by test cases so they
cannot be lost by accident: a bare word (the store holds no commands) is not
a reference, and a bare filename with no store path (reads settings.json at
startup) is not either. The cost is that # per the user's settings.json would
be missed — accepted, because the alternative fires on ordinary prose and a guard
that cries wolf gets switched off.
Why it needed its own check at all: the path tripwire models a leak as "text that
identifies a machine or a person". On 2026-09-01 a comment citing a section of the
author's personal instructions file shipped in cron/backup-push.sh and scored
zero matches — no absolute path, no username, nothing to match. Two classes of
leak, two checks. Neither catches a client name in prose, or policy that names
nothing ("push to main is fine here"); that is still a review question on every
--from-home sync, not only when you add to the MANIFEST: grep the incoming diffs,
test files included, for client and project names (one once arrived in a test
comment of a file already in the MANIFEST).
CONFIG_OK in sync-release.sh lists the files that legitimately operate on the
config surface — cron/check-hooks.sh (reads the settings file) and
cron/memory-index.sh (indexes the skills' knowledge dirs). Both are covered by
their own test cases: dropping either from the list must fail the suite, or the
list decays into a place where things get quietly added.
Layout
hooks/ the SessionStart/Stop hooks (installed into ~/.claude/hooks/)
cron/ scheduled maintenance: curate, distill, backfill, tripwires
scripts/ mem (retrieval seam), memory-maintain.py (LLM extraction with quota handling)
docs/ retrieval-interface.md, model-agnostic.md
migration/ one-shot scripts for store layout changes, kept for referencehooks/, cron/ and scripts/ are copies of a live ~/.claude install.
Do not hand-edit them here — edit the install, then run:
./sync-release.sh --check # what differs
./sync-release.sh --from-home # copy live -> repo, with the leak guardThe MANIFEST in sync-release.sh is the definition of what ships. Anything
not listed does not reach the public repo — which matters, because a live
~/.claude also holds per-client project memory that must never be published.
Tests
Every non-trivial guard has one. Run them before committing:
./sync-release.test.sh # the leak guard (8 cases)
bash cron/curate-audit.test.sh # curator veto
python3 cron/split-memory.test.py # split safety
python3 cron/jsonl-to-transcript.test.py
node hooks/project-store.test.js # store anchoring
bash scripts/skill-grep.test.sh # grep -> mem -> section listing
bash scripts/mem.test.sh # weak-result retry warning
bash cron/check-caps.test.sh # per-store cap override + stderr silence
node hooks/daily-log-nudge.test.js # nudge: link hints, DST, emitted JSONPrefer mutation-testing a new case: break the guard on purpose and confirm the test fails. A test that cannot fail is not a test.
Green is not proof — ask what the assertion cannot see
The .cap feature shipped five defects past five green suites in one session
(2026-08-31). In every one the code was fine and the assertion was too weak
to observe the failure. The pattern is worth more than the individual bugs:
| The assertion looked at | What it could not see |
| exit code only | a cap of 0 reported as 2600/0, indistinguishable from the default |
| stdout, stderr discarded | a failed redirection spamming the cron log on every store |
the string after $(cat) | NUL bytes, already spliced away before the regex ran |
.sh files only | versioned prose telling the agent the old number |
| the file as a whole | one mention reverted while another still satisfied the check |
So when a guard passes, ask "what is this assertion structurally unable to
observe?" — a channel it discards, a transformation upstream of it, a scope it
never enters. Then mutate that, not the case you already thought of. Twice
here a mutation "passed" because the test case was vacuous: .cap=0 flags
everything so the exit code was identical either way, and 25 00 spliced into
exactly the default value it was supposed to prove had not been used.
Assert the value, not just pass/fail; capture stderr rather than discarding it; validate bytes when text handling might transform them; and cover the prose that instructs the agent, because that is enforcement too.
Conventions
- Commit messages in pt-BR, semantic emoji prefix (
✨ feat:,🐛 fix:,🔒 security:,📚 docs:). Say why, not just what — the reasoning is the part that is expensive to recover later. - Comments explain the failure that motivated the code. Several of these files exist because something was silently lost once; keep that context.
- Character caps are measured in characters, not bytes — accented text inflates byte counts and produces false alarms.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

