Mental Model
CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself. Claude actively judges whether instructions are relevant and may deprioritize them. They are advisory, not enforced configuration. Every design decision in your CLAUDE.md should account for this.
The Load Order
Claude Code uses a layered discovery system with five scopes, loaded in a specific order. Each layer consumes tokens before you type a single character.
| Order | Component | Approx. Tokens | Notes |
|---|---|---|---|
| 1 | System prompt | ~4,200 | Core behavior, tool definitions. Identical for all users (enables prompt caching). |
| 2 | Auto memory (MEMORY.md) | ~680 | First 200 lines or 25KB. Claude's self-written notes from previous sessions. |
| 3 | Environment info | ~280 | Working directory, platform, shell, OS version, git status. |
| 4 | MCP tools (deferred) | ~120 | Tool names only. Full schemas load on demand. |
| 5 | Skill descriptions | ~450 | One-line descriptions. The only startup component that does NOT survive compaction. |
| 6 | ~/.claude/CLAUDE.md (User) | ~320 | Global preferences across all projects. |
| 7 | Project CLAUDE.md | ~1,800 | ./CLAUDE.md or ./.claude/CLAUDE.md. The most impactful file you control. |
| 8 | CLAUDE.local.md | varies | Personal project-specific overrides. Appended after CLAUDE.md at the same directory level. |
Total startup overhead before your first prompt: ~7,850 tokens minimum. A bloated CLAUDE.md pushes this past 15,000.
The Five Scopes
Every CLAUDE.md file belongs to exactly one scope. Understanding where each scope lives determines who it affects and whether it can be excluded.
| Scope | Location | Who It Affects | Excludable? |
|---|---|---|---|
| Managed policy | OS-specific system path | All users on the machine | No — cannot be excluded by any setting |
| User | ~/.claude/CLAUDE.md | You, across all projects | ✓ Yes |
| Project | ./CLAUDE.md or ./.claude/CLAUDE.md | Team members via source control | ✓ Yes |
| Local | ./CLAUDE.local.md | You, in this repository only (gitignored) | ✓ Yes |
| Subdirectory | ./src/CLAUDE.md, ./packages/api/CLAUDE.md | Loaded on demand when Claude reads files in that directory | Yes, via claudeMdExcludes |
The managed policy scope exists for enterprise deployments. On macOS it lives at /Library/Application Support/ClaudeCode/CLAUDE.md, on Linux/WSL at /etc/claude-code/CLAUDE.md, on Windows at C:\Program Files\ClaudeCode\CLAUDE.md. No setting can override it.
The five scopes create a layered filesystem structure:
/etc/claude-code/CLAUDE.md # Managed policy (Linux/WSL)
~/.claude/CLAUDE.md # User scope
~/projects/my-app/
├── CLAUDE.md # Project scope (committed)
├── CLAUDE.local.md # Local scope (gitignored)
├── src/
│ ├── api/
│ │ └── CLAUDE.md # Subdirectory scope (lazy loaded)
│ └── web/
│ └── CLAUDE.md # Subdirectory scope (lazy loaded)
└── .claude/
└── settings.local.json # Exclude subdirectory filesTo exclude subdirectory CLAUDE.md files you do not need, add claudeMdExcludes to your local settings:
{
"claudeMdExcludes": [
"**/packages/ios-app/CLAUDE.md",
"**/packages/legacy-service/**"
]
}Directory Walking
Two distinct loading behaviors govern when subdirectory instructions enter context.
Ancestor loading (immediate): When Claude Code starts in foo/bar/, it walks upward — loading foo/bar/CLAUDE.md, then foo/CLAUDE.md, and any CLAUDE.local.md alongside each, all the way to the filesystem root.
Descendant loading (lazy): CLAUDE.md files in subdirectories below your working directory are NOT loaded at startup. They load on demand when Claude reads or edits files in those subdirectories.
Sibling isolation: If your cwd is frontend/, CLAUDE.md files in backend/ never load. They are neither ancestors nor descendants. This isolation is a feature — it prevents cross-contamination in monorepos.
Precedence and Conflict Resolution
All discovered CLAUDE.md files are concatenated into context. There is no explicit override mechanism. When instructions conflict, three factors determine what Claude follows:
- Recency bias. Files loaded later take precedence. Within each directory,
CLAUDE.local.mdis appended afterCLAUDE.md, giving personal notes last-word advantage at that level. - Specificity wins in practice. Subdirectory-level instructions tend to override project-root instructions because they load later in the conversation.
- Genuine conflicts resolve arbitrarily. If two files give contradictory guidance for the same behavior, Claude may follow either one. There is no deterministic resolution — only probabilistic tendencies.
This means your CLAUDE.md architecture should avoid conflicts entirely rather than relying on precedence to resolve them.
Context Window Positioning
CLAUDE.md content is injected as a user message positioned between the system prompt and your first conversational message. Two implications:
- The system prompt always has higher priority — it appears first and you cannot modify it via CLAUDE.md.
- Your conversational messages appear after CLAUDE.md content, so recent conversation can override CLAUDE.md instructions through recency bias.
To elevate instructions to system prompt level, use the --append-system-prompt CLI flag. This must be passed every invocation, making it suited for CI/CD scripts rather than interactive use.
claude --append-system-prompt "CRITICAL: All output must use JSON format. Never include explanatory text outside JSON."What Survives Compaction
Compaction is where most instruction architectures break down. Understanding what persists and what disappears determines how reliable your setup is across long sessions.
| Component | After /compact | After /clear |
|---|---|---|
| Project-root CLAUDE.md | Re-read from disk, re-injected | Full reload from disk |
| Nested CLAUDE.md files | NOT re-injected; reloads lazily when Claude touches those directories again | Full reload |
| Skill descriptions | NOT re-injected (only invoked skills survive) | Full reload |
| Auto memory | Re-read from disk | Full reload |
| Conversation context | Summarized | Cleared |
The project-root CLAUDE.md is the only instruction file guaranteed to survive compaction automatically. Design your most critical rules to live there, not in subdirectory files or skills.
When CLAUDE.md Is Re-Read
- Session start: All ancestor files and CLAUDE.local.md files load immediately.
- During session: Subdirectory files load lazily when Claude touches files in those directories.
- After
/compact: Project-root re-injects from disk. Nested files reload on next directory access. - After
/clear: Everything reloads fresh. - External edits during session: The
InstructionsLoadedhook fires and Claude picks up changes. TheConfigChangehook can track these changes separately. - HTML comments: Block-level HTML comments (
<!-- notes -->) are stripped before injection. Use them for human-only notes at zero token cost.
# Build & Test
- `pnpm test` runs vitest
<!-- TODO: add integration test command after CI migration is complete -->
<!-- Last reviewed: 2026-03-15 by @dakota -->
## Architecture
- Express API in src/api/The two comment lines above cost zero tokens at runtime but keep maintenance notes visible when editing the file.
Token Budget Math
With a 200K context window (standard models) or 1M (Opus 4.6/Sonnet 4.6):
- A 200-line CLAUDE.md costs roughly 2,000-4,000 tokens
- A CLAUDE.md that
@importsREADME.md, package.json, and three doc files can hit 10,000+ tokens - Startup overhead plus a bloated CLAUDE.md means 15-20% of a 200K context gone before you type anything
- Performance degrades at 20-40% context fill, well before any hard limit
- Manual compaction is recommended when context reaches ~50%
Frontier models follow roughly 150-200 instructions before compliance drops. Claude Code's system prompt consumes ~50 of those slots, leaving ~100-150 for your rules. Every vague or redundant instruction in your CLAUDE.md wastes one of those slots.
The Instruction Attention Budget
Think of your CLAUDE.md as having an attention budget, not just a token budget. Claude can hold ~100-150 instructions from your CLAUDE.md reliably. Each instruction competes for the same finite attention window.
High-attention instructions: Concrete, verifiable, unfamiliar to Claude. "Run pnpm test -- --run for unit tests" takes one slot and is followed consistently.
Low-attention instructions: Vague, obvious, or matching Claude's defaults. "Write clean code" wastes a slot and teaches nothing.
Negative-attention instructions: Contradictory or negation-based rules actively confuse the model. "Do NOT use semicolons" forces Claude to process the concept then negate it — error-prone by design.
The priority positioning technique exploits this: place rules Claude violates most often at the very top (first 5 lines) and the very bottom (last 5 lines) of your CLAUDE.md. Put less critical rules in the middle. This leverages both primacy and recency bias in LLM attention.
Emphasis Escalation
Claude Code officially acknowledges that emphasis markers improve adherence:
IMPORTANT: Always use pnpm, never npm or yarn.
YOU MUST run tests before committing.
CRITICAL: Never modify files in src/generated/Use this sparingly. If every instruction is marked IMPORTANT, the emphasis loses its signal. Reserve it for the 3-5 rules that cause the most damage when violated.
Positive Framing Over Negation
Language models process negation unreliably. The model reads the concept first, then applies the negation — and sometimes drops the negation.
| Instead of | Write |
|---|---|
| "Do NOT use semicolons" | "Omit semicolons in JavaScript files" |
| "Don't import from src/internal" | "Import only from src/public API surfaces" |
| "Never commit directly to main" | "All changes go through feature branches" |
Every negation-based instruction in your CLAUDE.md is a probabilistic failure point. Reframe as positive directives wherever possible.
Practical Implications
Three facts shape every CLAUDE.md decision:
- CLAUDE.md is advisory, not enforced. If a rule must be followed 100% of the time, use a hook instead. CLAUDE.md is for guidance; hooks are for guarantees.
- Token cost is paid on every session. A 200-line CLAUDE.md costs 2,000-4,000 tokens whether you need those instructions or not. Move rarely-needed content to skills.
- Compaction is the reliability boundary. Only the project-root CLAUDE.md survives compaction automatically. Everything else requires re-loading or re-injection via hooks.
Design your instruction architecture around these constraints, not against them.