The context window as a budget
System prompt, tools, history and tool results share one window; when it fills, truncation, clipping or summarising decide what is kept and what is lost.
Loading the animation…
Concept
Everything the model reads shares one window: the system prompt, the tool definitions, the task, the model's own messages and every tool result. The window also has to leave room for the answer. In the animation the harness keeps 512 tokens free for the answer, and compacts when the next prompt would pass 80% of the window.
The task reads four design notes, each a few hundred tokens of mostly background with a few facts the answer needs (★). With a 3,000-token window and no strategy, the run stops at turn 5: the prompt no longer fits. The three strategies keep it going, and lose different things:
- Truncate drops the oldest messages until the prompt is back under 50% of the window. It is cheap and blind: here it threw away mem, bw, params, kv, the two notes read first, every number the answer needs.
- Clip cuts old tool results to their first 6 lines and keeps a marker of what was cut. A fact near the top of a note survives; one further down does not: it lost bw, kv, free, batch.
- Summarise asks the model to write a summary of the older messages and replaces them with it. Here the summariser keeps every fact marked important, and nothing needed was lost. It is not free: each summary is another model call that reads everything it replaces, so the run cost $0.0368 against $0.0306 for truncation.
With a 4,000-token window, compaction fires once, at the end. Summarising then loses only facts nobody needed (the meeting day and an old revision note).
Maths
With window , reserve for the answer and trigger fraction , the harness compacts before turn when . Truncation then removes the oldest messages until
with the target = 0.5 here. Summarising replaces messages by a summary , for the price of one more model call that reads them all:
It pays when enough later calls re-read the saving; and it is the only one of the three that can keep a fact from a dropped message.
Code
The trigger, cut from the vendored engine (harness.ts):
const before = this.promptTokens(system, toolNames, msgs, turn);
if (strategy === "none" || before + reserve <= ctx.trigger * window)
return msgs;
const target = ctx.target * window;
const keep = ctx.keep_last as number;
What the public harnesses do
Claude Code compacts automatically: it "summarizes conversation history when approaching context limits", accepts instructions on what to keep (/compact Focus on code samples and API usage), and counts its own compactions and clearing of old tool results as expected cache rebuilds, because rewriting the history changes the prompt prefix (Claude Code, manage costs, accessed 2026-10-07). The same page notes that /compact "reads the conversation it summarizes, so compacting a large context is itself a large request", the cost in the second equation above. Clipping tool output before it reaches the model is the other lever: the same page shows a hook that filters test output down to the failures.