Setting Up a CLAUDE.md File on a Real Full-Stack Repo
Set up Claude Code context files that persist across sessions. Load architecture decisions, conventions, and polyglot rules once—then let AI assistants reference them automatically.
When Claude Code starts a session in a directory, it looks for CLAUDE.md files and loads their contents into context before you type a single prompt. This is different from a one-off prompt because it's:
- Persistent — every session gets it, not just the one where you happened to explain your conventions.
- Versioned — it lives in git, so it evolves with the codebase and PRs can update it.
- Layered — multiple CLAUDE.md files at different directory levels compose together, which matters enormously in a polyglot monorepo.
The mistake most teams make is treating CLAUDE.md as documentation for humans that Claude happens to also read. It's an onboarding packet for an agent with no memory of your last conversation. Write it for that audience — an intelligent engineer who has never seen this repo and gets one shot to absorb your conventions before writing code.
The Memory Hierarchy: Where Files Actually Live
Claude Code resolves CLAUDE.md from multiple locations. Understanding the hierarchy lets you avoid duplicating instructions everywhere.
| Location | Scope | Typical use |
|---|---|---|
/etc/claude-code/CLAUDE.md (platform managed policy path) | Org-wide, enforced by admins | Security policy, compliance rules, banned dependencies |
~/.claude/CLAUDE.md | Personal, applies to every repo | Your own formatting preferences, personal shortcuts |
./CLAUDE.md at repo root | Project-wide, shared via git | Stack, structure, commands, standards — the bulk of what you'll write |
./CLAUDE.local.md | Project-local, gitignored | Machine-specific overrides (local ports, test DB credentials) |
Subdirectory CLAUDE.md (e.g. apps/api/CLAUDE.md) | Scoped to that directory tree | Backend-specific or frontend-specific rules, loaded only for that subtree |
Precedence runs from most specific to least: a subdirectory file can add to or override the root file for work in that tree, and managed policy sits above everything as a hard constraint. In practice, you'll touch ./CLAUDE.md and subdirectory files daily. CLAUDE.local.md is worth setting up early and gitignoring immediately — it's where "my Postgres runs on 5433 not 5432" lives without polluting the shared file.
Auto Memory: Let Claude Write Some of It For You
Newer Claude Code versions support auto memory — Claude can append learnings to memory files as you work. If you tell Claude "no, we use uv not pip in this repo" mid-session, that correction can get captured as a durable memory entry instead of evaporating when the session ends.
Treat auto memory as a first draft. It's useful for capturing subagent-level learnings, but auto-generated entries tend to be verbose. Review them the way you'd review a junior engineer's first pass: keep the signal, cut the narration, fold the useful bit into the permanent file during a deliberate edit rather than letting the file accumulate indefinitely.
The WHAT-WHY-HOW Framework
For the root CLAUDE.md, the most reliable structure is WHAT-WHY-HOW. It maps directly onto the three questions an agent needs answered before touching code.
- WHAT — What is this, in concrete terms? Tech stack, project structure, service boundaries.
- WHY — Why does it work this way? The one or two architectural decisions that would otherwise cause Claude to "fix" something that isn't broken.
- HOW — How do I operate on it? Build commands, test commands, where to run things, workflow conventions.
Here's a working root-level CLAUDE.md for a Next.js frontend + Django/FastAPI backend monorepo:
Notice what's absent: no explanation of what React is, no restating of Django basics, no generic "write clean code" filler. Everything in there prevents a specific, predictable mistake.
Directory-Scoped CLAUDE.md and .claude/rules/
Root-level context is necessarily generic. The moment Claude is actually inside apps/api, it needs backend-specific rules that would be noise in the root file. This is where subdirectory CLAUDE.md files and the .claude/rules/ convention earn their keep — they're loaded on demand, path-scoped to the work being done.
A reasonable split for this repo:
apps/web/CLAUDE.md— component conventions, TanStack Query patterns, Server vs Client Component boundaries.apps/api/CLAUDE.md— Django app structure, FastAPI authentication against Django tokens, migration discipline..claude/rules/database.md— Postgres schema specifics, if that changes independently of general API conventions.
Rule of thumb: if an instruction is only relevant when Claude edits files in a specific subtree, it belongs in that subtree's CLAUDE.md, not the root. This keeps the root file readable and avoids bloating context on unrelated tasks.
The External Docs Pattern
CLAUDE.md should be an entry point, not an encyclopedia. For anything long — full architecture rationale, detailed API contracts, an llms.txt-style index — put it in docs/ and reference it by name rather than inlining it.
This keeps the file that loads on every session small, and lets Claude fetch detail only when a task needs it. If you already maintain human-facing docs, don't duplicate them into CLAUDE.md — point at them.
Why "Less Is More" Isn't a Platitude Here
Instruction-following research on LLMs has found that reliability degrades as the number of simultaneous instructions grows. Accuracy doesn't fall off a cliff — it decays roughly exponentially as instruction count climbs, and the effect is more pronounced on smaller models than frontier ones. A CLAUDE.md with 150+ discrete directives isn't 150+ things Claude will follow; it's a file where a meaningful fraction get silently dropped.
This is the actual mechanism behind "Claude ignored my CLAUDE.md instruction" complaints. It's usually one of:
- Instruction overload — too many directives competing for attention, so lower-priority-looking ones lose out.
- Buried specificity — a critical rule stated once, in passing, inside a long paragraph, with no visual weight.
- Non-universal instructions treated as universal — a rule that only applies to one directory, stated at root level, so Claude applies or ignores it inconsistently.
- Staleness — the file describes an architecture the code no longer has, so Claude correctly infers from the actual code that the instruction is out of date.
The fix for all four is the same discipline: keep root CLAUDE.md under roughly 30–50 lines of actual instruction, push anything directory-specific down into scoped files, and push anything long-form into referenced docs. A short file where every line matters outperforms a comprehensive file where important lines get lost.
AGENTS.md Interoperability
If you work across tools — Claude Code, Cursor, OpenCode, or other agentic harnesses — you've likely encountered AGENTS.md as a competing convention. It's a similar idea but not tied to one vendor, and increasingly targeted by multiple harnesses so a single file can serve several tools.
Claude Code will generally respect an AGENTS.md file if one exists. On multi-tool teams, keep AGENTS.md as the canonical WHAT/WHY/HOW content, and let CLAUDE.md be a thin file that says "see AGENTS.md for project context" plus any Claude-Code-specific behavioral rules. Don't maintain two divergent full copies — they'll silently drift.
Maintenance: When to Actually Update the File
CLAUDE.md rot happens the same way all documentation rot happens: someone changes the architecture and forgets the file describing it. The workflow that keeps it honest:
- Update it during code review. If a PR reviewer corrects an approach Claude took, that's a candidate for a CLAUDE.md entry. Write it down before the context is lost.
- Treat repeated mistakes as a signal. If Claude makes the same wrong assumption twice, that's a missing or buried instruction. Add it explicitly.
- Prune as often as you add. Every new line has a cost against the instruction-count ceiling. If a rule is no longer relevant, delete it in the same PR that removes the code.
The Practical Checklist
For a Next.js + Django/FastAPI repo:
- Root
CLAUDE.mdusing WHAT-WHY-HOW, under ~50 lines. CLAUDE.local.md, gitignored, for machine-specific overrides.- Subdirectory
CLAUDE.mdfiles forapps/webandapps/api, loaded only when relevant. - A
docs/folder holding anything long-form, referenced rather than inlined. - A decision on AGENTS.md if your team uses more than one agentic tool.
- A habit — during review, not as a backlog item — of feeding real corrections back into the file and deleting what's stale.
The file itself takes twenty minutes to write. Keeping it short, accurate, and current is the actual work — and it's the difference between a CLAUDE.md that changes Claude's behavior and one that's technically present but functionally ignored.
FAQ
Does CLAUDE.md work the same way in every Claude Code version? The core mechanism — loading markdown context automatically at session start — has been stable, but specific features like auto memory are newer. Check your installed version's release notes before assuming a feature exists.
Should I commit CLAUDE.local.md?
No. Gitignore it, mirroring how you'd treat a local .env file.
How long should a root CLAUDE.md be? Well under 100 lines of actual instruction; many effective ones sit closer to 30–50. Length isn't the goal — every line should be something that, if removed, would cause a predictable mistake.
What if Claude keeps ignoring a specific instruction no matter where I put it? Check whether it contradicts something the code itself demonstrates. Claude weighs what it observes in actual files alongside what CLAUDE.md claims, and a stale instruction will lose to working code every time. Update the file to match reality first.
Can I use CLAUDE.md and AGENTS.md in the same repo? Yes — many teams do, especially when using more than one agentic tool. Keep one as canonical and have the other reference it rather than maintaining two independent copies.
Damian Hodgkiss
Senior Staff Engineer at Sumo Group, leading development of AppSumo marketplace. Technical solopreneur with 25+ years of experience building SaaS products.