memory-architecture
Skill0 starsChanged 46 days agoMITView on GitHub
Keeps coding-agent memory cheap and true, so Claude stops forgetting between sessions, re-reading bloated CLAUDE.md files, redoing research and acting on stale notes. Knows which files actually load and when (CLAUDE.md at every level, AGENTS.md, .claude/rules, MEMORY.md), where each fact belongs, and the gates that stop it rotting. Ships a self-testing audit script and a 0-10 score. Use it for any question about those files, even a narrow one, before answering from memory or searching by hand. That includes which CLAUDE.md files load in a folder, whether the paths an AGENTS.md or CLAUDE.md mentions still exist, why an agent ignored or broke a rule it was given, how to make Claude Code, Cursor and Codex follow the same rules, how to set up, audit, slim down or clean up agent memory, where a rule or fact should live, and why an agent keeps forgetting, redoing work or burning tokens. Also use it before saving a memory or writing an agent-facing doc, even if nobody says "memory".
5 other projects use a version of this.
Adopted by
Most recently taken up by
- thistleknot/skillstheir own version, first seen Nov 8, 2026
- Bitterbot-AI/bitterbot-desktoptheir own version, first seen Oct 8, 2026
- d-padmanabhan/agent-engineering-handbooktheir own version, first seen Sep 18, 2026
- sefaertunc/anthropic-watchtheir own version, first seen Apr 30, 2026
- sefaertunc/Worclaudetheir own version, first seen Apr 28, 2026
Other versions5 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 5
- Bitterbot-AI/bitterbot-desktop★ 2.5ksame name
- d-padmanabhan/agent-engineering-handbook★ 17same name
- sefaertunc/Worclaude★ 4same name
- sefaertunc/anthropic-watch★ 1same name
- thistleknot/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repositoryOne other file it gives its agents.
- AGENTS.mdAGENTS.md
The file
Show its rules and text
We split this skill into the rules it gives an agent
31 rules. 0 are common, 24 are distinctive, and 7 are very specific to this project.
0
Common
Most of the 5 edited versions we read keep these.
24
Distinctive
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Every layer has a load cost (when it enters context) and a rot rate (how fast it goes stale).
- Distinctive: line 42
Written rules are advice; enforcement is a wall: When breaking an invariant would be expensive, state it in the right written layer so the …
- Very specific: line 56
All worktrees of one repo share a single auto-memory directory.
- Distinctive: line 62
Ask these in order and stop at the first yes:
- Distinctive: line 69
Does it apply only when certain files are touched?: Use a path-scoped rule, or a folder CLAUDE.md if the scope is exactly one subtree.
- Distinctive: line 71
Is it true in every repo?: Put it in the global file, in one line.
- Very specific: line 75
When an auto-memory keeps pointing into the repo ("read docs/X.md first"), it is working as a router.
- Distinctive: line 81
Read references/templates.md for copy-ready templates of every file type.
- Distinctive: line 101
Retract visibly: When a number turns out wrong, strike it through and say why rather than deleting it silently, because someone may already …
- Distinctive: line 104
Update before you create: Look for an existing memory on the topic first.
- Distinctive: line 116
Index lines are hooks: Keep them under about 150 characters: what it is and when it matters.
- Distinctive: line 126
Only if both come up empty, search recall tools for "did we already try this".
- Distinctive: line 127
Treat every memory as a claim about the past: Before recommending a file, function, flag or command that a memory names, confirm it still …
- Very specific: line 155
The census: Every tracked agent-facing document is either covered by the gate or excluded from it with a stated reason.
- Very specific: line 158
Declared precedence: When two binding documents can disagree, give each an authority (binding > decision > brief > reference) and a status …
- Very specific: line 168
Private versus tracked: Keep private docs under a gitignored folder, but track the decision records inside it, because an untracked …
- Distinctive: line 177
When a status or context file is worth having, derive it from source and enforce invariants, not bytes.
- Distinctive: line 186
keep dates, hashes and counts out of anything a check compares.
- Distinctive: line 207
Run the audit script (below) to get a baseline.
- Distinctive: line 208
Write a root CLAUDE.md or AGENTS.md from the template, under about 150 lines to start.
- Distinctive: line 212
Add path-scoped rules or folder CLAUDE.md files only where a local invariant exists.
- Distinctive: line 214
Add a registry doc for each kind of work that has already been repeated: market numbers, benchmark results, asset sources, vendor quirks.
- Distinctive: line 218
Run the audit again and record the score.
- Distinctive: line 222
Run the deterministic checks first, since they're cheaper and more reliable than reading:
- Very specific: line 234
When index-budget, index-line-length, index-truncated, index-duplicate or memory-orphan fire, fix the index with a draft rather than by …
- Distinctive: line 276
Before adding a memory, check for one to update.
- Distinctive: line 277
When a memory proves wrong, fix or delete it now.
- Distinctive: line 278
When the index nears its budget, merge related memories or move clusters into a repo doc with a single router line.
- Very specific: line 280
When index lines have grown into findings, or memories have fallen out of the index, run --draft-index, show the owner the draft, and …
- Distinctive: line 283
When the same investigation happens twice, that is the trigger for a registry.
- Distinctive: line 285
Don't run repo-wide sweeps by default.
“Common” is measured: kept by at least 6 in 10 of the 5 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Memory architecture for coding agents
Memory exists for one reason: so the next session does not pay again for what this one already learned. Two things undo that. Memory that is expensive gets loaded every session whether it is needed or not. Memory that is false sends the next session the wrong way while sounding sure of itself. Everything below guards against one or the other.
Two ideas carry the whole skill:
- Put each fact in the cheapest layer that the agent who needs it will still find. Every layer has a load cost (when it enters context) and a rot rate (how fast it goes stale). The two usually trade off against each other.
- A claim with an enforcer stays true; a claim with only an author rots. Anything that can go stale either gets something that fails when it does, or it gets written as dated history rather than as a present-tense fact.
The layers
Load behaviour below is Claude Code's documented behaviour. Other harnesses differ, so
confirm yours with /memory or its docs before relying on a row.
| Layer | Enters context | Holds | Never holds |
Global ~/.claude/CLAUDE.md | every session, every repo | preferences true in a repo you haven't created yet | anything naming a stack, a path, a command or a project |
Project root CLAUDE.md / AGENTS.md | every session in the repo | the constitution: rules that forbid, require or disambiguate a decision, plus pointers to canonical docs | how-to (goes in a commands doc), history (goes in ADRs), descriptions of code (go in the code) |
CLAUDE.local.md | every session, this checkout only | personal, uncommitted project preferences | anything a teammate also needs |
Path-scoped rules .claude/rules/*.md with paths: | on demand, when a matching file is read | invariants for a glob such as **/migrations/** or src/billing/** | rules with no paths:, which load every session like the root file |
Folder CLAUDE.md | on demand, when files in that subtree are read | local invariants the code cannot show: "frozen", "owned by X", "never import from Y", "generated, do not edit" | a list of what each file does, which rots on the next commit |
Memory index MEMORY.md | every session, first 200 lines or 25KB only | one line per memory: a link and a hook | the finding itself |
| Memory topic files | on demand, via the index | one fact each: user, feedback, project or reference | anything the repo already records |
| Repo docs: ADRs, plans, postmortems, registries | on demand, via a pointer | decisions with rationale, measured evidence, the numbers a team relies on | volatile state |
Generated views: STATUS.md, CONTEXT.md | on demand | facts derived from source at generation time | anything a human typed |
| Code comments | when the code is read | why this code is shaped this way | claims about who calls it (the call graph already says so) |
| Recall tools: session search, observation stores, code graphs | when queried | "did we already try this?" | authority; anything recalled gets verified before it is acted on |
Enforcement: permission deny rules in .claude/settings.json, hooks, CI | never read; it blocks the action | invariants whose breach is costly ("never edit an applied migration", "billing/ is frozen") | preferences; a deny rule that fires on intended work gets deleted |
Written rules are advice; enforcement is a wall. When breaking an invariant would be expensive, state it in the right written layer so the agent plans around it, and also enforce it with a deny rule, a hook or CI, so that one skipped read can't break it.
Other agents read less. .claude/rules and folder CLAUDE.md files reach Claude Code
only. When Cursor or Codex also work in the repo, give a costly invariant one line in
AGENTS.md too, and rely on CI or a git hook to hold it: those stop every agent, whoever is typing.
Load timing matters for planning. A folder CLAUDE.md or a path-scoped rule loads
only once a matching file is read. Creating a new file, or planning before reading
anything, never triggers it. So a constraint that shapes the plan ("don't touch
billing/ until 2026-12-31") needs one line in the root file. The detail can stay local.
A few facts decide most placements. Parent-directory CLAUDE.md files load at startup.
All worktrees of one repo share a single auto-memory directory. @path imports resolve
relative to the importing file and go at most 4 hops deep. An index entry past line 200
is invisible, and so is the memory it points to.
Routing a new fact
Ask these in order and stop at the first yes:
- Can it be derived from the code or git? Then don't store it. If deriving it is expensive, generate a view (see "Generated views" below).
- Would a teammate or a fresh clone need it? Then it goes in the repo, never in personal memory. If it is a decision, write an ADR. If it is a rule, put it in the root file or a path-scoped rule. If it is evidence or numbers, put it in a registry doc.
- Does it apply only when certain files are touched? Use a path-scoped rule, or a
folder
CLAUDE.mdif the scope is exactly one subtree. - Is it true in every repo? Put it in the global file, in one line.
- Is it about this user, their corrections, or project state outside the repo? Write an auto-memory topic file and add one index line for it.
When an auto-memory keeps pointing into the repo ("read docs/X.md first"), it is
working as a router. That is the best use of personal memory: a line that costs almost
nothing and prevents a whole re-investigation.
Writing memory
Read references/templates.md for copy-ready templates of every file type.
Save when:
- the user corrects your approach, or confirms a non-obvious one;
- a decision is made and an alternative is rejected (record the rejected one, or it gets re-proposed);
- work is about to be redone, such as research, a measurement or an audit. Record where the result lives;
- external state is learned that the repo can't show: a dashboard, an account quirk, a service's real behaviour.
Don't save: code structure, past fixes, anything git log or the repo already records, or anything that only matters to the current conversation. If asked to remember one of these, ask what was non-obvious about it and save that instead.
Format rules and why they exist:
- One fact per file. A file that grows sections becomes a lab notebook that nobody can cite or supersede cleanly. Split it, or move it to a repo doc and leave a router memory.
- Feedback carries
**Why:**and**How to apply:**. A rule without its reason can't be applied to an edge case, and gets applied rigidly or not at all. - Absolute dates only. "Decided today" is false tomorrow.
- Status memories carry "as of
<date>" and the command that re-checks them. The reader can then verify in one step instead of trusting or re-investigating. - Retract visibly. When a number turns out wrong, strike it through and say why rather than deleting it silently, because someone may already have repeated it. Put the correction at the top.
- Update before you create. Look for an existing memory on the topic first. Two memories on one topic will eventually disagree.
- One current direction. Exactly one memory or doc says what is active now. When the direction changes, demote the old one to dated history in the same edit. A store where five files each call themselves "ACTIVE" or "NORTH STAR" is worse than no store at all, because each session picks one and redoes work another already closed.
- Keep a closed-questions ledger. Record each rejected option, dead hypothesis or settled question as one line: what was tried, the verdict, the date, and where the evidence lives. It is the single file that most directly prevents re-work. Keep it in the repo if the team needs it, in memory if only you do.
- Change the file and its index line together. An index hook that still says "next: build X" after the file records X as done sends every session to build X again.
- Index lines are hooks. Keep them under about 150 characters: what it is and when it matters. The detail belongs in the file the index points to.
Reading memory
This is where most tokens are saved or wasted.
- Before investigating anything, check whether it has already been answered. Scan the index, open only the topic files it points at, and follow any router to the repo doc. Then check the decision records (ADRs, plans, postmortems) for a closed question. Only if both come up empty, search recall tools for "did we already try this".
- Treat every memory as a claim about the past. Before recommending a file, function, flag or command that a memory names, confirm it still exists. Memory that disagrees with the code loses; fix or delete the memory in the same breath.
- Don't re-open what's closed without new evidence. A decision record with a rejected alternative is an answer. Re-litigating it costs a session and usually lands in the same place. If there is new evidence, say what it is.
- Cite by name, not number. Section numbers drift; "the Method section of
AGENTS.md" survives edits.
Keeping it true
These are the rules with a real incident behind each one. references/incidents.md has the stories. Read it when you need to explain a rule to a skeptical owner, or when a rule seems like overkill.
- The walk test. An agent with no memory must be able to orient itself, act and report
status from the files alone. That only holds if every pointer resolves. Backticks mean
"follow this": a backticked path must resolve, and a bare path is a name (a file under
discussion, quoted as broken, or known to be absent). Without that rule, no document
could report a dead pointer without containing one.
@pathimports and relative links in agent files are pointers too, and a path that resolves only as the tail of a longer one (settings/tips.tsforpackages/client/src/settings/tips.ts) should be written in full. A skill's markdown links are pointers too: its folder ships as it is, so a dead link breaks it for everyone who installs it. Its backticked paths are left alone, since they usually name files in the repo the skill is used on. - A rule with no gate is a preference. Whatever check proves the walk test has to
actually run: in CI, in
npm testor in a pre-commit hook. "Can be run" is not "runs". In abindingdoc, each rule says "Enforced by" and names its check, or says it isn't enforced. The reader then knows which rules hold, and the audit warns on a rule that does neither. - The census. Every tracked agent-facing document is either covered by the gate or
excluded from it with a stated reason. No document enters the repo invisibly. The script's
--censuslists every markdown file and how the walk test covers it. - Declared precedence. When two binding documents can disagree, give each an
authority(binding>decision>brief>reference) and astatus(live|historical) in frontmatter. A dead pointer in ahistoricaldoc is a warning; in alivedoc it is a failure. That split lets immutable ADRs sit next to a strict walk test. - ADRs are annotated, never rewritten. The body is the decision. Frontmatter and a dated "superseded by" line appended below are metadata, not edits.
- Derive numbers; don't type them into prose. A figure written into a sentence is stale the moment the source moves. Compute it where it is displayed, or point to where it is computed.
- Private versus tracked. Keep private docs under a gitignored folder, but track the
decision records inside it, because an untracked decision log lives on one machine with
no history. In
.gitignore,_internal/*then!_internal/docs/works; a bare_internal/stops git descending and the negation can't reach inside. Verify withgit check-ignore -v <exact file path>. Watch skills and tools that write plans to their own default paths, which may not be ignored.
Generated views
When a status or context file is worth having, derive it from source and enforce invariants, not bytes. A check that byte-compares a committed generated file against a fresh render turns red on every unrelated commit (a new caller, a date, CRLF on another OS), and a check that is always red gets switched off. Instead:
- gitignore the rendered view and stamp it with its generation time;
- enforce only what changes when status genuinely changes. Example: "no file in a covered directory becomes unreachable unless it is listed with a reason, and a listed file that comes back to life fails until the list is updated";
- keep dates, hashes and counts out of anything a check compares.
Don't restructure for tidiness
Moving every document into numbered stage folders feels like architecture, but it breaks every path citation at once and addresses none of the usual root causes. Those causes are dead pointers, an ungated check, undeclared precedence, unclassified documents and volatile generated files. Adopt the declarative part (frontmatter, census, walk test) and leave the folders alone unless a measured problem is a folder problem.
Memory tooling is a claim too
A recall plugin or memory server can die silently while its health endpoint keeps reporting "ok". Measure it by its output (rows written today, what a fresh session actually receives) and by its cost per day. Keep it only if recall visibly saves re-work after a few sessions.
Workflows
Set up from zero (new or unstructured repo)
- Run the audit script (below) to get a baseline.
- Write a root
CLAUDE.mdorAGENTS.mdfrom the template, under about 150 lines to start. Give it a pointer table to canonical docs and a Method section: how decisions get made here, not only the conclusions. - Move anything project-specific out of the global file.
- Add path-scoped rules or folder
CLAUDE.mdfiles only where a local invariant exists. Most folders need none. An empty-but-present folder file is noise. - Add a registry doc for each kind of work that has already been repeated: market numbers, benchmark results, asset sources, vendor quirks. Then add a router memory for each one.
- Wire the walk-test check into whatever already runs (a test, CI or a hook). Break it once on purpose to confirm it fails.
- Run the audit again and record the score.
Audit and score (0-10)
Run the deterministic checks first, since they're cheaper and more reliable than reading:
python <skill-dir>/scripts/audit_memory.py --project . # repo, its memory folder, global file
python <skill-dir>/scripts/audit_memory.py --self-test # proves every check can fireFAIL means a breach (an orphaned memory, a truncated index, a dead pointer in a live
doc). WARN means worth a look. Budgets live at the top of the script as named constants,
so change them on purpose rather than ignoring the warnings. In CI, --repo . --strict
fails on warnings too, which suits a repo that has already cleared them.
When index-budget, index-line-length, index-truncated, index-duplicate or
memory-orphan fire, fix the index with a draft rather than by hand:
python <skill-dir>/scripts/audit_memory.py --project . --draft-indexIt writes MEMORY.draft.md next to the index: one line of at most about 150 characters
per memory file, with the hook taken from the file's description (or the old index text),
the index's order kept, orphans appended, duplicates and dead links dropped. It prints
bytes, lines and estimated tokens before and after, and whether the draft fits the budget
and the load cap. It never touches MEMORY.md and won't overwrite an earlier draft
without --force. A human reviews the draft before it replaces MEMORY.md: a hook
rebuilt from description can lose a word the owner relied on. If the draft is still over
budget, trimming can't fix it; merge memories or move a cluster into a repo doc.
Then score. Each item is worth 1 point, or 0.5 if only partly met. Cite evidence for each item; don't grade on impression. If you can't see something (for example, you were given only the memory folder and not the repo), mark those items N/A, rescale over the items in scope, and say what the score covers. Scoring what you can't see as 0 measures access, not quality.
| # | Criterion | Evidence |
| 1 | Global file is universal only, under about 60 lines, and holds no one-time instructions | script: global-* clean |
| 2 | Root CLAUDE.md/AGENTS.md exists, is tracked, and holds only decision-changing rules plus pointers | read it; root-missing and agent-file-size clean |
| 3 | Folder or path-scoped files exist only where a local invariant exists, and every scope matches files | rule-dead-scope clean; spot-check 3 |
| 4 | Memory index under budget with hook-length lines; nothing truncated or orphaned | index-* and memory-orphan clean |
| 5 | Memory files hold one fact each, with type, Why (for feedback) and absolute dates | memory-* warnings under 10% of files |
| 6 | Repeated work has a registry doc and a router memory, there is exactly one current direction, and closed questions are in a ledger | competing-current clean; find the last re-done investigation and check a registry covers it |
| 7 | Every pointer in live agent-facing docs resolves, and a gate that runs proves it | walk-test clean; show where it runs |
| 8 | Documents declare authority and status, or the repo is small enough not to need it | frontmatter present; census clean |
| 9 | Generated views enforce invariants, not bytes; costly invariants are also enforced by deny rules, hooks or CI | read the check and .claude/settings.json |
| 10 | Private/tracked split verified, and decision records have git history | git check-ignore -v on one private file and one decision doc |
Report the score with the three highest-value fixes, each with its cost. The override rule: if a fix would add more friction than the failure it prevents, say so and skip it. A small solo repo can legitimately score 7 with no work left worth doing.
Maintain
Maintenance happens when you touch memory, not on a schedule:
- Before adding a memory, check for one to update.
- When a memory proves wrong, fix or delete it now.
- When the index nears its budget, merge related memories or move clusters into a repo doc with a single router line.
- When index lines have grown into findings, or memories have fallen out of the index, run
--draft-index, show the owner the draft, and replaceMEMORY.mdwith it only once they approve. - When the same investigation happens twice, that is the trigger for a registry.
Don't run repo-wide sweeps by default. A full audit is a decision the owner makes.
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.

