← Claude for Real Work

CLAUDE.md

Lesson 15 of 28 · 13 min · Updated

CLAUDE.md is a markdown file of project memory that loads at the start of every session in the directory it belongs to. Every session starts with an empty head. Claude does not remember yesterday, and the third time you type “the tests are run with vitest, not jest” you have found something that belongs in a file instead of in a chat.

That file is CLAUDE.md.

Watch it be wrong first

Stockroom has no CLAUDE.md. In a fresh clone, ask this:

How do I run the stock take variance report for ST-2026-06? Give me the exact command.

You will most likely get this:

npm run stockroom -- count ST-2026-06

Run it. It prints the usage text, because there is no count command. There was, once. It was renamed to stocktake and the README was not updated, and the README is the most confident-sounding thing in the repository.

Now put a file called CLAUDE.md in the root with four lines in it:

# stockroom

## Things the README gets wrong

- The variance command is `stocktake`, not `count`. The README was not updated when it
  was renamed. Trust the switch in `src/cli/main.ts` over the README.

Start a new session and ask the identical question:

npm run stockroom -- stocktake ST-2026-06

Same question, same model, opposite answers. That is the entire value proposition, and it is worth seeing once rather than being told.

Where these files live

They are markdown, they are loaded in full, and there are four places they can be. Load order runs from broadest to narrowest, so the file closest to where you started is read last:

  • Managed policy, deployed by an IT department. On macOS that is /Library/Application Support/ClaudeCode/CLAUDE.md. You will probably never write one.
  • User, at ~/.claude/CLAUDE.md. Your preferences, every project on your machine.
  • Project, at ./CLAUDE.md or ./.claude/CLAUDE.md. Committed, shared with the team. This is the one that matters.
  • Local, at ./CLAUDE.local.md. Your own notes for this project. Gitignore it.

Claude Code walks up from your working directory and loads every CLAUDE.md it finds on the way, concatenating rather than overriding. Files in subdirectories are different: they load on demand, when Claude reads a file in that directory.

To see what loaded, run /context and look at the Memory files table:

### Memory Files

| Type    | Path                    | Tokens |
|---------|-------------------------|--------|
| Project | /private/tmp/l15/CLAUDE.md | 104 |

If your file is not in that table, Claude cannot see it, and no amount of rewording it will help.

What should go in CLAUDE.md?

The test is whether you would have to say it again. Build commands, the conventions of this codebase, the layout, the traps. Things a new person would ask on their first afternoon.

Stockroom’s could reasonably be this:

# stockroom

Inventory for a small warehouse. Items, a movement ledger, five reports.

## Commands

- `npm test` runs the whole suite. `npx vitest run test/stock.test.ts` runs one file.
- `npm run stockroom -- <command>` runs the CLI. `npm run serve` starts the HTTP view.
- `npx tsc --noEmit` typechecks. There is no build step; Node runs the TypeScript.

## Conventions

- Money is whole cents, always. Never a float.
- Balances are never stored. Every quantity in a report is a sum over the movement
  ledger, so a report that disagrees with a stock take is a fact about the warehouse.
- No TypeScript parameter properties (`constructor(private x: string)`). Node's type
  stripping erases types rather than generating code, and they fail at runtime.

## Things the README gets wrong

- The variance command is `stocktake`, not `count`.

Every line there is something you would otherwise type twice. The last one is the one that paid for itself thirty seconds ago.

What does not go in it

Anything Claude can work out by looking. A directory listing, the dependency list, a paragraph describing what each module does. It can read. Those lines cost context on every single session and buy nothing.

Procedures. “To add a new report: create the file, add it to the barrel, write the tests, update the README.” That is a skill, and lesson 21 is about skills. The difference: a fact belongs in memory because it is needed every time, and a procedure belongs in a skill because it is needed occasionally and is longer.

Anything that must be enforced. CLAUDE.md is context, not configuration. Claude reads it and tries to follow it, and sometimes does not. “Never commit to main” in a CLAUDE.md is a request. In a hook it is a rule. That is lesson 23.

Vague instructions. “Write clean code” and “follow best practices” are decoration. “Use two-space indentation” and “run npm test before committing” are instructions. If you cannot check whether it was followed, neither can Claude.

Keep it under about 200 lines. Longer files cost more context and get followed less, which is a bad trade in both directions at once.

/init writes you a first draft by reading the codebase. It is a reasonable starting point and it is heavy on exactly the material this section says to cut, because that is the material a codebase can tell it about. Treat the output as something to delete from.

The other memory

There are two systems and they are easy to confuse.

You write CLAUDE.md. Instructions and rules, loaded every session.

Claude writes auto memory. As it works, it saves notes to itself about your project, in ~/.claude/projects/<project>/memory/. Build commands it worked out, mistakes you corrected it on, preferences it noticed. The first 200 lines of MEMORY.md load into every session. It is on by default, it is plain markdown, and you can read and edit all of it.

Run /memory to browse both. It lists your CLAUDE.md files and offers to open the auto memory folder. If you have been using Claude Code for a while, go and read what it has written about you. It is usually accurate and occasionally uncomfortable.

The one thing worth knowing: auto memory is machine-local. It is not committed and your team does not have it. Anything the team needs goes in CLAUDE.md.

When it stops working

Two failures, both common.

It grew. A CLAUDE.md that has been added to for a year contains contradictions, and when two rules disagree Claude picks one. Read yours occasionally and delete.

It got lost in a long session. Project-root CLAUDE.md survives compaction; Claude Code re-reads it from disk afterwards. A nested CLAUDE.md in a subdirectory does not, and neither does anything you only said in the conversation. That is lesson 16.

Your turn

Write a CLAUDE.md for stockroom. Keep it under 40 lines. Then prove it does something.

Before, in a clone with no CLAUDE.md:

claude -p "How do I run the stock take variance report for ST-2026-06? \
  Give me the exact command." < /dev/null

Write the file, including the line about stocktake, then run the identical command again.

Check: the first answer is count and the second is stocktake, and claude -p "/context" lists your file under Memory Files with a token count. If /context does not list it, the file is in the wrong place and nothing else about this exercise matters.

Then delete a line from your file, and ask yourself whether the session got worse. Most lines in most CLAUDE.md files do not survive that question.

Recap

CLAUDE.md is the thing you would otherwise say twice, written down once. Project scope at the root, personal scope in ~/.claude/, private scope in CLAUDE.local.md. Verify with /context, not by hoping.

Facts and conventions belong there. Directory listings do not, because it can read. Procedures belong in a skill. Rules that must hold belong in a hook. And it is context rather than configuration, so it shapes behaviour without guaranteeing it.

Auto memory is the other half: notes Claude writes to itself, machine-local, browsable with /memory.

Next: the thing that limits every session, and the two commands that give the room back.