Skip to content

AI CODING ASSISTANTS

Claude Code Slow: The CLAUDE.md Cause Nobody Checks

A claude code slow session gets blamed on the model. The likelier cause is the one context source Claude Code loads with no size limit at all: your CLAUDE.md.

A claude code slow session usually gets blamed on the model or the network. Check your CLAUDE.md before either of those: it is the only context source Claude Code loads in full, with no size limit, at the start of every session, and re-injects after every /compact. This guide shows how to measure the context floor your project pays before you type a single character, using a script written for this repository, and which fixes actually reduce it. Everything here was measured on Claude Code 2.1.222 against a real 135-line CLAUDE.md.

Key takeaways

  • CLAUDE.md has no truncation limit — Anthropic's documentation states it is "loaded in full regardless of length." Auto memory's MEMORY.md is the file that gets cut, at 200 lines or 25KB.
  • The 200-line guidance is a target you can exceed silently. Nothing warns you, and nothing truncates.
  • Splitting CLAUDE.md into @path imports does not reduce context, because imported files load at launch too. Path-scoped rules in .claude/rules/ do.
  • This repository's measured floor is 6,735 bytes across three sources before any prompt — roughly 1,683 tokens by a 4-chars-per-token estimate.
  • Whether file size hurts adherence is genuinely disputed; the token cost is not disputed at all, so optimise for that.

What actually makes a claude code slow session

Four things plausibly make Claude Code feel slow, and only one of them is worth checking first because only one is free to measure. Most claude slow reports name one of these without having checked which.

  • Model and effort level. A high reasoning effort spends thinking tokens before it answers. Real, but it is a setting you chose.
  • Tool round-trips. Every file read and shell command is another request carrying the whole conversation.
  • Cache misses. The expensive one, covered below.
  • The startup context floor. Everything loaded before you type. This is the one nobody checks, and it is the same cost on every single session.

The floor is where CLAUDE.md lives, and it compounds differently from the others: a slow tool call costs you once, while a bloated context file costs you on every request of every session for as long as the file stays that size. If you have not yet set one up deliberately, how to set up CLAUDE.md covers the structure; this article is only about what it costs you once it exists. For the wider picture of how the CLI assembles a session, see the complete Claude Code guide.

The one context source with no size limit

Here is the asymmetry that makes this worth an article. Claude Code has two persistent memory systems and they behave in opposite ways when they grow.

SourceBehaviour as it growsWarning when exceeded
MEMORY.md (auto memory)Truncated at 200 lines or 25KBYes — an error tells Claude to rewrite the index
CLAUDE.mdLoaded in full, no capNone

Anthropic's memory documentation is explicit about both halves. On auto memory: "The first 200 lines of MEMORY.md, or the first 25KB, whichever comes first, are loaded at the start of every conversation." And immediately after: "This limit applies only to MEMORY.md. CLAUDE.md files are loaded in full regardless of length, though shorter files produce better adherence."

So the file the tool writes for itself is capped and policed. The file you write by hand is uncapped and unpoliced. The widely-quoted "target under 200 lines" is guidance, not enforcement — cross it and nothing at all happens, visibly.

That contested point matters for how you should read the rest of this. The token floor is arithmetic and you can verify it in a minute. The claim that a big file makes Claude dumber is not settled, so this guide does not lean on it. See CLAUDE.md mistakes that slow Claude Code down for the evidence on both sides.

Measure the context floor before you type

/context inside a session lists which memory files loaded, which is the right tool for "did this file load at all." It is not the right tool for "what does this project cost me on every session," because it reports on a session already in progress and does not break the startup floor down by file.

So this repository has a script that does. It walks the files Claude Code loads at launch, applies the documented truncation rules per source, and prints the total:

Terminal
node scripts/check-context-weight.mjs

The interesting part is that the rules differ per source, so the script cannot treat them uniformly:

scripts/check-context-weight.mjs
// Auto memory's index is truncated on load; everything else loads in full.
let loadedChars = content.length;
let truncated = false;
if (opts.truncateAt) {
  const byLine = lines.slice(0, MEMORY_LINE_LIMIT).join("\n");
  const capped = byLine.length > MEMORY_BYTE_LIMIT ? byLine.slice(0, MEMORY_BYTE_LIMIT) : byLine;
  truncated = capped.length < content.length;
  loadedChars = capped.length;
}

It also strips what Claude Code strips. Block-level HTML comments are removed before CLAUDE.md is injected into context, so counting the raw file overstates the cost:

scripts/check-context-weight.mjs
function loadedContent(raw) {
  // Block-level HTML comments are stripped before CLAUDE.md enters context.
  return raw.replace(/^[ \t]*<!--[\s\S]*?-->[ \t]*\r?\n?/gm, "");
}

That detail is a small free win on its own: maintainer notes inside <!-- --> in a CLAUDE.md cost nothing, because they never reach the model.

What the measurement found in this repo

Run against this site's repository, on Claude Code 2.1.222:

