Context Files
In the Why We’re Doing This chapter, we compared a coding agent to a brilliant intern who knows nothing about your project. Context files are how you fix the “knows nothing” part.
A CLAUDE.md file is the onboarding doc you’d write for that intern. It tells the agent what your project is, how it’s built, what patterns to follow, and — critically — what not to touch. The difference from a regular README is that agents actually read it. Every single time. Every session starts by loading these instructions, so anything you put here shapes every interaction.
If you’ve already done Exercise 01 and run /init, you’ve got a machine-generated CLAUDE.md sitting in your repo. It’s a decent starting point, but it’s generic. This chapter shows you how to turn it into something actually useful.
The three levels
Section titled “The three levels”Claude Code reads CLAUDE.md files from three locations, layered on top of each other:
| Level | File | What it’s for | Shared? |
|---|---|---|---|
| Project | CLAUDE.md in the repo root | Project-specific: tech stack, build commands, conventions, constraints | Yes — committed to source control, shared with the team |
| Local | CLAUDE.local.md in the repo root | Your personal preferences for this project — maybe you like verbose output, or you want the agent to explain its reasoning | No — gitignored, stays on your machine |
| Global | ~/.claude/CLAUDE.md in your home directory | Machine-wide defaults that apply to every project — formatting preferences, git conventions, personal workflow habits | No — local to your machine |
Claude Code loads all three and combines them. Project-level instructions are the most important because they’re shared. If the whole team follows the same CLAUDE.md, the agent behaves consistently regardless of who’s driving.
The practical rule: Put anything the team needs to agree on in the project CLAUDE.md. Put personal preferences in local or global. If you’re not sure, start with the project file and move things to local only if they’re genuinely personal (like “always explain your reasoning step by step”).
If you use Claude Desktop or claude.ai for project work (not Claude Code), you can achieve a similar effect with Projects. Create a project per client or per repo and add context files to its knowledge base. The principle is the same — give the AI the context it needs upfront — even though the mechanism is different. The per-client isolation rules from the “Per-client isolation” section below apply here too.
What goes in a CLAUDE.md
Section titled “What goes in a CLAUDE.md”Here’s the structure we use. Every project CLAUDE.md should include the required sections. Optional sections get added when they’re relevant. The whole thing should stay under about 80–150 lines and 3,000 tokens.
Why the budget? Frontier LLMs reliably follow about 150–200 instructions before performance starts degrading. Boris Cherny (who helped build Claude Code) keeps his team’s CLAUDE.md at roughly 2,500 tokens (InfoQ). More isn’t better here. A bloated CLAUDE.md is like an onboarding doc that nobody reads — the important stuff gets buried.
How to check your token count: A rough rule of thumb is 1 token ≈ ¾ of a word, so 3,000 tokens is roughly 2,200 words. You can get a quick estimate with
wc -w CLAUDE.mdand multiplying by 1.3 (code and punctuation tokenise less efficiently than prose). For an exact count, ask Claude directly: “How many tokens is this file?”
Required sections
Section titled “Required sections”## Project overview[1–3 sentences. What is this project? What does it do? Who is it for?]
## Tech stack[Bulleted list of core technologies, frameworks, and versions.]
## Build and run commands[Exact commands. Not "run the tests" but the actual command.]- Build: `dotnet build src/MyProject.sln`- Test: `dotnet test src/MyProject.Tests/`- Lint: `dotnet format --verify-no-changes`- Run locally: `dotnet run --project src/Api/`
## Project structure[Key directories and what they contain. Focus on what's non-obvious.]- `/src/Api/` — ASP.NET Core Web API, entry point- `/src/Core/` — Domain entities, interfaces, business logic- `/src/Infrastructure/` — EF Core, external integrations- `/tests/Unit/` — xUnit unit tests with Moq- `/tests/Integration/` — Integration tests against test DB
## Code conventions[Your project's specific rules. Be concrete, not vague.]- Use async/await for all I/O operations- Repository pattern for data access — no direct DbContext in controllers- Use MediatR for command/query handling- Test naming: `MethodName_Scenario_ExpectedResult`- All public API endpoints must have XML doc comments
## Do NOT[Explicit prohibitions. These are the most important instructions.]- Do NOT modify database migrations without explicit approval- Do NOT add NuGet packages without noting it in the PR description- Do NOT change the API contract (route, request/response types) without spec approval- Do NOT use `var` for non-obvious types- Do NOT bypass the repository pattern with direct DbContext callsA few things worth noticing. The build commands are exact shell commands, not descriptions. The conventions are specific (“repository pattern for data access”) not generic (“use meaningful variable names”). And the “Do NOT” section is there because agents are helpful by default — sometimes too helpful. Without explicit prohibitions, they’ll cheerfully refactor things you didn’t ask them to touch.
The “Do NOT” section is the highest-value part of the file. When something goes wrong in an agent session, adding a “Do NOT” rule is often the fastest fix.
Optional sections
Section titled “Optional sections”Add these when your project needs them:
## Architecture decisions[Link to ADRs or briefly describe key decisions agents need to know.]- We use CQRS — commands and queries are separate (see /docs/adr/001-cqrs.md)- Authentication uses JWT with refresh tokens — never modify token handling
## Common patterns[Point the agent at examples to follow.]- New API endpoint: see `UserController.cs` for the standard pattern- New command: see `CreateUserCommand.cs` and `CreateUserCommandHandler.cs`- New content type: see `StandardPage.cs` for the base pattern
## Known issues and workarounds[Things the agent will hit. Save it the debugging time.]- EF Core migrations must be run from the /src/Infrastructure/ directory- The Docker compose setup requires `host.docker.internal` on macOS
## Client-specific notes[For client projects only. Context unique to this client.]- Client uses Azure AD B2C for authentication — do not switch to other providers- All UI text must support localisation (use resource files, not hardcoded strings)The “Common patterns” section is especially powerful. Instead of describing a pattern in words, you point the agent at a file that already does it right. This works because agents are excellent at reading code and mimicking the style. One see UserController.cs for the standard pattern is worth twenty lines of written conventions.
What NOT to include
Section titled “What NOT to include”- Secrets or credentials. CLAUDE.md gets committed. No API keys, passwords, or connection strings. Ever. (The Risks and Hard Rules chapter covers this as one of our hard rules.)
- Generic programming advice. The agent already knows how to write C# or TypeScript. Telling it “use meaningful variable names” wastes instruction budget on things it already does.
- Long documentation. If a section needs more than ten lines, link to a separate doc. The CLAUDE.md is a map, not an encyclopedia.
- Task-specific instructions. Project goals, one-off constraints, or “for this ticket only” details belong in the task prompt, not in the CLAUDE.md. The file should contain things that are true across all tasks.
Directory hierarchy
Section titled “Directory hierarchy”CLAUDE.md files are additive. Claude Code reads every CLAUDE.md from the project root down to whatever directory you’re working in, layering instructions as it goes. This means you can keep the root file lean and put directory-specific rules where they belong:
/project-root/ CLAUDE.md ← Project-wide: tech stack, build commands, top-level conventions /src/ /Api/ CLAUDE.md ← API-specific: controller patterns, routing conventions, auth rules /Frontend/ CLAUDE.md ← Frontend-specific: React patterns, component conventions, state management /tests/ CLAUDE.md ← Testing-specific: naming, fixtures, what to mockThe nearest file wins when instructions conflict. If the root says “use tabs” and /src/Frontend/CLAUDE.md says “use spaces,” the frontend directory uses spaces.
Rule of thumb: If an instruction only matters in a subdirectory, put it in that subdirectory’s CLAUDE.md. A root file that tries to cover everything for every directory ends up too long and too vague. Think of it like your project’s folder structure — you wouldn’t put everything in one directory, so don’t put all instructions in one file.
Most projects won’t need more than two levels: root plus one or two subdirectories. One clear root CLAUDE.md is better than six thin ones scattered around.
Per-client isolation
Section titled “Per-client isolation”This is non-negotiable for us as an agency. The Risks and Hard Rules chapter formalises it as one of our five hard rules, but you should start practising it now.
The rule: every client repo has its own CLAUDE.md. No shared context across clients. No referencing Client A’s code while working on Client B. No shared agent memories, no shared instruction files, no cross-pollination.
What this looks like in practice:
- Every client repo has its own CLAUDE.md. Start from a stack-specific template (the Templates chapter has these), then customise for the client.
- Start fresh sessions when switching clients. Don’t carry agent context from one client into another. Exit the session, start a new one.
- Your personal
~/.claude/CLAUDE.mdstays generic. Formatting preferences, git conventions, personal workflow habits — never client-specific context. - If you use Claude Desktop Projects or claude.ai Projects, the same rule applies. One project per client. Don’t share a project across clients even if the tech stack is similar.
Why does this matter? Two reasons. First, confidentiality. Clients trust us with their code and business logic. If an agent accidentally surfaces Client A’s implementation details while working on Client B’s project, that’s a breach — even if nobody intended it. Second, accuracy. Agent context from one project will pollute decisions in another. Different clients have different conventions, different architectures, different constraints. Mixing them leads to subtle bugs.
Keeping it lean
Section titled “Keeping it lean”A CLAUDE.md is a living document, but that doesn’t mean it should only grow. Here’s how to keep it useful:
Add rules when you learn something. When you review an agent PR and catch a mistake that better instructions would have prevented, add the instruction. This is Step 6 of the spec-first workflow — Merge and Learn. Boris Cherny’s team at Anthropic does this routinely. When a PR reveals an agent pitfall, they tag it for inclusion in the CLAUDE.md (InfoQ).
Remove rules that aren’t pulling their weight. During your monthly retro, spend ten minutes scanning the CLAUDE.md. Are there instructions that haven’t been relevant in weeks? Remove them. Are there positive instructions that the agent consistently follows anyway (because it’s part of standard language model behaviour)? Remove them too. Every instruction competes for attention.
Reword rules that aren’t working. If the agent keeps violating a rule that’s already in the CLAUDE.md, the instruction might need rewording. “Do NOT” phrasing tends to stick better than positive instructions. “Do NOT use var for non-obvious types” works better than “Prefer explicit types.” Try flipping the framing before giving up.
Treat changes like code. CLAUDE.md changes go through PR review, same as any other code change. Update the file in the same PR that reveals the need — don’t let learnings sit in someone’s head. This is version-controlled infrastructure, not a scratch pad.
Which file format to use
Section titled “Which file format to use”You’ll run across several formats in the wild. Here’s our approach:
| File | Tool | Our policy |
|---|---|---|
CLAUDE.md | Claude Code | Primary. Required in every active repo. |
.github/copilot-instructions.md | GitHub Copilot (chat, completions) | Required if you want Copilot instructions. This is Copilot’s primary custom instructions file for chat and code completions. You can use @CLAUDE.md import syntax to pull in shared content so you’re not duplicating everything. |
AGENTS.md | Most tools except Claude Code | Adopt now — with a caveat. AGENTS.md is now an industry-wide standard stewarded by the Agentic AI Foundation under the Linux Foundation. GitHub Copilot’s coding agent, Cursor, Windsurf, and 60,000+ open-source projects use it. Claude Code does not yet support it (open issue), so it won’t replace CLAUDE.md for our primary workflow. The practical pattern: use AGENTS.md for shared, tool-agnostic instructions + keep CLAUDE.md for Claude Code-specific guidance. When Claude Code adds support, AGENTS.md becomes the canonical shared file. |
Why CLAUDE.md as primary? It’s our main tool for deep work and delegation, and it’s what Claude Code reads. For Copilot’s inline chat and completions, .github/copilot-instructions.md is still the right file. The CLAUDE.md at the repo root is read by Copilot’s autonomous coding agent specifically — not by Copilot chat and completions.
AGENTS.md is now the practical cross-tool standard — adopted widely, with Claude Code as the notable holdout. Add one to your repos now to cover every other tool, and keep CLAUDE.md alongside it for Claude Code.
Custom commands (a quick recap)
Section titled “Custom commands (a quick recap)”You saw custom commands in the Claude Code in Action course. Here’s how they fit into the context file picture. They live in .claude/commands/ — part of the same directory structure as your settings and hooks — and let you package a common workflow into a single slash command.
.claude/ commands/ audit.md → /audit write-tests.md → /write-tests settings.json settings.local.jsonA command file is just a markdown prompt. For example:
Write unit tests for $arguments using xUnit and Moq.Follow the Arrange-Act-Assert pattern.Put tests in the corresponding tests/Unit/ directory.Run dotnet test when done.You’d run it with /write-tests src/Services/UserService.cs.
The $arguments placeholder takes whatever you type after the command name. This is a light way to standardise common tasks across the team — everyone runs /write-tests the same way, with the same conventions baked in.
The next chapter goes deeper on commands alongside hooks and MCP servers. For now, just know that commands exist, they live in .claude/commands/, and they’re a natural companion to your CLAUDE.md.
Exercise 03 — Write a CLAUDE.md and a custom command (frontend)
Section titled “Exercise 03 — Write a CLAUDE.md and a custom command (frontend)”Back in Exercise 01, you ran /init on the practice repo and got a machine-generated CLAUDE.md. Now you’re going to make it good.
Goal: Refine the /init-generated CLAUDE.md into a useful project context file, and create one custom command for a common workflow.
Repo: Rokkit200.Website (Next.js)
Steps:
-
Open the
CLAUDE.mdthat/initgenerated in Exercise 01. Read it critically — what did it get right? What’s missing or wrong? -
Compare it against the required sections from this chapter: project overview, build/run commands, code conventions, “Do NOT” rules, and testing approach.
-
Rewrite the CLAUDE.md to match our conventions. Specific things to get right for this repo:
- Build commands:
yarn install,yarn dev,yarn lint,yarn compile(GraphQL codegen) — not npm - Code conventions: SCSS modules for styling (not CSS-in-JS), Atomic Design component hierarchy (atoms → molecules → organisms), TypeScript
typepreferred overinterface,@/*path alias for imports - Do NOT section: Don’t edit generated files in
src/gql/(they come fromyarn compile), don’t use npm (Yarn 4 only), don’t add new CSS-in-JS libraries, don’t modify design tokens insrc/components/storybook/tokens/without approval
- Build commands:
-
Create a custom command file at
.claude/commands/write-component-tests.md. It should instruct Claude to write tests for a given component, using the test runner you set up in Exercise 01, following the project’s Atomic Design conventions. Use$ARGUMENTSfor the component path.Tip: If the command doesn’t appear when you press
/, restart Claude Code or reload VS Code (Ctrl+Shift+P→ Reload Window). -
Test your command: run
/write-component-tests src/components/storybook/atoms/icon/Icon.tsxand then run it again onsrc/components/storybook/molecules/text/Text.tsx. Does it produce consistent, convention-following output both times? -
Test your CLAUDE.md: delegate a small task (e.g. “add a
disabledstate to the Button atom”) and check whether Claude follows the conventions you wrote.
Check your work:
- CLAUDE.md is under 150 lines and covers all required sections
- “Do NOT” section contains real, project-specific constraints (not generic advice like “write clean code”)
- Build commands use
yarn, notnpm - Custom command exists at
.claude/commands/write-component-tests.mdand uses$ARGUMENTS - Running the custom command on two different components produces consistent, convention-following output
- Delegating a small task shows the agent following your CLAUDE.md conventions
Reflect: Look at the CLAUDE.md you wrote. If a new team member joined tomorrow and this was the only document they read about the project, would they understand the important constraints? What would they still need to ask about?
Exercise 03b — Write a CLAUDE.md and a custom command (backend)
Section titled “Exercise 03b — Write a CLAUDE.md and a custom command (backend)”Same skill, different stack. Frontend-only devs can skip this one. Backend and fullstack devs — do both.
Goal: Write a CLAUDE.md and custom command for the Alloy CMS 13 repo.
Repo: Rokkit200.Training.CMS13.Alloy (Optimizely CMS 13)
Steps:
-
Run
/initon the Alloy repo if you haven’t already. Read the generatedCLAUDE.mdcritically. -
Rewrite it to match our conventions. Specific things to get right for this repo:
- Build commands:
dotnet build Alloy.sln,dotnet run --project Alloy/Alloy.csproj— include the LocalDB prerequisite andApp_Data.zipextraction step - Code conventions: Content types named
[Name]Page/[Name]Block, all pages inherit fromSitePageData, all blocks fromSiteBlockData, controllers inheritPageControllerBase<T>, property groups defined inGlobals.cs(Default, Content, Contact, Metadata, etc.), content types registered with[ContentType]and[SiteContentType]attributes with GUIDs - Do NOT section: Don’t change existing content type GUIDs, don’t modify
Program.csorStartup.cswithout explicit instruction, don’t remove NuGet package sourceapi.nuget.optimizely.comfromnuget.config, don’t edit anything in themodules/folder (read-only CMS infrastructure)
- Build commands:
-
Create a custom command at
.claude/commands/add-content-type.md. It should instruct Claude to scaffold a new content type (page or block) following the existing patterns: proper base class,[ContentType]attribute with a new GUID, property groups fromGlobals.cs, and a corresponding Razor view. Use$ARGUMENTSfor the content type name.Tip: If the command doesn’t appear when you press
/, restart Claude Code or reload VS Code (Ctrl+Shift+P→ Reload Window). -
Test your command: run
/add-content-type TestimonialBlockand check whether the output follows the patterns in existing files likeModels/Blocks/TeaserBlock.csandViews/Shared/Blocks/TeaserBlock.cshtml. -
Test your CLAUDE.md: delegate a small task (e.g. “add a
Phoneproperty toButtonBlock”) and check whether Claude follows the conventions you documented — correct base class, correct attributes, correct property group.
Check your work:
- CLAUDE.md is under 150 lines and covers all required sections
- “Do NOT” section includes the content type GUID rule and the
modules/folder rule - Build commands reference the correct solution/project paths and mention LocalDB
- NuGet package source
api.nuget.optimizely.comis documented - Custom command exists at
.claude/commands/add-content-type.mdand uses$ARGUMENTS - Running the command produces output that follows the
SiteBlockData/SitePageDatainheritance pattern - The project builds cleanly after the agent’s changes (
dotnet build)
Reflect: Compare the two CLAUDE.md files you’ve written (Next.js and Alloy). What’s similar? What’s fundamentally different? Which conventions were harder to articulate?
Putting it together
Section titled “Putting it together”Context files are how you scale your knowledge. The conventions and constraints you carry around in your head — the ones that make you effective on a project — are now written down where agents (and new teammates) can use them.
Writing instructions for an agent feels different from writing them for a human. You can’t rely on shared assumptions. The agent doesn’t know what you mean by “the usual pattern.” You have to point at a file. That precision is what makes the agent useful, and the CLAUDE.md is where most of it lives.
Next up, we’ll look at the tools that enforce these rules automatically: hooks, custom commands in depth, and MCP servers.