Writing CLAUDE.md: The Memory File That Actually Works
A practical guide to writing CLAUDE.md files that Claude Code actually follows, instead of ignoring after 200 lines of noise.
Who this is for: developers and teams running Claude Code on a real codebase who have noticed their CLAUDE.md file is either ignored, too long to matter, or full of rules nobody remembers writing. If your agent keeps breaking conventions you were sure you documented, the problem is usually the file, not the model.
A CLAUDE.md file is the closest thing Claude Code has to a memory of your project between sessions. Get it right and the agent stops hardcoding text where you use t(), stops touching files outside its lane, and stops re-explaining your folder structure to you every session. Get it wrong - which is most CLAUDE.md files I've seen - and you end up with a 400-line wall of aspirational rules that gets skimmed once and then silently deprioritized once the context window fills with actual code.
What CLAUDE.md actually is (and isn't)
CLAUDE.md is plain markdown that Claude Code loads into context automatically at the start of a session, plus again whenever it's relevant. It is not a config file the tool parses and enforces - there's no schema, no validator, no error if you write nonsense. It's a prompt. Every rule in it is competing for attention with your actual request, your codebase, and whatever else is in context at that moment.
That distinction matters because it changes what "good" looks like. A config file rewards completeness - list every rule, cover every edge case. A prompt rewards precision - the fewer, sharper the rules, the more weight each one carries. Most bad CLAUDE.md files were written like config files.
Claude Code also supports directory-scoped memory: a CLAUDE.md in src/components/ only loads when Claude is working inside that directory, on top of the root one. This is the single most underused feature of the system - see the per-directory section below.
The core problem: token budget, not rule count
Every line in CLAUDE.md is tokens spent before the actual task starts. On a long session, root CLAUDE.md content stays resident while your codebase context churns - it's exactly the kind of standing instruction most vulnerable to being "there but not weighted." I've measured this informally across projects: past roughly 150-200 lines of instructions, compliance on any single rule drops noticeably unless that rule is either very recent in the file or repeated in the task prompt itself.
This isn't a Claude-specific quirk - it's true of GPT-5.x and Gemini 3 as well, covered in ChatGPT vs Claude vs Gemini for business. Long system-level instructions decay in effective weight the further they sit from the live task. The fix isn't a smarter model, it's a shorter file.
Rule of thumb: if your root CLAUDE.md is over 100 lines, at least a third of it is either dead weight (rules from a stack you don't use anymore) or better expressed as a directory-scoped file.
What to include
Write CLAUDE.md as if you're onboarding a contractor who is smart but has zero context and won't ask clarifying questions before touching your code. That framing filters out a lot.
Include
- Commands that aren't obvious from package.json alone - the actual dev/build/test/lint commands, especially if they differ from framework defaults (a custom
npm run verifythat runs typecheck + tests + a smoke script, for instance). - Non-negotiable architectural facts - "this project uses Firebase, not a custom backend", "i18n keys live in he.json first, en.json must mirror it", "state lives in Zustand stores under src/stores, not component state for anything shared."
- Things that look like a good idea but are explicitly banned - "do not add three.js/R3F, it was removed in the 2026-05 rewrite and is not coming back", "do not create new .md report files unless asked."
- Where things live when the folder structure is not self-explanatory - which directory owns i18n copy, where env vars are documented, which script generates the sitemap.
- How to verify a change actually worked - point to a real command or a manual check, not "test your changes" (see eval-driven AI development for why this matters more than most teams think).
Omit
- Restating language/framework defaults. Claude already knows React hooks start with
use, that CSS needs vendor consideration, that SQL injection is bad. A rule like "use semantic HTML" burns tokens telling the model something it does unprompted 95% of the time. - Aspirational rules nobody enforces. If "100% test coverage" isn't actually checked by CI, don't put it in CLAUDE.md - it trains the agent to see the file as decorative, which bleeds credibility onto rules you do care about.
- Anything that changes weekly. Current sprint tasks, today's bug list, this week's deploy target - these belong in a todo file or the task prompt, not in standing memory that has to be re-read every session.
- Long prose explaining why. One line of rationale is fine; a paragraph of justification per rule doubles file length for no compliance gain.
Directory-scoped CLAUDE.md files
This is the feature most teams miss entirely. Claude Code will load a CLAUDE.md sitting in a subdirectory when you're working on files inside it, layered on top of root CLAUDE.md. That means the root file can stay genuinely short - global truths only - while domain-specific rules live where they're relevant.
A real example from a production site:
.claude/rules/components.md -> component conventions (one per file, no side effects, t() only)
.claude/rules/hooks.md -> hook naming, cleanup, 50-line limit
.claude/rules/locales.md -> i18n key structure, he.json-first rule
.claude/rules/styles.md -> CSS variables, logical properties, RTL
.claude/rules/api.md -> validation, rate limiting, error i18n
.claude/rules/pages.md -> per-page SEO/a11y requirements
.claude/rules/public.md -> asset format and size rules
Each file is 5-8 lines. None of them load unless Claude is actually touching a component, a hook, a locale file, or a style. The agent never pays the token cost of the API validation rules while it's editing a Tailwind class, and vice versa. This is the same principle behind good prompt caching - put stable, narrow context exactly where it's needed instead of one giant prefix everyone pays for.
| Approach | Root file size | Rule specificity | Compliance under long sessions |
|---|---|---|---|
| One giant CLAUDE.md | 300+ lines | Generic, has to cover everything | Degrades - later rules get deprioritized |
| Root + directory-scoped | 30-60 lines root | Sharp, contextual per domain | Holds up - each file is small and relevant |
| No CLAUDE.md at all | 0 | None | Consistent only by accident |
Writing memory files that survive contact with reality
Beyond CLAUDE.md, Claude Code can maintain longer-running memory across sessions - project facts, prior decisions, things that were tried and rejected. The failure mode here is different: not bloat, but staleness. A memory note that says "using dark theme" six weeks after the redesign moved to light theme is worse than no note at all, because it actively misleads.
Practical rules for memory files
- Timestamp every entry. "Redesign v9 - light theme (2026-05-28)" tells the reader whether this is still true without them having to check.
- Mark superseded entries explicitly, don't delete them. Keep a one-line pointer ("superseded by v12, see below") so history stays legible instead of silently vanishing.
- Write outcomes, not narration. "User rejected 3 sequential reskins - redesign means new IA, not new theme" is a usable lesson. "Worked on redesign today, discussed options" is not.
- One fact per entry. A memory entry mixing five unrelated facts becomes impossible to supersede cleanly when only one of them changes.
Warning: memory files that just log a chronological diary of every session become a second CLAUDE.md problem - too long to be read carefully, so nothing in them gets weighted correctly. Prune aggressively. If an old entry no longer changes what the agent should do today, it should say "superseded" in one line, not carry its full original detail forward forever.
Common mistakes
- Copy-pasting a CLAUDE.md template from a blog post (including this one) without cutting the parts that don't apply to your stack. A Next.js App Router boilerplate rule doesn't help a Vite SPA - it's just noise that dilutes real rules.
- Writing rules as vague virtues instead of checkable facts. "Write clean, maintainable code" is unenforceable and Claude has no idea what specifically to change. "No component over 200 lines - split it" is checkable.
- Never revisiting the file after the stack changes. If you ripped out three.js and R3F in a rewrite, that needs a line in CLAUDE.md saying so - otherwise the agent may suggest bringing them back the next time 3D comes up, having no memory that this was already tried and reversed.
- Putting security-sensitive or business-sensitive detail in a file the agent will happily quote back into an artifact or a shared conversation. Treat CLAUDE.md like any other file that ends up in context - don't put API keys, internal pricing, or anything you wouldn't want repeated verbatim.
- Confusing CLAUDE.md with documentation. README.md is for humans onboarding to the project; CLAUDE.md is for steering agent behavior on this project specifically. There's overlap but they answer different questions - README explains what the project is, CLAUDE.md constrains how an agent should act inside it.
- One CLAUDE.md trying to serve unrelated agent roles. If you use subagents for specialized tasks - a code-reviewer, a doc-writer - don't try to cram all their rules into one file. Scope rules to where the relevant agent or directory actually operates.
A minimal, real-world root CLAUDE.md
Shorter is a feature, not a compromise. Here's a root file that's dense with actual signal:
# Project: nisai-site
Stack: React + Vite + Tailwind + Firebase Hosting. No backend server - static site + EmailJS for forms.
Domain: nisai.dev, proxied through Cloudflare (cache-bust with ?v= on asset changes).
## Non-negotiables
- All copy through t() - he.json is source of truth, en.json must mirror every key.
- No three.js/R3F - removed in the 2026 rewrite, do not reintroduce.
- Never git push unless explicitly asked.
- Don't create .md report files unless requested.
## Verify before done
Run `npm run build` - if it fails, the change isn't done.
See .claude/rules/*.md for component/hook/style/locale specifics.
Thirteen lines of substance. Everything domain-specific lives in the scoped files. This is the shape to aim for - not because shorter always wins, but because every rule you add past this point should have to earn its place against the ones already there.
FAQ
How long should a CLAUDE.md file be?
There's no hard limit, but compliance measurably degrades past roughly 150-200 lines on the root file, especially for rules buried in the middle. Push domain-specific rules into directory-scoped CLAUDE.md files instead of growing the root file - that keeps the root under 50-100 lines while total documented rules can be much larger.
Does CLAUDE.md get enforced automatically, or can Claude ignore it?
CLAUDE.md is loaded as context, not parsed as a rule engine - there's no built-in enforcement mechanism. Claude follows it because it's instructed to, the same way it follows any other part of a prompt, which means vague or contradictory rules get followed inconsistently. For anything that must be enforced mechanically (lint rules, type checks, CI gates), use actual tooling alongside CLAUDE.md rather than instead of it.
Should CLAUDE.md be committed to git?
Yes, in almost all cases - it's project documentation for how an agent should behave in this codebase, and teammates using Claude Code benefit from the same rules you do. The exception is anything containing secrets or business-sensitive detail, which shouldn't be in there regardless of git status.
What's the difference between CLAUDE.md and memory files?
CLAUDE.md is loaded fresh every session and describes standing rules for the project - conventions, stack facts, things that rarely change. Memory files are more like a running log of decisions, rejections, and context across sessions - "we tried X, user rejected it, here's why." Keep memory entries timestamped and pruned; treat CLAUDE.md as the stable rulebook.
Can I have multiple CLAUDE.md files in one project?
Yes - one at the project root plus additional ones in any subdirectory, and Claude Code loads the directory-scoped file on top of root when working inside that folder. This is the recommended pattern for larger projects: keep root short and universal, push specifics (component rules, API rules, style rules) into .claude/rules/*.md or directory-level files.
Where this fits
A well-written CLAUDE.md pays off most on projects using Claude Code subagents or hooks, since those extend the same standing-context problem across parallel workers. If you're deciding whether Claude Code is the right tool at all for a non-technical team, that's covered separately in Claude Code for business, non-devs. And if the real issue is token cost rather than compliance, see Claude Code token cost control for the budget side of the same coin.
Setting this up properly on a real project - root file, scoped rules, a memory convention that doesn't rot - usually takes an hour once, and saves that much time back within the first week of not re-explaining the same conventions to the agent. If you want a second pair of eyes on your setup, we do a free 30-minute call: reach out through the contact form or on WhatsApp at wa.me/972585802298.