Terminal
node scripts/check-context-weight.mjs
# → SOURCE                                      LINES    BYTES  ~TOKENS
# → project CLAUDE.md                             135     6157     1539
# → auto memory MEMORY.md                           1      141       35
# → skill write-article (frontmatter only)          5      437      109
# →   ↳ body 3085 B loads only on /write-article
# → TOTAL (always loaded)                                 6735     1683

Three things in that output are worth reading carefully.

The token column is an estimate and says so. It divides characters by four. That is a heuristic, not a tokeniser, and the script prints a disclaimer under every run for exactly that reason. Bytes and lines are measured; tokens are not. An article that quoted a precise token count here would be inventing precision it does not have.

The skill body is not in the floor. .claude/skills/write-article/SKILL.md is 3,085 bytes of instructions, and only its 437-byte frontmatter counts at startup — the body loads when the skill is invoked. That is the entire architectural argument for moving instructions into skills rather than growing CLAUDE.md, expressed as a number: 437 bytes always, versus 3,522 bytes always if the same content lived in CLAUDE.md.

135 lines is under the target and still dominates. CLAUDE.md is 91% of this project's floor. It is not a bloated file by any standard, and it is still the whole problem, which is what makes "just keep it under 200 lines" weaker advice than it sounds.

For a before-and-after on the same file, this repository's own history has one. Commit 38d964a removed two rules that had gone stale against the code:

Terminal
git show 38d964a^:CLAUDE.md | wc -lc
# → 138    6309
git show 38d964a:CLAUDE.md | wc -lc
# → 135    6199

Three lines and 110 bytes — about 27 estimated tokens per session. On its own that is nothing, and pretending otherwise would be dishonest. The point is the direction of travel: a file that is never trimmed only grows, and the cut that matters is the one that removes a whole section rather than three lines.

Three bugs the script hit first

The measurement was wrong three times before it was right, and each failure is a trap worth naming because two of them fail silently.

The auto-memory directory was never found. Claude Code derives the per-project directory name from the working directory path, and D:\Projects\Devventa becomes D--Projects-Devventa — two dashes, because the drive colon and the separator each become one. The first version collapsed the run:

The bug
const repoSlug = repoRoot.replace(/[:\\/]+/g, "-");  // → D-Projects-Devventa

One dash, no match, no error. The script cheerfully reported a total that omitted auto memory entirely. A missing file and an empty directory look identical to existsSync, so nothing failed.

A one-line file reported as truncated. Stripping the trailing newline for the line count but not for the byte comparison made capped.length < content.length true by exactly one character, so a 141-byte MEMORY.md printed a warning that it exceeded a 25KB limit.

The output leaked an absolute home path. This is the one that mattered, because the script's output was always going to be quoted in an article. The path logic assumed path.relative() returns a .. prefix when a file sits outside the repo — true on a single-volume layout, false on Windows across drives, where it returns a full absolute path instead:

scripts/check-context-weight.mjs
function displayPath(file) {
  const norm = (p) => p.split(path.sep).join("/");
  const inRepo = path.relative(repoRoot, file);
  if (inRepo && !inRepo.startsWith("..") && !path.isAbsolute(inRepo)) return norm(inRepo);
  const inHome = path.relative(homedir(), file);
  if (inHome && !inHome.startsWith("..") && !path.isAbsolute(inHome)) return `~/${norm(inHome)}`;
  return path.basename(file);
}

The isAbsolute check is the fix. The general lesson is narrower than it looks: a measurement script that prints paths is a redaction surface, and on Windows the cross-drive case is the one that catches you.

Why splitting CLAUDE.md does not help

The instinct when a context file gets long is to break it up. Whether that works depends entirely on which mechanism you reach for, and the two obvious ones do opposite things.

  • @path imports do not help. Anthropic's memory docs are unambiguous: imported files "are expanded and loaded into context at launch alongside the CLAUDE.md that references them," and splitting "helps organization but doesn't reduce context, since imported files load at launch." You get tidier files and an identical bill.
  • Path-scoped rules do help. A file in .claude/rules/ with a paths: frontmatter key only enters context when Claude reads a matching file. This is the actual deferral mechanism.
  • Skills help most. A skill contributes its frontmatter at startup and its body only when invoked — the 437-versus-3,085-byte split measured above.
  • HTML comments are free. Block-level <!-- --> comments are stripped before injection.
.claude/rules/mdx-authoring.md
---
paths:
  - "content/**/*.mdx"
---

Write string attributes on every MDX component prop: width="1200", never width={1200}.

Rules like that one load when Claude opens an MDX file and cost nothing on a session spent in lib/. The script reports path-scoped rules separately and excludes them from the always-loaded total, which is the distinction that makes the number honest.

Where the time actually goes

Reducing the floor by a few hundred tokens will not, on its own, make a slow claude session feel fast. Searches for claude code too slow usually come from a session that has been open for hours rather than from a fresh one, and that distinction matters: it is worth being precise about where the time in a long session really goes, because two of the three causes are about context size and one is not.

