Complete Guide

How to Write a CLAUDE.md File
That Actually Works

The definitive guide to CLAUDE.md best practices. Real examples, common anti-patterns, and a checklist to audit your governance file.

Table of Contents

  1. What is a CLAUDE.md file?
  2. Essential sections every CLAUDE.md needs
  3. Writing effective hard constraints
  4. Stack-specific architecture rules
  5. Session modes and behavioral switches
  6. Common anti-patterns to avoid
  7. Real-world examples
  8. CLAUDE.md audit checklist

1. What is a CLAUDE.md File?

A CLAUDE.md file is a governance document placed at the root of your repository that instructs Claude Code how to behave in your project. It is automatically read by Claude Code at the start of every session.

Think of it as a combination of:

Without a CLAUDE.md, Claude Code operates with zero project context. It will guess at your conventions, make assumptions about your architecture, and frequently violate patterns you have carefully established. A well-written CLAUDE.md eliminates this entirely.

2. Essential Sections Every CLAUDE.md Needs

Project Identity

Start with a 2-3 sentence description of what the project is, who it serves, and the core tech stack. This gives Claude immediate context for every decision.

# FleetTracker Pro — CLAUDE.md

FleetTracker Pro is a B2B SaaS platform for fleet management.
Tech stack: Python/FastAPI backend, React/TypeScript frontend,
PostgreSQL via SQLAlchemy async. Deployed on AWS ECS.

Architecture Rules

Describe your patterns explicitly. Claude will follow whatever patterns it sees in your code, but if those patterns are inconsistent, it needs a source of truth.

## Architecture Rules

### Backend (Python/FastAPI)
- Follow service layer pattern: routers → services → repositories
- All database access through SQLAlchemy async — no raw SQL in handlers
- Pydantic models for ALL request/response schemas
- Structure: app/routers/, app/services/, app/models/, app/schemas/

Hard Constraints

The most important section. These are rules Claude must never violate, formatted as NEVER/WHY/INSTEAD blocks for maximum clarity.

Testing Requirements

Specify your test framework, coverage expectations, and what constitutes a valid test.

Git Discipline

Branch naming, commit message format, PR requirements.

3. Writing Effective Hard Constraints

Hard constraints are the single most impactful thing you can put in a CLAUDE.md. The format is critical — Claude responds best to the NEVER/WHY/INSTEAD pattern:

## Hard Constraints

```
NEVER: Modify migration files after they have been applied
WHY: Causes schema drift between environments, breaks rollbacks
INSTEAD: Create a new migration that modifies the schema

NEVER: Use string concatenation for SQL queries
WHY: SQL injection vulnerability
INSTEAD: Use parameterized queries via SQLAlchemy

NEVER: Commit .env files or hardcoded secrets
WHY: Credential exposure, security incident
INSTEAD: Use environment variables, reference .env.example

NEVER: Skip writing tests for new API endpoints
WHY: Regressions reach production
INSTEAD: Write at minimum one happy-path and one error test
```

DO: Be Specific

"NEVER use raw SQL in router handlers" is actionable. Claude knows exactly what to avoid and where.

DON'T: Be Vague

"Write clean code" gives Claude no signal. It already tries to write clean code. Tell it what YOUR definition of clean is.

DO: Explain Why

"WHY: Causes schema drift between environments" helps Claude understand the consequence and make better judgment calls in edge cases.

DON'T: Just Say No

"Don't do X" without a reason gets ignored when Claude thinks it has a good reason to do X.

4. Stack-Specific Architecture Rules

Generic rules produce generic code. The best CLAUDE.md files include rules that reference your exact tools, libraries, and patterns.

Python/FastAPI Example

### Backend Rules
- All routes use dependency injection for database sessions
- Services NEVER import from routers (dependency flows one way)
- Use `Depends(get_db)` for session management, never manual session creation
- Pydantic v2 model_validator for complex validation, not root_validator
- Background tasks via FastAPI BackgroundTasks, not raw threading

React/TypeScript Example

### Frontend Rules
- Components in src/components/, pages in src/pages/
- All API calls go through src/lib/api-client.ts — never fetch() directly
- Use TanStack Query for server state, Zustand for client state
- Co-locate tests: Button.tsx → Button.test.tsx in same directory
- No `any` types — use `unknown` and narrow, or define proper interfaces

Next.js Example

### Full-Stack Rules
- Server components by default, 'use client' only when needed
- API routes in app/api/ follow RESTful conventions
- Server actions for mutations, NOT API routes called from client
- Database queries ONLY in server components or server actions
- Use next/image for all images, never raw <img> tags

