Skip to main content

The Complete Guide to Writing a Great CLAUDE.md

A practical, research-backed reference for writing CLAUDE.md files that Claude Code actually follows. Compiled from Anthropic's official docs and field-tested community practices.


1. What CLAUDE.md Is (and Isn't)

CLAUDE.md is a plain markdown file that gives Claude persistent instructions for a project, your personal workflow, or your whole organization. Claude reads it at the start of every session and injects it into the context window.

Key mental model:

  • It is context, not enforced configuration. Claude reads it and tries to follow it — there is no guarantee of strict compliance, especially for vague or conflicting instructions.
  • It is delivered as a user message after the system prompt, not as part of it.
  • If you need something to run always, at a fixed point (e.g. before every commit), use a hook, not CLAUDE.md.
  • If you need to hard-block a tool/command/path, use managed settings (permissions.deny), not CLAUDE.md.

Rule of thumb: CLAUDE.md shapes behavior. Hooks and settings enforce it.


2. The Golden Rules

  1. Keep it under 200 lines (~300 is the absolute ceiling). It loads every session and consumes context budget that could go to your actual code. Many strong examples are under 60 lines.
  2. Every line must earn its place — it should prevent a mistake or save a repeated explanation.
  3. Be specific and verifiable. "Use 2-space indentation" beats "format code properly."
  4. Write imperative commands, not observations. "Never use inline mocks — use src/test/factories/*" beats "we generally try to avoid inline mocks."
  5. Negative rules matter as much as positive ones. "Never commit .env", "No class components", "No SSR." Without them, Claude defaults to the most common pattern it knows — which may not be yours.
  6. Don't make a linter's job an LLM's job. Use deterministic tools (linters, formatters) for style enforcement; they're faster, cheaper, and reliable.
  7. Use emphasis sparingly. IMPORTANT and YOU MUST genuinely improve adherence — but only if rare. Mark everything important and nothing is.
  8. Resolve contradictions. If two rules conflict, Claude picks one arbitrarily. Review periodically.

Why the line limit matters

Frontier thinking models can reliably follow roughly 150–200 instructions total. Claude Code's own system prompt already uses ~50 of those. Instruction-following degrades as the count grows — so every instruction you add competes with the rest for attention. Smaller/non-thinking models follow fewer still.


3. File Locations & Load Order

CLAUDE.md files can live in several places. They are concatenated (not overridden), loaded from broadest to most specific scope — so more specific instructions are read last and take priority.

ScopeLocationPurposeShared with
Managed policymacOS: /Library/Application Support/ClaudeCode/CLAUDE.md · Linux/WSL: /etc/claude-code/CLAUDE.md · Windows: C:\Program Files\ClaudeCode\CLAUDE.mdOrg-wide standards, security/complianceAll users in org (cannot be excluded)
User~/.claude/CLAUDE.mdYour personal prefs across all projectsJust you, all projects
Project./CLAUDE.md or ./.claude/CLAUDE.mdTeam-shared project instructionsTeam via version control
Local./CLAUDE.local.mdPersonal project-specific prefs (gitignore it)Just you, current project

Directory walk: Claude walks up the tree from your working directory, loading every CLAUDE.md / CLAUDE.local.md it finds. Content is ordered root → working dir, so instructions closest to where you launched are read last. Within a directory, CLAUDE.local.md is appended after CLAUDE.md.

Subdirectories: Nested CLAUDE.md files below your working dir are not loaded at launch — they load on demand when Claude reads files in those directories.

Filename is case-sensitive: exactly CLAUDE.md (uppercase CLAUDE, lowercase .md).


4. What to Put In It

Cover these, roughly in order of impact:

a. Build / Test / Lint commands

Claude does not know how to build, test, or lint your project. Tell it explicitly. Without this it'll try npm test when you use pnpm vitest and burn turns failing.

## Commands
- Build: `pnpm build`
- Test: `pnpm vitest run`
- Lint: `pnpm lint --fix`
- Typecheck: `pnpm tsc --noEmit`

b. Coding rules (positive AND negative)

## Code style
- TypeScript strict mode; never use `any`
- Named exports only, no default exports
- Use the project logger, never `console.log`
- Tailwind utility classes only — no inline styles

c. Architecture / project layout

Give Claude a map, especially in monorepos.

## Layout
- API handlers live in `src/api/handlers/`
- Shared types in `packages/types/`
- Never edit generated files in `src/gen/`

d. Gotchas & non-obvious constraints

## Gotchas
- API tests require a local Redis instance (`docker compose up redis`)
- The legacy `v1/` routes are frozen — do not refactor them

The WHAT / WHY / HOW framework

A useful structure to sanity-check coverage:

  • WHAT — tech stack (with version numbers!), project structure, codebase map
  • WHY — project purpose and goals
  • HOW — build commands, testing, verification

Claude can't guess your framework version. State it. "React 19", "Node 22", "Python 3.12".


5. What to Leave Out

  • ❌ Style rules a linter/formatter already enforces.
  • ❌ Task-specific or one-off instructions that don't apply universally → use a skill.
  • ❌ Multi-step procedures or rules that only matter for one part of the codebase → use a path-scoped rule or skill.
  • ❌ Duplicated authoritative info (full README, schema dumps). Link to it instead.
  • ❌ "Hotfix" entries added to patch one bad session. Treat root cause, not symptom.

6. Keeping It Lean: Imports & Progressive Disclosure

@ imports

Pull in other files with @path/to/file:

See @README for the overview and @package.json for npm commands.

# Workflow
- Git conventions: @docs/git-instructions.md
  • Relative paths resolve from the importing file. Recursive imports allowed, max depth 4.
  • Caveat: imported files still load into context at launch — imports help organization, not context size.

Progressive disclosure

Keep the main file lean; point Claude to detail docs it can read on demand:

agent_docs/
├── building_the_project.md
├── running_tests.md
├── code_conventions.md
└── service_architecture.md

Reference each with a one-line description and let Claude decide which to open.

Prefer file:line references over code snippets

Pointing to src/api/handlers/user.ts:42 won't go stale the way a pasted snippet will.

Maintainer comments are free

Block-level HTML comments (<!-- note to humans -->) are stripped before entering Claude's context — use them for human-only notes without spending tokens. (Comments inside code blocks are preserved.)


7. Scaling Up: .claude/rules/

For larger projects, split instructions into topic files under .claude/rules/. One topic per file.

your-project/
├── .claude/
│ ├── CLAUDE.md
│ └── rules/
│ ├── code-style.md
│ ├── testing.md
│ └── security.md
  • Rules without paths frontmatter load every session (same priority as .claude/CLAUDE.md).
  • Path-scoped rules load only when Claude touches matching files — saving context:
---
paths:
- "src/api/**/*.{ts,tsx}"
- "tests/**/*.test.ts"
---
# API rules
- All endpoints must validate input
- Use the standard error response format
PatternMatches
**/*.tsAll TS files anywhere
src/**/*Everything under src/
*.mdMarkdown in project root
  • Rules can be symlinked to share across projects.
  • User-level rules live in ~/.claude/rules/ (loaded before project rules, so project wins).

8. CLAUDE.md vs Auto Memory vs Skills vs Hooks

MechanismWho writes itWhen it loadsUse for
CLAUDE.mdYouEvery session, in fullStandards, workflows, architecture
Auto memory (MEMORY.md + topic files)ClaudeEvery session (first 200 lines / 25KB of MEMORY.md)Learnings, debugging insights, discovered prefs
SkillsYouOn demand when relevant/invokedRepeatable multi-step procedures
Rules (.claude/rules/)YouEvery session, or when matching files openModular/path-scoped standards
HooksYouFixed lifecycle events (shell commands)Things that MUST run, regardless of Claude's choice
Managed settingsIT/adminAlways enforced by clientHard blocks: deny tools/paths, sandbox, auth

When you tell Claude "always use pnpm, not npm," it saves that to auto memory. To put it in CLAUDE.md instead, say "add this to CLAUDE.md."

AGENTS.md interop

Claude Code reads CLAUDE.md, not AGENTS.md. If your repo uses AGENTS.md, create a CLAUDE.md that imports it:

@AGENTS.md

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

9. Bootstrapping & Maintenance

Start with /init

Run /init in your project root. Claude analyzes the codebase and drafts a CLAUDE.md with discovered commands, tests, and conventions. Always review it — cut the obvious, add what Claude can't discover (your team's actual conventions, gotchas, the why). Starting from /init beats a blank file; shipping /init output unreviewed does not.

