How to Write a CLAUDE.md (Project Prompt for Claude Code)

CLAUDE.md is the instruction file Claude Code loads every session. What to put in it, where to place it, and how it loads — verified against the June 2026 docs.

TL;DR

CLAUDE.md is a plain-Markdown instruction file that Claude Code loads at the start of every session and re-reads after /compact. Put a project file at ./CLAUDE.md (or ./.claude/CLAUDE.md), commit it, and keep it under 200 lines. Cover five things: build/test/lint commands, conventions, forbidden paths, project layout, and “always do X” rules. Generate a first draft with /init, then refine. As of June 2026, Claude Code also keeps auto memory (notes it writes itself), so you no longer hand-write everything — and the old # “add to memory” shortcut is gone.

What CLAUDE.md actually is

It is not a README for humans. According to the official Claude Code memory docs, CLAUDE.md content is delivered as a user message right after the system prompt, then loaded into the context window at the start of every session. So it is durable context, not enforced configuration: Claude reads it and tries to follow it, but there is no hard guarantee. The more specific and concise the instructions, the more reliably they stick.

That single fact drives every rule below. Because it competes for tokens with your actual conversation, and because vague lines get skimmed, the goal is a short file of concrete, verifiable rules — not a wiki.

This guide is for engineers running Claude Code on a real project who keep hitting the same friction: it ignores your import order, edits files you said to leave alone, runs the wrong test command, or rewrites idioms it should have followed.

Two memory systems, June 2026

Claude Code has shipped two complementary memory mechanisms, and they are both loaded at the start of every conversation. Knowing which is which decides what you should write by hand.

CLAUDE.md filesAuto memory
Who writes itYouClaude
ContainsInstructions and rulesLearnings Claude discovered
ScopeProject, user, or orgPer git repository
LoadedIn full, every sessionFirst 200 lines / 25 KB of MEMORY.md, every session
Best forStandards, workflows, architectureBuild commands, debug insights, preferences it picks up

Auto memory requires Claude Code v2.1.59 or later (check with claude --version) and is on by default. It lives at ~/.claude/projects/<project>/memory/, keyed off the git repo, so all worktrees in the same repo share it. When you see “Writing memory” or “Recalled memory” in the UI, that is auto memory, not your CLAUDE.md. Browse or disable it with /memory, or set CLAUDE_CODE_DISABLE_AUTO_MEMORY=1.

Practical upshot: do not spend CLAUDE.md lines on things Claude reliably learns after one session. Reserve the file for what it would otherwise re-derive or get wrong every time.

Where the file goes (and the load order)

CLAUDE.md can live at several scopes. They are concatenated, not overridden, in this load order — broadest first, so the most specific instruction is read last and wins ties:

ScopeLocationCommitted?
Managed policy (org)macOS /Library/Application Support/ClaudeCode/CLAUDE.md; Linux/WSL /etc/claude-code/CLAUDE.md; Windows C:\Program Files\ClaudeCode\CLAUDE.mdPushed by IT/MDM
User (personal)~/.claude/CLAUDE.mdNo (your machine)
Project (team)./CLAUDE.md or ./.claude/CLAUDE.mdYes, via source control
Local (private)./CLAUDE.local.mdNo — add to .gitignore

Claude walks up the directory tree from your working directory and loads every CLAUDE.md and CLAUDE.local.md it finds along the way, in full, at launch. Files in subdirectories below you are loaded on demand, only when Claude reads a file in that subdirectory. Within a directory, CLAUDE.local.md is appended after CLAUDE.md, so your personal notes are read last at that level.

For a monorepo, that means a root CLAUDE.md with global rules plus a per-package frontend/CLAUDE.md or services/api/CLAUDE.md for stack-specific rules. If an ancestor file from another team leaks in, exclude it with claudeMdExcludes in .claude/settings.local.json (glob patterns against absolute paths).

Generate the first draft with /init

Do not start from a blank file. Run /init in the repo: Claude analyzes the codebase and writes a starting CLAUDE.md with the build commands, test instructions, and conventions it can detect. If a CLAUDE.md already exists, /init suggests improvements instead of overwriting. It also reads existing AGENTS.md, .cursorrules, .devin/rules/, and .windsurfrules and folds the relevant parts in. Setting CLAUDE_CODE_NEW_INIT=1 enables an interactive multi-phase flow that asks follow-up questions and shows a reviewable proposal before writing.

Treat the generated file as a draft. The high-value content is what /init cannot discover: your unwritten conventions, forbidden paths, and the mistakes you are tired of correcting.

What to actually put in it

