Back to blog
Context layer

CLAUDE.md and Claude Code Best Practices (+ Sample)

What belongs in CLAUDE.md, what doesn't, and a sample file you can copy. Plus the one kind of context a static file can't keep current.


A small navy robot with a sky visor and a green live-dot, happily reading a white brief whose text faces away from us, on an ice grid

Open a fresh Claude Code session and ask it to add a feature. It reads your CLAUDE.md, looks around the repo, and makes a plan that sounds confident. That confidence tells you nothing about whether it knows what actually matters: that your team tried this exact approach four months ago and killed it, or that the naming convention it’s about to break was a hard-won compromise from a meeting nobody wrote down.

A good CLAUDE.md is short, specific, and limited to things that stay true for months: build and test commands, conventions, project layout, and “always do X” rules. Decisions that change week to week don’t belong in it, because nobody edits the file fast enough to keep them current. Those need a live source the agent can query.

The short version of CLAUDE.md and Claude Code best practices, from Anthropic’s own Claude Code docs and from watching agents work on real codebases:

  • Keep each file under 200 lines. Longer files use more context and get followed less reliably.
  • Write instructions concrete enough to check: “Run npm test before committing,” not “test your changes.”
  • Add a line when the agent makes the same mistake twice, or when code review catches something it should have known.
  • Move anything that only matters for one part of the codebase into a path-scoped rule.
  • Keep fast-changing decisions out. That’s the part most guides skip, and the rest of this post is about why.

We’ve seen how much this problem resonates. In Thor’s own Reddit ad testing, the campaign built around the idea that a coding agent starts every session at zero ran at roughly double the click-through rate of any other campaign we’ve run there. People recognize it the moment it’s named.

What is CLAUDE.md, and how does Claude Code memory work?

CLAUDE.md is a markdown file Claude Code reads at the start of every session. Each session begins with an empty context window, so this file is how instructions carry over from one session to the next. Claude Code also has auto memory, notes Claude writes for itself from your corrections. Both load every session, and both are treated as context to follow, not settings it’s forced to obey.

The file can live in a few places, each with a different reach:

Location Who it applies to Good for
./CLAUDE.md (project root) Everyone on the repo, via source control Build commands, conventions, architecture
~/.claude/CLAUDE.md Just you, in every project Personal preferences
./CLAUDE.local.md (gitignored) Just you, in this project Your sandbox URLs, local test data
A managed policy file set by IT Everyone in the organization Company-wide security or compliance rules

If your repo already uses AGENTS.md, Claude Code can read that too, on its own or alongside CLAUDE.md.

What should go in a CLAUDE.md file?

Anything you’d otherwise explain again every session, and nothing else. The test for every line: would the agent get this wrong without being told, and will it still be true next quarter?

Good candidates:

  • The exact commands to build, test, and lint
  • Where things live (“API handlers are in src/api/handlers/”)
  • Conventions the code alone doesn’t make obvious, like a naming rule or an error-handling pattern
  • Hard constraints: a directory that’s off-limits, a security rule that isn’t optional
  • How the team wants PRs and commits written

What to leave out: the full history of how the codebase got here, a copy of your README, long step-by-step procedures (those work better as a skill), and anything that changes faster than someone will update the file.

A sample CLAUDE.md you can copy

Here’s a realistic starting point for a small web service. Run /init in Claude Code to generate a first draft from your own codebase, then trim it toward something like this.

# Payments API

## Commands
- Install: `pnpm install`
- Test: `pnpm test` (run before every commit)
- Lint and format: `pnpm lint --fix`
- Local stack: `docker compose up db redis`

## Layout
- HTTP handlers: `src/api/handlers/`
- Business logic: `src/services/` (handlers stay thin)
- Database migrations: `db/migrations/`, never edit an applied one

## Conventions
- TypeScript strict mode. No `any`.
- Services return results; they don't throw for expected failures.
- Anything shared across instances (rate limits, locks, caches) goes in Redis, never in memory.

## Don't
- Touch `src/legacy/` without asking first.
- Log request bodies. They can contain card data.

## Ownership
- Webhooks and auth headers: payments team. Tag them on any change.