Cache misses are the expensive event. Claude Code re-sends the conversation with every request and relies on prompt caching to make that affordable. Anthropic's cost documentation states that "your first message after a break longer than the cache lifetime misses the cache and reprocesses your full context," and that the lifetime "is an hour on a subscription and drops to five minutes once you're drawing on usage credits." Every byte in your startup floor is in that reprocessed prefix, and it is reprocessed on each miss.

Compaction re-reads everything. /compact "reads the conversation it summarizes," so compacting a large context is itself a large request. Project-root CLAUDE.md is then re-injected from disk afterwards — a design that keeps your instructions alive across compaction, and also means the file is paid for again.

Long sessions cost more regardless. A one-line question in a session that has been open all day still carries the whole conversation. /clear between unrelated tasks is the highest-leverage habit here and it costs nothing.

Set expectations accordingly. Trimming CLAUDE.md is a real fix for a real cost, and it is a smaller lever than clearing context between tasks. When a claude code slow session is the complaint, do both, and do the free one first.

Best practices for a lean context floor

  • Measure before you cut. Run the script, or at minimum /context, and find out which file is actually the problem. In this repo it was 91% one file, which no amount of guessing would have told you.
  • Move procedures to skills, not to imports. A multi-step workflow belongs in a skill that loads on invocation. An import is a filing decision, not a cost decision.
  • Scope rules by path when they only apply to part of the tree. MDX rules for content/**, database rules for lib/.
  • Delete rather than reorganise. The /doctor checkup, on Claude Code 2.1.206 and later, proposes trims for a checked-in CLAUDE.md and specifically cuts what Claude can derive from the codebase itself — directory layouts, dependency lists, architecture overviews.
  • Keep pitfalls, drop descriptions. The content worth its tokens is what differs from the tool's defaults: the trap, the reason, the convention Claude would otherwise get wrong.
  • Put maintainer notes in HTML comments. They are stripped before injection, so they are genuinely free.

Common mistakes

  • Assuming the 200-line target is enforced. It is not. Nothing truncates CLAUDE.md and nothing warns you. The symptom is a file that has quietly reached 400 lines while you assumed a limit was protecting you. Fix: measure it, on a schedule.
  • Splitting into imports to "reduce context." Tempting because the file gets shorter and the directory looks organised. The symptom is no change at all in token usage. Fix: use path-scoped rules or skills, which actually defer.
  • Trusting a grep to find your config. The mistake made while building the script for this article: a path derived by pattern rather than verified against the filesystem. The symptom is a total that silently omits a source. Fix: assert the file exists and fail loudly when it does not.
  • Quoting token counts as measurements. A chars-per-token heuristic is fine for comparing two versions of the same file and useless as an absolute figure. Fix: label estimates as estimates, and compare bytes when precision matters.
  • Blaming the model first. The cheapest checks are the startup floor and /clear. Both are free and take a minute; changing models is neither.

Conclusion

Treat a claude code slow session as a context question before a configuration one, and spend the first minute there. Run /context, confirm which files loaded, and measure what your project pays before you type — in this repository that floor was 6,735 bytes, 91% of it a single CLAUDE.md that was already inside the recommended size. Then fix it in the order that pays: /clear between unrelated tasks, procedures into skills, path-scoped rules for anything that only applies to part of the tree, and imports for nothing at all. Next, read CLAUDE.md mistakes that slow Claude Code down for what belongs in the file once you have made room.

Frequently asked questions

Does a long CLAUDE.md make Claude Code slower?
It raises the token floor of every session, which is measurable. Whether it degrades response quality is contested: Anthropic's memory documentation states longer files reduce adherence, while a factorial study across 1,650 Claude Code sessions found no detectable adherence effect from file size. Treat the context cost as real and the adherence cost as unproven.
Is there a size limit on CLAUDE.md?
No. Anthropic's documentation states CLAUDE.md files are loaded in full regardless of length. The 200-line figure is a target, not a cap. Auto memory's MEMORY.md is the file that actually gets truncated, at 200 lines or 25KB whichever comes first, with everything past the limit dropped on the next load.
Does splitting CLAUDE.md into imports reduce context?
No. Imported files are expanded and loaded into context at launch alongside the CLAUDE.md that references them, so @path imports help organisation and change nothing about token cost. Path-scoped rules in .claude/rules/ are the mechanism that genuinely defers loading, because they only enter context when Claude reads a matching file.
How do I see what loaded into my session?
Run /context and read the Memory files list. It shows which CLAUDE.md and CLAUDE.local.md files actually loaded, which is the fastest way to catch a file you thought was being read and isn't. For a per-file byte and token breakdown before you start a session, measure the files on disk instead.
Why does a claude slow session get worse the longer it runs?
Claude Code sends the full conversation with every request, so a long session carries more each turn. The sharp edges are cache misses and compaction: a first message after a break longer than the cache lifetime reprocesses the whole context, and /compact reads the conversation it summarises, making it a large request in its own right.

Muhammad Kashif

Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.