5. Session Modes and Behavioral Switches

Advanced CLAUDE.md files define session modes that change Claude's behavior based on what you are doing. This is a powerful pattern for large codebases.

## Session Modes

### MODE: implement
Default mode. Write code, follow architecture rules, write tests.
- Ask before making architectural changes
- Always create feature branches
- Run tests before suggesting commit

### MODE: refactor
Improve existing code without changing behavior.
- MUST maintain all existing tests passing
- No new features — only structural improvements
- Document every change in commit message

### MODE: debug
Investigate and fix a specific bug.
- Reproduce the bug FIRST, then fix
- Add a regression test that would have caught this bug
- Minimize blast radius — smallest possible change

### MODE: review
Review code without making changes.
- Read only — do not modify files
- Flag violations of Hard Constraints
- Suggest improvements with specific file:line references

You activate modes by telling Claude: "We're in refactor mode" at the start of a session. Claude then adjusts its behavior according to the mode rules.

6. Common Anti-Patterns to Avoid

Anti-Pattern: The Novel

CLAUDE.md files longer than ~500 lines start losing effectiveness. Claude has a context window, and a 2000-line governance file crowds out the actual code. Be concise. If you need extended documentation, link to it.

Anti-Pattern: The Wish List

"It would be nice if Claude did X" is not a governance rule. Every line in your CLAUDE.md should be a directive, not a suggestion. Use imperative mood: "Use X", "Never do Y", "Always check Z".

Anti-Pattern: Copy-Pasted Generic Rules

"Follow SOLID principles" adds zero value. Claude already knows SOLID. Your CLAUDE.md should contain things Claude cannot infer from your code — like which service talks to which database, why that one weird table exists, or that the auth system is fragile and should not be touched without tests.

Anti-Pattern: No Hard Constraints

If your CLAUDE.md has zero NEVER blocks, it is a suggestion document, not a governance document. Hard constraints are the highest-value section. Start there.

Anti-Pattern: Stale Information

A CLAUDE.md that references a database you migrated away from 6 months ago actively misleads Claude. Treat it like code — update it when the system changes.

7. Real-World Example

Here is a minimal but effective CLAUDE.md for a Next.js SaaS application:

# Acme Dashboard — CLAUDE.md

## Project Identity
Acme Dashboard is a B2B analytics SaaS. Next.js 14 (App Router),
TypeScript, Prisma ORM, PostgreSQL on Neon, deployed to Vercel.

## Architecture
- app/ directory structure with route groups: (auth), (dashboard), (marketing)
- Server components default, 'use client' only for interactive elements
- Database queries through Prisma client in lib/db.ts — never raw SQL
- Auth via NextAuth.js v5 with Google OAuth + email magic links
- Payments via Stripe with webhook handler in app/api/webhooks/stripe/

## Hard Constraints
```
NEVER: Query the database from client components
WHY: Exposes connection string, bypasses server-side auth checks
INSTEAD: Use server components, server actions, or API routes

NEVER: Modify the Stripe webhook handler without testing locally first
WHY: Broken webhooks = lost revenue, silent failures
INSTEAD: Use stripe listen --forward-to localhost:3000/api/webhooks/stripe

NEVER: Add 'use client' to a component unless it uses hooks, event handlers, or browser APIs
WHY: Client components break streaming, increase bundle size
INSTEAD: Keep components server-side, extract interactive parts into small client islands

NEVER: Skip Prisma migrations — don't use db push in production
WHY: db push can drop data, migrations are auditable
INSTEAD: npx prisma migrate dev to create, npx prisma migrate deploy in CI
```

## Testing
- Vitest for unit tests, Playwright for E2E
- Run: `npm test` (unit), `npm run test:e2e` (E2E)
- New API routes require at minimum one test

## Known Fragile Areas
1. **Auth session refresh** — race condition under high load, extra tests needed
2. **Stripe webhook idempotency** — must check event ID before processing
3. **Dashboard chart queries** — slow on large datasets, always paginate

CLAUDE.md Audit Checklist

Click each item to check it off. Use this to audit your existing CLAUDE.md or verify a new one.

Want a production-grade CLAUDE.md in 30 seconds?

The premium generator creates 300+ line governance files with session modes, failure pattern detection, self-evolution hooks, and stack-specific rules calibrated on real production systems.

Get Premium Generator — $9.99

Or try the free version first:

Free CLAUDE.md Generator