Grow it organically

Add an entry when:

  • Claude makes the same mistake a second time
  • A code review catches something Claude should have known
  • You type the same correction you typed last session
  • A new teammate would need the same context

Prune it regularly

Every few weeks, ask Claude to review and optimize the file: remove obsolete rules, consolidate redundancy, resolve conflicts. Instructions accumulate and decay.


10. Troubleshooting

"Claude isn't following my CLAUDE.md"

  • Run /memory to confirm the file is actually loaded (if it's not listed, Claude can't see it).
  • Make instructions more specific and verifiable.
  • Hunt for contradictions across nested files and rules.
  • If it must run at a fixed point → convert to a hook.
  • For system-prompt-level instructions → --append-system-prompt (must pass every invocation; best for scripts).

"My CLAUDE.md is too large"

  • Trim to what's needed every session.
  • Move conditional content to path-scoped rules.
  • Note: @ imports help organization but don't reduce context.

"Instructions seem lost after /compact"

  • Project-root CLAUDE.md is re-injected after compaction. Nested subdirectory files reload only when Claude next reads a file there.
  • If something vanished, it was likely conversation-only — add it to CLAUDE.md to persist.

Debug what's loaded: use the InstructionsLoaded hook to log exactly which instruction files load, when, and why.


11. Quick Checklist

  • Under 200 lines
  • One-line project description + tech stack with versions
  • Build / test / lint / typecheck commands
  • Positive and negative coding rules
  • Architecture / file-layout map
  • Non-obvious gotchas
  • Every instruction specific and verifiable
  • IMPORTANT/YOU MUST used sparingly
  • No linter-replaceable style rules
  • No contradictions
  • Detail offloaded to imports / rules / skills
  • Reviewed (not raw /init output)

12. Minimal Template

# <Project Name>

<One-line description.> Stack: <e.g. Next.js 15, React 19, TypeScript 5.6, Postgres>.

## Commands
- Dev: `pnpm dev`
- Build: `pnpm build`
- Test: `pnpm vitest run`
- Lint: `pnpm lint --fix`
- Typecheck: `pnpm tsc --noEmit`

## Code style
- TypeScript strict; never `any`
- Named exports only
- Use `logger`, never `console.log`

## Architecture
- API handlers: `src/api/handlers/`
- Shared types: `packages/types/`
- Never edit generated code in `src/gen/`

## Rules
- IMPORTANT: Never commit secrets or `.env*` files
- Run `pnpm test` before committing
- No new dependencies without justification

## Gotchas
- Integration tests need local Redis: `docker compose up -d redis`

See @README.md for full overview. Detailed conventions: @docs/conventions.md

Sources