Context Engineering for Claude Code: The Levers That Decide What It Sees
Claude Code gives you about eight separate controls over what is in its context window: CLAUDE.md files and their scopes, imports, rules, memory, compaction, subagents, skills and hooks. Here is what each one loads, when, and what survives a long session.
8 min read
Context engineering for Claude Code comes down to one question per mechanism: does this load every session, only when something triggers it, or only inside a separate context? CLAUDE.md files, unscoped rules and auto memory load at the start of every session. Path-scoped rules, nested CLAUDE.md files and skill bodies load on demand. Subagents do their reading in their own window and send back a summary. Hooks can add text at set moments. /compact, /clear and /rewind decide what the conversation itself keeps. Put each piece of information in the cheapest place that still reaches Claude when it is needed.
The general idea, curating what a model sees rather than polishing one prompt, is covered in context engineering for AI agents and context engineering vs prompt engineering. This page is about the specific controls Claude Code gives you.
Start by looking: /context and /memory
Before changing anything, run /context. It shows a live breakdown of what is using the window, by category, including which CLAUDE.md and auto memory files loaded. /memory lists the memory files across user and project scopes, opens them for editing and toggles auto memory. If an instruction is being ignored, the first check is whether its file appears in that list at all.
CLAUDE.md: four scopes, concatenated
Anthropic’s memory documentation (opens in a new tab) lists four places a CLAUDE.md can live, loaded broadest first:
- Managed policy: a file your organisation deploys to every machine, such as
C:\Program Files\ClaudeCode\CLAUDE.mdon Windows. It cannot be excluded. - User:
~/.claude/CLAUDE.md, your own preferences in every project. - Project:
./CLAUDE.mdor./.claude/CLAUDE.md, committed and shared with the team. - Local:
./CLAUDE.local.md, your personal notes for this project; add it to.gitignore.
None of them overrides another; they are joined together. Claude Code reads the files in your working directory and every directory above it at launch, and picks up CLAUDE.md files in subdirectories only when it reads files there. So where you start the session changes what it knows, which matters in a monorepo; Claude Code across multiple projects covers that layout. A repository that already has an AGENTS.md and no CLAUDE.md can be read directly too.
Three details are worth knowing. The docs suggest keeping each file under 200 lines, because longer files cost more context and are followed less reliably. Block-level HTML comments are stripped before the text reaches Claude, so notes for human maintainers cost nothing. And if two rules contradict each other, Claude may pick either, so conflicts are a context problem, not a style one.
Imports organise; they do not save space
A CLAUDE.md can pull in another file with @path/to/file. Relative paths resolve from the importing file, imports can nest up to four hops, and an @path inside backticks stays literal text. An import outside your working directory triggers a one-time approval prompt the first time Claude Code sees it in a project.
<!-- Maintainers: keep this under 200 lines. Stripped before Claude sees it. --> # Project - Build: pnpm build. Test one file: pnpm test -- <file>. - API handlers live in src/api/handlers/. - Release steps: @docs/release.md
The catch: imported files are expanded and loaded at launch with the file that imports them. Imports keep instructions tidy and shared across tools; they do not keep anything out of the window. For that you need one of the on-demand mechanisms below.
Rules that load only for matching files
Markdown files in .claude/rules/ load at launch like CLAUDE.md, unless they carry a paths field. Then they load only when Claude reads a file that matches.
--- paths: - "db/migrations/**/*.sql" --- - Never edit a migration that has shipped; add a new one. - Every migration needs a matching rollback file.
This is the right home for rules about one part of the codebase. One trade-off: a path-scoped rule arrives as part of the conversation, so compaction summarises it away and it comes back only when a matching file is read again. A rule that must hold all session belongs in the project-root CLAUDE.md or an unscoped rule.
Auto memory: what Claude writes for itself
Auto memory is on by default. Claude keeps notes per repository under ~/.claude/projects/<project>/memory/, with a MEMORY.md index of which the first 200 lines or 25KB load every session. Asking it to “remember” something goes there; asking it to “add this to CLAUDE.md” goes in the file you control. Claude Code memory covers what to keep and what to prune; for context engineering, the point is that MEMORY.md competes for the same window as everything else, so an index that grows without pruning costs you in every session.
/compact, /clear and /rewind
The conversation is the part of context that grows fastest. Claude Code compacts automatically as the window fills, and you can act first:
/clearwhen you switch to unrelated work. Old conversation crowds out what the next task needs and costs tokens on every message./compact focus on the auth bug fixbefore a long new stretch, so the summary keeps what you choose rather than what the automatic pass guesses./rewind, then a message, then “Summarize from here” or “Summarize up to here”, to compact only part of the conversation.
The context window guide (opens in a new tab) has a table of what survives. After compaction, the project-root CLAUDE.md, unscoped rules and auto memory are re-read from disk, as is a plan written in plan mode. Up to five recently modified files are re-read. Skills you invoked are re-injected but capped at 5,000 tokens each. Anything you said only in chat is summarised with everything else, which is why an instruction that must last belongs in a file, not a message. Long sessions also degrade in quieter ways; AI context rot explains why.
Subagents: read a lot, return a little
A subagent runs in its own context window with its own system prompt and tools, and returns only its result. The subagents documentation (opens in a new tab) puts it plainly: use one when a side task would flood your conversation with search results, logs or file contents you will not look at again. The built-in Explore subagent is read-only and is what Claude reaches for when it needs to search a codebase. Your own live in .claude/agents/ (project) or ~/.claude/agents/ (you), as Markdown with a name, a description and optionally a tools list. A subagent does not see your conversation history, so the task you hand it must say everything it needs. Claude Code subagent examples has patterns to copy.
Skills: long instructions that cost almost nothing until used
A skill is a folder with a SKILL.md, in .claude/skills/<name>/ or ~/.claude/skills/<name>/. According to the skills documentation (opens in a new tab), only its description sits in context until the skill is used, by you with /name or by Claude when the description matches the task. That makes skills the place for procedures: a release checklist, a migration recipe, a review routine. Add disable-model-invocation: true and even the description stays out of context until you call it. Because re-injection after compaction keeps the start of the file, put the instructions that matter most at the top.
Hooks that put context back
Most hook output goes only to the debug log. Two events are different: text a SessionStart or UserPromptSubmit hook prints is added to Claude’s context, as the hooks reference (opens in a new tab) describes. SessionStart matchers include startup, resume, clear and compact, so a hook matched on compact can restore something the summary would lose.
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/current-task.sh" }
]
}
]
}
}Keep what the script prints short: a hook that dumps a large file on every start is a CLAUDE.md you cannot see in /memory.
MCP tools are context too
By default Claude Code lists MCP tool names at startup and loads full schemas only when a task needs them. Tool results are another matter: the MCP documentation (opens in a new tab) says Claude Code warns when one output passes 10,000 tokens and, by default, saves anything over 25,000 to a file instead of the conversation. A server whose tools return tight, filtered answers is a context decision you make when you choose the server.
Keep task state outside the session
None of the levers above is a good home for the state of the work: what is in progress, what was decided, what the last session could not finish. Chat is summarised, memory is per machine, and CLAUDE.md is for rules that rarely change. Put the work on a board the next session can read. With fenbs connected over MCP, one CLAUDE.md line (“at the start of every session, call fenbs_get_context and list In Progress”) gives each session the AI context notes previous sessions left and the tasks already under way, at the cost of two tool calls rather than a growing file. Decisions people recorded sit on the same board, one fenbs_list_decisions call away. The Claude Code task-tracking workflow shows the full rhythm, and hooks that update the board automate the end of it.
Related
Connect Claude Code to a board with one command on the Claude Code integration page. AI context explains the notes fenbs keeps for assistants, and Claude Code project structure shows where each of these files sits in a repository.