02 - Context and CLAUDE.md
📋 Jump to Takeaways🎁 Two engineers give Claude the same task on the same repo. One gets code that fits the codebase, the other gets a confident mess. The difference isn't the prompt, it's what Claude already knew before they typed it.
Claude Code is only as good as the context it has. Give it nothing and it guesses your conventions, your build commands, your architecture. Give it the right context and it stops guessing. This lesson is about controlling what Claude knows.
Context Determines Output
The model doesn't know your project. It knows patterns from training. When you ask for "a new endpoint," it invents one that looks plausible, not one that matches how your team writes endpoints.
Watch what happens without context:
You: Add a health check endpoint.
Claude: (writes an Express route, but your repo uses Fastify)
(returns { status: "ok" }, but your API wraps everything in { data })
(skips the auth middleware every other route uses)Nothing there is wrong in the abstract. It's just wrong for you. The fix isn't a longer prompt every time. It's giving Claude persistent context it reads on its own.
CLAUDE.md as Project Memory
CLAUDE.md is a file at your repo root that Claude Code loads automatically at the start of every session. It's project memory: the stuff you'd tell a new hire on day one so they stop asking.
Put the things Claude can't infer and keeps getting wrong:
# Project: Payments API
## Commands
- Build: `make build`
- Test: `make test` (never `npm test`, it skips integration tests)
- Lint: `make lint` (must pass before commit)
## Conventions
- Framework is Fastify, not Express.
- All responses wrap data: `{ data: ... }` or `{ error: ... }`.
- Every route goes through `authPlugin`. No exceptions.
## Gotchas
- `db.query` is synchronous in tests, async in prod. Use the repo layer.Keep it short and factual. It's not documentation for humans, it's a briefing for an agent. Commands, conventions, architecture notes, and the traps that bite people. Skip anything Claude can read from the code itself.
File References with @
CLAUDE.md is always-on context. Sometimes you want to pull in a specific file just for the task at hand. Reference it with @ and Claude reads it into context on demand.
Refactor the retry logic in @src/lib/http-client.ts to use
the backoff helper in @src/lib/backoff.ts. Match the style
of @src/lib/rate-limiter.ts.Now Claude has the exact files instead of searching for them or guessing their contents. Use @ when the task depends on specific code. It beats pasting the file, and it beats hoping Claude finds it.
Context Budget
More context isn't better. Everything you load competes for the model's attention, and a giant CLAUDE.md full of history and edge cases dilutes the signal.
Be selective:
# Good CLAUDE.md: 30 lines of what matters
Commands, conventions, three real gotchas.
# Bad CLAUDE.md: 400 lines
Every architecture decision since 2022, full API docs,
a changelog, and "we value clean code" fluff.Include what changes the output. Cut what doesn't. If a line wouldn't change a single thing Claude writes, it's noise. Same with @ references, pull in the three files that matter, not the whole src/ tree.
Memory Precedence
Claude Code reads memory from more than one place, and they stack. Knowing the order lets you keep personal notes out of your teammates' way.
~/.claude/CLAUDE.md # global: applies to every project you work on
./CLAUDE.md # project: shared with the team, committed to git
./CLAUDE.local.md # personal notes for this project, gitignoredPut team conventions in ./CLAUDE.md so everyone gets them. Put your own preferences (your shortcuts, your scratch commands) in the global file or CLAUDE.local.md. The local file is gitignored by convention, so your notes don't end up in a pull request.
Keeping CLAUDE.md Fresh
A stale CLAUDE.md is worse than none. If it says the test command is make test but the team switched to just test, Claude confidently runs the wrong thing every session.
Treat it like code:
When conventions change:
- Update CLAUDE.md in the same PR that changes the convention.
- Delete gotchas that no longer apply.
- If Claude keeps making the same mistake, that's a missing line.The best signal for what belongs in CLAUDE.md is your own frustration. Every time you correct Claude on the same thing twice, that correction is a line you should have written down.
Key Takeaways
- Claude's output quality is bounded by its context. Without context it guesses your conventions
CLAUDE.mdat the repo root is loaded automatically every session. It's project memory, not human docs- Put commands, conventions, architecture notes, and gotchas in
CLAUDE.md. Keep it short and factual - Reference specific files on demand with
@path/to/fileinstead of pasting or hoping Claude finds them - More context isn't better. Include what changes the output, cut the rest, both in
CLAUDE.mdand@refs - Memory stacks: global
~/.claude/CLAUDE.md, shared./CLAUDE.md, personal gitignored./CLAUDE.local.md - Update
CLAUDE.mdwhen conventions change. Correcting Claude twice on the same thing means a line is missing
🎁 You've given Claude perfect context, but it still built the wrong thing. What if the problem isn't what Claude knows, but how you asked, describing the steps instead of the outcome you actually wanted?