# Claude Code memory: CLAUDE.md, rules and auto memory

URL: https://developertoolkit.ai/en/claude-code/build/memory-system/
Description: Set up CLAUDE.md, path-scoped rules, imports and auto memory in Claude Code, prove each file loads and is obeyed, and keep them short as the repo changes.

Claude Code memory is two mechanisms that carry knowledge between sessions: `CLAUDE.md` files and `.claude/rules/` that people write, and auto memory that Claude writes for itself. All of them load as context, concatenated rather than overriding one another, so they guide Claude but never enforce anything. Anything that must always happen belongs in a hook or a permission rule.

A new teammate asks Claude Code to "add an endpoint for refunds". Claude writes an Express route in JavaScript under `src/routes/`, while your service is Fastify, TypeScript-only, and keeps handlers in `src/api/v2/`. Two weeks later a senior engineer's session gets it right, because their personal `~/.claude/CLAUDE.md` happens to say so, and the team argues about whether "the AI" is reliable. The model is the same in both sessions. The context it was given is not.

This page is for the developer who owns a repository's agent setup and for the tech lead who wants the same behaviour from every session on the team. It assumes Claude Code is installed and has been run once in the repository; if not, start with [project initialization](/en/claude-code/quick-start/project-initialization/).

## What you get from a working Claude Code memory setup

- A map of every file Claude Code loads, when it loads, and who else sees it
- A five-step setup for a new or existing repository, with a prompt that grounds `/init` output in how the repo really works
- A decision table for where each instruction belongs: `CLAUDE.md`, a path-scoped rule, a local file, a skill, a hook, or nowhere
- Four copy-paste prompts: bootstrap, audit, compress, and promote auto memory into `CLAUDE.md`
- A verification routine that proves the files loaded and are obeyed, without reading every diff
- Failure modes with the command that diagnoses each one

## Which memory files does Claude Code load, and when?

Every file below is read as context. None of them overrides another: Claude Code concatenates them, from the broadest scope to the most specific, and within a directory `CLAUDE.local.md` comes after `CLAUDE.md`. When two instructions conflict, Claude may follow either one, so the fix for a conflict is to delete one of them, never to rely on order.

| Scope | Location | Loads | Shared with |
| --- | --- | --- | --- |
| Managed policy | macOS `/Library/Application Support/ClaudeCode/CLAUDE.md`, Linux and WSL `/etc/claude-code/CLAUDE.md`, Windows `C:\Program Files\ClaudeCode\CLAUDE.md`, or the `claudeMd` key in managed settings | At launch; cannot be excluded | Everyone on the machine |
| User | `~/.claude/CLAUDE.md` and `~/.claude/rules/*.md` | At launch | You, in every project |
| Project | `./CLAUDE.md` or `./.claude/CLAUDE.md`, plus any `CLAUDE.md` in directories above the one you launched from | At launch | The team, through git |
| Project rules | `.claude/rules/**/*.md` | At launch, or only when Claude reads a matching file if the rule has `paths` frontmatter | The team, through git |
| Local | `./CLAUDE.local.md` | At launch, right after the `CLAUDE.md` in the same directory | You, in this checkout. Add it to `.gitignore` yourself |
| Subdirectory | `packages/web/CLAUDE.md` and similar, below the launch directory | When Claude reads a file in that directory | The team, through git |
| Auto memory | `~/.claude/projects/<project>/memory/MEMORY.md` plus topic files | First 200 lines or 25 KB of `MEMORY.md` at launch; topic files on demand | You, on this machine, across all worktrees of the repo |

