Claude Code memory: what 538 auto memory files taught me about the 200-line index
- claude-code
- context-engineering
- agent-ops
Claude Code memory is two mechanisms that carry knowledge across sessions, because every session starts with a fresh context window: CLAUDE.md files you write, and auto memory that Claude writes for itself. Both load at the start of every conversation, and the docs are blunt that Claude treats both as context, not enforced configuration. On 4 September 2026 I measured my own copy of each: a 244-line CLAUDE.md and 538 auto memory files behind a 101-line index. This post is the docs read against those numbers.
- What it is. CLAUDE.md holds instructions you write, at managed, user, project or local scope. Auto memory holds notes Claude writes: your preferences, your corrections, project context it cannot derive from the code, and pointers to places outside the repo.
- How it loads. Every session. CLAUDE.md files from the working directory up,
concatenated in order. Auto memory as the first 200 lines or 25 KB of
MEMORY.md, with the topic files behind it read on demand. - Where it lives.
./CLAUDE.mdor./.claude/CLAUDE.mdfor the project,~/.claude/CLAUDE.mdfor you,./CLAUDE.local.mdfor private notes, and~/.claude/projects/<project>/memory/for auto memory, which never leaves the machine. - What my copy looks like. 538 memory files. By filename: 255 feedback, 152 project, 98 reference, one user, and 32 named before the convention. An index of 101 lines and 19,949 bytes: half the line cap and about four fifths of the byte cap.
- The rule underneath. Memory is context, not a fence. For anything that must never happen, the docs point at a hook, and my own config learned that the expensive way.
The 482-line file I measured in the CLAUDE.md audit is 244 lines today. This post is about what the docs say that file should hold, and about the other memory, the one Claude keeps for itself.
CLAUDE.md vs auto memory: two systems, one reader
The memory page in the Claude Code docs opens with the reason memory exists at all: each session begins with a fresh context window, so two mechanisms carry knowledge across sessions. CLAUDE.md files are "instructions you write to give Claude persistent context". Auto memory is "notes Claude writes itself based on your corrections and preferences".
The docs' own comparison, condensed:
| CLAUDE.md files | Auto memory | |
|---|---|---|
| Who writes it | You | Claude |
| What it contains | Instructions and rules | Learnings and patterns |
| Scope | Project, user, or org | Per repository, shared across worktrees |
| Loaded into | Every session | Every session, first 200 lines or 25 KB |
| Use for | Coding standards, workflows, project architecture | Your preferences, corrections, context Claude cannot derive from the code |
One sentence on that page carries more weight than the table: "Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead." A memory changes what the model knows. It does not change what the model is allowed to do. The fence for that is a PreToolUse hook, and the docs say so before any file path.
A second sentence, from the troubleshooting section: "CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself." Your instructions arrive the way your typed messages do, which is why the docs never promise strict compliance. The difference between those two layers is the system prompt entry in the glossary.
How auto memory works
Auto memory is on by default. As Claude works it saves four kinds of notes and
records the kind as a type field in the file's frontmatter. It skips anything it
can derive from the codebase and anything your CLAUDE.md files already say, and it
does not save something every session.
user: your role, expertise, and working preferencesfeedback: corrections you give Claude and approaches you confirmproject: ongoing work, deadlines, and decisions Claude cannot derive from the code or git historyreference: where to find information outside the project, such as an issue tracker or dashboard
Storage is one directory per project: ~/.claude/projects/<project>/memory/.
The path is derived from the git repository, so all worktrees and subdirectories
of one repo share it. Inside: MEMORY.md as an index, one line per memory, and
one topic file per memory. The index is what loads: the first 200 lines of
MEMORY.md, or the first 25 KB, whichever comes first. Content past that
threshold is not loaded at session start. After Claude writes to the index,
Claude Code measures it against both limits. Near a limit it reminds Claude to
shorten the file. Over a limit the write still succeeds, but Claude Code returns
an error telling Claude to rewrite the index, because everything past the limit
is dropped on the next load.
Topic files are not loaded at startup; Claude reads them on demand with its normal
file tools, which is what "Recalled 2 memories" in the interface means. Since
v2.1.214, a memory file with YAML frontmatter gets a modified field with an ISO
8601 timestamp on every write, so you and Claude can both see how current a fact is.
Switches: autoMemoryEnabled in user or project settings, the /memory toggle
that writes it, CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 from the environment, and
autoMemoryDirectory to move the store. Two boundaries. Auto memory is
machine-local, never shared across machines or cloud environments. And the
main conversation's auto memory does not reach a
subagent unless it is a fork, which inherits
the parent conversation. A subagent's own store is a
separate directory.
Where Claude Code memory files live
CLAUDE.md files can live in four places: a managed policy path, ~/.claude/CLAUDE.md
for you, ./CLAUDE.md or ./.claude/CLAUDE.md for the project, and
./CLAUDE.local.md for private notes. Claude Code loads them from your working
directory up, in order from broadest scope to most specific.
| Scope | Location | Shared with |
|---|---|---|
| Managed policy | /Library/Application Support/ClaudeCode/CLAUDE.md on macOS, /etc/claude-code/CLAUDE.md on Linux and WSL, C:\Program Files\ClaudeCode\CLAUDE.md on Windows | All users in the organization |
| User instructions | ~/.claude/CLAUDE.md | Just you, all projects |
| Project instructions | ./CLAUDE.md or ./.claude/CLAUDE.md | Team members via source control |
| Local instructions | ./CLAUDE.local.md, added to .gitignore | Just you, current project |
All discovered files are concatenated rather than overriding each other, ordered from the filesystem root down, so the instructions closest to where you launched are read last. Files in subdirectories are not loaded at launch; they come in when Claude reads files there.
Two mechanisms extend the file. Imports, written as @path/to/import, expand at
launch alongside the file that references them, up to four hops deep; a path in
backticks stays literal. And .claude/rules/ holds markdown rules discovered
recursively. A rule without paths frontmatter loads at launch with the same
priority as .claude/CLAUDE.md. A rule with a paths glob loads only when Claude
reads a matching file. User-level rules in ~/.claude/rules/ load before project
rules, so project rules win. Two smaller facts: block-level HTML comments
are stripped before the content reaches Claude, and a file up to 4 MiB loads in
full while a larger one is skipped.
What 538 auto memory files look like on one repo
On the afternoon of 4 September 2026 the memory directory for this repository
held 538 files, not counting the index and two secondary index files. The
filename carries the kind: 255 start with feedback, 152 with project, 98
with reference, one with user, and 32 predate the convention. The index,
MEMORY.md, was 101 lines and 19,949 bytes. Every number here is a snapshot.
The docs cap the loaded index at 200 lines or 25 KB, whichever comes first. Mine sits at half the line cap and about four fifths of the byte cap. The lines are long: the index groups several links on one line, each with a short hook. One line can name four or five memories. The byte cap will hit first. The audit post recorded the same index at 85 lines on 17 August. Sixteen lines in eighteen days, none typed by me.
A topic file in my directory starts with frontmatter: 529 of the 538 carry
name and description. The type field the docs describe is on 194 of them,
and it is the older files that have it: about half of the files last written in
June carry it, and almost none of the files written in August or September do.
Then the fact, then two labeled lines, Why and How to apply, then
[[name]] links to related memories. I keep the
description to one sentence carrying the finding, and the index line to a
shorter hook that points at it.
The entry saved this week reads, in short: a reviewer agent started before the
writer had finished and judged a moving file; start the judge after the writer's
final report. A feedback memory doing exactly what the docs describe.
Where memory goes wrong
Four failure modes, three from my own files and one from the docs.
A number copied from memory instead of the source. On 31 August a panel showed
Approved (6). The README and the memory recorded 3, and the next session read the
false state back as fact. My CLAUDE.md now carries the rule: copy the number from
the source, not from memory. A memory is a claim about the past with a timestamp,
which is why the modified field matters and why a reference memory should point
at the panel rather than quote it.
History mistaken for state. A context file that accumulates dated entries stops describing now and starts reading like a log. My rule: context files hold state, dated material moves to a changelog.
Context mistaken for enforcement. In the audit I sorted 26 shouted rules and found eight that gate production access. They stay in the file, but the enforcement is a hook. The docs say it plainly: an instruction that must run at a specific point should be a hook, because hooks "apply regardless of what Claude decides to do".
Contradictions. From the docs: "if two rules contradict each other, Claude may pick one arbitrarily." With a 244-line project file and a 210-line user rules file, contradictions are a maintenance task; the docs suggest periodic review of all of them together.
One more that looks like memory loss and is not. After /compact, Claude re-reads
the project-root CLAUDE.md from disk and re-injects it; nested files and
path-scoped rules reload as Claude reads the files they apply to. What does not come
back is an instruction you gave only in conversation; the docs say to move it into
CLAUDE.md. What else survives compaction belongs to the
context window.
/memory, /context, /init, /doctor
/memory lists your CLAUDE.md, CLAUDE.local.md and other memory file locations
across user and project scopes, including entries for files that do not exist yet.
It also toggles auto memory and opens the auto memory folder. "Remember this" goes
to auto memory; "add this to CLAUDE.md" goes to the file.
/context answers the question /memory does not: which files actually loaded
into this session. The list under Memory files is the first place to look when an
instruction is being ignored. If the file is not there, Claude cannot see it.
/init generates a starting CLAUDE.md by reading the codebase, or suggests
improvements to one that exists. With CLAUDE_CODE_NEW_INIT=1 it asks which
artifacts to set up, explores the codebase with a subagent, and shows a proposal
before writing anything.
/doctor is the one I lined up in the audit and had not run at the time. Its trim
check, since v2.1.206, proposes cuts for a checked-in CLAUDE.md: directory layouts,
dependency lists and architecture overviews go; "pitfalls, rationale, and
conventions that differ from tool defaults" stay. The audit's sort, automated.
When none of the four explains a missing instruction, the InstructionsLoaded
hook logs which instruction files loaded, when, and why.
CLAUDE.md size: 244 lines against the 200-line guidance
The docs' size guidance is one number: "target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence." My project file was 482 lines and 43 KB when I audited it on 17 August. On 4 September it is 244 lines and 24,459 bytes. Half the file is gone and it is still 44 lines over.
The docs give two moves for the remainder. Path-scoped rules in .claude/rules/
load only when Claude works with matching files, so a rule about the deploy script
stops taxing a session about a spreadsheet.
Splitting the file into imports, on the other hand, "helps organization but
doesn't reduce context, since imported files load at launch". The @path pieces
are tidier and cost the same tokens.
The third move is the one the audit already named: procedures belong in skills, which load only when you invoke them or when Claude decides they fit your prompt. I have 56 on disk; each costs its description at startup and its body only when used, per how Claude Code works. What earns its place, by the docs' list: build commands, conventions, project layout, "always do X" rules. What does not, by the docs: anything derivable from the repo. The traffic runs the other way too: auto memory skips what your CLAUDE.md already says.
Memory plugins, AGENTS.md and the other memory leak
Three things a search for this string turns up that are not the two systems above.
Third-party memory plugins exist; claude-mem is the one that ranks for this
string. I have not run it, so no verdict. The docs' answer to "I don't know what
auto memory saved" is /memory and a folder of plain markdown.
Before adding another source of persistent context, inspect a Claude Code plugin before installing it and check which components it loads.
"Claude Code memory leak" is a different question, about the process consuming RAM, and this post does not cover it.
For teams arriving from another agent: "Claude Code reads CLAUDE.md, not
AGENTS.md." The docs' pattern is a CLAUDE.md that imports it: one line of
@AGENTS.md. That is the setup my own site repo uses, described in
the system prompt post. /init also reads Cursor
rules in .cursor/rules/ or .cursorrules and Copilot rules in
.github/copilot-instructions.md. With CLAUDE_CODE_NEW_INIT=1 set it also reads
AGENTS.md, .devin/rules/, .windsurf/rules/ or .windsurfrules, and
.clinerules. /import, since v2.1.213, appends a one-time copy of files such as
AGENTS.md to the matching CLAUDE.md and carries over MCP servers, commands,
subagents and skills. Those two commands are the whole of what the docs say about
other agents' files, and the whole of what I checked.
What I keep and what I would cut
The two fail differently. A CLAUDE.md failure is a rule the model did not follow;
the fix is a more specific sentence or, if the rule matters, a hook. An auto memory
failure is a fact that went stale or was never true, and the fix is the modified
date and a habit of pointing at sources instead of quoting them.
Cut from CLAUDE.md whatever /doctor would cut, and watch the index of the other
memory as it grows: mine will hit the 25 KB cap long before the 200-line one. The
number that matters is not how much Claude remembers. It is how much of it loads,
and that is two hundred lines or 25 KB of an index, whichever comes first, plus
whatever it decides to read.
Sources: the Claude Code docs page How Claude remembers your project, read on 4 September 2026, source of every quoted sentence and every limit above except the one about skills, which is from How Claude Code works, read the same day; the file counts, sizes and dates for my own setup, measured the same day on my own machine; and the August numbers from the CLAUDE.md audit.