Five sections carry almost all the value. Keep each rule concrete enough to verify, with a tiny example.

  1. Project summary — 3 to 5 sentences: what it is, primary entry points. Example: Next.js 15 app, App Router, deployed via Vercel. Entry: app/page.tsx. Background jobs: lib/jobs/*.ts.
  2. Build / test / lint commands — the single most valuable section. Without it, Claude tries npm test when you use pnpm test --run and burns turns debugging. Be exact: Test: pnpm test --run. Lint: pnpm lint. Type: pnpm typecheck. Run all three before declaring a task done.
  3. Conventions, each with an example — “Use named exports, no default exports” beats “write clean code.” The docs’ own benchmark: “Use 2-space indentation” works; “format code properly” does not.
  4. Forbidden paths — be explicit: Do not edit src/generated/*, prisma/migrations/*, or any file matching *.gen.ts. Claude honors this well.
  5. Per-task hints — a short “When asked to add a route” block naming the files to touch and the order. Same for components, migrations, and tests.

Keep a small “Corrections” section at the bottom and add a line whenever you catch the agent drifting. Block-level HTML comments (<!-- maintainer note -->) are stripped before the content reaches Claude, so use them for human-only notes without spending context tokens.

Stay under 200 lines

The docs target under 200 lines per CLAUDE.md file. Longer files consume more context and measurably reduce adherence — rules at the bottom get skimmed. When it grows, you have three options that beat a giant file:

  • Path-scoped rules. Put topic files in .claude/rules/ (for example testing.md, security.md). Add a paths: frontmatter glob like "src/api/**/*.ts" and the rule only loads when Claude touches matching files, saving context the rest of the time. Rules without paths load every session at the same priority as .claude/CLAUDE.md.
  • Imports. Reference other files with @path/to/file syntax anywhere in CLAUDE.md. Relative paths resolve against the importing file; recursion is capped at four hops. Note: imports help organization but not context size, since imported files still load at launch.
  • Skills. Move multi-step procedures into a skill, which only loads when invoked or judged relevant — not on every session.

Reuse AGENTS.md instead of duplicating

Claude Code reads CLAUDE.md, not AGENTS.md. If your repo already keeps an AGENTS.md for other agents, do not copy it. Create a one-line CLAUDE.md that imports it, then add Claude-specific lines below:

@AGENTS.md

## Claude Code
Use plan mode for changes under `src/billing/`.

A symlink (ln -s AGENTS.md CLAUDE.md) also works when you have nothing Claude-specific to add; on Windows use the @AGENTS.md import since symlinks need Administrator rights.

Editing memory mid-session

The old # prefix that prepended a line to memory was removed. As of June 2026 you have two clean paths: run /memory to list every loaded CLAUDE.md, CLAUDE.local.md, and rules file and open any of them in your editor, or just tell Claude “add this to CLAUDE.md” in chat. Asking Claude to “remember” something without naming the file routes it to auto memory instead.

When CLAUDE.md is not the right tool

CLAUDE.md shapes behavior; it does not enforce it. If a rule must run at a fixed point — before every commit, after every edit — write a hook instead. Hooks execute as shell commands at lifecycle events regardless of what Claude decides, so “block edits to migrations/” or “run make lint before commit” belong there, not in prose. To force an instruction into the system prompt itself, pass --append-system-prompt (better for scripts than interactive use).

First-run exercise

  1. Skim a recent PR you reviewed in this repo. Write down your top 3 nitpicks.
  2. Convert each into a one-sentence rule in CLAUDE.md, with a tiny example.
  3. Run a small Claude Code task that touches similar code. Confirm it follows the rules.
  4. If it ignored one, sharpen the wording (concrete example beats abstract principle) and re-run.

Quality check before you commit

  • Run /memory and confirm the file is actually listed as loaded. If it is not there, Claude cannot see it.
  • Is it under 200 lines and roughly one to two screens?
  • Are commands copy-pasteable exactly as written? “run tests” confuses; pnpm test --run does not.
  • Does each rule carry a concrete example? Abstract rules regress.
  • Scan for contradictions across your root, nested, and .claude/rules/ files — conflicting guidance gets resolved arbitrarily.

FAQ

  • How long should CLAUDE.md be? Target under 200 lines. The file loads in full regardless of length, but longer files consume more context and reduce adherence; rules at the bottom get skimmed.
  • Why isn’t Claude following my CLAUDE.md? Most often the file is not loaded (check with /memory), the rule is too vague, or two files conflict. CLAUDE.md is context, not enforcement — for must-run rules use a hook.
  • Should secrets go in CLAUDE.md? No. It is committed source. Reference env var names, not values. Put personal, gitignored bits in CLAUDE.local.md.
  • What’s the difference between CLAUDE.md and auto memory? You write CLAUDE.md (standards, rules). Claude writes auto memory (build commands, debug insights it discovers). Both load every session; auto memory needs v2.1.59+ and is on by default.
  • Do nested CLAUDE.md files survive /compact? The project-root file is re-read from disk after compaction. Nested subdirectory files are not re-injected automatically — they reload the next time Claude reads a file in that subdirectory.
  • Do I need one for a solo project? Even a 15-line file helps. Without it, Claude re-derives your conventions every session.

Common mistakes

  • Writing it once and never updating — agent behavior shifts and the file goes stale. Add a line each time you correct the same thing twice.
  • Vague constraints (“write clean code”) instead of verifiable ones (“named exports, no default exports”).
  • Letting it grow past 200 lines instead of moving topics into .claude/rules/ or skills.
  • Mixing human-onboarding content with agent rules — keep README.md and CLAUDE.md separate.
  • Omitting forbidden paths — the agent will eventually edit generated code if you do not say not to.
  • Skipping the exact test/lint/build commands — the agent guesses, often wrongly.
  • Hand-writing things auto memory already learned — wasted lines. Run /memory to see what it figured out on its own.

Tags: #AI coding #Tutorial #Claude Code