DEV Community

astronaut
astronaut

Posted on Edited on

How Claude Code Loads CLAUDE.md and Skills, and How to Use It

In the first article of this series we put four 2026 context-engineering principles on one map. This one covers the first of them: how Claude Code actually loads context, why extra context costs accuracy and not just tokens, and what we did about it on our own systems.

TL;DR.

  1. The root CLAUDE.md is the exception. It enters the context at the start of the session and is included in full in every request.
  2. Skills load only their name and description at first. The body loads when the skill triggers. This is just-in-time context: pointers stay in the window, and the content is pulled in as the work goes.
  3. We applied the same principle to our own files: one routing rule (Task Complexity Levels), and a root file cut from 238 lines to about 80.
  4. On our systems we noticed that the agent started using fewer tokens, especially in cross-service development.

The problem: a monolith in every request

When we started building our own harness and moving development to an agentic SDLC, the first wall we hit was context management inside our services. We have dozens of services, and each one has its own CLAUDE.md. Before we could fix that, we had to understand how Claude works with context in the first place.

A typical root file was about 238 lines long and loaded in full into every request. The agent needs to fix one test in a service, and the context already holds the schemas, configs, and migration notes of every module in that service. If a task touches three services, three of these files end up in the context in full, even though only a small part of each is needed.

On top of that, the agent still did not know which parts mattered for the task, so it rebuilt the picture from scratch: it grepped through message-queue configs, read proto files, and opened go.mod. And we paid for all of that in tokens on every turn.

Extra context costs accuracy, not just tokens

Effect What the research showed Source
Irrelevant content distracts Accuracy drops noticeably when you simply add irrelevant facts to the problem, even on short tasks (GSM-IC) Shi et al., ICML 2023, arXiv:2302.00093
The middle gets lost Models use information from the middle of the context worse than from the start or the end: a U-shaped curve Liu et al., "Lost in the Middle", TACL, arXiv:2307.03172
Length hurts on its own Quality drops by 13.9–85% as input grows, even when all relevant content is retrieved, and even when the extra text is replaced with whitespace arXiv:2510.05381
Frontier models are no exception All 18 tested models degraded, including GPT-4.1, Claude Opus 4, and Gemini 2.5 Chroma, "Context Rot", 2025

Anthropic calls this context rot: a model has a limited "attention budget," and the more tokens sit in the window, the worse it gets at finding what it needs. Hence their principle: keep the smallest possible set of high-signal tokens in context.

A note on scale: one root file will not break a model, and the length effects were measured on contexts of several thousand tokens and up. But an agent's context accumulates: files it has read, grep output, and turn history pile up on top of the monolith. The monolith becomes a layer of noise at the base of every request.


How Claude Code loads context

Claude Code builds its context in layers, and almost every layer loads only when it is actually needed.

The root CLAUDE.md is the exception. It enters the context at the start of the session and is included in full in every request. 238 lines is roughly 1,500 tokens that the model sees on every turn, whatever the task is about.

