What it is
Every Claude Code session begins with a fresh context window. Nothing carries over on its own - not the fact that this repo uses pnpm, not the naming convention you corrected twice yesterday. CLAUDE.md is a plain markdown file you write, and Claude reads it at the start of every session. That is the whole mechanism.
It is not configuration and it is not code. There is no schema to satisfy, no keys to get right. You write sentences a new teammate would find useful, Claude gets them as context before you type your first prompt, and the session starts informed instead of blank.
The word "context" is doing real work there. CLAUDE.md shapes behavior; it does not enforce it. Claude reads the file and tries to follow it, the same way a colleague follows a style guide - reliably when the guidance is specific, less so when it is vague or contradicts itself. If something must happen every time regardless of what the model decides, that is a job for a hook, not a memory file. This is the single most useful thing to understand about CLAUDE.md, and the reason most complaints about it are really complaints about how it was written.
What belongs in it
The simplest test: CLAUDE.md is where you write down what you would otherwise re-explain. Four moments are the signal to add a line.
The same mistake twice
Once is a miss. Twice is missing context - write the rule down instead of correcting it again.
A review catches something
If a code review flags something Claude should have known about this codebase, that knowledge belongs in the file.
You retype a correction
Any clarification you typed last session and typed again today is a CLAUDE.md line waiting to be written.
A teammate would need it
If a new engineer needs the same context to be productive, so does Claude. Same file, same purpose.
What stays out matters just as much. Keep it to facts that hold in every session: build and test commands, conventions, project layout, "always do X" rules. If an entry is a multi-step procedure, it is a skill. If it only matters for one corner of the codebase, it is a path-scoped rule (section 08). Everything you leave out is context budget you keep for the actual work.
Where the files live
CLAUDE.md is not one file in one place. There are four scopes, listed here from broadest to most specific - which is also the order they land in context, so the more specific instruction is read last.
The whole organization
Deployed by IT to a fixed system path, for company standards and compliance rules. Applies to every session on the machine and cannot be excluded by individual settings.
Just you, everywhere
~/.claude/CLAUDE.md - personal preferences that travel with you across every project on your machine.
The team, via git
./CLAUDE.md or ./.claude/CLAUDE.md - architecture, standards, workflows. Committed, so everyone gets the same context.
You, in this repo
./CLAUDE.local.md - your sandbox URLs and test data. Add it to .gitignore so it stays yours.
The project file is the one that matters most, because it is the one under version control. Personal preferences go up a level to the user file; anything you would be embarrassed to commit goes in the local file.
How they load
Claude Code walks up the directory tree from wherever you launched it, collecting CLAUDE.md and CLAUDE.local.md from every directory on the way. Start in foo/bar/ and it loads foo/bar/CLAUDE.md, foo/CLAUDE.md, and the local files beside them.
Two properties of that walk are worth holding on to:
- Files are concatenated, not overridden. A nested file does not replace its parent - every discovered file contributes. Content is ordered from the filesystem root down to your working directory, so the instructions closest to where you launched are read last, and within a directory
CLAUDE.local.mdcomes afterCLAUDE.md. - Subdirectories load on demand. A CLAUDE.md below your working directory is not read at launch. It arrives when Claude actually reads a file in that directory - which is what makes per-package files in a monorepo affordable.
One small convenience: block-level HTML comments are stripped before the file reaches Claude, so notes for human maintainers cost nothing in context.
The cascade, and how it differs from .gitignore
It looks like .gitignore: one file per directory, the deeper ones closer to the work. It does not behave like it. Here is a monorepo, with Claude Code launched from apps/web/:
Four files, stitched together in that order. So far, so much like git. The difference shows up the moment two of them disagree:
The deeper file wins
Result: debug.log is tracked. Git resolves the two rules into one final answer, and the answer is enforced.
Both lines stay
Result: Claude is told both. The second line does not cancel the first, it just comes after it - and Claude may follow either one.
Two things follow from that, and they are the whole difference:
- Deeper does not mean stronger. Being read last is not the same as winning. There is no precedence rule to lean on, so a nested file cannot quietly correct the one above it.
- Nothing can be un-said. CLAUDE.md has no equivalent of
!. The only way to remove an instruction is to delete it from the file it lives in.
Which makes the maintenance rule simple: write each rule once, in the file that owns it, and delete the copy that contradicts it. Three things help when the tree gets big:
- Skip files you do not want.
claudeMdExcludesin your settings takes glob patterns and drops matching files - handy when another team's root CLAUDE.md keeps getting picked up. Managed-policy files are the one exception and always load. - Scope by path instead of by folder. A rule in
.claude/rules/with apathsfield (section 08) loads only when Claude opens a matching file, so it costs nothing the rest of the time. - Extra directories stay quiet. Folders you add with
--add-dircontribute no CLAUDE.md unless you setCLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1.
One thing to watch in long sessions. When the context window fills up, /compact replaces the conversation so far with a summary of it. Memory files are not part of that summary, so what comes back afterwards is worth knowing:
- The project-root CLAUDE.md comes back in full. Claude Code re-reads it from disk and re-injects it, which also means an edit you made mid-session takes effect from that moment on.
- Nested files do not. A CLAUDE.md in a subdirectory is not re-injected. It returns the next time Claude reads a file in that directory, the same on-demand behavior as the first load, and the same for path-scoped rules.
- Anything you only said in chat is gone unless the summary happened to keep it. Instructions that must outlive a compaction belong in the file, not in the conversation.
That explains the classic monorepo symptom: a package-level rule that held for an hour quietly stops applying, usually right after a long stretch of work. Nothing broke - the nested file simply has not been re-read yet. Open any file in that directory, or restate the rule, and it is back.
A worked example
A good project file is short, structured, and specific enough to check. This one is about as long as most should get:
Notice what is absent: no description of what the service does, no dependency list, no directory tree dump. Claude can read the codebase for those. The file carries what the codebase does not say out loud - the pitfalls, the "we decided this on purpose," the conventions that differ from the tool defaults.
Imports with @path
A CLAUDE.md can pull in other files with @path/to/file syntax. Imports are expanded and loaded at launch alongside the file that references them, relative paths resolve against the importing file, and an imported file can import further files up to four hops deep.
Two details save time later. To mention a path without importing it, wrap it in backticks - import parsing skips code spans and fenced blocks. And an import that resolves outside the working directory, like the home-directory line above, is treated as external: the first time Claude Code sees one in a project it asks for approval, because someone else may have committed it.
Imports organize; they do not shrink. Every imported file still enters the context window at launch, so splitting a 400-line file into four 100-line files buys readability, not budget.
This is also the clean answer to AGENTS.md. Claude Code reads CLAUDE.md, not AGENTS.md, so a repo that already keeps instructions there can add a two-line CLAUDE.md that imports it and appends anything Claude-specific:
Splitting into rules
When a project outgrows one file, instructions move into .claude/rules/ - one markdown file per topic, discovered recursively, loaded with the same priority as the project CLAUDE.md.
The reason to bother is the paths frontmatter. A rule that declares which files it governs only enters context when Claude reads a matching file, which is the one honest way to cut what every session pays for:
A rule with no paths field loads unconditionally. Personal rules live in ~/.claude/rules/ and apply to every project, loaded before project rules so the project keeps the higher priority.
CLAUDE.md vs auto memory
Claude Code carries knowledge across sessions two ways, and they are easy to confuse. The difference is simply who does the writing.
Instructions and rules
- Coding standards, workflows, architecture
- Scoped to a project, a user, or an org
- Committed and shared with the team
- Loaded in full, every session
Learnings and patterns
- Build commands and debugging insights it picks up
- One directory per repository, machine-local
- Plain markdown you can read, edit, or delete
- Index file loaded to a 200-line cap
Auto memory is on by default and needs nothing from you: Claude decides a detail is worth keeping and writes it to a MEMORY.md index under ~/.claude/projects/, with longer notes in topic files it reads on demand. Only the first 200 lines (or 25KB) of that index load at session start, which is why Claude keeps it terse.
Use CLAUDE.md to direct behavior, and let auto memory learn from your corrections. When you tell Claude to remember something mid-session, it goes to auto memory by default - say "add this to CLAUDE.md" when you want it committed and shared instead.
Writing rules that stick
Because the file is context rather than enforcement, how you write it changes how reliably it is followed. Four things carry most of the weight:
- Size. Target under 200 lines. Longer files eat context and lower adherence - and a rule that gets diluted is a rule that gets skipped.
- Structure. Headers and bullets, not paragraphs. Claude scans structure the way a reader does.
- Specificity. "Use 2-space indentation" beats "format code properly." "Run
npm testbefore committing" beats "test your changes." Write rules concrete enough that you could verify them. - Consistency. Review the whole set periodically and delete what is stale. Two rules that disagree are worse than neither.
When something is still being ignored, run /context and look under Memory files: if your file is not listed, Claude never saw it, and no amount of rewording will help. If it is listed and still ignored, the instruction is usually too vague, or another file in the tree contradicts it.
Getting started
Three commands cover the whole lifecycle:
Start with /init: Claude reads the codebase and writes a first file with the build commands, test instructions, and conventions it can discover on its own. If a CLAUDE.md already exists, it suggests improvements rather than overwriting. Then do the part it cannot do - add the decisions, the pitfalls, and the reasons that live only in your team's heads.
After that, treat it like any other file in the repo. Edit it when a rule changes, delete lines that stopped being true, and add one every time you catch yourself explaining the same thing twice.