How to write a CLAUDE.md that changes Claude Code's behavior
The five sections that shift how Claude Code works in your repo, plus what to leave out so the file stays under 200 lines.

By the end of this you'll have a CLAUDE.md that makes Claude Code follow your project conventions without you re-explaining them every session. The file is short and lives at the root of your repo. Five sections, no more.
You need two things first. Claude Code already installed in a project that has a package.json, Cargo.toml, or similar root marker. About 15 minutes to draft and prune.
What CLAUDE.md is and where it lives
CLAUDE.md is a plain markdown file Claude Code reads at the start of every session. The file gets loaded as a user message right after the system prompt, so its rules apply to every tool call you make in that session.
Three locations exist, and they stack. The project file at ./CLAUDE.md or ./.claude/CLAUDE.md is the one your whole team sees. A user-level file at ~/.claude/CLAUDE.md applies to every repo on your machine. A personal project file at ./CLAUDE.local.md is where you stash notes only you care about. Add it to .gitignore yourself, or let /init do it when you pick the personal option.
Anthropic's memory doc says target under 200 lines per file. Past that, adherence drops because important rules get buried in noise.
Run /init first, then edit
Open the project in Claude Code and run the /init command. It scans the repo for your build system, test framework, package manager, and folder layout, then writes a starter CLAUDE.md to the root.
claude
> /initThe output is usable but generic. It often picks up commands from package.json scripts and infers a layout from your top-level folders. Treat it as scaffolding. The next five sections are where you turn scaffolding into something that changes behavior.
Section 1: build and test commands
This is the section that moves the needle most. Claude cannot guess pnpm vitest when your package.json looks like a normal npm project, and it will often reach for the wrong command without a hint.
List the exact commands you run.
## Commands
- Install: `pnpm install`
- Dev: `pnpm dev`
- Test: `pnpm vitest run` (watch mode is `pnpm vitest`)
- Lint: `pnpm biome check --apply .`
- Typecheck: `pnpm tsc --noEmit`
- Build: `pnpm build`Every line is a command Claude can copy verbatim into a Bash tool call. No prose, no "we use vitest for testing". The rule is verifiable: if a Claude run goes wrong, you can point at the exact line that should have prevented it.
Section 2: project layout and where things go
Tell Claude where new code belongs. Three or four lines is enough for most repos.
## Layout
- `app/` Next.js App Router routes. Server components by default.
- `lib/` shared utilities and types. No React here.
- `components/` shared UI. Each component lives in its own folder.
- `content/` MDX articles and news. Read-only at runtime.The goal is to stop Claude from putting a new route in lib/ or a utility function inside a component file. If your repo follows a common framework convention exactly, you can skip this section. If you have any custom rule, write it down.
Section 3: code style rules that differ from defaults
Only write rules that differ from what Claude already knows. "Use 2-space indentation" stays if your repo uses tabs. "Write clean code" goes, because it gives Claude nothing to act on.
Good rules look like this.
## Style
- TypeScript strict mode. No `any` without a `// reason:` comment on the same line.
- Imports sorted by Biome. Do not reorder manually.
- React components use named exports. No default exports outside of `app/` route files.
- Tailwind classes only. No CSS Modules, no inline styles.Each line names the rule and the violation. Claude reads "no default exports outside of app/ route files" and stops trying to add export default to your components. Vague rules like "follow existing patterns" make the file longer without changing anything.
Section 4: areas to avoid and gotchas
This section saves you from Claude editing files it shouldn't touch. Generated code, vendored libraries, migration folders, and lock files are the usual suspects.
## Do not edit
- `app/generated/` Prisma client output. Regenerated by `pnpm db:generate`.
- `supabase/migrations/` migration files are append-only. Add a new one, never edit existing.
- `public/covers/` produced by `scripts/generate-cover.ts`. Regenerate, don't hand-edit.
## Gotchas
- The Next.js version in this repo has breaking API changes from training data. Always read `node_modules/next/dist/docs/` before writing route handlers or server actions.The gotchas line is where you can warn Claude about repo-specific traps. A breaking framework change, a custom build step, a weird tsconfig setting. One sentence per trap.
Section 5: workflow rules for this repo
Repo etiquette Claude cannot infer. Branch naming, commit message format, what to run before pushing.
## Workflow
- Branch names: `feat/<slug>`, `fix/<slug>`, `chore/<slug>`.
- Commit messages follow Conventional Commits. Run `pnpm typecheck` and `pnpm vitest run` before committing.
- Open PRs against `main`. No direct pushes to `main`.
- Cover images are generated, not hand-drawn. Run `/cover <slug>` after `/lint` passes.These rules turn into actions Claude takes without being asked again. The commit-before-push rule is one of the most common things people add and then forget they added.
What to leave out
The Anthropic best-practices doc has a useful prune rule. For every line in your CLAUDE.md, ask: would removing this cause Claude to make a mistake? If the answer is no, cut it.
Things that almost always belong in the cut pile.
- Project mission statements and one-liner descriptions. Claude does not need to know your product vision to write code.
- Generic best practices Claude already follows. "Write tests for new features" is a default, not a rule.
- Long architecture explanations. If the layout section names the folders, that's enough. Save deep architecture for
docs/. - Anything that changes weekly. Volatile rules go stale and start lying.
Block-level HTML comments in CLAUDE.md get stripped before the file enters context, so they cost zero tokens. Use them for human maintainer notes that Claude should never see.
<!-- Maintainer note: we tried adding a "no console.log" rule here and it caused Claude to refactor logging into a logger module. Reverted. -->When to use a hook instead
CLAUDE.md is advisory. Claude follows it most of the time, not always, which is fine for shaping behavior but not enough for anything that must happen every run.
For deterministic rules, write a hook in .claude/settings.json instead. Format-on-save, lint-before-commit, blocking specific file edits, running pnpm typecheck after every code change. Hooks fire every time the matching event happens, with no model judgment in the loop.
The split is simple. Behavior shaping goes in CLAUDE.md. Things that must happen every time go in hooks.
Keep it under 200 lines
If your CLAUDE.md grows past 200 lines, split it. The pattern is .claude/rules/*.md with a paths: frontmatter so each rule file only loads when matching files are touched. A rule about migrations only loads when Claude reads or writes files in supabase/migrations/.
Long files are the most common reason Claude ignores your rules. The fix is not to add an emphatic "PLEASE FOLLOW THESE RULES" at the top. The fix is to cut the file in half and put the other half behind a path matcher.
Newsletter
A short weekly email about AI tools and what's worth trying.
Free. No spam. Unsubscribe anytime.
More like this
All articles →
Get Claude Code to write tests you'll keep
Claude Code writes tests that pass without checking anything. Write them before the code, lock the assertions, and keep the tests worth running.

Claude Code sub-agents: when to spawn one (3 cases)
A sub-agent runs in its own context window and hands back a summary. Here is the one rule for when to spawn one, with three worked examples.

Run two Claude Code sessions in one repo with worktrees
Claude Code has a native -w flag for git worktrees. Run a refactor and a feature in parallel, each in its own files, with no merge pain.

Claude Code agent loop: 3 causes and the fix
Claude Code looping on the same edit means one of three things: lost context, a failing command, or a vague task. Here is the fix for each.
Was this helpful?
