How to Write a CLAUDE.md File That Actually Works

How to Write a CLAUDE.md File That Actually Works

How to Write a CLAUDE.md File That Actually Works

If you're using Claude Code without a CLAUDE.md file, you're starting every session from scratch. Claude has no idea what your project does, how your team names things, which commands are safe to run, or what you tried last week that broke everything. You're explaining context you've already explained, every single time.

A CLAUDE.md file fixes that. It's a plain markdown file that sits in your project root and gives Claude persistent context about your codebase, conventions, and instructions. Claude reads it automatically at the start of every session, before you've typed a single prompt.

This post covers what goes in one, why each section matters, and what a real working example looks like — not the boilerplate version you'll find in the docs.



What is CLAUDE.md and why does Claude Code need it

CLAUDE.md is a project-level markdown file that gives Claude Code persistent context about your codebase, conventions, and instructions. Claude reads it automatically at the start of every session, so you don't have to re-explain your project every time you open a new conversation.

Think of it like an onboarding document for a new developer, except the developer forgets everything between sessions. CLAUDE.md is how you get them back up to speed instantly, every time.



How Claude Code reads and uses CLAUDE.md

When you start a Claude Code session in a directory, Claude looks for CLAUDE.md in the project root and reads it before anything else. That content becomes part of the context window for the entire session.

This means anything in CLAUDE.md is always in scope. If you tell Claude to use a specific test runner, it'll use that test runner. If you tell it never to modify the database migration files directly, it won't. If you explain that your staging environment is called preprod not staging, it won't confuse the two.

Claude also picks up CLAUDE.md files in subdirectories. So if you have a monorepo with separate frontend and backend packages, you can have a root CLAUDE.md with shared context and subfolder CLAUDE.md files with package-specific instructions. Claude reads all the relevant ones based on what files you're working with.



What happens without one

Without a CLAUDE.md, Claude is working blind. It can read your code, figure out what's there, and make reasonable guesses about your conventions. But it doesn't know what it doesn't know.

It doesn't know that you're mid-migration from one ORM to another and shouldn't use the old pattern in new files. It doesn't know that your CI pipeline runs on every push to main and a broken test will hold up three other people. It doesn't know that your client has a specific naming convention for API endpoints that looks wrong but is intentional.

These are the things that cause Claude to produce technically correct but practically useless output. Not wrong, just not right for your specific situation.



Anatomy of a well-structured CLAUDE.md file

There's no enforced schema for CLAUDE.md. Claude reads plain markdown, so you have flexibility. But after writing these for our own projects and for clients, there are four sections that consistently make the biggest difference.



Project overview section

Start with a short paragraph explaining what the project does, who it's for, and its current state. Not a sales pitch. A technical summary.

Something like: this is a Node.js API that handles order processing for a B2B wholesale platform. The codebase is about 18 months old. We're mid-way through migrating from REST to GraphQL. New endpoints should use GraphQL. Existing REST endpoints are being left as-is until migration is complete.

That one paragraph tells Claude something it couldn't reliably infer from reading the code: the direction of travel. It stops Claude from helpfully refactoring REST endpoints into the new pattern when you've specifically chosen not to.



Tech stack and conventions

List your stack explicitly. Not because Claude can't figure out you're using TypeScript, but because conventions aren't always obvious from code alone.

This section should cover your language and runtime versions, key frameworks and libraries, code style rules including linter and formatter, naming conventions for files, variables, functions, and database tables, and your folder structure — where different types of files live.

Be specific. "We use camelCase for variables and PascalCase for classes" is useful. "Follow TypeScript best practices" is not. It means nothing Claude doesn't already know.

If you have a linter config, you don't need to duplicate it in CLAUDE.md. Just reference it: ESLint config is in .eslintrc — Claude should not suggest changes that violate it.



Commands Claude should and shouldn't run

This is probably the most important section, and the one most people skip.

Claude Code can run terminal commands. That's useful. It's also where things go wrong if Claude runs something it shouldn't. A CLAUDE.md file is where you draw the lines clearly.

Tell Claude what your test command is, what your dev server command is, how to run a specific file. These are things Claude will need repeatedly and gets right immediately if you specify them upfront.

Then tell it what not to run. Don't run database migrations directly. Don't push to git. Don't install packages globally. Don't run anything that touches the production environment. Whatever your danger zones are, put them here explicitly.

This isn't because Claude is reckless. It's because "run the migrations" is sometimes the right answer and sometimes a disaster, depending on context Claude doesn't have. CLAUDE.md is where you give it that context.



Common gotchas specific to your codebase

