The model reads its whole context window again on every call, and an agent's history grows by every step. Context engineering is deciding what goes into each request: the stable parts first so the cache can read them, and one move (select, compress, write or isolate) for each part that grows.
Prompt engineering tuned the wording of one message. An agent at step 30 has a different problem: its window is full of old tool output, and no wording fixes that. Anthropic calls the discipline context engineering. It sits between the harness (what the model can touch) and the loop (how the work repeats). The guide's Context Engineering section is the full lesson; this post is the map.
The window is re-read on every call
6,000 tokens of system prompt and tools, plus 2,500 tokens per step (the call and a whole-file result). Call n reads 6,000 + 2,500 × (n − 1). Sonnet 5.5 list prices of 2026-10-08: $2 per million input, $2.50 cache write, $0.10 cache hit.
The agent loop keeps no state except messages[], and it sends all of it every time. Current models have a 1M-token window, so overflow comes late. The bill and the quality loss come early. This run crosses the default 150,000-token compaction trigger at call 59.
Interactive: add steps until the run crosses the 150,000-token compaction trigger, then swap whole-file steps for grep-sized ones.
Counts depend on the tokenizer. Claude 4.7 and later models produce about 30% more tokens for the same text than Sonnet 4.6 and earlier. If you measured 2,500 tokens a step on an older model, budget about 3,250 on Sonnet 5.5: a per-token price comparison understates the change.
Context rot: quality drops before the window is full
Long before a request is too long, it gets worse. Anthropic's docs call this context rot: accuracy and recall fall as tokens accumulate. The best-known measurement is “Lost in the Middle” (Liu et al., 2023): facts placed mid-context were recalled worst. It measured 2023 models, so treat the curve as a shape, not a number; the advice it gives still holds.
An agent that starts strong and then repeats tool calls, loses the goal or ignores a rule it followed earlier is almost never a model problem. Look at what is in its window before you reach for a bigger model.
Select: retrieve the smallest slice that answers the step
{"type": "tool_use", "name": "describe_table",
"input": {"table": "orders"}}
stop_reason: "tool_use"orders(id uuid pk, customer_id uuid fk, status text,
total_cents int, created_at timestamptz)
Two lines in the window instead of an 8,000-line schema in the system prompt.Pasting the whole schema, the whole wiki or every file “just in case” is the most common mistake. Give the agent tools that fetch what a step needs, when it needs it: a search, a file read with line ranges, a describe_table. Good tool results are short by design. This is retrieval discipline from RAG, applied inside the loop.
Compress on the server, never by rewriting turns
- delete old tool results, summarise turns 1–40 in place
- a 400 on the newest models (Fable 5.1, Opus 5.5) for accounts created on or after 2026-08-31
- the cache misses from the edit onward
- you send the history exactly as it grew
- compaction summarises older turns into one block
- context editing clears finished tool results and old thinking
Rule of thumb: on current Claude models, history is append-only. Shrinking it is the server’s job.
import anthropic
client = anthropic.Anthropic()
resp = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=16000,
betas=["compact-2026-01-12"],
context_management={"edits": [{"type": "compact_20260112"}]},
tools=TOOLS,
messages=messages,
)
# Append ALL of content: it can carry a compaction block.
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "tool_use":
messages.append({"role": "user", "content": run_tools(resp.content)})
elif resp.stop_reason != "end_turn": # max_tokens, pause_turn, refusal
handle_stop(resp)
Threshold compaction fires at 150,000 input tokens by default (minimum 50,000). The docs now recommend the on-demand variant (beta compact-2026-09-04) where it is available: your code picks the moment, and it can keep recent turns word for word.
The trap is appending only the text: the compaction block rides in resp.content, and dropping it makes the agent forget silently. Writing your own summary is still valid on other providers, or by starting a new conversation from it. The details, including what compaction costs, are in Context Management.
Write durable state outside the window
- Plan to a fileThe agent writes the checklist to
MIGRATION.md. - Do one itemOnly that item’s files enter the window.
- Tick it offProgress lives on disk, not in history.
- Read the next itemNever the record of everything already done.
The window is working memory: fast, small and gone when the session ends. Anything that must outlive it goes outside: a plan file, a task list, a CLAUDE.md of project conventions, or the API’s memory tool, which lets Claude read and write files you store. The window stays lean because the memory is not in it. Which kind of memory lives where is in Agent Memory.
Isolate side work whose output dwarfs its answer
“Find every call site of the deprecated auth() helper” runs in a subagent with a fresh window. The parent sees the list, never the files. Isolation buys a clean window, not a cheaper task: Anthropic’s research system used about 15 times the tokens of a chat. Use it where the main window would otherwise flood, as in Hierarchical Delegation.
Order the request for the cache
| Change | Effect | Do this |
|---|---|---|
| A timestamp in the system prompt | misses on every call | put it in the newest turn |
| An edit to an earlier turn | misses from the edit | append a turn instead |
| A tool added mid-session | the whole cache misses | freeze tools at start |
The cache matches a prefix in one order: tools, then system, then messages. One changed byte invalidates everything after it. That is why the hero puts the stable sources first. On Sonnet 5.5 a cache hit costs 0.05× of input, which is how the run above drops from $9.57 to $0.85. Check usage.cache_read_input_tokens on every call; the mechanics are in Prompt Caching.
Worked example: a refactor at call 60
- call 60 reads 153.5K tokens, mostly stale file dumps
- crosses the compaction trigger at call 59
- 4.8M input tokens: $9.57 uncached, $0.85 cached
- re-reads
auth.tsa third time and redoes the login flow
- grep finds 12 call sites; the subagent did the search
- call 60 reads 59.1K tokens; no compaction needed
- 2.0M input tokens: $3.91 uncached, $0.34 cached
- progress lives in
MIGRATION.md: login and signup done
Same model, same task. The only difference is what was allowed into the window.
Input only, Sonnet 5.5 list prices of 2026-10-08, each call writing its new tail to the 5-minute cache and reading the rest. Per-step sizes are illustrative.
Treating a 1M window as permission to stuff it. Appending resp.content[0].text after enabling compaction. Clearing tool results every turn “to save tokens”, which turns every request into a cache write. Quoting token budgets measured on an older tokenizer.
“The agent’s context window is full after 10 tool calls. What do you do?” Name the source that grew, then the move: shorter tool results (select), server-side clearing or compaction (compress), a plan file (write), a subagent (isolate). Say that you never edit sent history on current models, and that caching fixes the bill, not the quality.
Your agent is at call 50 on Opus 5.5 and the history is too long. A teammate proposes deleting the oldest 20 tool results client-side. What goes wrong?
On the newest models history is append-only: editing earlier turns invalidates the thinking blocks after them, and accounts created on or after 31 August 2026 get a 400. Even where it is accepted, the prompt cache misses from the edit onward. Use server-side context editing (clear_tool_uses) or compaction instead; the client keeps sending the full history.
Caching cut the run's input bill from $9.57 to $0.85. Is the context problem solved?
No. Caching makes re-reading cheap, not short. The model still reads 153.5K tokens on call 60, and recall still sags in the middle. Cost and quality are separate budgets; select, compress, write and isolate shrink both.
A search over 40 files would add 60K tokens to the main window. Which move, and what does it cost?
Isolate it in a subagent: it burns its own window and returns a short list. The main window stays clean, but total tokens go up, not down (Anthropic measured multi-agent systems at about 15 times the tokens of a chat), so isolate work whose output is much larger than its answer.
- Every call re-reads the whole request; history grows by every step, so cost and quality both degrade early.
- Context rot starts long before overflow: keep the goal and rules where they are read well.
- Four moves: select what a step needs, compress history on the server, write state to files, isolate side work.
- History is append-only on current Claude models: compaction and context editing are how it shrinks.
- Put stable sources first so the cache reads them; caching makes re-reading cheap, not short.