Memory
Give Claude Code lasting knowledge with CLAUDE.md, AGENTS.md and .claude/rules, and understand how auto memory lets Claude keep its own notes between sessions.
Every Claude Code session starts with an empty context window. Nothing from yesterday's conversation carries over by itself. Two mechanisms bridge the gap:
- Instruction files you write:
CLAUDE.md(or an existingAGENTS.md) and rules in.claude/rules/. - Auto memory Claude writes: short notes it keeps for itself about your preferences, corrections and project context.
Getting these right is the single most effective thing I have done to make Claude Code reliable on client projects. This page covers both, plus how to debug them when Claude seems to ignore you.
The two systems side by side
Instruction files (CLAUDE.md) | Auto memory | |
|---|---|---|
| Author | You | Claude |
| Holds | Rules, commands, conventions | Learned preferences, corrections, context not visible in the code |
| Scope | Organisation, user, project or local | One repository, shared across its worktrees |
| Loaded | Every session | Every session (the first 200 lines or 25 KB of the index) |
Both are context, not enforcement. Claude reads them and tries to comply, and specific, concise instructions are followed far more consistently than vague ones. If something must never happen, block it with a PreToolUse hook or a permission rule.
Subagents can keep their own separate memory too; see subagents.
CLAUDE.md
When to add something
Treat CLAUDE.md as the place for anything you would otherwise explain twice. Good triggers:
- Claude repeats a mistake.
- A code review catches something Claude should have known about this codebase.
- You find yourself typing the same correction you typed last week.
- A new teammate would need the same information.
Keep it to facts that matter on every task. A multi-step procedure belongs in a skill; guidance for one corner of the codebase belongs in a path-scoped rule (below). Features overview has a fuller decision guide.
Where the files live
Listed from broadest to most specific, which is also the order they appear in context:
| Scope | Location | Typical contents | Who sees it |
|---|---|---|---|
| Managed policy | macOS: /Library/Application Support/ClaudeCode/CLAUDE.md; Linux and WSL: /etc/claude-code/CLAUDE.md; Windows: C:\Program Files\ClaudeCode\CLAUDE.md | Company standards, security and compliance reminders | Everyone on the machine |
| User | ~/.claude/CLAUDE.md | Your personal style and tooling habits | You, in every project |
| Project | ./CLAUDE.md or ./.claude/CLAUDE.md | Architecture, commands, team conventions | The team, through git |
| Local | ./CLAUDE.local.md | Your sandbox URLs, test accounts, personal shortcuts | You, in this project (add it to .gitignore) |
Files in the working directory and above load at launch. Files in subfolders load later, on demand.
Creating a project file
Run /init and Claude will study the codebase and draft a CLAUDE.md with the build commands, test instructions and conventions it finds. If one already exists, it suggests improvements instead of overwriting. Then add what Claude could not have worked out on its own.
For a more thorough, interactive setup, set CLAUDE_CODE_NEW_INIT=1 (in your shell or the env block of a settings file) before running /init. It then asks which things to set up (instruction files, skills, hooks), explores with a subagent, asks follow-up questions and shows a proposal for review before writing anything. You can leave the variable set permanently.
Run /context and look under Memory files to confirm your file loaded.
Writing instructions that stick
Be concrete enough that compliance is checkable:
| Vague | Concrete |
|---|---|
| Write clean code | Functions over 40 lines need a comment explaining why they cannot be split |
| Test your work | Run pnpm vitest run --changed before saying a task is done |
| Keep things organised | Background jobs live in src/jobs/, one file per job |
And keep files tidy:
- Size. Aim for under 200 lines per file. Longer files cost more context and reduce adherence. Imports help organise a file but do not reduce cost, because imported files also load at launch. Path-scoped rules do reduce it.
- Structure. Headings and bullet lists beat dense paragraphs.
- Consistency. Contradictory instructions lead Claude to pick one at random. Review your root and nested
CLAUDE.mdfiles and rules every so often.
Here is roughly what mine looks like for a Next.js client site:
# Acme marketing site
## Commands
- Dev server: `pnpm dev` (port 3200)
- Type check: `pnpm tsc --noEmit`
- Tests: `pnpm vitest run`
## Conventions
- Server components by default; add "use client" only when state or effects are needed
- Copy lives in `content/` as MDX, never hard-coded in components
- UK English in all user-facing text
## Gotchas
- The CMS preview route bypasses caching; do not add `revalidate` there
Auditing your instruction files
/doctor prompt-audit asks Claude to check your instruction files for problems: guidance written for older models, references to files or commands that no longer exist, and files that contradict each other. You get a report with proposed edits, and nothing changes until you ask. By default it covers CLAUDE.md, CLAUDE.local.md and AGENTS.md, plus rules, skills, commands, subagents and output styles under .claude/ and ~/.claude/. Pass a path to audit just one file or folder, for example /doctor prompt-audit .claude/rules.
It needs v2.1.283 or later and runs through the bundled /claude-api skill, so it is unavailable if that skill is turned off via skillOverrides or disableBundledSkills.
Importing other files
Write @path/to/file anywhere in a CLAUDE.md to pull that file in at launch:
Project background is in @docs/overview.md and available scripts are in @package.json.
## Deployment
- Follow @docs/runbooks/deploy.md
The rules:
- Relative paths resolve from the file containing the import, not your working directory. Absolute paths work too.
- Imports can nest up to four levels deep.
- For paths with spaces, escape each space with a backslash, as in
@Team\ Notes/style.md. Without escapes the path stops at the first space; a quoted path is not imported at all. - Imports inside inline code or fenced code blocks are ignored, so wrap a path in backticks to mention it without importing it.
CLAUDE.local.md only exists in the worktree where you created it. To share personal notes across several worktrees of one repo, import a file from your home folder instead, for example @~/.claude/acme-notes.md.
Warning: An import in a project file that points outside the working directory counts as external. The first time Claude Code meets external imports in a project, it asks you to approve them. Decline and they stay disabled without asking again. This protects you from files someone else committed. Imports in your own user-level files (
~/.claude/CLAUDE.md,~/.claude/rules/) are trusted without a prompt, except in Cowork sessions on the desktop, which skip user-level imports that resolve outside the working directory, a~/.claude/CLAUDE.mdthat is a symlink or hard link, and symlinked rules pointing outside it.
How loading works
Claude Code collects CLAUDE.md and CLAUDE.local.md from your working directory and every parent folder. Start in services/payments/ and it reads services/payments/CLAUDE.md, services/CLAUDE.md, the repo root's file and any local variants beside them.
Nothing overrides anything. Everything is concatenated, ordered from the filesystem root down to your working directory, so the instructions nearest to where you launched come last. Within a folder, CLAUDE.local.md follows CLAUDE.md.
Files in subfolders below the working directory load when Claude uses Read, Write or Edit on something in that subfolder (unless Claude has already opened that CLAUDE.md directly). For worktrees under .claude/worktrees/, see worktrees.
Block-level HTML comments such as <!-- reviewed March, keep --> are stripped before injection, so you can leave notes for humans at no context cost. Comments inside code blocks are kept, and opening the file with the Read tool shows them.
In a large monorepo, the claudeMdExcludes setting (below) skips other teams' files. Large codebases covers monorepo layouts in depth.
Extra directories
--add-dir grants access to folders outside the working directory, but their instruction files are not loaded by default. Turn that on with an environment variable:
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 claude --add-dir ../design-system
Put it in the env block of ~/.claude/settings.json to make it permanent. It loads CLAUDE.md, .claude/CLAUDE.md, .claude/rules/*.md and CLAUDE.local.md from the extra folder (the last is skipped if local is excluded via --setting-sources).
Rules in .claude/rules/
Rules split instructions into one Markdown file per topic. All .md files under .claude/rules/ are found recursively, so subfolders such as frontend/ and backend/ are fine.
.claude/
├── CLAUDE.md
└── rules/
├── security.md
├── frontend/
│ └── accessibility.md
└── backend/
└── queues.md
A rule without paths frontmatter loads at launch with the same priority as .claude/CLAUDE.md. Project rules are skipped if you exclude project from --setting-sources (before v2.1.211, on-demand rules loaded anyway).
Path-scoped rules
Add paths frontmatter and the rule only loads when Claude reads, writes or edits a matching file:
---
paths:
- "app/**/*.{tsx,jsx}"
- "components/**/*.tsx"
---
# Accessibility
- Every interactive element needs a visible focus style
- Icon-only buttons need an aria-label
- Never use colour alone to convey state
It does not fire on other tool uses such as Grep. Symlinked paths into the project match as well.
| Pattern | Matches |
|---|---|
**/*.go | Every Go file, anywhere |
infra/**/* | Everything under infra/ |
*.md | Markdown files in the project root only |
app/routes/*.tsx | Route files in one folder |
Some details:
- Brace expansion multiplies patterns:
src/*.{ts,tsx}becomes two,{a,b}/{c,d}/*.{ts,tsx}becomes eight. A rule's wholepathslist shares a budget of 1,000 expanded patterns and 4 MiB (patterns without braces are free). A pattern that would exceed it is used unexpanded and its literal braces match nothing. Before v2.1.217, heavy brace use could stall or crash startup. - Square brackets start a character class. An unclosed one, such as
logs [old/**, makes that pattern invalid and match nothing while the others keep working. Escape a literal bracket as\[. Before v2.1.207, one bad pattern broke the Read tool for every file the rule was checked against. - Frontmatter.
pathsis the only field read; it accepts a YAML list or a comma-separated string. Other fields are silently ignored, and frontmatter is removed before the rule enters context. If the YAML does not parse, the rule loads as though it had nopaths;claude --debugshows the error.
Sharing rules with symlinks
.claude/rules/ follows symlinks (and copes with circular ones), so you can keep a shared set and link it into several projects:
ln -s ~/dev/agency-rules .claude/rules/agency
ln -s ~/dev/standards/secrets.md .claude/rules/secrets.md
A link whose target is outside the working directory is treated like an external import: nothing loads until you approve external imports for the project (one dialog per project at the start of an interactive session), and even then only rules without paths load. To skip the approval entirely, keep shared rules in ~/.claude/rules/. Links to network locations (UNC shares like \\server\share, or paths under /net or /Network) are never followed; \\wsl$ paths are fine.
Personal rules
Rules in ~/.claude/rules/ apply to every project on your machine. They load before project rules, so project rules appear later in context, but neither overrides the other. Keep them consistent.
Organisation-wide instructions
Administrators can deploy a managed CLAUDE.md to the policy path for each OS (listed in the table above) using MDM, Group Policy, Ansible or similar. It applies to every session in every repository and cannot be excluded by users. Alternatively, put the text directly in managed settings with the claudeMd key:
{
"claudeMd": "Never commit secrets or .env files.\nAll new services must expose a /healthz endpoint."
}
claudeMd is honoured only in managed and policy settings; it does nothing in user, project or local files. It loads before user and project instructions.
Use the right tool for each concern:
| Concern | Put it in |
|---|---|
| Blocking tools, commands or paths | Managed settings: permissions.deny |
| Enforcing sandboxing | Managed settings: sandbox.enabled |
| Environment variables and provider routing | Managed settings: env |
| Login method and organisation lock | Managed settings: forceLoginMethod, forceLoginOrgUUID |
| Coding standards, data handling reminders, behavioural guidance | Managed CLAUDE.md |
Settings are enforced by the client; CLAUDE.md shapes behaviour. See managed settings.
Excluding files you do not want
In a big monorepo you may inherit instructions that have nothing to do with your area. claudeMdExcludes skips files by absolute path or glob. I put it in .claude/settings.local.json so it only affects me:
{
"claudeMdExcludes": [
"**/platform/CLAUDE.md",
"/Users/me/src/platform/payments/.claude/rules/**"
]
}
It works at every settings level and arrays merge across levels. For a symlinked rule, a pattern matching either the link path under .claude/rules/ or the target excludes it (before v2.1.239, only the target worked). Managed policy CLAUDE.md files cannot be excluded.
AGENTS.md
If a repository is already set up for other coding agents with an AGENTS.md, Claude Code can read it directly. Reading it natively requires v2.1.277 or later.
| The repo has | Claude reads |
|---|---|
AGENTS.md, and no CLAUDE.md or CLAUDE.local.md in the working directory or above | AGENTS.md |
AGENTS.md plus a CLAUDE.md or CLAUDE.local.md in the working directory or above | The CLAUDE.md files only |
A CLAUDE.md that imports @AGENTS.md | CLAUDE.md, with AGENTS.md pulled in by the import |
What counts as "having a CLAUDE.md"
- Counts (so
AGENTS.mdis skipped):CLAUDE.md,.claude/CLAUDE.mdorCLAUDE.local.mdin the working directory or any parent. - Does not count (and keeps loading alongside
AGENTS.md):~/.claude/CLAUDE.md, the managedCLAUDE.md, and.claude/rules/files.
Watch out for the trap here: adding a CLAUDE.local.md for your own notes in an AGENTS.md project stops Claude reading AGENTS.md. Set Project instructions to claude-md-and-agents-md to have both.
When AGENTS.md is in use:
- Every
AGENTS.mdand.claude/AGENTS.mdfrom the working directory upwards loads at startup, and an interactive session shows a line such asno CLAUDE.md found; AGENTS.md loaded: /path/to/AGENTS.md. - A subfolder's
AGENTS.mdloads when Claude opens a file there with Read, provided that folder has none of the threeCLAUDE.mdvariants. @pathimports andclaudeMdExcludesapply, and subagents that skip project instructions skip these too.AGENTS.local.md,AGENTS.override.mdand anything under.agents/are not read.
Choosing which files load
Run /config and set Project instructions:
| Value | Behaviour |
|---|---|
claude-md-or-agents-md | Default. CLAUDE.md files, or AGENTS.md when there is no CLAUDE.md or CLAUDE.local.md |
claude-md-and-agents-md | Both, with each folder's CLAUDE.md files first and AGENTS.md after. An AGENTS.md already loaded via import or symlink is not read twice |
claude-md | CLAUDE.md files only |
managed-only | Only the managed CLAUDE.md and auto memory at launch. Project, local and user CLAUDE.md, .claude/rules/ and all AGENTS.md files are left out, though subfolder CLAUDE.md files, subfolder rules and path-scoped rules still load on demand |
To set it in a file instead, use pluginConfigs with the built-in plugin ID cc-plugin-agents-md@builtin. It is read from ~/.claude/settings.json, a --settings file or managed settings, and ignored in project and local settings:
{
"pluginConfigs": {
"cc-plugin-agents-md@builtin": {
"options": { "instructionFiles": "claude-md" }
}
}
}
Before v2.1.285 the ID was agents-md@builtin; newer versions accept either. Changes apply from your next message.
When AGENTS.md is not available
Claude reads CLAUDE.md only, and Project instructions is missing from /config, if you are on a version before v2.1.277, have disabled the built-in plugin via /plugin, or (sometimes) in the first session after upgrading from v2.1.276 or earlier. Before v2.1.281, some sessions (Bedrock, or with telemetry off) also could not read it. In those cases, import it from a CLAUDE.md.
Differences from CLAUDE.md
CLAUDE.md | AGENTS.md read via the setting | |
|---|---|---|
InstructionsLoaded hooks | Fire | Do not fire (they do for an AGENTS.md reached by import or symlink) |
--add-dir folders with CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD set | Load | Do not load |
External @path imports | Prompt for approval | Load only if external imports were already approved, silently |
Cleaning up old workarounds
- A
CLAUDE.mdcontaining just@AGENTS.mdcan stay; it never causes double loading. Delete it if it adds nothing, unless some sessions cannot readAGENTS.mdnatively. - A
CLAUDE.mdthat merely says "read AGENTS.md" in prose is unreliable, because Claude only sees the file if it decides to open it. Delete it, or replace the sentence with an@AGENTS.mdimport. - A
CLAUDE.mdsymlinked toAGENTS.mdcan stay or go; the content is read once. - A
SessionStarthook that printsAGENTS.mdshould be removed, or Claude gets two copies.
One file for every tool
If you need a CLAUDE.md anyway, import the shared file and add Claude-specific notes underneath:
@AGENTS.md
## Claude Code only
- Use plan mode before touching anything under `infra/terraform/`
A symlink (ln -s AGENTS.md CLAUDE.md) also works if you have nothing Claude-specific, with two caveats: the Edit and Write tools refuse to write through symlinks and will point Claude at AGENTS.md instead, and on Windows symlinks need Administrator rights or Developer Mode and are checked out as plain text files unless core.symlinks is on. If anyone uses Windows, prefer the import. Either way, confirm with /context.
Migrating from other tools
/init reads Cursor rules (.cursor/rules/, .cursorrules) and Copilot instructions (.github/copilot-instructions.md) and folds the useful parts into the new CLAUDE.md. With CLAUDE_CODE_NEW_INIT=1 it also reads AGENTS.md, .devin/rules/, .windsurf/rules/, .windsurfrules and .clinerules.
/import (v2.1.213 or later) brings over another agent's configuration: it appends a one-off copy of instruction files such as AGENTS.md to the matching CLAUDE.md and carries across MCP servers, commands, subagents and skills.
Auto memory
Auto memory lets Claude build up knowledge without you writing anything. It saves four kinds of note, recorded as a type in each file's frontmatter:
| Type | What it captures |
|---|---|
user | Your role, expertise and working preferences |
feedback | Corrections you made and approaches you confirmed |
project | Ongoing work, deadlines and decisions not visible in code or git history |
reference | Where to find things outside the repo, such as a tracker or dashboard |
It deliberately skips things it can derive from the codebase (architecture, file paths, past debugging fixes) and anything your CLAUDE.md already says. It does not save something every session; only what will be useful later.
When you say "remember that the integration tests need the local MinIO container running", Claude saves it to auto memory. If you want it in CLAUDE.md instead, say so ("add this to CLAUDE.md") or edit the file through /memory.
Turning it on and off
Auto memory is on by default for local sessions. Sessions in a self-hosted environment default to off (except Claude Tag sessions).
- Use the toggle in
/memory, which writesautoMemoryEnabledto~/.claude/settings.json. - Disable it for one project by setting
"autoMemoryEnabled": falsein that project's settings. - Disable it everywhere with
CLAUDE_CODE_DISABLE_AUTO_MEMORY=1.
In a background session, or a session launched by another Claude Code session (for instance via its Bash tool), the toggle can turn memory off but not on. It reads off · can't be turned on here; use a session started outside Claude Code. Run claude directly in a terminal to turn it back on.
Where it is stored
Each project has ~/.claude/projects/<project>/memory/. The project key comes from the git repository, so every worktree and subfolder of one repo shares a single memory folder; outside git, the project root is used. Memory is local to your machine and is not synced to other machines or cloud environments.
~/.claude/projects/<project>/memory/
├── MEMORY.md # the index: one line per memory
├── user_role.md
├── feedback_migrations.md
└── reference_dashboards.md
- Set
CLAUDE_CODE_PROJECT_DIR_NAMEalongsideCLAUDE_CONFIG_DIRand that name is used as the project folder for every repo launched with that config directory, so they share one memory (v2.1.234 or later). See sessions. - Set
autoMemoryDirectoryto store memory elsewhere. The value must be absolute or start with~/, and it is read from any settings scope. In project or local settings it is only honoured under the same workspace trust rule as hooks, and whilepermissions.blockReadsOutsideWorkingDirectoriesis on, Claude Code neither loads from nor saves to a directory chosen by a repository-supplied settings file.
The retention sweep that deletes old transcripts never deletes memory files; they stay until you or Claude remove them.
How it is used
At the start of every conversation, the first 200 lines or 25 KB of MEMORY.md (whichever comes first) are loaded. Anything beyond that is not. Topic files are not loaded at startup; Claude opens them with its normal file tools when relevant.
After each write to MEMORY.md, Claude Code checks it against those limits. Near a limit, it nudges Claude to tighten up: one line per entry, details moved to topic files, stale entries merged or dropped. Over a limit, the write succeeds but returns an error telling Claude to rewrite the index, because the overflow would be lost next session.
That limit applies only to MEMORY.md. A CLAUDE.md is loaded in full up to 4 MiB and skipped entirely if larger.
From v2.1.214, whenever Claude writes a memory file that has YAML frontmatter, Claude Code stamps a modified field with an ISO 8601 time so both of you can judge how fresh it is. Files without frontmatter are left alone.
Notices such as "Saved 2 memories" or "Recalled 2 memories" mean Claude is writing to or reading from the memory folder.
Subagents do not receive the main session's auto memory; a fork is the exception because it inherits the parent conversation and system prompt. A subagent's own memory (enabled with its memory field) lives elsewhere.
/memory
/memory lists every instruction and memory file location across user and project scopes, including ones that do not exist yet, so you can create them. It has the auto memory toggle and a shortcut to open the memory folder. Selecting a file opens it in your editor. GUI editors open in a separate window and the session stays usable (from v2.1.216); terminal editors like Vim take over until you quit.
Troubleshooting
Claude is not following CLAUDE.md
CLAUDE.md is delivered as a user message after the system prompt, not inside it, so compliance is likely but not guaranteed. Work through:
- Run
/contextand check Memory files. If your file is not listed, Claude cannot see it. - Remember that subfolder
CLAUDE.mdfiles are not listed there because they load on demand; aLoadedline appears when they do. To test one, create it from your shell (not by asking Claude), then ask Claude to read a file in that folder. - Check the file is in a location that loads for this session.
- Make the instruction more specific.
- Look for contradictions across files.
- Check you are not fighting Claude Code's own guidance. If you define commit or pull request rules, disable the built-in ones with
includeGitInstructionsand set attribution text withattribution(see settings reference).
Anything that must happen at a fixed point (before every commit, after every edit) should be a hook. For system-prompt-level instructions in scripts, use --append-system-prompt at launch (CLI reference).
Tip: An
InstructionsLoadedhook can log which instruction files load, when and why. It is the quickest way to debug path-scoped rules. See the hooks reference.
AGENTS.md is not loading
Usually a CLAUDE.md somewhere on the path is winning. Check, in order:
- Is there a
CLAUDE.md,.claude/CLAUDE.mdorCLAUDE.local.mdin the working directory or a parent (other than~/.claude/CLAUDE.md)? If so, either remove it or set Project instructions toclaude-md-and-agents-md. - Does
claude --versionshow v2.1.277 or later (v2.1.281 or later for Bedrock or telemetry-off sessions)? - In
/config, is Project instructions set toclaude-mdormanaged-only? If the option is missing, your session cannot readAGENTS.md.
Check with /memory, which lists the AGENTS.md path when it loaded (before v2.1.280, neither /memory nor /context showed it; ask Claude what its instructions say instead). As a fallback, import it from a CLAUDE.md.
What did auto memory save?
Open /memory, choose the auto memory folder and read the files. They are plain Markdown; edit or delete anything wrong.
CLAUDE.md is too large
Files over 200 lines produce a warning at startup and in /status; you are also warned when several individually reasonable files add up past a combined limit (each CLAUDE.md, rules file and import counts separately). Files over 4 MiB are skipped. Move narrow guidance into path-scoped rules and trim anything not needed every session. On v2.1.206 or later, /doctor proposes trims for a checked-in CLAUDE.md, removing what Claude can derive from the code (directory listings, dependency lists, architecture summaries) and keeping pitfalls, rationale and non-default conventions.
Instructions vanished after /compact
The root CLAUDE.md is re-read from disk after compaction. If something disappeared, it was only ever said in chat, lives in a nested CLAUDE.md that has not reloaded yet, or is a path-scoped rule that has not matched a file since. Put lasting instructions in CLAUDE.md. Context window lists exactly what survives.