Every project has things that look wrong but are intentional. Or things that look like the obvious approach but cause a specific problem in your setup. This section is for those.

Some examples from real projects: the config folder looks unused but it's loaded by the deployment pipeline so don't suggest removing it. The UserService class is not redundant. It wraps a third-party SDK with custom error handling we need. Tests that hit the database use a separate test connection string defined in .env.test. Don't hardcode connection strings in tests.

You'll add to this section over time. Every time Claude does something that made sense but caused a problem, that's a candidate for the gotchas section. It's a living document, not a one-time setup.



Real CLAUDE.md examples by project type

Here's what these sections look like in practice across three different project types.



Node.js API project

A typical setup for a Node.js REST API might look like this:



Python data pipeline

For a Python project the structure is the same, the specifics are different:



Business automation project

This is closest to what we build at AMPL. Here's a stripped-down version of a real internal CLAUDE.md for a client onboarding automation project:

That last example shows something worth pointing out: the gotchas section explains why decisions were made, not just what they are. "Don't do X" is useful. "Don't do X because we tried it and it caused Y" is more useful. Claude will understand the reasoning and apply it sensibly in edge cases.



Common mistakes that make your CLAUDE.md useless

The most common issue is writing a CLAUDE.md that's too generic to matter. Things like "follow clean code principles" or "write readable code" tell Claude nothing it doesn't already know. If the instruction could apply to any project by any team anywhere, cut it.

Second most common: writing it once and forgetting about it. Your codebase changes. If you add a new integration, switch test runners, or discover a new gotcha, update the file. A stale CLAUDE.md is worse than a short one because it actively misleads.

A few other patterns that cause problems:

  • Too long. CLAUDE.md takes up context window space. If you're pasting in your entire architecture document, you're wasting tokens on things Claude could figure out by reading the code. Keep it to things Claude can't infer itself.

  • No commands section. The most immediately useful thing you can give Claude is the exact commands it needs. Don't make it guess your test runner or dev server setup.

  • Vague restrictions. "Be careful with the database" is not actionable. "Don't run any SQL directly — always use the query wrapper in /src/db/safe-query.ts" is.

  • No gotchas. This is where the real value compounds over time. Every codebase has quirks. Document them.



And don't let perfect be the enemy of useful. A short CLAUDE.md with five specific, accurate pieces of information is better than a long one with twenty generic ones. Start small and add to it as you go.



FAQ



Where does the CLAUDE.md file go?

Put it in the root of your project, the same place you'd put your README.md. Claude Code looks for it there automatically. In a monorepo, you can have one in the root and additional CLAUDE.md files in subdirectories for package-level context. Claude reads all the relevant ones based on what you're working on.



How long should a CLAUDE.md file be?

As short as it can be while still being useful. For most projects, 50 to 150 lines covers everything worth covering. The file takes up context window space, so every line should earn its place. If you're writing something Claude could figure out by reading the code, cut it.



Does CLAUDE.md work differently from just explaining things in the chat?

Yes. Context you explain in the chat disappears when the session ends. CLAUDE.md persists between sessions, so you document something once and it's always there. It also loads before any conversation starts, which means Claude has the full project context before your first prompt rather than catching up partway through.



Can I have multiple CLAUDE.md files in one project?

Yes. Claude Code reads them hierarchically, the root file plus any relevant subdirectory files based on what you're working on. This is particularly useful in monorepos where different packages have different stacks or conventions. Keep the root file focused on genuinely shared context and let the subdirectory files handle the specifics.



Should CLAUDE.md be committed to version control?

Yes, in almost every case. It's project documentation and everyone on the team should benefit from it. The only exception is if it contains sensitive information, which it generally shouldn't. Config values and secrets belong in environment files, not in CLAUDE.md.



How is CLAUDE.md different from a system prompt?

A system prompt is set at the API or application level and applies regardless of which project you're in. CLAUDE.md is project-specific and lives with the code. Think of a system prompt as your general preferences for how Claude behaves, and CLAUDE.md as the project-specific briefing on top of that. They work together rather than replacing each other.



Start simple, build from there

If you're not using CLAUDE.md at all right now, start with three things: a two-sentence project overview, your key commands, and one or two gotchas you already know about. That alone will make a noticeable difference to how quickly Claude gets useful work done.

Then update it when something goes wrong. Every time Claude does something technically sensible but wrong for your project, that's a CLAUDE.md entry. Over a few weeks you'll have a document that genuinely reflects how your codebase works, not a generic template, but something specific to your situation.

If you're building with Claude Code and want to get the project setup right from the start, we're happy to take a look. Book a free audit at amplconsulting.ai and we'll go through what's worth documenting for your specific build.