A CLAUDE.md file at your repo root tells Claude the rules before you ever type a prompt. Every new conversation loads it automatically. Done well, it prevents 80% of the “no, that’s not how we do it here” corrections.
This page is a reference, not a template. The template lives at 01-bootstrap-a-repo/templates/CLAUDE.md.template. This page teaches you how to write one.
Every production CLAUDE.md in TurtleWolfe’s workspace has the same eight sections in the same order. Some are tiny, some are long. But the skeleton is the same:
That’s it. If your CLAUDE.md is missing any of these, add them. If it has more than those (project history, team bios, a changelog), cut them — that’s not context Claude needs.
# CLAUDE.md
This file provides guidance to Claude Code when working with this repository.
## Core Development Principles
1. **Proper Solutions Over Quick Fixes** - Implement correctly the first time
2. **Root Cause Analysis** - Fix underlying issues, not symptoms
3. **Stability Over Speed** - This is a production template
4. **Clean Architecture** - Follow established patterns consistently
5. **No Technical Debt** - Never commit TODOs or workarounds
Note the phrasing. These are rules, not aspirations. “Proper Solutions Over Quick Fixes” tells Claude to push back when you ask for a band-aid fix. Claude will say “are you sure you want to do this — the proper fix is X.” That’s the goal.
## Docker-First Development (MANDATORY)
**CRITICAL**: This project REQUIRES Docker. Local pnpm/npm commands are NOT supported.
### NEVER Install Packages Locally
**ABSOLUTELY FORBIDDEN**:
npm install
pnpm install
### CORRECT
docker compose exec scripthammer pnpm install
Note the specificity. “Do not install packages” is weak. “Never run pnpm install on the host, only docker compose exec scripthammer pnpm install” is strong. Give Claude the exact commands, not just the prohibition. If you only prohibit, Claude tries to find the allowed alternative and often gets it wrong.
The actual file goes on for ~200 more lines covering component scaffolding, the SpecKit workflow, the test stack, and deployment. Read the real one at ~/repos/ScriptHammer/CLAUDE.md once — treat it as a masterclass.
SpokeToWork uses Supabase and local JWTs. Its CLAUDE.md leads with the secrets rule because that’s the single most dangerous thing Claude could get wrong:
## NEVER Hardcode Secrets in Committed Files (MANDATORY)
**CRITICAL**: No secret, token, key, or credential may appear as a literal
value in any file that is committed to git.
### The Rules
1. **ALL secrets go in `.env`** (gitignored). No exceptions.
2. **Committed files use `${VAR:-placeholder}`** where `placeholder` is a
non-secret default like `change-me-realtime-secret-key-base` or
`set-anon-key-in-env-file`.
3. **`.env.example` shows variable names only** with commented-out
placeholder values.
4. **NEVER allowlist secrets in `.gitleaks.toml`** — not in `regexes`,
not in `commits`, not anywhere.
5. **If a secret leaks into git history**, scrub it with
`git-filter-repo --replace-text` and force push.
Note the justification structure. Each rule has a “why” embedded. Rule 4 doesn’t just say “never allowlist secrets” — it says “not in regexes, not in commits, not anywhere” because some Claude session in the past tried to work around a rule by finding an exception. The rule grew teeth from experience.
Lesson: When Claude surprises you by violating an implicit rule, write it down explicitly. Your CLAUDE.md grows teeth over time.
TurtleWolfe’s CLAUDE.md has a section that most don’t: pending configuration TODOs:
## Pending Configuration (TODO)
- **basePath Restoration**: Once the Squarespace domain redirect to GitHub
Pages is configured, restore `/TurtleWolfe/` as the basePath in
`public/manifest.json` (icon paths, start_url, scope, shortcuts,
screenshots, share_target) and verify `next.config.ts` auto-detection
picks it up.
- **Portfolio Mode**: Supabase is currently disabled. `useAuth()` returns
a safe default context when used outside `AuthProvider`. No auth secrets
are required for CI/CD.
Why this works. These are facts Claude should know that aren’t derivable from reading the code. The basePath situation is a deliberate temporary state. Without this section, Claude would see basePath: '' in next.config.ts, assume it was a bug, and “fix” it. With this section, Claude knows to leave it alone until the migration completes.
Lesson: If your repo has deliberate quirks (“this looks wrong but is correct because X”), document them in CLAUDE.md. Code alone can’t express intent.
git log is for.README.md is for humans. CLAUDE.md is for Claude. They should share facts (tech stack) but serve different purposes (README = how to use, CLAUDE = how to modify).Target: 100-250 lines. If it’s under 50, you’re under-specifying. If it’s over 300, you’re probably repeating yourself — split into multiple files and reference them. ScriptHammer’s is ~450 lines and it’s at the upper limit of what’s manageable. Most should be smaller.
Claude loads the whole file every session. Every line you add is a line loaded on every conversation. Be ruthless.
Don’t try to write the perfect CLAUDE.md on Day 1. Write a 50-line starter. Then:
it, use test.” “Run lint inside the container.”CLAUDE.md.In six weeks you’ll have a 200-line CLAUDE.md that catches every common mistake before it happens. That’s the goal.
CLAUDE.md mid-session01-bootstrap-a-repo/templates/CLAUDE.md.template — the starter templateprinciples/context-hygiene.md — the war story behind /clear over /compact