A CLAUDE.md in a nested directory, such as internal/<subsystem>/CLAUDE.md, loads automatically, but only when the agent starts working with files in that directory. Other documents, such as docs/context/*.md, never load on their own: the agent reads them when the task calls for it.

Skills work the same way, just in three steps. At startup, only each skill's name and description enter the context: tens of tokens, about 100 at most. The SKILL.md body loads when the skill triggers, and nested files load later still, if the body references them.

So everything except the root CLAUDE.md loads on demand. That one exception is exactly where the leverage is.

What loads, and when: almost everything on demand, except the root CLAUDE.md

Just-in-time context

Anthropic calls this behavior just-in-time context: the window holds lightweight identifiers (paths, links, a compact index), and heavy data is pulled in as the work goes.

One important detail: the root map loads upfront, so it is not just-in-time itself. It is the index that makes just-in-time possible: the agent uses it to find module files and docs/context/*. The job of the root file is to be a compact map, not to contain the whole territory.

Skills are ready-made proof that the approach works: Claude Code already keeps only their name and description in the window. Our 238-line CLAUDE.md broke a rule that the tool itself already follows.

One routing level is enough

Progressive disclosure means revealing detail in stages. The finding from arXiv:2607.17598 is narrow and practical: one routing level is enough, and a second one "never helps and sometimes breaks accuracy." So you need one level, not a decision tree.


What we did

We wrote that routing level down as an instruction in the root CLAUDE.md and called it Task Complexity Levels:

Level Task What the agent reads
1 config fix, typo root CLAUDE.md only
2 change in one module root CLAUDE.md + internal/<subsystem>/CLAUDE.md
3 change across several modules, new feature + docs/context/systemPatterns.md
4 grooming a cross-service task + integrations.md, service.yaml, projectBrief.md, productContext.md

The agent picks the level itself. We only wrote down the rule.

Task Complexity Levels: each level adds files on top of the previous one

The file layout: pointers on top, details loaded on demand.

# Loaded into every request, so we keep it compact:
#   root CLAUDE.md = a navigation map (~80 lines), not a manual

<service-root>/
├── CLAUDE.md                 # map + Task Complexity Levels   (POINTERS, upfront)
├── docs/context/
│   ├── service.yaml          # machine-readable index          (DETAILS, on demand)
│   ├── integrations.md       # cross-service links             (DETAILS, level 4)
│   ├── systemPatterns.md     # architecture patterns           (DETAILS, level 3)
│   └── errors.md             # production error catalog        (DETAILS, on incident)
└── internal/<subsystem>/
    └── CLAUDE.md             # module details                  (DETAILS, auto-loaded)
Enter fullscreen mode Exit fullscreen mode

The root file shrank from about 238 lines to about 80. That is roughly 900 fewer tokens in every request, before the agent reads a single detail file.

Before: 1,500 tokens on every turn. After: a ~600-token map plus details only when needed

Third-party benchmarks point the same way: RepoGraph reports an average relative gain of 32.8% in resolve rate across four methods on SWE-bench-Lite (arXiv:2410.14684), and in "Less Context, Better Agents" the share of complete answers rose from 71.0% to 91.6% while tokens dropped by 62.6% (arXiv:2606.10209).

Cline Memory Bank, minus its main rule

We took the file set from Cline Memory Bank (projectBrief, productContext, systemPatterns, techContext), where context is already split by how often it changes. But we dropped its central rule: "I MUST read ALL memory bank files at the start of EVERY task." That rule loads every detail upfront, which is exactly what we were moving away from. Same files, opposite loading strategy.

Tradeoffs

  • A human writes the map. It pays off: in the ETH study, files written by developers beat generated ones (p=0.038), while generated files mostly add cost (arXiv:2602.11988).
  • The agent picks the level. That is a real decision, and the agent can get it wrong, which is why there is only one level and no tree.
  • The map assumes the detail files are up to date. If integrations.md is stale, a level 4 task will rely on wrong data. Keeping files fresh needs its own mechanism, and that is the topic of a later article in this series.
  • The root map still loads every time. The win is not loading nothing. It is an 80-line index instead of a 238-line monolith. If the map grows, the win disappears.

Why fewer tokens does not automatically mean less money is the subject of the next article.


Conclusion

A context file should be an index that triggers just-in-time loading, not cargo that sits in the window all day. The right question is not "how many lines should CLAUDE.md have," but "what belongs in the window on every request (pointers), and what should load on demand (details)." Answer that, and the line count takes care of itself.

Next in the series: how trimming context affects answer quality, and why fewer tokens does not mean a smaller bill.


Sources

  • Anthropic: just-in-time context / effective context engineering (Anthropic Engineering; "Equipping agents with Agent Skills")
  • Progressive disclosure: arXiv:2607.17598 ("Is Progressive Disclosure All You Need for Long-Context Agents?")
  • Repo-map benchmark: RepoGraph (arXiv:2410.14684)
  • Less but more relevant: "Less Context, Better Agents" (arXiv:2606.10209)
  • Hand-written beats generated: "Evaluating AGENTS.md" (arXiv:2602.11988)
  • Irrelevant context distracts: Shi et al., "Large Language Models Can Be Easily Distracted by Irrelevant Context" (ICML 2023, arXiv:2302.00093)
  • Position in context: Liu et al., "Lost in the Middle: How Language Models Use Long Contexts" (TACL, arXiv:2307.03172)
  • Effect of length: "Context Length Alone Hurts LLM Performance Despite Perfect Retrieval" (arXiv:2510.05381)
  • Chroma, "Context Rot: How Increasing Input Tokens Impacts LLM Performance" (research.trychroma.com/context-rot)
  • Anthropic, "Effective context engineering for AI agents" (context rot, attention budget)
  • Cline Memory Bank (Nick Baumann): github.com/cline/prompts

Top comments (7)

Collapse
 
skillselion profile image
Skillselion •

One boundary detail changes how this plays out in a multi-service repo. "Root" here is every CLAUDE.md from the launch directory up, not one file. The memory docs say files in the hierarchy above the working directory load at launch, and only files in subdirectories wait for a read. So a developer who starts Claude Code inside internal/<subsystem>/ gets the service map and the subsystem file both at launch, and every task in that session pays the level 2 context cost upfront.

The second trap is @path imports. The same docs say imports help organize a long file but don't reduce its context cost, because imported files load together with the file that imports them. One @docs/context/systemPatterns.md line in the 80-line map quietly undoes the split.

Did you settle on a rule for which directory the team launches from?

Collapse
 
astronaut27 profile image
astronaut •

Thanks! Good catch, and both points match the docs.

On the launch directory: you're right. "Root" in the article means every CLAUDE.md from the launch directory up, not one specific file. Our rule is to launch from the service root. That way only the map loads at startup, and module files load on demand.

Collapse
 
alex_ml_ai profile image
Alex •

Adding to the @imports point, since it bit us too. The fix is simple: in the map, list detail files as plain paths (in backticks if you like), never as @path. Then they stay pointers and the agent opens them only when the task needs them. One stray @ and that file is back in every request.

Collapse
 
lena_lis_94cbd1623ba281af profile image
Lena Lis •

Great article, really on point. We’re currently building agentic development in our company, and everything about the monolithic CLAUDE.md and just-in-time context hits home.

Especially liked how Skills already do it the right way (just name + description), while we were loading 238 lines into every request. Cutting it down to ~80 lines + a single routing level is a solid approach.

One small wish: would love to see more before/after examples of actual agent answer quality, not just token savings. Otherwise — very useful, thanks.

Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

Nice framing, treating the root file as a map instead of a manual. How strict are you about keeping that 80-line map from creeping back up over time?

Collapse
 
astronaut27 profile image
astronaut •

Thanks! Honestly, there's no hard limit yet, just one rule for every new line: does every task need it? If not, it goes into docs/context/ or a module CLAUDE.md, and the map only gets a pointer to it. The map grows when the service gets new areas, not when someone adds detail. Keeping the detail files fresh is the harder part, and that's a later article in the series.

Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

That pointer-only rule is a clean way to keep the map short, and the detail files staying fresh sounds like the harder part to watch.