How to Write a CLAUDE.md That Actually Changes What Claude Does
Most CLAUDE.md files are either empty or a wall of generic advice Claude would have followed anyway. What to put in one, what to leave out, how the files load, and how to tell whether yours is working.
Every Claude Code session starts with an empty context window. Whatever it learned yesterday about your project — that tests need a running database, that utils/ is legacy and shouldn't be extended, that you deploy from release and never from main — is gone.
CLAUDE.md is how you give it back. It's a Markdown file Claude Code loads at the start of every session, and it's the cheapest, highest-leverage thing you can do to make an agent better at your codebase specifically.
It's also where a lot of people waste effort, writing instructions Claude would have followed anyway and omitting the ones it could never guess.
How the files load
Before deciding what to write, know where it goes. Per Anthropic's documentation:
| File | Scope | Shared? |
|---|---|---|
./CLAUDE.md (or ./.claude/CLAUDE.md) |
This project | Yes — commit it |
./CLAUDE.local.md |
This project, just you | No — add to .gitignore |
~/.claude/CLAUDE.md |
Every project on your machine | Just you |
subdir/CLAUDE.md |
That part of the codebase | Yes |
Files in the directory you launch from, and every directory above it, load at startup and are concatenated — they don't override each other. Files in subdirectories load on demand, when Claude reads files in that directory. That makes nested files a good home for instructions that only matter in one area: a CLAUDE.md in migrations/ that says "never edit a migration that has already been merged" costs nothing until Claude goes near a migration.
You can also pull other files in with @path/to/file imports, though imported content still loads at launch and still takes up context.
Run /init in a project to have Claude generate a starting file from what it can discover in the codebase. It's a reasonable first draft. The valuable part is what you add afterwards.
The test for every line
Ask one question of each instruction: would Claude get this wrong without being told?
"Write clean, readable code" fails the test. So does "use TypeScript" in a repository full of .ts files, or "follow existing conventions." Claude does those already. Those lines cost context and dilute the ones that matter.
What passes the test is knowledge that isn't in the code, or is in the code but is easy to misread:
- Commands that aren't obvious. How to run a single test file. Which script seeds the database. That the dev server needs
npm run dev:apiandnpm run dev:web. - Things that look usable but aren't. "
lib/legacy-auth/is being removed — do not import from it." Without this, Claude sees a working auth module and uses it. - Non-local consequences. "Changing anything in
schema.prismarequires a migration; runnpm run db:migrateand commit the generated file." - Environment facts. "Tests need Postgres running on port 5433, not 5432." "The API key in
.env.exampleis fake; real keys are in the team vault." - Decisions already made. "We use Zod for validation, not Yup — don't add Yup even where it would be shorter." "Dates are stored as UTC and formatted only in the UI layer."
- Workflow rules. "Never push to
main. Open a pull request." "Runnpm run lintbefore declaring a task done."
A good one is short
Anthropic's own guidance is to keep each file under roughly 200 lines, because longer files consume context and reduce how consistently instructions are followed. That matches experience: the most effective files are dense and specific, not comprehensive.
A good project CLAUDE.md often looks something like this:
# Project: billing-api
## Commands
- Install: `pnpm install`
- Dev: `pnpm dev` (needs Postgres — `docker compose up db`)
- Test one file: `pnpm vitest run path/to/file.test.ts`
- Before finishing any task: `pnpm lint && pnpm test`
## Architecture
- `src/routes/` is thin: validate with Zod, call a service, return.
- Business logic lives in `src/services/`. Services never import from `routes/`.
- `src/legacy/` is frozen. Read it, never extend it.
## Rules
- Money is integer cents everywhere. Never use floats for amounts.
- Every schema change needs a migration: `pnpm db:migrate`, commit the file.
- Never push to `main`; open a PR.
Twenty lines, and nearly every one of them prevents a specific, realistic mistake.
Write rules, not essays
Instructions work better as short, direct statements than as paragraphs of reasoning. "Money is integer cents" beats a paragraph about floating-point precision. If the reason matters — because it helps Claude handle cases the rule doesn't cover — add it in one clause: "Money is integer cents (floats caused rounding bugs in invoices)."
Be specific about scope. "Don't use any" is ambiguous in a codebase that already has fifty. "Don't add new any types; leave existing ones alone unless the task is about them" is not.
And watch for contradictions. If two files disagree, Claude may follow either. Nested files and a user-level file make this easy to do by accident.
What doesn't belong in CLAUDE.md
- Secrets. It's committed and it's read into a model's context. Keys belong in environment variables.
- Things that must never happen.
CLAUDE.mdis context, not enforcement — Claude treats it as guidance. If a command must never run, block it with a permission deny rule or a hook. We cover those in Running Claude Code Unattended. - Documentation for humans. Your README explains the project to people.
CLAUDE.mdshould hold the operational knowledge an agent needs, and can import the README if it's genuinely useful. - Task-specific instructions. "Today we're refactoring the invoices module" belongs in the prompt, not the file every future session loads.
Maintaining it
Treat CLAUDE.md like code. The best trigger for an edit is a mistake: when Claude does something wrong that a sentence would have prevented, add the sentence. When a rule stops being true — the legacy module is finally deleted — remove it, because stale instructions actively mislead.
Review it in pull requests like anything else. It shapes every session anyone on the team runs.
The limit of what it can fix
A good CLAUDE.md solves session amnesia about knowledge: conventions, commands, decisions. It doesn't solve amnesia about state. If every session starts in a fresh environment, Claude still has to reinstall dependencies, restart the database, and reproduce the bug it had already narrowed down yesterday — no instruction file brings that back. We go into that distinction in Why Your AI Agent Keeps Forgetting.
The two fixes are complementary: write down what the agent should know, and give it an environment that keeps what it did.
EasySpawn gives Claude Code a persistent workspace per project — your CLAUDE.md, dependencies, database, and the agent's own notes all survive between sessions. See how it works or join the waitlist.
Related: Why Your AI Agent Keeps Forgetting · Running Claude Code Agents in Parallel With Git Worktrees
Keep reading
Running Claude Code Agents in Parallel With Git Worktrees
Two agents in one checkout will overwrite each other's work. Git worktrees give each Claude Code session its own files and branch on the same repository. How to set it up, and the parts nobody warns you about: ports, databases, and dependencies.
How to Use Claude Code From Your Phone: Every Option Compared
You can check on — and steer — a Claude Code session from your phone in at least four different ways. They differ in where the code runs, what happens when your laptop sleeps, and how much you can actually do on a small screen.