Topic · A1
The CLAUDE.md Playbook
What CLAUDE.md is, where it lives, how to write one that actually works, and stack-specific templates for Next.js, Python, Rails, and Go. Based on HumanLayer's <60-line standard and Karpathy's 109k-star example.
# The CLAUDE.md Playbook
CLAUDE.md is the highest-ROI file most Claude Code teams haven't written yet.
It's a Markdown file at your repo root that Claude reads at session start and injects into every prompt thereafter. It's not prompting; it's project context. Done right, it removes the 80% of repetition where you tell Claude "we use Bun, not Node" or "tests live in __tests__/, not tests/" every single session.
Done wrong, it's a 400-line dossier that burns 4,000 tokens per turn for context that doesn't help — what HumanLayer calls the 60-line standard is the right floor.
This is the playbook: what it is, where it lives, how to write one, and four stack-specific templates.
What CLAUDE.md actually does
Mechanically: at session start, Claude Code reads everyCLAUDE.md from your working directory up the tree to the project root, plus the global ~/.claude/CLAUDE.md, concatenates them, and injects the result as a system-level instruction block. From then on, every prompt you send is implicitly prefixed by that context.
It's not a prompt template — you don't reference variables from it. It's not a skill — it loads unconditionally. It's the thing that sits one layer below skills and shapes how Claude interprets every other instruction.
The implication: every line costs tokens forever. Anything project-wide and invariant belongs here. Anything stack-specific or task-specific belongs in a skill, where it loads only when relevant. The /topic/skill-not-triggering guide explains the skill side of that split.
The hierarchy
``
~/.claude/CLAUDE.md <- global, all projects
└── /your-project/CLAUDE.md <- project root
└── /your-project/apps/web/CLAUDE.md <- subdirectory (monorepo)
`
Claude Code reads all of them, in that order, when you start a session inside /your-project/apps/web/. Later files override earlier ones for conflicting instructions. The merge is purely additive — Claude sees the full concatenation.
For most projects, you want:
~/.claude/CLAUDE.md — your personal taste, banned phrases, tool preferences. Doesn't change per project.
./CLAUDE.md — committed to the repo, shared across the team. The project's conventions and stack.
- Subdirectory CLAUDE.md — only in monorepos, only when a subtree has materially different rules.
How to write one (the 60-line rule)
HumanLayer's writing-a-good-claude-md post is the reference. The headline: keep it short, keep it specific, keep it actionable.
What belongs in CLAUDE.md:
- The stack. "We use Next.js 16, Bun, Postgres via Prisma, deployed to Vercel." One line. Saves you the explanation every session.
- Conventions Claude wouldn't guess. "Tests live in
__tests__/. We don't use Jest's describe; we use plain test()." Things that contradict defaults.
- What to avoid. "Never modify
prisma/migrations/. Never run npm install — we use bun install." Deny-rules, in prose.
- Where things live. "Server actions are in
src/actions/. API routes are deprecated; only legacy code uses them." Navigation hints.
What does NOT belong in CLAUDE.md:
- Things Claude already knows. "TypeScript is strongly typed." "Use async/await." You're paying tokens for nothing.
- Stack-specific rules that don't apply to every task. Move those to skills that load on demand.
- Code style. Use Prettier + ESLint + tsconfig. They enforce style deterministically. CLAUDE.md is for things tools can't enforce.
- Marketing language. "We pride ourselves on quality" is not context; it's filler.
Andrej Karpathy's CLAUDE.md (109k stars on his karpathy/nanochat repo) is the most-referenced public example. It's roughly 40 lines. It says what the project is, what the build commands are, what to read first, and what not to touch. That's it.
Stack templates
Each of these is a starting point — not a complete CLAUDE.md. Copy, then prune to your actual project.
Next.js 16 + Prisma + Vercel
`markdown
# CLAUDE.md
Stack
- Next.js 16 (App Router, RSC by default, Cache Components enabled)
- TypeScript strict mode, Bun runtime
- Prisma + Postgres (Neon, via Vercel Marketplace)
- Auth: Clerk via @clerk/nextjs
- UI: shadcn/ui composed locally, Tailwind v4
Commands
bun dev — local dev server
bun run build — production build (must pass before any commit)
bunx prisma migrate dev — schema changes
bun run lint and bunx tsc --noEmit — pre-commit gates
Conventions
- Server Components by default; mark
"use client" only when interactivity required
- Server Actions live in
src/actions/, not app/api/
- Forms use
useActionState; no SWR/React Query for mutations
- Database access only inside Server Actions or Route Handlers; never in client code
What NOT to do
- Don't modify
prisma/migrations/ — generate them, don't hand-edit
- Don't add
app/api/ routes — Server Actions only
- Don't install npm packages — use
bun add
- Don't write Storybook stories without asking first
`
Python 3.13 + FastAPI + uv
`markdown
# CLAUDE.md
Stack
- Python 3.13, FastAPI, Pydantic v2
- uv for package management (NOT pip, NOT poetry, NOT pipenv)
- Postgres via SQLAlchemy 2.0 (async) + asyncpg
- Tests: pytest + pytest-asyncio
- Linting: ruff (replaces black, isort, flake8)
Commands
uv sync — install dependencies
uv run uvicorn main:app --reload — local dev
uv run pytest — tests must pass before any commit
uv run ruff check . and uv run ruff format . — linting
Conventions
- All endpoints async; no sync def for routes
- Pydantic models in
app/schemas/, SQLAlchemy models in app/models/
- Dependency injection via
Depends(); no global state
- Database sessions opened per-request, closed in finally
What NOT to do
- Don't add
requirements.txt — pyproject.toml is the source of truth
- Don't add sync route handlers — always async
- Don't use
print() for logging — use structlog
`
Rails 8 + Hotwire
`markdown
# CLAUDE.md
Stack
- Rails 8 (Hotwire, Solid Queue, Solid Cache, propshaft)
- Ruby 3.3
- Postgres 16
- ViewComponent for reusable UI
Commands
bin/rails server — dev
bin/rails test — tests must pass before any commit
bin/rubocop — style enforcement
bin/brakeman — security check before any deploy
Conventions
- Hotwire Turbo Frames before any JavaScript framework
- Stimulus controllers in
app/javascript/controllers/, one job each
- Background jobs via Solid Queue, not Sidekiq
- Strong Parameters always; never
params.permit!
What NOT to do
- Don't add Webpack/Vite — propshaft + importmaps is the stack
- Don't write React components; use ViewComponent + Stimulus
- Don't bypass strong params for any reason
`
Go 1.23 + chi + sqlc
`markdown
# CLAUDE.md
Stack
- Go 1.23
- HTTP router: chi (NOT gin, NOT echo, NOT mux)
- Database: pgx + sqlc (generated queries; never write raw SQL in handlers)
- Logging: log/slog (stdlib structured logging)
- Tests: stdlib testing + testify/assert
Commands
go run ./cmd/server — dev
go test ./... — tests must pass before any commit
go vet ./... and golangci-lint run — pre-commit
sqlc generate — regenerate query code after schema changes
Conventions
- Errors wrapped with
fmt.Errorf("context: %w", err), never lost
- Context.Context as first parameter on every exported function that does I/O
- No global state; dependencies injected via constructors
- HTTP handlers return error; middleware translates to status codes
What NOT to do
- Don't introduce gorm or any ORM — sqlc is the contract
- Don't use
panic() for control flow
- Don't import
os.Getenv directly in business logic — use the config struct
`
Where this fails
1. CLAUDE.md is global to the session. If you're working on two unrelated subsystems in the same session, both subsystems' rules apply at once. There's no way to scope a CLAUDE.md rule to "only when editing files matching *.api.ts" — that's what skills are for.
2. Conflicting rules silently merge. If ~/.claude/CLAUDE.md says "always use TypeScript strict mode" and your project CLAUDE.md doesn't, you'll get strict mode. If your project says "we don't use strict mode for legacy reasons", later rules win — but the conflict is invisible. Skim the concatenation by running /doctor if you suspect rule conflict.
3. The format is unenforced. Nothing validates CLAUDE.md. Misspell Postgres as Posgres` and Claude reads it without complaint. The cost is silent: Claude's mental model of your stack is whatever the file says, typos included.
4. It biases toward what's listed. If you list 8 stack components, Claude considers those 8 the universe. Mention a 9th in passing in a prompt and Claude may try to map it onto the listed 8. The fix: keep the stack section accurate, and update it on stack changes.
What to read next
- /topic/agents-md — the cross-tool successor / supplement to CLAUDE.md
- /topic/skill-not-triggering — where stack-specific rules belong instead
- /topic/best-claude-code-skills — the 30 skills our audit recommends
- /topic/claude-code-hooks-cookbook — deterministic enforcement on top of CLAUDE.md
- /topic/autoresearch — pre-loaded context that improves long-running research
- /for/claude-code — install the harness
- /for/obra-superpowers — Obra's own CLAUDE.md is in the repo as a reference
Sources
- Anthropic. "Memory and CLAUDE.md". The four-scope priority order, hierarchical reading.
- HumanLayer. "Writing a Good CLAUDE.md". The 60-line standard. Quoted across every other reference.
- Karpathy, Andrej. nanochat. 109k stars; the most-forked public CLAUDE.md template.
- Hacker News. "The creator of Claude Code just revealed his workflow". Boris Cherny's CLAUDE.md is a recurring reference.
- Hacker News. "Can't we standardize on AGENTS.md instead of all these specific CLAUDE.md...". Confirms cross-tool friction.
- Cherny, Boris (Anthropic Claude Code lead). "Opus 4.7 carries context across sessions". Context persistence is the model-side complement to CLAUDE.md.
Related GitHub projects
Frequently asked
- What is CLAUDE.md?
- CLAUDE.md is a Markdown file Claude Code reads at session start and injects into every conversation. It's the project's prose configuration — what stack you use, what conventions you follow, what to avoid. It's not a prompt template; it's persistent context. Anthropic introduced the file with Claude Code's launch; the convention has since been forked by Codex CLI (`AGENTS.md`), Cursor (`.cursorrules`), and Aider (`CONVENTIONS.md`).
- Where does Claude Code look for CLAUDE.md?
- Four scopes, in priority order: (1) enterprise-managed settings; (2) `~/.claude/CLAUDE.md` (user-global, all projects); (3) `./CLAUDE.md` at the repo root (project); (4) `<plugin>/CLAUDE.md` (plugin). Claude merges all four into context, with later scopes overriding earlier ones for conflicting instructions. Subdirectory `CLAUDE.md` files are also auto-discovered for monorepos. ([source: code.claude.com/docs/en/memory](https://code.claude.com/docs/en/memory))
- How long should CLAUDE.md be?
- Shorter than you think. HumanLayer's [definitive post](https://www.humanlayer.dev/blog/writing-a-good-claude-md) recommends staying under 60 lines for a project-level file. Every line of CLAUDE.md is in context for every prompt — at 400 lines, you're paying 2-4k tokens per turn for context you mostly don't need. The fix is to move stack-specific rules into skills (loaded only when relevant) and keep CLAUDE.md to genuinely project-wide invariants.
- What's the difference between CLAUDE.md and AGENTS.md?
- CLAUDE.md is Claude Code-specific. AGENTS.md is the cross-tool standard — Codex CLI, Cursor, Gemini CLI, Aider, Windsurf, Zed, Warp, and RooCode all read it. Claude Code doesn't read AGENTS.md natively as of May 2026. The standard workaround is a symlink: `ln -s AGENTS.md CLAUDE.md`. See [/topic/agents-md](/topic/agents-md) for the full picture.
- Can I have multiple CLAUDE.md files?
- Yes. Claude Code reads CLAUDE.md from every level of the directory hierarchy from the current working directory up to the project root, plus the global `~/.claude/CLAUDE.md`. In a monorepo this is useful: a top-level CLAUDE.md for the org conventions, and a `apps/web/CLAUDE.md` with Next.js-specific rules that only loads when working in that subtree.
- Should I commit CLAUDE.md to git?
- Yes. CLAUDE.md belongs in version control alongside your code. It's a team artifact — anyone running Claude Code on your repo benefits from the shared context. For personal preferences you don't want to push, use the global `~/.claude/CLAUDE.md` or add a `.local.md` companion (gitignored).