Three details from the [official memory reference](https://code.claude.com/docs/en/memory) change how you write these files:

- **Size.** Anthropic's target is under 200 lines per `CLAUDE.md`. Claude Code loads a file of up to 4 MiB in full and skips a larger one, and warns at startup (and in `/status`) when a file, or all files together, pass the recommended length.
- **Delivery.** `CLAUDE.md` content arrives as a user message after the system prompt. That is the mechanical reason it is advisory.
- **Comments.** Block-level HTML comments (`<!-- note for maintainers -->`) are stripped before injection. Use them for notes to humans that should cost no tokens.

`AGENTS.md` fits into the same table. From v2.1.277, Claude Code reads `AGENTS.md` when there is no `CLAUDE.md`, `.claude/CLAUDE.md` or `CLAUDE.local.md` in the launch directory or above it; sessions on Amazon Bedrock, Google Cloud, Microsoft Foundry, an LLM gateway or with telemetry off need v2.1.281. Both versions are on the `latest` and `stable` release channels since `stable` reached v2.1.287 (checked 2026-10-12); an older build still needs the `@AGENTS.md` import shown below. The **Project instructions** setting in `/config` changes the default, for example to `claude-md-and-agents-md` to read both.

## Where does each instruction belong?

Most memory problems are routing problems: a line in the always-loaded file that only matters for one directory, or a "must" that only a hook can guarantee.

| The instruction is… | Put it in | Why |
| --- | --- | --- |
| A fact every session needs: build, test and lint commands, a non-obvious convention, a decision you did not take the obvious way on | Project `CLAUDE.md` | Loads everywhere, reviewed like code |
| Only relevant to one part of the tree (API handlers, migrations, React components) | `.claude/rules/<topic>.md` with `paths` | Loads only when Claude reads a matching file |
| A multi-step procedure you run sometimes (release, incident triage) | A [skill](/en/claude-code/automate/custom-commands/) | Loads when invoked or judged relevant, not every session |
| Something that must happen every time (format on edit, block `git push --force`) | A [hook](/en/claude-code/automate/hooks-automation/) or a `permissions.deny` rule | Executes regardless of what Claude decides |
| Your own sandbox URL, local port, or test account | `CLAUDE.local.md` | Personal and uncommitted |
| A preference you hold in every repo | `~/.claude/CLAUDE.md` or `~/.claude/rules/` | Follows you, not the project |
| A company-wide policy reminder | Managed `CLAUDE.md` | Every user on the machine, cannot be excluded |
| Architecture summaries, directory maps, dependency lists | Nowhere | Claude derives them from the code, and a written copy goes stale |

The last row is the one teams resist. The cross-tool argument for deleting rather than adding, with a protocol for testing each cut, is in [Pruning CLAUDE.md and AGENTS.md](/en/workflows/context/pruning-context-files/).

## Set up memory for a repository

1. **Generate a draft with `/init`.** Inside a session in the repository root, run `/init`. Claude analyses the codebase and writes a `CLAUDE.md`, or suggests improvements if one already exists. It also folds in Cursor rules (`.cursor/rules/`, `.cursorrules`) and `.github/copilot-instructions.md`. Moving over from another agent wholesale? `/import codex|gemini|cursor` (v2.1.213 and later; Cursor v2.1.265; not available on Amazon Bedrock, Google Cloud's Agent Platform, Microsoft Foundry or Claude Platform on AWS) appends a one-time copy of that agent's instruction files, such as `AGENTS.md`, to the matching `CLAUDE.md` and carries over its MCP servers, commands, subagents and skills; run the audit prompt further down on the result.

   For an interactive flow, set `CLAUDE_CODE_NEW_INIT=1` in your shell or in the `env` block of a settings file before you run `/init`. It then asks which artifacts to create (`CLAUDE.md` files, skills, hooks), explores with a subagent, asks follow-up questions, and shows a proposal before writing. With the variable set, `/init` also reads `AGENTS.md`, `.windsurf/rules/`, `.devin/rules/` and `.clinerules`, and its personal option creates `CLAUDE.local.md` and adds it to `.gitignore`.

2. **Ground the draft in what the repo really does.** `/init` output tends to describe the file tree, which Claude can already see. Replace it with what Claude cannot derive, using the bootstrap prompt below.

3. **Move directory-specific rules out of the root file.** Anything that applies to one area goes into `.claude/rules/` with a `paths` list (see [path-scoped rules](#scope-rules-to-part-of-the-codebase)).

4. **Add your personal layer.** Put machine-specific details in `CLAUDE.local.md` and add `CLAUDE.local.md` to `.gitignore`. If you work across several git worktrees, the local file exists only in the worktree where you created it, so import a home-directory file instead: `@~/.claude/payments-api-personal.md`.

5. **Confirm what loaded.** Run `/context` and check the **Memory files** list. A file missing from that list is invisible to Claude, however good it is.

**Copy-paste prompt: bootstrap a project-grounded CLAUDE.md**

```text
Read package.json (or the equivalent manifest), the scripts it defines, the
README, the CI workflow files and the directory layout, then rewrite CLAUDE.md
for this repo. Keep it under 80 lines. Include only:
- the real build, test, lint and dev commands a contributor runs daily, and
  for each one say when to run it; mark any that are not obvious from the manifest
- conventions you can see the code actually following, with one file path
  as evidence for each (not aspirational rules)
- non-obvious gotchas: env vars required to boot, generated files that must
  not be hand-edited, commands that are destructive
- decisions where we did NOT take the obvious approach, with the reason
Leave out the project description, the architecture summary and any
file-by-file map: you can derive all three from the code, and they go stale.
Do not invent standards we do not follow. Use terse imperative bullets.
Show me the file and wait for my approval before writing it.
```

## What a project CLAUDE.md that earns its lines looks like

This is the result for the refunds scenario above: 27 lines, each one something Claude would otherwise get wrong.

```markdown
# Payments API

<!-- Owner: platform team. Review changes to this file like code. -->

## Commands
- `pnpm dev` starts the API on port 3000; it needs Redis on localhost:6379
- `pnpm test` runs Vitest; run it before you say a change is done
- `pnpm typecheck` is the type gate; CI fails without it
- `pnpm db:migrate` applies Prisma migrations to the local database only
- `pnpm db:reset` DROPS the local database; never run it unless I ask

## Conventions
- Fastify + TypeScript only. No Express, no `.js` source files
- HTTP handlers live in `src/api/v2/<resource>/`, one file per route
- Validate every request and response with the Zod schemas in `src/schemas/`
- Errors are RFC 7807 problem details via `problem()` in `src/lib/errors.ts`
- Log with `logger` from `src/lib/logger.ts`, never `console.log`

## Decisions that look wrong but are deliberate
- Money is an integer number of cents (`amountCents`), never a float,
  because the ledger reconciles to the cent
- We do not use Prisma transactions for refunds; `src/ledger/refund.ts`
  uses an outbox table so the provider call can be retried idempotently

## Never
- Edit a migration file after it is merged; add a new migration
- Add a dependency without asking first
```

Two properties make it work. Every instruction is concrete enough to check ("run `pnpm test` before you say a change is done", not "test your changes"), and every "why" is attached to the rule it justifies, so Claude can apply the rule to a case the file never mentions.

What to leave out matters as much. Emphasis stacks such as `**ALWAYS**`, `MUST` or `IMPORTANT` do not make a rule stick; when a rule is being ignored, the cause is usually length, vagueness or a contradiction elsewhere. A git workflow, PR etiquette or onboarding checklist that already lives in `CONTRIBUTING.md` does not need a second copy: import it, or leave it for Claude to read when a task needs it.

## How do you split a large CLAUDE.md with imports?

`CLAUDE.md` can pull in other files with `@path` syntax anywhere in the text:

```markdown
See @README.md for the product overview and @package.json for scripts.

## Git workflow
- Follow @docs/git-workflow.md
```

Relative paths resolve from the file that contains the import, imports can nest up to four hops deep, and paths inside code spans or fenced blocks are not imported. Imports organise; they do not save context, because every imported file loads at launch. The first time a project imports a file outside the working directory, Claude Code asks you to approve external imports; declining disables them for that project.

If the repository already has an `AGENTS.md` for Codex or other agents, keep it as the single shared file and put Claude-specific additions in a small `CLAUDE.md` next to it:

```markdown
@AGENTS.md

## Claude Code
- Use plan mode for any change under `src/ledger/`
```

The import works on every version and provider, including sessions that cannot read `AGENTS.md` directly. How Codex reads the same file is covered in [AGENTS.md and skills in Codex](/en/codex/build/agents-md-optimization/).

## Scope rules to part of the codebase

A file in `.claude/rules/` without frontmatter loads in every session, with the same priority as `.claude/CLAUDE.md`. Add a `paths` list and it loads only when Claude reads a file that matches:

```markdown
---
paths:
  - "src/api/**/*.ts"
  - "src/schemas/**/*.ts"
---

# API handler rules

- Every handler validates input and output with a Zod schema from `src/schemas/`
- Return `ApiResponse<T>`; never return a raw Prisma model
- Rate-limit public routes with the `rateLimit` plugin registered in `src/app.ts`
```

What the reference documents about rule files, and what trips people up:

- `paths` is the only frontmatter field Claude Code reads (checked against v2.1.283, 2026-09-26). It accepts a YAML list or a comma-separated string, and brace expansion (`src/**/*.{ts,tsx}`).
- If the YAML does not parse, Claude Code ignores the frontmatter and loads the rule everywhere. Run `claude --debug` to see the parse error.
- A rule triggers when Claude reads a matching file, not on every tool call. Until then, it is not in context.
- `.claude/rules/` is searched recursively, so `frontend/` and `backend/` subfolders work.
- For a monorepo where other teams' `CLAUDE.md` files load into your sessions, set `claudeMdExcludes` (a list of globs matched against absolute paths) in `.claude/settings.local.json`. [Claude Code in large codebases](/en/claude-code/build/large-codebase/) covers the full monorepo layout.

## What auto memory saves, and how to keep it honest

Auto memory is on by default. As Claude works, it saves notes of four types (recorded in each file's `type` frontmatter field): `user` (your role and preferences), `feedback` (corrections you give and approaches you confirm), `project` (ongoing work, deadlines and decisions it cannot derive from code or git), and `reference` (where outside information lives, such as a tracker or dashboard). It skips what it can derive from the codebase and what your `CLAUDE.md` already says. "Saved 2 memories" or "Recalled 2 memories" in the interface means it is reading or writing that directory.

`MEMORY.md` is an index, one line per memory. Only its first 200 lines or 25 KB, whichever comes first, load at launch; Claude Code nudges Claude to shorten it near the limit and returns an error when a write pushes it over. Topic files load only when Claude opens them. From v2.1.214, each memory file with frontmatter carries a `modified` timestamp, so you can see how old a fact is.

Three distinctions decide whether auto memory helps or quietly misleads:

- **"Remember X" goes to auto memory, not `CLAUDE.md`.** Saying "remember that the API tests need a local Redis" saves a private note on your machine. To change the team's file, say "add this to CLAUDE.md", or open it with `/memory`.
- **It is machine-local.** Your teammates, your CI runners and your cloud sessions never see it. A correction that matters to everyone has to be promoted into `CLAUDE.md` or a rule.
- **Subagents do not inherit it.** The main conversation's auto memory is not loaded into subagents (a fork is the exception). A subagent can keep its own with the `memory` field; see [custom subagents](/en/claude-code/automate/custom-subagents/).

To turn it off, use the toggle in `/memory` (it writes `autoMemoryEnabled` to your user settings), set `"autoMemoryEnabled": false` in one project's settings, or export `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`.

**Copy-paste prompt: promote auto memory into the team's CLAUDE.md**

```text
List every file in your auto memory directory for this project and read them.
Sort each memory into one of three groups:
1. Team-relevant: a correction or convention that would help anyone working
   in this repo. Propose the exact bullet for CLAUDE.md, or for a rule file in
   .claude/rules/ with the paths it should match.
2. Personal: my preferences or my local setup. Leave it in auto memory.
3. Stale or wrong: contradicted by the current code or CLAUDE.md. Cite the file
   that contradicts it and propose deleting the memory.
Show the three lists and the proposed diff to CLAUDE.md. Do not edit anything
until I approve.
```

## Capture a rule at the moment you correct Claude

The cheapest time to write a rule is right after Claude gets something wrong for the second time, or a code review catches something Claude should have known. Pick the destination by who needs it:

```text
add to CLAUDE.md: we use pnpm, never npm or yarn
remember that my local Postgres runs on port 5433
```

The first line changes the shared file, which then goes through review with the rest of your diff. The second stays in your auto memory. Write the rule as specifically as you would write a prompt: "we use pnpm, never npm or yarn" is checkable, "remember our package manager" is not.

## How do you prove the memory files work?

A memory setup is only as good as its effect on the output, and you should not have to read every diff to know it is working. Check three things, from cheapest to strongest.

**1. The file loaded.** Run `/context` and read **Memory files**. For path-scoped rules and subdirectory files, which load later, log every load with the `InstructionsLoaded` hook. Add this to `.claude/settings.local.json`; it needs `jq`:

```json
{
  "hooks": {
    "InstructionsLoaded": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{file: .file_path, scope: .memory_type, why: .load_reason, via: .trigger_file_path}' >> ~/.claude/instructions-loaded.log"
          }
        ]
      }
    ]
  }
}
```

`load_reason` is `session_start`, `nested_traversal`, `path_glob_match`, `include` or `compact`, and `trigger_file_path` names the file whose read pulled in a lazy load, so the log shows exactly when and why a rule entered the context. The hook is observability only: it cannot block or change loading. It also does not fire for an `AGENTS.md` that Claude reads directly through **Project instructions** (checked against v2.1.283, 2026-09-26); it does fire when a `CLAUDE.md` imports `AGENTS.md`, which is one more reason to keep the import.

**2. The instruction is visible to the model.** A headless probe asks Claude to quote what it was given, which separates a rule Claude never received from one it received and did not follow. Run it in the terminal from the directory whose rules you are testing:

```bash
claude -p "Without reading any files, quote word for word every instruction you were given about database migrations. If there is none, answer NONE."
```

The probe sees only what loads at launch; to test a path-scoped rule, have it first read a file the rule matches (for example `Read prisma/migrations/<latest>/migration.sql, then quote…`).

**3. The behaviour changed.** Keep three representative tasks for the repository (for example: add an endpoint, add a migration, fix a failing test). After a change to memory, run each in a fresh session and let the existing gates judge the result: typecheck, lint, tests, and any hook that enforces a convention. A rule that no gate can check and that the probe cannot quote is a candidate for deletion.

Treat `CLAUDE.md` and `.claude/rules/` as code: changes go through a pull request, the author pastes the probe output and the gate results into the description, and the tech lead who owns the agent setup approves it. Anything a gate already enforces does not need a sentence in memory; anything that must never happen belongs in a hook or permission rule, where it is enforced rather than requested.

## How do you audit and compress a CLAUDE.md that has grown?

Files rot the same way everywhere: rules contradict each other, instructions outlive the code they described, and the file passes the length where Claude follows it reliably. Start a fresh session (`/clear`) so earlier conversation does not bias the review, then run the audit.

**Copy-paste prompt: audit CLAUDE.md for contradictions and rot**

```text
Read @CLAUDE.md and every file in .claude/rules/, and audit them as if you
had to follow every rule literally. Report, as a short list:
1. Direct contradictions, including between CLAUDE.md and a rule file
2. Rules the current code clearly violates, or that point at paths, scripts
   or tools that no longer exist; name the file that proves it
3. Vague directives nobody could check ("write clean code")
4. Content you could derive from the code: directory maps, dependency lists,
   architecture summaries
5. Rules that only matter for one directory and should move to a path-scoped rule
6. Anything that must always happen and should be a hook instead
Do not edit anything. Give me the findings so I can decide.
```

**Copy-paste prompt: compress CLAUDE.md into terse rules**

```text
Rewrite @CLAUDE.md to be as short as possible without losing any rule that
changes your behaviour. Constraints:
- imperative bullets ("Use X", "Never Y"), grouped under a few H2 headings
- merge duplicates; drop anything vague, derivable from the code, or already
  enforced by a lint rule, test or hook
- keep commands, paths, gotchas and the reason behind each non-obvious
  decision verbatim
- target under 100 lines
Output only the new file, then one line listing what you removed and why.
```

The built-in `/doctor` checkup (alias `/checkup`, v2.1.206 and later for this check) proposes the same kind of cut for a checked-in `CLAUDE.md`: it removes what Claude can derive from the codebase, keeps pitfalls, rationale and conventions that differ from tool defaults, and can move always-loaded guidance into skills or nested `CLAUDE.md` files. It reports first and asks before changing anything. After either route, run the three checks above again.

## When Claude Code memory does not behave

**Claude ignores an instruction.** Run `/context` to confirm the file loaded. If it did, look for length, vagueness or a contradiction in another file: two conflicting rules mean Claude may pick either. Make the rule concrete and delete its rival. If the instruction must run at a fixed point, such as before every commit, move it to a hook.

**An instruction disappears after `/compact`.** The project-root `CLAUDE.md` is re-read from disk after compaction. Subdirectory `CLAUDE.md` files and path-scoped rules come back only when Claude next reads a matching file, and instructions you gave only in chat are gone. Put anything you want to survive into a file.

**A path-scoped rule applies everywhere, or nowhere.** Everywhere usually means the frontmatter failed to parse (so the rule loaded unconditionally) or the file has no `paths` at all; run `claude --debug`. Nowhere usually means a glob that does not match, or a `[` in a pattern that is not a valid bracket expression. Test with a plain pattern such as `src/**/*.ts` first.

**`AGENTS.md` is not being read.** Any `CLAUDE.md`, `.claude/CLAUDE.md` or `CLAUDE.local.md` in the launch directory or above it takes precedence, including a local file you created for your own notes. Check `claude --version`: v2.1.277 or later, or v2.1.281 on Bedrock, Google Cloud, Foundry, a gateway or with telemetry off. If **Project instructions** is missing from `/config`, the built-in `agents-md` plugin is disabled or the version is too old, and the first session after an upgrade can still skip the file. The fix that works on every version is a `CLAUDE.md` containing `@AGENTS.md`.

**Your `CLAUDE.local.md` ended up in a commit.** Claude Code does not gitignore it for you (checked against v2.1.283, 2026-09-26; only the `CLAUDE_CODE_NEW_INIT=1` personal option does). Add it to `.gitignore`, remove it from the index with `git rm --cached CLAUDE.local.md`, and move anything secret out of it.

**Teammates get different behaviour from the same repo.** Compare their `/context` **Memory files** lists. User-level files and rules load alongside project files, and a user rule that conflicts with a project rule is followed unpredictably. Ask everyone to keep project conventions out of `~/.claude/`.

**Auto memory holds something wrong.** Run `/memory`, open the auto memory folder, and edit or delete the file. A stale memory is worse than none, because Claude trusts it. If `MEMORY.md` is past 200 lines, entries beyond that point are not loaded at all; ask Claude to consolidate the index.

**A CI or scripted run ignores the project's memory.** `claude --bare` skips `CLAUDE.md` discovery and auto memory by design. For jobs that check out untrusted code, run `claude --bare --setting-sources "" --strict-mcp-config` so that no project instructions, settings, hooks or MCP servers load; for trusted jobs that need the conventions, drop `--bare` or pass the rules explicitly with `--append-system-prompt`. The [CI/CD guide](/en/claude-code/ship/ci-cd/) covers which to use when.

**The file states goals, not facts.** "100% test coverage" in a repo at 40% makes Claude either nag on every change or ignore the rule. Write what is true today and track goals elsewhere.

## Where to go next with Claude Code memory

- [Pruning CLAUDE.md and AGENTS.md](/en/workflows/context/pruning-context-files/): the ablation protocol for deciding which lines to delete, and when to re-run it after a model change
- [Long-term context retention patterns](/en/workflows/context/memory-patterns/): the same ideas across Claude Code, Codex and Cursor
- [Hooks automation](/en/claude-code/automate/hooks-automation/): turn the rules that must never be broken into enforcement
- [Enterprise integration](/en/claude-code/team/enterprise-integration/): deploy a managed `CLAUDE.md` and managed settings across an organisation
- [Cursor project rules](/en/cursor-ide/quick-start/project-rules/): the equivalent mechanism if part of your team works in Cursor
