How Do I Write a CLAUDE.md That Actually Changes Claude's Behavior?

Every Claude Code user eventually writes a CLAUDE.md file and most of them are bad. They're either a wall of preferences Claude ignores, or a terse "be concise" that doesn't change anything. A good CLAUDE.md is the difference between "Claude keeps suggesting patterns we don't use" and "Claude already knows how we write code here." Here's how to write one that actually changes behavior on your next run.
Why this matters
CLAUDE.md is the file Claude Code reads on every session start. It gets prepended to Claude's context as an instruction, not a reference document. Which means: every line costs tokens, every line is evaluated, and every line needs to be doing work.
Most CLAUDE.md files are where good intentions go to die. They accumulate like a junk drawer — "also don't do X", "prefer Y", "we discussed Z in Slack last week" — until the file is 400 lines of noise and Claude follows none of it. The trick is treating it like production code: small, tested, revised.
Before you start
You need:
- Claude Code installed. If you don't have it yet, see How Do I Set Up Claude Code on macOS?.
- A project you're actively working in. CLAUDE.md without a codebase to constrain is useless.
- About 30 minutes of honest reflection on which Claude behaviors frustrate you.
Step 1: Find your project's CLAUDE.md
Claude Code looks for CLAUDE.md in three places, in order:
- Project root —
./CLAUDE.md(versioned with your code, shared with your team). - Home directory —
~/.claude/CLAUDE.md(personal, across all projects). - Parent directories up to the repo root — useful for monorepos.
Create one in your project root if it doesn't exist:
touch CLAUDE.mdProject-root is where 80% of your instructions should live. Home-dir is for your personal preferences that span every project (e.g., "always use U.S. spelling").
Step 2: Start with a list of things Claude keeps getting wrong
Not what you want Claude to do in some idealized sense. What it keeps getting wrong right now.
Open the last three or four Claude Code sessions and scan for corrections you had to make. Things like:
- "No, we use Tailwind, not CSS modules."
- "Import from
@/lib/foo, not relative paths." - "Don't add comments like
// fetch user dataabovefetchUser()." - "We never use
any— if you can't type it, say so." - "Server Components by default;
'use client'only when there's an interactive reason."
Each of those is a CLAUDE.md candidate. Write them down raw.
Step 3: Rewrite each one as a short imperative
Bad: "I would prefer if you could generally lean toward using TypeScript generics when we're dealing with collection operations because it improves type inference..."
Good: "Use generics on collection helpers. Never return any[]."
The rules of thumb:
- Imperative voice. "Use X." "Don't use Y." Not "I think maybe we should."
- One rule per line. Compound rules get ignored.
- Concrete examples. "Use
cn()from@/lib/utils" beats "use our class utility." - Negative rules beat positive ones. "Never add try/catch unless the error is recoverable" is clearer than "handle errors thoughtfully."
Step 4: Structure the file so Claude can scan it
Claude reads top to bottom and weights earlier content slightly more. Structure:
# Project: [Name]
One-line description of what this is.
## Stack
- Next.js 16, Tailwind 4, Prisma 7, Postgres
- Deployed on Railway
- Tests: Vitest
## Conventions
### Imports
- Use `@/` path alias, never relative `../`.
- Group: external libs, then `@/`, then same-folder.
### Components
- Server Components by default.
- `'use client'` only for interactivity (state, effects, browser APIs).
### Types
- Never `any`. Use `unknown` and narrow, or generic.
- Prefer interfaces over types for object shapes.
## Running the app
- `npm run dev` — local with Turbopack.
- `npm run build` — production build; must pass before every PR.
## Don't
- Don't add "helpful" comments that restate the code.
- Don't create new files unless they're needed; extend existing ones.
- Don't run destructive git commands without asking.Sections let Claude grep; short bullets let it comply.
Step 5: Add one "forbidden patterns" section with examples
This is the highest-ROI block. Claude follows "don't do X" most reliably when you show the X.
## Forbidden patterns
BAD (useless comment):ts // Get the user const user = await getUser();
GOOD:ts const user = await getUser();
BAD (relative import):ts import { foo } from '../../../lib/foo';
GOOD:ts import { foo } from '@/lib/foo';
Three or four examples is enough. Each one saves you from correcting the same thing a hundred times.
Step 6: Test it with a small task
Restart your Claude Code session so it re-reads CLAUDE.md. Then ask Claude to do something that would have tripped your old rules — e.g., "add a helper function that fetches a user's posts" — and watch if it now uses the conventions you specified.
If it doesn't:
- Your rule may be too vague. Tighten it.
- Your rule may be buried under noise. Delete 30% of the file.
- Your rule may contradict something else in the file. Resolve it.
Iterate. The file is code.
Verify it worked
1. Session picks it up. Start a new Claude Code session and type /context — Claude shows what's in its prompt. CLAUDE.md should be visible.
2. Behavior changed. Ask Claude to do three tasks that previously required correction. Count how many you had to correct. Target: zero.
3. File is short. Under 200 lines for most projects. If yours is longer, you're probably documenting things Claude can infer from the codebase. Delete those.
Where this breaks
- Contradicting existing code. If your CLAUDE.md says "use Tailwind" but half the codebase is in CSS modules, Claude will follow the code it sees, not your file. Align the two before writing rules.
- Over-specifying style. "Always use 2-space indent" is wasted tokens — Prettier or Biome handles this. Save CLAUDE.md for things formatters can't enforce.
- Secrets in CLAUDE.md. The file often gets committed to Git. Never put API keys, DB URLs, or anything you wouldn't put in a README.
- Rules that are actually team debates. "Prefer function declarations over arrow functions." If your team hasn't agreed, Claude is going to pick one side. Settle the debate human-to-human first, then encode it.
- The "big list of don'ts" that grows forever. Review and prune every month. If a rule hasn't been violated in 60 days, delete it — you solved the problem.
What to try next
- How Do I Set Up Claude Code on macOS Without Breaking My Shell Config? — if you haven't installed Claude Code yet.
- How Do I Build a Claude Code Skill Army That Replaces My Checklist of Prompts? — the next layer up: bundle rules + workflows into reusable Skills.
- How Do I Set Up Claude Code Hooks for Auto-Quality? — enforce CLAUDE.md rules mechanically with pre-commit hooks so drift can't happen.
Let's talk about your AI + SEO stack
If you'd rather skip the how-to and have it shipped for you, that's what I do. Start a conversation and we'll figure out the fastest path to results.
Let's Talk