Skip to content

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 every CLAUDE.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:
  1. The stack. "We use Next.js 16, Bun, Postgres via Prisma, deployed to Vercel." One line. Saves you the explanation every session.
  1. Conventions Claude wouldn't guess. "Tests live in __tests__/. We don't use Jest's describe; we use plain test()." Things that contradict defaults.
  1. What to avoid. "Never modify prisma/migrations/. Never run npm install — we use bun install." Deny-rules, in prose.
  1. 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:
  1. Things Claude already knows. "TypeScript is strongly typed." "Use async/await." You're paying tokens for nothing.
  1. Stack-specific rules that don't apply to every task. Move those to skills that load on demand.
  1. Code style. Use Prettier + ESLint + tsconfig. They enforce style deterministically. CLAUDE.md is for things tools can't enforce.
  1. 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.txtpyproject.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

Sources

  • Karpathy, Andrej. nanochat. 109k stars; the most-forked public CLAUDE.md template.

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).

Related topics