DH
10 min read

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.

aiautomationtypescript

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.

LocationScopeTypical use
/etc/claude-code/CLAUDE.md (platform managed policy path)Org-wide, enforced by adminsSecurity policy, compliance rules, banned dependencies
~/.claude/CLAUDE.mdPersonal, applies to every repoYour own formatting preferences, personal shortcuts
./CLAUDE.md at repo rootProject-wide, shared via gitStack, structure, commands, standards — the bulk of what you'll write
./CLAUDE.local.mdProject-local, gitignoredMachine-specific overrides (local ports, test DB credentials)
Subdirectory CLAUDE.md (e.g. apps/api/CLAUDE.md)Scoped to that directory treeBackend-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:

# CLAUDE.md

## WHAT
Monorepo: two apps:
- `apps/web` — Next.js 14 (App Router), TanStack Query, Tailwind. Deployed to Cloudflare Pages.
- `apps/api` — Django (auth, billing, admin) + a separate FastAPI service
(`apps/api/realtime`) for websocket/streaming. Postgres via Neon.

Package managers: `pnpm` for JS, `uv` for Python. Do not use npm or pip directly.

## WHY
- Django and FastAPI are split because Django's ORM/admin/auth stack is worth keeping,
but its async story is weak for streaming endpoints. They share one Postgres instance,
not two databases.
- TanStack Query owns all server state. Local component state only for UI-only concerns.
Don't introduce a global store.
- API responses use snake_case; the web app converts at the fetch boundary
(`apps/web/lib/api-client.ts`). Don't "fix" casing in components.

## HOW
- Install: `pnpm install` at root, `uv sync` in `apps/api`.
- Dev: `pnpm dev` (web), `uv run manage.py runserver` + `uv run uvicorn realtime.main:app --reload` (api).
- Tests: `pnpm test` (Vitest), `uv run pytest` (api).
- Migrations: Django only — `uv run manage.py makemigrations`. FastAPI has no ORM;
it reads via raw SQL against shared tables.
- Before commit: `pnpm lint` and `uv run ruff check .`

## Behavioral guidelines
- Simplicity first. Don't introduce a new dependency for something solvable in ten lines.
- Make surgical changes. Don't refactor adjacent code you weren't asked to touch.
- For billing or auth: state your plan and wait for confirmation before editing.
- Goal-driven, not activity-driven. If a task is ambiguous, ask.

See `docs/architecture.md` for system diagram and `docs/api-contracts.md` for request/response shapes.

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:

  1. Instruction overload — too many directives competing for attention, so lower-priority-looking ones lose out.
  2. Buried specificity — a critical rule stated once, in passing, inside a long paragraph, with no visual weight.
  3. 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.
  4. 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.md using WHAT-WHY-HOW, under ~50 lines.
  • CLAUDE.local.md, gitignored, for machine-specific overrides.
  • Subdirectory CLAUDE.md files for apps/web and apps/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

Damian Hodgkiss

Senior Staff Engineer at Sumo Group, leading development of AppSumo marketplace. Technical solopreneur with 25+ years of experience building SaaS products.

Creating Freedom

Join me on the journey from engineer to solopreneur. Learn how to build profitable SaaS products while keeping your technical edge.

    Proven strategies

    Learn the counterintuitive ways to find and validate SaaS ideas

    Technical insights

    From choosing tech stacks to building your MVP efficiently

    Founder mindset

    Transform from engineer to entrepreneur with practical steps