The one-sentence version: CLAUDE.md lives in context permanently, so "short and specific" beats "long and comprehensive" by a wide margin; conventions that apply to only some files belong in rules files with paths:, loaded on demand.
Why this lesson comes today
In D1 we saw that every turn of Claude Code's agentic loop starts from the same context, and CLAUDE.md is the fixed, present-in-every-session part of it — loaded at session start and carried on every turn after. D2 then did the math: every line of permanent context keeps costing tokens. Connect the two and you get this lesson's central question: where should this always-present file live, what should it say, and how should it be split once it grows long.
It also paves the way forward: Skills in D7 are the other half — "loaded on demand". CLAUDE.md and rules without paths: sit in context permanently, while skills load only when invoked; telling these two classes apart is the basis of any configuration setup. And Hooks in D8 handle what CLAUDE.md cannot: CLAUDE.md is advice, hooks are enforcement.
Core concepts, explained
What CLAUDE.md is: persistent instructions you write
OfficialEvery Claude Code session starts from a blank context. Two mechanisms carry knowledge across sessions: CLAUDE.md (instructions you write) and auto memory (notes Claude keeps for itself). Both load at the start of every session. This lesson focuses on the former; for auto memory, three facts are enough for now: it is on by default, it lives in ~/.claude/projects/<project>/memory/, and each session loads only the first 200 lines or 25KB of its index, MEMORY.md.
OfficialThe key framing: both kinds of memory are "context", not "enforced configuration". Claude reads them and does its best to follow them, but nothing hard-constrains it — to block an action no matter what, use a PreToolUse hook (expanded in D8). The more specific and concise the instructions, the more reliably they are followed.
Four levels, one concatenation order
OfficialCLAUDE.md can live in four places, scoped from widest to narrowest. At load time they are concatenated into context in that wide-to-narrow order, so project instructions appear after user instructions; the official note on the global CLAUDE.md says the same: both are present, and when instructions conflict, the project level wins.
| Level | Location | Who it serves | In version control? |
|---|---|---|---|
| Managed policy | macOS /Library/Application Support/ClaudeCode/CLAUDE.md (Linux/WSL and Windows have their own paths) | The whole organization, pushed by IT; individuals cannot opt out | Managed by IT |
| User | ~/.claude/CLAUDE.md | You, across all projects | No |
| Project | ./CLAUDE.md or ./.claude/CLAUDE.md | The team, shared with the source | Yes, committed to git |
| Project-local | ./CLAUDE.local.md | You, this project only | No — add it to .gitignore |
Loading rules: everything upward, on demand downward
OfficialAt startup, Claude Code walks from the current working directory all the way up to the filesystem root, loading every CLAUDE.md and CLAUDE.local.md it passes. All files are concatenated into context, never overriding one another: files higher up the directory tree come first, files closer to the working directory come later; within one directory, CLAUDE.local.md comes after CLAUDE.md. Subdirectories work the other way around: a CLAUDE.md below the working directory is not loaded at startup — it is brought in on demand once Claude actually reads a file in that directory.
OfficialA few easily missed details: block-level HTML comments (<!-- … -->) in CLAUDE.md are stripped before injection into context, so they make free human-facing maintenance notes that cost no tokens; a file can pull in other files with the @path/to/import syntax, and imported files are expanded and loaded at startup too (relative paths resolve against the containing file, up to 4 levels of recursion; wrapping the reference in backticks suppresses the import); an import in a project file that points outside the working directory triggers a confirmation dialog the first time. Also, Claude Code reads CLAUDE.md, not AGENTS.md — for repos that already have an AGENTS.md, the official advice is a one-line @AGENTS.md import in CLAUDE.md, or simply a symlink.
What belongs in it, and what doesn't
OfficialThe test is a single question: for every line, ask "if I delete this, will Claude make a mistake because of it?" If not, delete it. The official trade-off table:
| Write this | Not this |
|---|---|
| Build/test/deploy commands Claude cannot guess | Anything inferable from the code (directory layout, dependency lists) |
| Code style rules that differ from the defaults | Universal language conventions (Claude already knows them) |
| How to run tests and the preferred test runner | Detailed API documentation (link to it instead) |
| Repo etiquette: branch naming, PR conventions | Information that changes frequently |
| Project-specific architecture decisions | Long explanations and tutorials |
| Environment quirks (required environment variables) | File-by-file codebase descriptions |
| Common pitfalls and unintuitive behavior | Unverifiable platitudes like "write clean code" |
OfficialSize target: keep a single CLAUDE.md under 200 lines. An overlong file still loads in full, but it crowds the context and lowers compliance. Three writing principles: specific and verifiable ("indent with 2 spaces" beats "format properly"), structured (headings plus lists, not long paragraphs), and conflict-free (when two rules clash, Claude may follow either one). When splitting, note that @import only solves organization — imported files still load at startup and save no context; what actually saves context is the path-scoped rules below.
Rules: split instructions into files, activated per path
OfficialOnce the project grows, split instructions into the .claude/rules/ directory: one .md file per topic (say testing.md, api-design.md); subdirectories are discovered recursively too. Rules without a paths: frontmatter load at startup, with the same precedence as .claude/CLAUDE.md; rules with paths: load only when Claude reads a file matching the glob:
---
paths:
- "src/api/**/*.ts"
---
# API Development Rules
- All API endpoints must include input validation
- Use the standard error response format
OfficialGlobs support multiple patterns and brace expansion (like src/**/*.{ts,tsx}). Personal, universal conventions can go in ~/.claude/rules/, applying to all projects and loading before project rules (project rules win); .claude/rules/ also supports symlinks, handy for sharing one rule set across repos. In a monorepo, if an ancestor directory drags in another team's CLAUDE.md, exclude it by path with the claudeMdExcludes setting (managed-policy files excepted). Note: rules are the same kind of thing as CLAUDE.md — advice Claude reads, not enforced configuration.
The classic misconception: "I wrote it and Claude ignores it"
OfficialThe misconception is treating CLAUDE.md as a config file where writing something guarantees effect. In reality it enters the context as a user message after the system prompt; Claude reads it and tries to follow it, but nothing enforces it. The official troubleshooting order: first run /context and check the Memory files list to confirm the file actually loaded (if it isn't listed, Claude cannot see it at all); then check that the file sits at a level that gets loaded; then make the instructions more specific; finally look for conflicts across multiple files.
Our takeIn practice the most common cause of "wrote it, ignored" is a file that is too long: the important rules drown in noise — the official best-practices doc warns in as many words that a bloated CLAUDE.md makes Claude miss your real instructions. /doctor can suggest trims for a committed CLAUDE.md (needs v2.1.206+). For the full diagnose-and-slim walkthrough, see the tip: Claude ignores your CLAUDE.md — it’s probably too long. And remember the division of labor: anything that must happen at a given moment (like running lint before every commit) should not be a hope written into CLAUDE.md — make it a hook (D8).
Hands-on: doable today
- If the project has no CLAUDE.md yet, run
/initin a session. Expected: Claude analyzes the codebase and generates a CLAUDE.md with build commands, test practices, and project conventions; if one already exists, it proposes improvements rather than overwriting. Skip to the next step if you already have one. - Run
/contextand confirm in the Memory files list that your CLAUDE.md (plus CLAUDE.local.md and rules) actually loaded. Expected: you can see the file list; a file that is missing means it sits at a level that isn't loaded. - Use the prompt below to have Claude audit your CLAUDE.md and slim it against the table above:
Audit this project's CLAUDE.md (and .claude/rules/ if present):
1. List anything Claude could infer from the code itself (directory layout, dependency
lists, architecture overview) and suggest deleting it;
2. List instructions too vague to verify (like "keep the code clean"), each with a
specific, verifiable rewrite;
3. List contradictory or duplicated instructions;
4. For instructions that only apply to certain directories or file types, suggest moving
them into .claude/rules/ with a paths: glob.
Output the audit report first; wait for my confirmation before changing any files.
- Build a path-scoped rule by hand:
mkdir -p .claude/rules, then create.claude/rules/testing.mdwith content like the below (adjust the globs to your project). Then start a new session, run/contextfirst to confirm it is not in the startup load list (rules with paths load on demand), then have Claude read a matching test file and restate the testing conventions currently in effect. Expected: the rule's content shows up in Claude's answer only after it reads a matching file.--- paths: - "**/*.test.ts" - "**/*.test.tsx" --- # Testing Rules - Name tests "should [expected result] when [condition]" - Mock external dependencies, not internal modules - (Optional) Run
/memoryto browse where each level's memory files live, and open the auto memory directory to see what Claude has already noted about this project on its own.
How to know you've learned it
- You can recite CLAUDE.md's four levels and their concatenation order without the diagram, and say which load at startup and which on demand.
- You can name at least three kinds of content that do not belong in CLAUDE.md, and justify it with D2's context costs.
- The project has a CLAUDE.md under 200 lines that passed the step-3 audit, plus at least one rules file with
paths:whose on-demand loading you verified. - Self-test: a monorepo root and the subpackage you own each have a CLAUDE.md, and you start Claude Code in the subpackage directory — which ones load, and in what order? (Answer: both load at startup, root first, subpackage after; a CLAUDE.md in a deeper subdirectory below the subpackage loads on demand only once Claude reads a file in that directory.)