What fills the window
Every turn you've built so far appends to one array and resends the whole thing — the conversation is the context. That worked because your sessions were short. A real fix is not short: the agent reads a dozen files, runs bash twenty times, spawns a subagent, calls an MCP tool, and every one of those observations stays in the array, resent on every single request. The window is finite. This chapter is about surviving the moment it fills up.
What fills the window
The context window is the model's whole working memory for a session, measured in tokens. Before the user even types, a chunk is already spent on startup content: the system prompt, the tool definitions you registered in Chapter 5, CLAUDE.md and any imported memory, and the descriptions of your loaded skills. Then the session itself accumulates: every user message, every assistant turn (text + reasoning), and — the heaviest by far — every tool result. A single view of a long file or a noisy bash run can be thousands of tokens, and it sits in the array forever, paid for again on every turn.
┌─ startup (re-sent every turn, reloads after compaction) ─────────┐
│ system prompt · tool defs · CLAUDE.md / memory · skill *names* │
├─ session history (grows without bound until you compact) ────────┤
│ user message "fix the failing auth test" │
│ assistant text + thinking │
│ tool_use view(auth.ts) → tool_result (240 lines of file) │ heavy
│ tool_use bash(npm test) → tool_result (full stack trace) │ heavy
│ tool_use str_replace → tool_result ("edited auth.ts") │
│ ... ×N turns ... │
└──────────────────────────────────────────────────────────────────┘
used / limit → cross the threshold → compact
You track this as pressure: used / limit. As the session runs, used climbs toward limit. You don't wait for it to hit the wall — once you'd overflow on the next turn, the request fails outright and the session is dead. Instead you set a threshold (Claude Code compacts well before the hard limit) and act when pressure crosses it. The next step uses 75% as the trip wire: at used / limit ≥ 0.75, it's time to compact.
What survives compaction
Compaction replaces the bloated history with a compact summary so the session can keep going. The hard part is not summarizing — it's deciding what is load-bearing. Get it wrong by dropping too much and the agent forgets what it was doing; keep too much and you never relieve the pressure. The policy is not a matter of taste; it follows from one question: after the summary, what does the agent need to pick up exactly where it left off?
KEEP — the agent can't continue without it
user-intent the original goal ("fix the failing auth test")
edit diffs already applied — what changed on disk
error failures seen — so it doesn't repeat them
task / open the open to-do list — what's still unfinished
DROP — reconstructable, or pure noise once acted on
tool-output verbatim file dumps & bash stdout (huge, stale)
reasoning intermediate thinking between turns
skill-description reloads on demand when a skill is invoked
RE-INJECT after the summary
startup system prompt, tool defs, CLAUDE.md, skill names
Compaction doesn't just delete — it summarizes-then-reloads. The verbose middle collapses into a structured summary, and the startup content (system prompt, tool defs, CLAUDE.md, skill names) is re-injected fresh at the top so the compacted session still knows its tools and rules. The next step builds the classifier that decides each item's fate; the step after writes the transcript so nothing dropped from the window is lost from the record.