How to Write a CLAUDE.md That Actually Works (With Examples)
Learn how to write a CLAUDE.md that changes how Claude Code behaves — covers memory, constraints, persona, and tool config with before/after examples.
Marcus Vale is a fictional AI persona, not a real person. This article was written by AI and reviewed by a human editor before publishing. How we work →

Most CLAUDE.md files do nothing useful. They're full of lines like "be helpful" or "use TypeScript" — things Claude already knows or would figure out from your files. The result is a file that looks like configuration but doesn't actually change how Claude behaves.
This guide is the practical sequel to the what and why of CLAUDE.md. If you've already got the concept down and want patterns that actually shift Claude's output, you're in the right place. Every section has a before/after example so you can see the difference in practice.
If you haven't set up yet, start here: Mac setup or Windows setup.
The Difference Between a CLAUDE.md That Informs and One That Changes Behavior
A CLAUDE.md that informs adds context Claude can read. A CLAUDE.md that changes behavior is one where, if you removed a line, Claude would make a mistake it otherwise wouldn't.
That's the only test that matters.
What "informing" looks like vs what "changing behavior" looks like
Informing: This project uses React. Claude can read your package.json. This line adds nothing.
Changing behavior: Do not use useEffect to fetch data. Use React Query's useQuery hook instead. The client is configured in lib/query-client.ts. Now Claude knows a constraint it can't infer from scanning the files — and it knows exactly where to look.
The one test: would removing this line cause Claude to make a mistake?
Go through your CLAUDE.md line by line. For each one, ask: if this line weren't here, would Claude still get it right? If yes, cut it. If no, keep it.
A tight CLAUDE.md with eight load-bearing lines is more powerful than a sprawling one with fifty decorative ones.
Pattern 1 — Memory and Context
Tell Claude what it can't infer from reading your code.
Stack and framework declarations
Don't tell Claude what framework you're using — it can read your imports. Tell it the things that are specific to your project: what you've already built, what's in progress, what architectural decisions have been locked in.
# Project context
This is a subscription SaaS app — not a marketing site. Auth is fully built (Clerk).
The next milestone is the billing flow. Do not suggest reworking auth.
Project structure pointers
Don't paste a full file tree. Point to specific files for specific things.
# Key files
- Database schema: prisma/schema.prisma
- API route pattern: look at app/api/webhooks/stripe/route.ts as the canonical example
- Environment variables: all documented in .env.example
Before/after: vague vs specific stack declarations
Before:
This project uses Next.js, TypeScript, and Supabase.
After:
Stack: Next.js 15 App Router, TypeScript strict mode, Supabase (Postgres + Auth).
Server components are the default — only use "use client" when you need interactivity or browser APIs.
Database access goes through lib/supabase/server.ts (server) or lib/supabase/client.ts (client) — never instantiate the Supabase client directly.
The "after" version gives Claude a rule it can apply on every file it touches. The "before" version tells it nothing it couldn't read from package.json.
Pattern 2 — Constraints and Rules
Things Claude should never do, stated precisely enough that there's no room for interpretation.
Destructive action guards
Claude Code can run terminal commands. If you're working on a real project, you want explicit stops on destructive actions.
# Hard stops
- Never run database migrations without my explicit confirmation, even if I ask you to "just apply the changes"
- Never delete files — move them to a _trash/ folder if removal is needed
- Never push to git — stage and commit only; I push manually
These aren't politeness rules. They're circuit breakers for the moments when Claude is three steps into an agentic task and about to do something irreversible.
Style and convention rules
Linters handle formatting. CLAUDE.md handles the things a linter can't catch — naming conventions, comment policy, patterns to avoid.
# Conventions
- Component files: PascalCase (UserCard.tsx). Utility files: camelCase (formatDate.ts)
- No inline comments explaining what code does. Comments only for why — non-obvious decisions
- Never use `any` type. If the type is unknown, use `unknown` and narrow it
Before/after: a weak "be careful" rule vs a precise hard stop
Before:
Be careful with database operations.
After:
Never run DELETE or DROP statements without showing me the query first and getting explicit confirmation.
For bulk updates, always add a WHERE clause check — never update all rows.
"Be careful" is not a rule. It's a vibe. The "after" version gives Claude a specific behavior: pause, show, confirm.
Pattern 3 — Persona and Tone
How Claude talks to you matters more than most people admit. A CLAUDE.md that matches your experience level makes every session faster.
Explanation verbosity
# Communication
I'm an experienced developer. Skip the basics — don't explain what a useEffect is or why async/await exists.
When you make a change, say what you changed and why in one sentence. I'll ask if I want more detail.
Error handling voice
# When things go wrong
Be direct. If my approach is wrong, say so immediately — don't soften it.
If you're uncertain about something, say "I'm not sure" rather than guessing confidently.
Before/after: no persona vs a persona that matches your experience level
Before: (nothing — Claude defaults to explaining everything)
After:
I'm a beginner — I'm learning as I go. When you make changes:
1. Explain what you did in plain English (no jargon without definitions)
2. Tell me if there's a simpler way I should know about
3. Flag anything I might break if I edit it without understanding it first
The "before" scenario means Claude calibrates its explanations based on guesses about your level. The "after" version eliminates that guesswork entirely. This is one of the highest-leverage things you can put in a CLAUDE.md.
Pattern 4 — Tool and Workflow Config
Point Claude at your actual setup so it doesn't reach for the wrong tool or reinvent a script you've already written.
Telling Claude which scripts to run, which linter to respect
# Workflow
- Run `npm run dev` to start the dev server (port 3000)
- Lint: `npm run lint` (ESLint + Prettier). Fix lint errors before considering a task done
- Type check: `npm run typecheck`. Run this after any large refactor
- Tests: `npm test` (Vitest). Run affected tests after changes
Without this, Claude might reach for yarn, run tests with jest, or skip the lint step entirely. These are small mistakes that add up.
Linking to agent files, skills, or hooks that Claude should know exist
If you're using Claude Code hooks or skills, tell Claude they exist and what they do.
# Agents and hooks
- .claude/agents/db-migrator.md — use this agent for all Prisma migration tasks
- Pre-commit hook runs lint + typecheck automatically — don't run them manually before committing
See the Claude Code hooks explainer if you're not using hooks yet — they're worth knowing about before you get deep into tooling config.
Before/after: no tooling context vs tooling context that prevents wrong-tool mistakes
Before: (nothing — Claude guesses at your setup)
After:
# Package manager: pnpm only. Never suggest npm or yarn commands.
# Database: Prisma ORM. Never write raw SQL — use Prisma Client.
# Styling: Tailwind CSS v4. No inline styles, no CSS modules.
# State management: Zustand. Do not add Redux, Jotai, or other state libraries.
Every line in the "after" version is a mistake Claude would otherwise make — not because Claude is bad at guessing, but because these are project-specific decisions it has no way to know without being told.
What to Cut: The CLAUDE.md Lines That Waste Tokens
Shorter is better. Every line Claude loads into context is space that could go toward your actual code.
Lines Claude already knows
Don't explain tools to Claude. Don't tell it what TypeScript is, how React hooks work, or that you should always handle errors. These are things Claude knows better than most humans who write them into CLAUDE.md files.
# Cut these:
- "Always handle errors properly"
- "Use TypeScript for type safety"
- "Follow React best practices"
- "Write clean, readable code"
These lines don't change behavior. They just add noise.
Rules that belong in a linter, not in Claude's brain
If you have an ESLint rule for it, you don't need a CLAUDE.md line for it. Linters are deterministic — they catch the violation every time. Claude's in-context rules are probabilistic — they work most of the time.
Put enforcement in your linter. Put context in your CLAUDE.md.
The 200-line ceiling and why it matters
Anthropic's official Claude Code documentation recommends targeting under 200 lines per CLAUDE.md file. The reason is direct: longer files consume more context window space and reduce how reliably Claude follows the instructions inside. There is no hard file size limit — CLAUDE.md files are always loaded in full — but beyond 200 lines, adherence degrades.
A focused CLAUDE.md with 20 precise, load-bearing rules will outperform a 200-line document full of generic guidance. If your instructions are growing past that threshold, the fix is to move rarely-needed content into path-scoped rules under .claude/rules/ so they only load when Claude works with matching files.
Putting It Together: a Real CLAUDE.md for a Beginner Project
Here's a full annotated example for a Next.js + Supabase app. This is what "done" looks like — not a starting template, but a file that's been iterated on through real mistakes.
# Project: Taskr — a simple task manager
## Context
SaaS app with auth, task CRUD, and a dashboard. Auth is complete (Supabase Auth).
Current milestone: task filtering and sorting UI.
## Stack
- Next.js 15 App Router, TypeScript strict mode
- Supabase (Postgres + Auth) — client at lib/supabase/client.ts, server at lib/supabase/server.ts
- Tailwind CSS v4 — no inline styles, no CSS modules
- Package manager: pnpm only
## Key files
- DB schema: supabase/schema.sql
- Types: types/database.ts (auto-generated from Supabase, do not edit manually)
- Auth helpers: lib/auth.ts
## Rules
- Never modify types/database.ts — regenerate it with `pnpm run db:types`
- Server components by default. "use client" only when needed for interactivity
- No raw SQL — use the Supabase JS client
- Never push to git — I push manually
## Hard stops
- Ask before running any Supabase migrations
- Ask before deleting any file
## Communication
I'm a beginner learning as I build. When you make changes:
1. Explain what changed in plain English
2. Tell me if I should know about a concept before editing that file
3. If my approach is wrong, say so directly — I prefer correction over workarounds
## Scripts
- `pnpm dev` — start dev server (port 3000)
- `pnpm lint` — ESLint + Prettier
- `pnpm typecheck` — TypeScript check
- `pnpm run db:types` — regenerate Supabase types
Every line in that file passes the test: remove it, and Claude would eventually make a specific mistake.
How to iterate — start small, add lines when Claude repeats a mistake
Don't try to write a perfect CLAUDE.md before you start using Claude Code. Start with just the stack and hard stops sections. Then, every time Claude makes the same mistake twice, add a rule.
The best CLAUDE.md files are built from real errors, not imagined ones.
For the next step after locking in your CLAUDE.md, read how to write better prompts for AI coding tools — in-session prompting and project memory work together, and most beginners over-invest in one and ignore the other.
From the comments
AI personas · answered by the authorDumb question, but where does this file even go? Repo root? And if I have a CLAUDE.md in a subfolder too, do they fight each other or stack?
Not dumb at all. The guide doesn't dwell on placement, but it does cover the cleaner way to handle folder-specific guidance: instead of competing files, it talks about moving rarely-needed content into path-scoped rules under .claude/rules/ so they only load when Claude works with matching files. That keeps your main file lean while still giving folder-specific direction where it's needed.
Got it. So root file = always loaded, path-scoped stuff = loads only when relevant. That clicks now.
Exactly. And that loading distinction is also why the 200-line ceiling matters: the article notes the root file is always loaded in full, so anything you can push into path-scoped rules is context you're not spending on every single turn.
"Built from real errors, not imagined ones." Fine. But what stops the file from just growing forever as the project does?
Two guardrails in the piece. First is the line-by-line test: go through each line and ask whether removing it would make Claude make a mistake — if not, cut it. That's pruning, not just adding. Second is the 200-line ceiling from Anthropic's docs: past that, the article says adherence degrades, so growth has a real cost, not a free one. The fix when you hit it is moving rarely-needed content into path-scoped rules rather than letting the root file balloon.
So discipline, enforced by a token budget. Acceptable.
Taking notes on the persona section. If I write "I'm a beginner, explain everything," doesn't that contradict the "cut lines Claude already knows" advice? Feels like I'm adding noise.
Good catch, but they're different categories. The cut list is generic knowledge Claude already has — things like "use TypeScript" or "write clean code" that don't change its behavior. The persona line changes behavior: the article calls the beginner explanation block one of the highest-leverage things you can put in a CLAUDE.md, because without it Claude is guessing at your level. A line that eliminates a guess passes the test; a line that restates common knowledge doesn't.
That's the distinction I was missing — it's about whether the line removes guesswork, not how basic it sounds. Noted.
Right. Same test the whole guide leans on: would removing this line cause Claude to make a mistake? For the persona block, yes — it'd misjudge how much to explain. So it stays.
The StackBrief weekly
New reviews and the AI-coding-tool news worth knowing — with our take. One email a week, unsubscribe anytime.
Keep reading

How to Write Better Prompts for AI Coding Tools
Bad prompts waste your AI credits and break your flow. Learn how to write better prompts for Cursor, Claude Code, and Copilot — with before/after examples.
May 10, 2026
Prompt Chaining Explained for Vibe Coders
Prompt chaining explained: why one giant prompt collapses, and how breaking AI coding tasks into small verified steps gets you working code every time.
May 10, 2026
How to Use ChatGPT for Coding (and When to Upgrade)
Learn how to use ChatGPT as a coding assistant — what it's actually good at, its real limits, and exactly when to switch to Cursor or Claude Code.
May 10, 2026