How to Write a CLAUDE.md That Actually Works
You asked Claude Code to add a new API endpoint. It created the file in the wrong directory, used Jest instead of Vitest, forgot your authentication middleware, and ignored your naming conventions. You spent 20 minutes fixing what should have taken 5 minutes to write by hand.
The problem is not the AI. The problem is that you dropped an agent into your codebase with zero context and expected it to read your mind.
That is what CLAUDE.md fixes.
What CLAUDE.md Is
CLAUDE.md is a markdown file you place in the root of your repository (or in a .claude/ directory). When Claude Code starts a session, it reads this file automatically and treats its contents as project-level instructions. Think of it as a README for your AI pair programmer.
You already write onboarding docs for new developers. CLAUDE.md serves the same purpose, but optimized for an agent that needs to know your build commands, directory structure, testing setup, and the landmines to avoid.
The file follows no rigid schema. It is plain markdown. But what you put in it, and how you structure it, determines whether Claude Code acts like a junior developer on day one or a teammate who has read the internal wiki.
Why It Matters More Than You Think
Without a CLAUDE.md, every AI coding session starts from scratch. The agent has to infer your tech stack from package.json, guess your directory conventions from existing files, and hope that your test runner works the way it expects.
This leads to predictable failures:
- Wrong build commands. The agent runs
npm testwhen you usepnpm vitest run. - Wrong file locations. It creates a new component in
src/components/when your project usesapp/features/{feature}/components/. - Wrong patterns. It writes a class component in a codebase that exclusively uses hooks. It adds default exports when you use named exports everywhere.
- Dangerous edits. It modifies a shared utility function used by 40 other files without understanding the blast radius.
A good CLAUDE.md eliminates these problems. In our experience building AI agents at Kerex, the difference between a repo with solid agent instructions and one without is the difference between a 90% success rate and a 40% success rate on coding tasks.
The Six Sections Every Good CLAUDE.md Needs
After analyzing hundreds of repositories and watching where AI agents succeed and fail, we have identified six sections that belong in every CLAUDE.md.
1. Project Overview
Tell the agent what it is working on. This sounds obvious, but most CLAUDE.md files skip it entirely.
What to include:
- What the project does (one to two sentences)
- The primary language and framework
- Whether it is a monorepo, a library, or a standalone application
- Any critical context (e.g., "this is a B2B SaaS product" or "this is an open source CLI tool")
Example:
## Project Overview
This is a Next.js 14 SaaS application for managing restaurant reservations.
It uses the App Router, Server Components, and connects to a PostgreSQL
database via Prisma. The frontend uses React with TypeScript. This is a
monorepo managed by Turborepo.
Common mistake: Writing a paragraph of marketing copy. The agent does not need to know your company's mission statement. Keep it to the facts that affect code decisions.
2. Tech Stack and Build Commands
This is the most impactful section. An agent that knows how to build, lint, and test your project can verify its own work. An agent that does not know these commands will produce code it has never validated.
What to include:
- Package manager and version
- Build command
- Dev server command
- Lint command
- Type check command
- Test command (specify the runner)
- Any other commands the agent might need
Example:
## Tech Stack & Build Commands
- **Runtime:** Node.js 20
- **Package manager:** pnpm 9
- **Framework:** Next.js 14 (App Router)
- **Database:** PostgreSQL 16 + Prisma ORM
- **Styling:** Tailwind CSS v4
### Commands
| Task | Command |
|------|---------|
| Install deps | `pnpm install` |
| Dev server | `pnpm dev` |
| Build | `pnpm build` |
| Type check | `pnpm tsc --noEmit` |
| Lint | `pnpm lint` |
| Test all | `pnpm vitest run` |
| Test single file | `pnpm vitest run src/lib/pricing.test.ts` |
| DB migrate | `pnpm prisma migrate dev` |
| DB generate | `pnpm prisma generate` |
Common mistake: Listing the tech stack but not the commands. The agent does not benefit from knowing you use Vitest if it does not know the exact invocation.
3. Architecture and Directory Map
AI agents are surprisingly bad at figuring out where files go. A flat src/ directory is fine, but the moment you have feature-based folders, a packages/ directory, or any non-obvious structure, you need to spell it out.
What to include:
- Top-level directory structure with brief descriptions
- Where new files of each type should be created
- Any important files the agent should know about
Example:
## Architecture & Directory Map
app/ # Next.js App Router pages and layouts (auth)/ # Auth-related routes (grouped) (dashboard)/ # Dashboard routes (grouped) api/ # API route handlers src/ lib/ # Shared utilities and business logic components/ ui/ # Generic UI components (Button, Modal, etc.) features/ # Feature-specific components hooks/ # Custom React hooks types/ # TypeScript type definitions db/ # Prisma schema and seed scripts packages/ email/ # Email template package shared/ # Shared types between frontend and backend
### Where to put new files
- New API routes: `app/api/{resource}/route.ts`
- New pages: `app/(dashboard)/{page}/page.tsx`
- New UI components: `src/components/ui/{ComponentName}.tsx`
- New feature components: `src/components/features/{feature}/{ComponentName}.tsx`
- New hooks: `src/hooks/use{Name}.ts`
- Database changes: modify `src/db/schema.prisma`, then run `pnpm prisma migrate dev`
Common mistake: Showing the full output of tree with 200 files. The agent needs a curated map, not an exhaustive listing. Highlight the directories that matter for decision-making.
4. Testing Instructions
This section prevents the agent from writing tests that do not match your patterns, or worse, writing no tests at all.
What to include:
- Test runner and configuration
- Where test files live (colocated, separate
__tests__directory, etc.) - Naming conventions for test files
- How to run a single test
- Any setup requirements (env variables, test databases, seed data)
- Mocking conventions
Example:
## Testing
- **Runner:** Vitest
- **Test location:** Colocated with source files (`*.test.ts` or `*.test.tsx`)
- **Naming:** `{filename}.test.ts` (unit), `{filename}.integration.test.ts` (integration)
### Running tests
- All tests: `pnpm vitest run`
- Single file: `pnpm vitest run src/lib/pricing.test.ts`
- Watch mode: `pnpm vitest`
### Conventions
- Use `describe` / `it` blocks (not `test`)
- Mock external services with `vi.mock()`, never make real HTTP calls in tests
- Database tests use a test database seeded by `src/db/test-seed.ts`
- Prefer `userEvent` over `fireEvent` in component tests
Common mistake: Saying "we use Vitest" and nothing else. The agent needs to know your mocking conventions, file naming, and how to run individual tests. Without this, it will default to patterns from its training data, which may not match yours.
5. Code Conventions
This is where you encode the style guide that lives in your team's heads. Every team has unwritten rules. Write them down here.
What to include:
- Import style (named vs default exports, path aliases)
- Component patterns (functional only, specific hook patterns)
- Error handling approach
- Naming conventions
- Any patterns to always use or always avoid
Example:
## Code Conventions
- **Exports:** Use named exports everywhere. No default exports except for Next.js pages.
- **Imports:** Use the `@/` path alias for all imports from `src/`. Example: `import { Button } from "@/components/ui/Button"`
- **Components:** Functional components only. Use `interface` for props (not `type`). Props interface must be named `{Component}Props`.
- **Error handling:** All API routes must use the `withErrorHandler` wrapper from `@/lib/api-utils`. Never return raw error messages to the client.
- **Naming:**
- Files: `kebab-case.ts` for utilities, `PascalCase.tsx` for components
- Variables/functions: `camelCase`
- Types/interfaces: `PascalCase`
- Constants: `SCREAMING_SNAKE_CASE`
- **State management:** Use React Context for global state. No Redux. No Zustand.
- **Data fetching:** Use Server Components for initial data. Use `useSWR` for client-side fetching.
### Do NOT
- Do not use `any` type. Use `unknown` and narrow with type guards.
- Do not use `console.log` in production code. Use the logger from `@/lib/logger`.
- Do not modify files in `packages/shared` without discussing the change first.
Common mistake: Being too vague. "Write clean code" tells the agent nothing. "Use named exports, not default exports" gives it a clear rule to follow.
6. High-Risk Areas
Every codebase has files and modules where a careless change can break everything. Flag them.
What to include:
- Files or directories that should not be modified without careful review
- Shared utilities or types that are widely imported
- Configuration files that affect the entire build
- Database migrations (which are append-only)
- Any modules with known gotchas
Example:
## High-Risk Areas
- **`src/lib/auth.ts`** - Authentication logic. Changes here affect every protected route. Do not modify without thorough testing.
- **`src/db/schema.prisma`** - Database schema. Migrations are irreversible in production. Always create a new migration, never edit existing ones.
- **`packages/shared/types.ts`** - Shared types used by both frontend and backend. Changes here require rebuilding both packages.
- **`next.config.js`** - Build configuration. Incorrect changes here will break the production build.
- **`src/middleware.ts`** - Request middleware. Runs on every request. Performance-sensitive.
- **Environment variables** - Never hardcode secrets. All env vars must go through `src/lib/env.ts` which validates them at startup.
Common mistake: Not having this section at all. This is the one that prevents the really expensive mistakes, the ones where the agent "helpfully" refactors your auth middleware and breaks login for every user.
Complete Template: TypeScript / Node.js Project
Copy this into a file called CLAUDE.md (or .claude/CLAUDE.md) at the root of your repo and fill in the blanks.
# Project Instructions
## Project Overview
<!-- One to two sentences: what does this project do? -->
<!-- Primary language, framework, and project type (monorepo, library, app) -->
## Tech Stack & Build Commands
- **Runtime:** Node.js XX
- **Package manager:** npm | pnpm | yarn
- **Framework:** Express | Next.js | Fastify | NestJS
- **Database:** PostgreSQL | MongoDB | SQLite
- **ORM:** Prisma | Drizzle | TypeORM | Knex
### Commands
| Task | Command |
|------|---------|
| Install | `npm install` |
| Dev | `npm run dev` |
| Build | `npm run build` |
| Type check | `npx tsc --noEmit` |
| Lint | `npm run lint` |
| Test | `npm test` |
| Test single | `npx vitest run path/to/file.test.ts` |
## Architecture & Directory Map
```
src/
# describe your directory structure here
```
### Where to put new files
- API routes: `...`
- Components: `...`
- Utilities: `...`
- Types: `...`
- Tests: `...`
## Testing
- **Runner:** Vitest | Jest
- **Location:** colocated | `__tests__/` | `test/`
- **Naming:** `*.test.ts` | `*.spec.ts`
- **Run single test:** `...`
- **Mocking:** `vi.mock()` | `jest.mock()`
### Conventions
- <!-- describe block style, mocking approach, etc. -->
## Code Conventions
- **Exports:** named | default
- **Imports:** path aliases? style?
- **Components:** functional only? hooks patterns?
- **Error handling:** how?
- **Naming:** files, variables, types, constants
### Do NOT
- <!-- list things the agent should never do -->
## High-Risk Areas
- **`path/to/critical/file`** - why it is high-risk
- <!-- list other high-risk areas -->
Complete Template: Python Project
# Project Instructions
## Project Overview
<!-- One to two sentences: what does this project do? -->
<!-- Python version, framework, project type -->
## Tech Stack & Build Commands
- **Python version:** 3.11+
- **Package manager:** pip | poetry | uv
- **Framework:** FastAPI | Django | Flask
- **Database:** PostgreSQL | SQLite
- **ORM:** SQLAlchemy | Django ORM | Tortoise
### Commands
| Task | Command |
|------|---------|
| Install | `pip install -e ".[dev]"` |
| Dev server | `uvicorn app.main:app --reload` |
| Lint | `ruff check .` |
| Format | `ruff format .` |
| Type check | `mypy src/` |
| Test all | `pytest` |
| Test single | `pytest tests/test_auth.py -v` |
| Test with coverage | `pytest --cov=src` |
## Architecture & Directory Map
```
src/
app/
# describe your directory structure here
tests/
# describe test structure
```
### Where to put new files
- API routes: `src/app/routers/{resource}.py`
- Models: `src/app/models/{model}.py`
- Schemas: `src/app/schemas/{schema}.py`
- Services: `src/app/services/{service}.py`
- Tests: `tests/test_{module}.py`
## Testing
- **Runner:** pytest
- **Location:** `tests/` directory, mirroring `src/` structure
- **Naming:** `test_{module}.py` with functions named `test_{behavior}`
- **Fixtures:** defined in `tests/conftest.py`
- **Run single test:** `pytest tests/test_auth.py::test_login_success -v`
### Conventions
- <!-- fixture usage, mocking approach, factory patterns -->
## Code Conventions
- **Imports:** stdlib, then third-party, then local (enforced by ruff)
- **Type hints:** required on all function signatures
- **Docstrings:** Google style, required on public functions
- **Error handling:** raise custom exceptions from `app/exceptions.py`, caught by middleware
- **Naming:**
- Files/modules: `snake_case.py`
- Classes: `PascalCase`
- Functions/variables: `snake_case`
- Constants: `SCREAMING_SNAKE_CASE`
- **Models:** use Pydantic v2 `model_validator` not `validator`
### Do NOT
- Do not use `print()`. Use the logger from `app.core.logging`.
- Do not use `*` imports.
- Do not write raw SQL. Use the ORM.
- <!-- list other prohibitions -->
## High-Risk Areas
- **`src/app/core/auth.py`** - Authentication logic. Changes affect all protected endpoints.
- **`alembic/versions/`** - Database migrations. Never edit existing migrations.
- **`src/app/middleware/`** - Request middleware. Runs on every request.
- <!-- list other high-risk areas -->
How to Test if Your CLAUDE.md Is Working
Writing the file is step one. Knowing whether it is any good is step two.
The simplest test: start a new Claude Code session and ask it to perform a task that requires project knowledge. Ask it to create a new API endpoint, or add a test for an existing function. If it puts the file in the right place, uses the right patterns, and the code passes your linter and tests on the first try, your CLAUDE.md is working.
For a more structured assessment, run your repository through the readiness checker at ready.kerex.app. It analyzes your repo's agent-readiness across multiple dimensions, including whether your CLAUDE.md covers the areas that matter most, and gives you a concrete score with specific recommendations for improvement.
What About Other Tools?
CLAUDE.md is specific to Claude Code, but the concept of giving AI tools project context is universal. Other tools have their own equivalents:
- AGENTS.md is a more generic format that several AI tools can read. If you work with multiple tools, consider maintaining both.
- .cursorrules is the equivalent for Cursor. It uses a similar plain-text format.
- .github/copilot-instructions.md gives GitHub Copilot project-level context.
The content across these files is largely the same. If you maintain a CLAUDE.md, creating the others is mostly a copy-paste job. The important thing is that the information exists somewhere your tools can find it.
The Payoff
A well-written CLAUDE.md takes about 30 minutes to create. After that, every AI-assisted coding session in your repo gets better. The agent stops guessing and starts following your conventions. It puts files where they belong. It runs the right test commands. It avoids the code that should not be touched.
The best CLAUDE.md files we have seen are living documents. Teams update them when they add a new package, change a convention, or discover a new footgun. Treat your CLAUDE.md the same way you treat your CI config: it is infrastructure that makes everything else work better.
Start with the templates above, fill them in for your project, and run it through ready.kerex.app to see where you stand.