← All posts

How to Write a CLAUDE.md That Actually Works

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:

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:

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:

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:

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:

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:

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:

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:

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.

Check how ready your codebase is for AI coding agents.

Try the AI Readiness Checker