Notice what’s in that file: a decision (“shared state goes in Redis”) and an owner (“payments team”). Both are fine there today. Both are also the lines most likely to be wrong in six months, which leads to the real limit of the file.

Where a static CLAUDE.md file stops working

A CLAUDE.md file is accurate at the moment someone writes it. It’s the right home for things that don’t change week to week. What it can’t do is keep up with a decision made in yesterday’s design review, because nobody edits the file every time the team changes its mind.

Here’s what that looks like. Take one prompt: “Add rate limiting to the webhook endpoint.” Same codebase, same model, same prompt, two situations.

When the decision never made it into CLAUDE.md, the agent has the file tree and a generic CLAUDE.md. It picks a reasonable approach: an in-memory token bucket, keyed by IP. Clean code, passes its own tests. Except this team already tried in-memory rate limiting eight months ago and pulled it after a postmortem, because it doesn’t survive a pod restart and doesn’t work across their three running instances. That decision lives in a closed Linear ticket and a Slack thread from March. The agent had no way to see either one, so it rebuilt the thing the team already threw away.

When the decision travels with the task, the same prompt arrives with three facts attached. Rate limiting was tried in memory in Q1 and rejected because it didn’t survive restarts or work across instances. The team standardized on Redis-backed limiters for anything cross-instance. And the webhook module is owned by the payments team, so tag them on anything touching auth headers. The agent picks the Redis approach and flags the payments team for review. Same model, different and correct output, because the constraint that mattered was in front of it instead of buried in a ticket it never queried.

A bigger model wouldn’t have fixed the first case. The failure is missing information, and more reasoning can’t recover a fact the model was never shown. Pasting more of the repo into the prompt doesn’t fix it either. The agent reads more, but the one sentence that would have changed the plan is still sitting in Slack.

What travels with each task, and what stays in the file

Split it by how often it changes. CLAUDE.md holds the stable layer. Each task needs a short brief with the current layer: the handful of recent facts that would change what gets built.

Belongs in CLAUDE.md Needs to travel with the task
Build and test commands An approach the team rejected last month, and why
Naming and structure conventions Who owns this module right now
Off-limits directories A constraint decided in this week’s meeting
Long-standing architecture choices A spec change agreed in a Slack thread after the ticket was written

For the right-hand column, someone, or something, has to pull the current answer at the moment the task starts. That’s what Thor does. Thor is the context infrastructure for AI-native software teams. It keeps one current record of what your team decided, changed, and left stale across Slack, GitHub, Linear, and meetings. Coding agents read that record through Thor’s MCP server. For example, they can ask for a context pack on a Linear or GitHub issue and get back the related decisions, docs, meetings, and work, not just the issue text. We cover the difference between more context and correct context in what “context” actually means, and the bigger picture in the context layer, explained.

Your CLAUDE.md file and Thor do different jobs. One is a stable reference you maintain by hand. The other keeps up with the team.

FAQ

How long should a CLAUDE.md file be?

Under 200 lines per file is Anthropic’s guidance. Longer files use more of the context window and get followed less consistently. If yours is growing past that, move instructions that only apply to part of the codebase into path-scoped rules, which load only when Claude works on matching files.

What’s the difference between CLAUDE.md and Claude Code’s auto memory?

You write CLAUDE.md. Claude writes auto memory, based on your corrections and preferences. Both load at the start of every session. Use CLAUDE.md for rules you want followed, and let auto memory pick up the smaller things you’d otherwise repeat.

Should I use CLAUDE.md or AGENTS.md?

If your repo already has an AGENTS.md for other coding agents, Claude Code can read it, on its own or alongside CLAUDE.md. Keep one source for shared instructions so the two files don’t drift apart and contradict each other.

Does a bigger context window remove the need for CLAUDE.md?

No. A bigger window lets an agent read more of what’s already there. It doesn’t decide which of it matters, and it doesn’t pull in a decision that only exists in a Slack thread or a closed ticket.

Can CLAUDE.md track decisions that change every week?

Not reliably. It’s only as current as its last edit, and nobody’s job is to update it after every meeting. Keep the stable rules in the file and get fast-changing decisions from a live source when each task starts.

See how your coding agents get the team’s current decisions, not last quarter’s CLAUDE.md. Book a demo.

Related Posts