DEV Community

Cover image for How to Structure CLAUDE.md: It's a Loading Policy, Not a Document
John Young
John Young

Posted on • Originally published at jyoung.dev

How to Structure CLAUDE.md: It's a Loading Policy, Not a Document

When a developer filed a bug titled [BUG] Claude Code continually ignores CLAUDE.MD file, Anthropic closed it not-planned and labeled it area:model — bug-tracker shorthand for this is not a defect we can patch (anthropics/claude-code#34197). The report carried its own confession, pasted straight from the session that triggered it:

The rules are clear in the CLAUDE.md and memory files — read them, I know them, and I still violated them.
GitHub: anthropics/claude-code#34197

If the model knows the rules and breaks them anyway, a longer, sterner CLAUDE.md is not the fix. The fix is structural: CLAUDE.md is not a document you fill, it is a loading policy you configure. Most of what goes wrong is content sitting in the wrong tier — billed to every session whether that session needs it or not.


The Three Loading Tiers Claude Code Already Runs

Before you decide what belongs in a CLAUDE.md, look at where it loads — because Claude Code already sorts your instructions into three tiers, and the tier decides the bill.

CLAUDE.md and CLAUDE.local.md files in the directory hierarchy above the working directory are loaded in full at launch. Files in subdirectories load on demand when Claude reads files in those directories.
Claude Code Docs: How Claude remembers your project

That splits your configuration into three tiers with three different costs:

Tier What lives here When it loads Who pays
Always-loaded Root and ancestor CLAUDE.md, @-imports, unscoped .claude/rules/ In full, at launch Every session
Pay-per-read Subdirectory CLAUDE.md, path-scoped rules When Claude reads a matching file Only sessions that touch that code
Pay-per-trigger Skills ~100-token blurb always; body on trigger Only sessions that invoke it

The pay-per-read tier is lazy and file-access-triggered, not a startup scan — Claude Code's creator confirmed as much when he closed a request to make subdirectory loading eager: Claude automatically reads a subdirectory's CLAUDE.md as it works on files in that directory (anthropics/claude-code#4275). The vendor's large-codebases guidance describes the same additive behavior — "root file for the big picture, subdirectory files for local conventions" (Claude by Anthropic: Large codebases). The pay-per-trigger tier is quantified: a skill costs roughly 100 tokens of always-loaded metadata, and its body — under 5k tokens — enters the context window only when the skill fires (Anthropic: Agent Skills overview).

This is context engineering, and Anthropic frames it that way: "Context, therefore, must be treated as a finite resource with diminishing marginal returns," with CLAUDE.md as the part "naively dropped into context up front" while glob and grep retrieve the rest just-in-time (Anthropic: Effective context engineering). The always-loaded tier is exactly that — in context at the start of every session, before you type a word (Claude by Anthropic: Using CLAUDE.md files).

Now take a real file. A developer split a 2,100-line CLAUDE.md into a 150-line core plus five @-imported docs — testing.md (270 lines), typescript.md (305), code-style.md (370), workflow.md (671), and examples.md (278) — the tidy, modular layout every "keep it lean" guide recommends (anthropics/claude-code#11759). Map it onto the table and the tidiness evaporates. @-imports load at launch, so all six files ride the always-loaded tier. The split changed the file browser, not the bill. This corpus recurs in every section below — it already made the naive fix and measured the result.

Verify the Pay-Per-Read Tier on Your Own Surface

The pay-per-read tier is documented design, but it has a reliability caveat — confirm it before you bet directory conventions on it. It has unresolved reports of not firing:


The Over-Specified CLAUDE.md Is a Named Failure Mode

Prune your CLAUDE.md on adherence grounds, not tidiness. Past the file's attention budget, every rule you add subtracts from the ones already there. The rules you actually need to land a change on the first try are the ones that get buried. Anthropic names the pattern directly:

The over-specified CLAUDE.md. If your CLAUDE.md is too long, Claude ignores half of it because important rules get lost in the noise.
Claude Code Docs: Best practices

This is measured, not folklore. IFScale, a benchmark that scales a single prompt from 10 to 500 simultaneous instructions, found that even the best frontier models top out at 68% accuracy once you hit 500 — and their bias toward earlier instructions peaks around 150–200 (arXiv: How Many Instructions Can LLMs Follow at Once?). The instruction ceiling is real and closer than it looks, which is the whole argument of the companion post on the root file's budget.

The mechanism is well-documented and not specific to CLAUDE.md. Chroma's context-rot study across 18 models found performance grows unreliable as input length grows, and that distractors compound:

Even a single distractor reduces performance relative to the baseline (needle only), and adding four distractors compounds this degradation further.
Chroma: Context Rot

It gets worse with position — models are worst at using information stranded in the middle of a long context (Liu et al.: Lost in the Middle) — and worse with sheer length: one study measured accuracy dropping 13.9–85% as input grew, even when the model could perfectly retrieve every relevant fact (Du et al.: Context Length Alone Hurts LLM Performance). A single irrelevant sentence is enough to derail a problem the model solves cleanly without it (Shi et al.: Distracted by Irrelevant Context); on a controlled reasoning benchmark, step accuracy fell from 26% to 2% as distractors climbed from one to fifteen (arXiv: GSM-DC).

One honest caveat keeps this from overreaching. Truly unrelated filler — text with no plausible bearing on the task — mostly costs latency, not accuracy: one study saturated a 70B model with 15,000 words of generic noise and watched accuracy fall only from 98.5% to 98%, while latency rose 719.64% (Ponnusamy et al.: Context Discipline and Performance). The accuracy damage comes from the plausible-but-inapplicable line — the TypeScript convention that looks relevant during a bash task. So the rule is not "delete everything." It is: treat each non-universal line as a suspect, because the ones that read like they might apply are the ones that do the damage.

That is what makes the corpus above worse than a monolith. Its author measured that 85–90% of the loaded content is irrelevant to most conversations (anthropics/claude-code#11759). Most of its per-session tax buys distraction, not guidance — 2,100 lines competing for an attention budget that starts thinning well before 500 instructions.


Why @imports Won't Save You

When a CLAUDE.md gets too long, the reflex is to break it apart with @path imports and call it lean. That reflex is wrong, and it is wrong in a specific, measurable way: splitting the file is organization, not load reduction.

Bad: the 2,100-line file split into a 150-line core with five @docs/*.md imports. Reads modular. Loads identically — all ~2,100 lines enter context at launch, every session. The author who built exactly this split measured the outcome: "the same tokens as a monolithic file, providing organizational benefits only" (anthropics/claude-code#11759).

Good: the same content moved to tiers that actually gate loading. typescript.md becomes a path-scoped rule that loads only when Claude touches .ts files; workflow.md becomes a skill that loads only when invoked. Now a bash-only session pays for none of it.

The documentation states the mechanic plainly, and states it more than once:

Splitting into @path imports helps organization but does not reduce context, since imported files load at launch.
Claude Code Docs: How Claude remembers your project

This matters because the wrong model is actively taught. One popular guide frames @-imports as pure leanness — "Put detailed instructions in separate markdown files, then reference them. Claude pulls in the content when relevant" (Builder.io: How to Write a Good CLAUDE.md). "When relevant" is exactly what imports do not do; they load at launch, relevant or not. Even the guides that state the mechanic correctly — imports "do not reduce context usage" because the "content is expanded inline and still counts against the active window" (Bijit Ghosh: The Complete Guide to CLAUDE.md) — stop at the mechanic and never turn it into a placement rule. That rule is the next section.


Route Every Line by the Sessions That Need It

Here is the fix that actually holds. For every line in your CLAUDE.md, ask one question — which sessions need this? — and let the answer pick the tier. That is Anthropic's own instruction: "If an entry is a multi-step procedure or only matters for one part of the codebase, move it to a skill or a path-scoped rule instead" (Claude Code Docs: How Claude remembers your project).

Content class Route to Loads when
Facts every session needs — build commands, "always do X", critical gotchas Root CLAUDE.md, kept short In full, at launch
Conventions for one file type or directory — a .ts style rule, a package's local rules Path-scoped rule or nested CLAUDE.md Claude reads a matching file
A procedure or occasional reference — a multi-step workflow, a bank of examples A skill Metadata always; body on trigger

The skills row is where the docs are most direct: "CLAUDE.md is loaded every session, so only include things that apply broadly. For domain knowledge or workflows that are only relevant sometimes, use skills instead" (Claude Code Docs: Best practices). Named practitioners land in the same place — a skill "only takes up a few dozen extra tokens, with the full details only loaded in should the user request a task that the skill can help solve" (Simon Willison: Claude Skills). The discipline for the root file is to keep it "concise and universally applicable" (HumanLayer: Skill Issue).

The routing question is therefore not "is this rule good?" but "which sessions should pay for it?"

Run the corpus through it. typescript.md and code-style.md govern specific file types — path-scoped rules matching **/*.ts and your source globs, loaded only when Claude edits those files. testing.md rides along with the test files it describes. workflow.md (671 lines of TDD procedure) and examples.md (278 lines of patterns) are a procedure and a reference bank — skills, bodies loaded only on trigger. Layer boundaries are the natural seams here: what governs one layer routes to that layer's files. What is left of the 150-line core shrinks toward what the root is actually for:

The root file should be pointers and critical gotchas only; everything else drifts into noise.
Claude by Anthropic: Large codebases

That is not an aspiration. HumanLayer's production root CLAUDE.md runs "less than sixty lines," on the rule to "Prefer pointers to copies" (HumanLayer: Writing a good CLAUDE.md).

On-Demand Is Not Free Once It Fires

Routing to a skill is not a free lunch, and pretending otherwise sets a footgun. A skill's body stays out of context until something triggers it — but once it fires, it stays:

When you or Claude invoke a skill, the rendered SKILL.md content enters the conversation as a single message and stays there for the rest of the session.
Claude Code Docs: Extend Claude with skills

So a triggered skill is a recurring cost from that point on, not a one-time read. The routing win is real — a bash-only session never pays for your TDD skill — but budget the skill body as if it will load, because in the sessions that need it, it does, and it lingers.


The Measured Cost of a Wrongly Routed Line

Here is the failure mode people underweight. A rule in the wrong tier is not quietly ignored — it is dutifully obeyed, at a price you can measure. A benchmark of repository context files across multiple coding agents found the compliance itself is the cost: the files "tend to reduce task success rates compared to providing no repository context, while also increasing inference cost by over 20%" (Gloaguen et al.: Evaluating AGENTS.md).

The measured penalty, across SWE-bench Lite and a benchmark of developer-written files (Gloaguen et al.: Evaluating AGENTS.md):

What the study measured Result with a repository context file
Task success / resolution rate Lower than the no-context baseline
Inference cost +20–23%
Extra steps per task +2.45 and +3.92 across the two benchmarks

The mechanism is obedience — "agents generally follow instructions present in the context files" — so a misplaced line is therefore not inert weight; it is an instruction the agent will burn steps satisfying. And the thing most root files try hardest to do — narrate the codebase — is the thing the same study found they fail at. Context files "are not effective at providing a repository overview."

Put the two failure modes together and the corpus's real cost comes into focus. The rules you need get lost in the noise (the over-specified failure), and the rules you don't need get executed anyway (the compliance cost). The 2,100-line always-loaded corpus pays both, every session — including the ones that only touch a bash script — to carry content its own author measured as 85–90% irrelevant. That is pure context burn.

And because it is a per-session cost, it compounds. In an iterative loop that restarts context repeatedly, the misrouted tax is paid on every pass — the recurring-cost problem that breaks playbooks built for one-shot sessions.


A Routing Flowchart for Every Line You Keep

You do not need a quarterly re-prune ritual. You need to run each line you keep through one decision path — and then most of the pruning takes care of itself. Ask these in order:

Is it needed in every session?
→ Root file — but it now competes for the adherence budget that caps out well before 500 instructions. Keep it to pointers and critical gotchas.

Is it needed in one directory or file type?
→ Nested CLAUDE.md or path-scoped rule — the pay-per-read tier. Verify it loads on your surface with /memory first.

Is it a procedure or an occasional reference?
→ Skill — pay-per-trigger. Budget the body anyway; once it fires it sticks for the session.

Do you just want the file shorter?
→ That is organization, not savings. @-imports change nothing — they load at launch.

Can't say which sessions need it?
→ Delete it. Every surviving line binds and bills.

Run the corpus through the gates and it lands where it should have started: a ~150-line root of pointers and gotchas, three path-scoped files next to the code they govern, and two skills that load only when invoked. Same content, a fraction of the per-session tax, and no standing re-prune ritual — Anthropic's own cadence is a configuration review every three to six months, not a weekly file diet (Claude by Anthropic: Large codebases).

You do not have to run this flowchart by hand. I packaged it as a Claude Code skill — agent-engineering-toolkit — that inventories your repo's three tiers, expands every @-import, totals the real always-loaded token cost, and emits the routing report above. It is the audit I ran on my own repos while writing this.

And the skill transfers. The same nearest-file hierarchy is now the cross-tool AGENTS.md convention — "Agents automatically read the nearest file in the directory tree, so the closest one takes precedence and every subproject can ship tailored instructions" (AGENTS.md) — with the same discipline attached: keep the root short and push specifics down the tree (Addy Osmani: AGENTS.md). Route by tier once and the discipline is portable.

The pay-per-read and pay-per-trigger tiers you just routed into are just-in-time retrieval by another name — and just-in-time retrieval has failure modes of its own. That is the next thing worth understanding before you push your whole config into the lazy tiers: where lazy retrieval silently breaks.


References

Research and Data

  1. Chroma: Context Rot — Hong, Troynikov, Huber — Across 18 LLMs, model performance grows unreliable as input length grows, and even one topically-plausible distractor measurably degrades it. Backs the degradation-by-analogy argument.
  2. arXiv: How Many Instructions Can LLMs Follow at Once? — The best frontier models reach only 68% accuracy at 500 simultaneous instructions, with the early-instruction bias peaking around 150–200. Backs the instruction-ceiling claim.
  3. Liu et al.: Lost in the Middle — Models are worst at using information stranded in the middle of a long context. Backs the position-dependence point.
  4. Du et al.: Context Length Alone Hurts LLM Performance — Accuracy drops 13.9–85% as input grows even under perfect retrieval, well within claimed context windows. Backs the length-alone degradation point.
  5. Shi et al.: Distracted by Irrelevant Context — A single irrelevant sentence degrades accuracy on problems the model otherwise solves cleanly. Backs the distraction mechanism.
  6. arXiv: GSM-DC — Reasoning Distracted by Irrelevant Context — GPT-4.1 step accuracy falls from 26% to 2% as distractors climb from one to fifteen. Backs distractor compounding.
  7. Ponnusamy et al.: Context Discipline and Performance — A 70B model held 98% accuracy under 15,000 words of generic filler while latency rose 719.64%. Backs the honest caveat that unrelated filler costs latency, not accuracy.
  8. Gloaguen et al.: Evaluating AGENTS.md — Repository context files reduced task success while raising inference cost over 20%, because agents comply with everything the file says, and are not effective at providing a repository overview. Backs the measured-cost section.

Practitioner Guidance

  1. Claude Code Docs: How Claude remembers your project — Ancestor CLAUDE.md files load in full at launch, subdirectory files load on demand when Claude reads files there, and @imports load at launch without reducing context. The loading-policy spec the whole post routes against.
  2. Claude Code Docs: Best practices for Claude Code — "The over-specified CLAUDE.md" is a named failure: too long and Claude ignores half of it, so route sometimes-relevant content to skills. Backs the prune-on-adherence and routing sections.
  3. Claude by Anthropic: How Claude Code works in large codebases — Root file should be pointers and critical gotchas only, Claude loads files additively as it moves through the codebase, and teams should review configuration every three to six months. Backs the root-scope rule and the cadence.
  4. Anthropic: Effective context engineering for AI agents — Context is a finite resource with diminishing marginal returns; CLAUDE.md is dropped in up front while glob and grep retrieve just-in-time. Backs the finite-budget and hybrid-tier framing.
  5. Anthropic: Agent Skills overview — Progressive disclosure: ~100 tokens of metadata always loaded, the under-5k body only when triggered, resources effectively unlimited. Backs the pay-per-trigger cost model.
  6. Claude Code Docs: Extend Claude with skills — A skill's body loads only when used, but once invoked it stays in context for the rest of the session. Backs the routing rule and the on-demand-is-not-free caveat.
  7. Claude by Anthropic: Using CLAUDE.md files — Every conversation starts with the always-loaded context already in place. Backs the every-session recurring-cost framing.
  8. Builder.io: How to Write a Good CLAUDE.md File — Gopinath — Frames @imports as "Claude pulls in the content when relevant," the naive model the loading docs refute. The SERP foil in the @imports section.
  9. Bijit Ghosh: The Complete Guide to CLAUDE.md — States correctly that imports don't reduce context usage, but never turns the mechanic into a placement rule. The gap the post fills.
  10. Simon Willison: Claude Skills are awesome — Each skill costs a few dozen extra tokens until invoked. Named-author validation of metadata-first loading.
  11. HumanLayer: Writing a good CLAUDE.md — Kyle — HumanLayer's root CLAUDE.md runs under sixty lines on the rule to prefer pointers to copies. Backs the trimmed-root target.
  12. HumanLayer: Skill Issue — Harness Engineering for Coding Agents — Keep CLAUDE.md concise and universally applicable. Backs the route-by-scope rule.
  13. AGENTS.md — Agents read the nearest file in the directory tree, so the closest one takes precedence. Backs the cross-tool generalization.
  14. Addy Osmani: Lesson 16 — AGENTS.md — Agents read the nearest file in the current directory or its parents; aim for 150 lines or fewer. Backs the cross-tool close.
  15. anthropics/claude-code#34197 — "Claude ignores my CLAUDE.md" closed not-planned and labeled area:model, locating the failure in model behavior rather than fixable tooling. The hook.
  16. anthropics/claude-code#4275 — Boris Cherny confirms subdirectory CLAUDE.md files load lazily as Claude works on files there. Backs the pay-per-read tier.
  17. anthropics/claude-code#11759 — A 2,100-line CLAUDE.md split across six @-imported files consumed the same tokens as a monolith, ~85–90% irrelevant to most conversations. The running-thread artifact.
  18. anthropics/claude-code#24987 — Subdirectory CLAUDE.md files reported not loading on the VS Code extension while the CLI works. Backs the verify-your-surface caveat.
  19. anthropics/claude-code#2571 — Subdirectory CLAUDE.md files reported not auto-loading on macOS, closed not-planned. Backs the reliability caveat.
  20. agent-engineering-toolkit: audit-claude-md — This post's routing flowchart as a runnable Claude Code skill: tier inventory, @import expansion, token estimates, and a per-section routing report. MIT-licensed, runs standalone.

Author's Judgment (not directly sourced)

The following framings are my own synthesis. They follow logically from the sourced material above, but no source states them directly:

  • "CLAUDE.md is a loading policy, not a document" — my lens on the mechanics; follows from Anthropic's documented tiers (memory docs), which describe the loading behavior but never frame the file this way.
  • Applying the context-rot and instruction-density literature to CLAUDE.md — Chroma, IFScale, Liu, Du, Shi, GSM-DC, and Ponnusamy never test CLAUDE.md itself; the transfer is my analogy, disclosed in-prose as "not specific to CLAUDE.md."
  • The "quarterly re-prune ritual" the flowchart retires — my characterization of the periodic-review habit; Anthropic recommends a three-to-six-month configuration review but does not frame it as a symptom of wrong routing.

Top comments (0)