31 tools· updated sep 2026

Claude Code memory: what 538 auto memory files taught me about the 200-line index

Marek.

  • 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.md or ./.claude/CLAUDE.md for the project, ~/.claude/CLAUDE.md for you, ./CLAUDE.local.md for 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 filesAuto memory
Who writes itYouClaude
What it containsInstructions and rulesLearnings and patterns
ScopeProject, user, or orgPer repository, shared across worktrees
Loaded intoEvery sessionEvery session, first 200 lines or 25 KB
Use forCoding standards, workflows, project architectureYour 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 preferences
  • feedback: corrections you give Claude and approaches you confirm
  • project: ongoing work, deadlines, and decisions Claude cannot derive from the code or git history
  • reference: 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.

ScopeLocationShared 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 WindowsAll users in the organization
User instructions~/.claude/CLAUDE.mdJust you, all projects
Project instructions./CLAUDE.md or ./.claude/CLAUDE.mdTeam members via source control
Local instructions./CLAUDE.local.md, added to .gitignoreJust 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.