What You Need to Know
The context window is everything the model reads on one request: the system prompt, the conversation, the tool results and the response it writes. An agentic run is a job in which the model calls tools step after step. Prompt engineering asks what the instructions say. Context engineering asks what is in the window at all. Anthropic defines it as "the set of strategies for curating and maintaining the optimal set of tokens (information) during LLM inference". That covers everything that lands in the window, not only the text you wrote. Agentic runs are where these choices count, because there the window fills up on its own.
A garden centre runs an agent each week to plan restocking and plant care. Over hundreds of steps it looks up stock records, reads supplier price lists and checks watering logs. The manager set the standing rules at step one: prices in pounds, one order line per supplier, and no chemical sprays on the café's herb beds.
Bloat and Drift Are Not the Same Fault
A long run can fail in two ways, each with its own cause and fix.
Bloat is a problem of volume. An agentic run collects full API payloads, whole file contents and complete search results. The window fills with material whose useful content was extracted twenty steps ago. Cost and latency climb with each step, and in the end a request no longer fits. At the garden centre, a stock lookup from step ten became one line: order 40 trays of begonias. Its full record still sits in the window.
Drift is a problem of behaviour. The standing rules were stated once. They now sit hundreds of turns back, behind everything piled up since, so the model stops following them. Formats vary, a rule gets skipped, and an established fact gets contradicted. The task stays the same while the output changes character. By step three hundred, order lines mix suppliers and one plan sprays the herb beds.
Length makes both faults worse, not only more expensive, because attention is finite. Anthropic says models have "an 'attention budget' that they draw on when parsing large volumes of context. Every new token introduced depletes this budget by some amount". As the token count grows, "the model's ability to accurately recall information from that context decreases".
A bigger window is not a fix
Moving to a model with a larger context window postpones the size failure. It does nothing about recall. A run that degrades at 150k tokens degrades at 400k instead, having spent more per step. With a bigger window, the garden centre's herb-bed rule is still three hundred steps back. Pruning and compaction address bloat. Placement, moving the rules to where the model reads them, addresses drift. Window size addresses neither.
The cheapest cure for bloat is to keep material out of the window until the task needs it. Anthropic's engineering guidance, current as of September 2026, calls this "just in time" loading. Instead of pasting every record into the prompt up front, the agent keeps "lightweight identifiers (file paths, stored queries, web links, etc.)". It loads the data through its tools when the task calls for it. The garden centre's agent would hold product codes and open a record only when it needs one. Lookups at run time are slower than data loaded in advance, so the same guidance describes a hybrid. A small core goes in up front, the way Claude Code loads CLAUDE.md. The agent fetches everything else as it needs it.
Pruning Spent Tool Output
Raw tool results are the largest single source of bloat. The fix keeps the fact the agent extracted and discards its payload. The guide calls this tool output pruning. Current docs implement it as context editing, a Messages API beta behind the header context-management-2025-06-27.
import anthropic
client = anthropic.Anthropic()
response = client.beta.messages.create(
model="claude-sonnet-5-5",
max_tokens=4096,
betas=["context-management-2025-06-27"],
tools=TOOLS,
messages=messages,
context_management={
"edits": [
{
"type": "clear_tool_uses_20250919",
# Start clearing at 60k rather than the 100k default.
"trigger": {"type": "input_tokens", "value": 60000},
# Keep the five most recent tool use/result pairs intact.
"keep": {"type": "tool_uses", "value": 5},
# Clear enough to be worth the cache write it costs.
"clear_at_least": {"type": "input_tokens", "value": 8000},
# Results still cited downstream must survive.
"exclude_tools": ["fetch_site_record"],
"clear_tool_inputs": False,
}
]
},
)
for edit in response.context_management.applied_edits:
print(edit.type, edit.cleared_tool_uses, edit.cleared_input_tokens)Three mechanics matter most. First, the clearing is server-side. Your client keeps the full, unmodified history and needs no bookkeeping of its own. Second, each cleared result is replaced with placeholder text telling Claude something was removed. So the model knows it once had that material. By step fifty, the begonia record is a placeholder, and the agent can tell something was there.
Third, the response reports what happened in context_management.applied_edits, with cleared_tool_uses and cleared_input_tokens. Those are the numbers worth logging on each step. The token-counting endpoint previews the effect, returning original_input_tokens alongside the post-clearing input_tokens. A second strategy, clear_thinking_20251015, does the same job for extended-thinking blocks. When both are present, it must be listed first in the edits array.
Clearing invalidates the cached prefix from the clearing point. That is why clear_at_least exists. It stops the run paying a cache write to reclaim a trivial number of tokens. Cache mechanics belong to 2.3 and cache economics to 5.4.
Compaction and the Preservation Contract
Compaction is for a long transcript that has to continue rather than end. It replaces the settled portion with a structured summary and carries on from it. As of September 2026 the API supports it in two forms, both in beta. The docs say: "Use on-demand compaction wherever it is available".
- Compaction on demand (beta header
compact-2026-09-04). Your code decides when. You send the conversation as it stands with the top-levelcompactionparameter, and the response is a singlecompactionblock withstop_reasonofcompactionand no reply. Your code then swaps the block in: it goes first inmessages, in place of the messages it summarises. - Compaction at a token threshold (beta header
compact-2026-01-12). The API decides when. Acompact_20260112edit incontext_managementsummarises inside an ordinary request once input tokens reach the trigger, and you append the response as usual.
The compaction parameter cannot be sent with context_management. The threshold edit cannot run on a request that carries an on-demand block.
# On demand: your code asks for the summary, then swaps it in.
summary = client.beta.messages.create(
model="claude-sonnet-5-5",
max_tokens=4096,
betas=["compact-2026-09-04"],
system=SYSTEM,
tools=TOOLS, # the same system prompt and tools as the rest of the run
messages=messages,
compaction={"type": "summarize"},
)
if summary.stop_reason == "compaction":
# The block replaces every message it summarised and goes first.
messages = [{"role": "assistant", "content": summary.content}]# At a token threshold: the API compacts inside an ordinary request.
response = client.beta.messages.create(
model="claude-sonnet-5-5",
max_tokens=4096,
betas=["compact-2026-01-12"],
messages=messages,
context_management={
"edits": [
{
"type": "compact_20260112",
# Minimum accepted value is 50,000; the default is 150,000.
"trigger": {"type": "input_tokens", "value": 120000},
# WARNING: this REPLACES the default summarisation prompt.
"instructions": (
"Preserve: decisions already taken and why, facts established "
"and their sources, constraints and prohibitions still in force, "
"open questions, and the state of unfinished work. Drop raw tool "
"payloads already reduced to facts, and superseded attempts."
),
"pause_after_compaction": False,
}
]
},
)
# Compaction is billed as its own iteration and is NOT in the top-level counts.
total = sum(it.input_tokens + it.output_tokens for it in response.usage.iterations)Two mechanics matter here. First, the summarised turns stop informing the model, and nothing is archived anywhere you can retrieve it. In the threshold form, the API ignores every content block before the compaction block on the next request. In the on-demand form, your code has already removed those messages. Documents, images and fetched URLs inside the summarised turns are lost with them, so re-send anything a later turn still needs.
Second, in both forms a custom instructions string replaces the default summarisation prompt entirely. It does not add to it. Anything the default would have kept is no longer asked for unless your string names it. A hand-written line saying "summarise the code changes" gets you the code changes and little else. A garden centre string asking for "the orders placed" keeps the orders and drops the herb-bed rule.
So the preservation contract is an engineering artefact you write down in advance. It names what to preserve:
- decisions and their reasons
- established facts and their sources
- constraints and prohibitions still binding
- open questions
- the state of partially finished work
It drops the raw material those decisions came from, superseded attempts, and verbose payloads already reduced to facts. Anthropic states the risk plainly: "overly aggressive compaction can result in the loss of subtle but critical context whose importance only becomes apparent later". No crash follows. A contradiction appears fifteen steps on, traced back to a summary written long before, if anyone traces it at all.
The compaction pass is billed as its own iteration and appears in usage.iterations. The top-level input_tokens and output_tokens exclude it, and on an on-demand compaction request they read zero. A cost model that reads only the top-level fields undercounts every compacting run.
Context awareness can work against compaction. As of September 2026, Claude Sonnet 5, Claude Sonnet 4.6, Claude Sonnet 4.5 and Claude Haiku 4.5 have it. The API tells these models their total window and, after each tool call, how much of it is left. In a harness that compacts, such a model "may sometimes naturally try to wrap up work as it approaches the context limit". The job stops unfinished, with the garden centre's weekend plan half written. The documented fix is a line in the prompt saying the context will be compacted automatically, so the model should not stop early.
Isolating the Sprawl
The guide's phrase is context isolation through subagents or multi-step agentic workflows. The saving comes from keeping the exploration out of the main window entirely, not from summarising it afterwards. The Agent SDK says each subagent "runs in its own conversation, which starts fresh unless the subagent is a fork". And "either way, intermediate tool calls and results stay inside the subagent; only its final message returns to the parent". A subagent that reads forty files returns a paragraph, and the forty files cost the main conversation nothing. At the garden centre, those could be forty supplier price lists.
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition
async def main():
async for message in query(
prompt=(
"Use the log-triage agent to find the cause of the 03:12 batch failure. "
"The run log is at /var/log/batch/2026-08-19.log, the failing job is "
"settle-nightly, and retries are capped at three by policy. Return a "
"cause, the log lines that support it, and nothing else."
),
options=ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"],
agents={
"log-triage": AgentDefinition(
description="Reads large log files and returns a single cause with evidence.",
prompt="You isolate failures in batch logs. Report one cause and the lines that support it.",
tools=["Read", "Grep", "Glob"],
),
},
),
):
if hasattr(message, "result"):
print(message.result)
asyncio.run(main())Unless the subagent is a fork, its context window "starts fresh, with no parent conversation, but isn't empty". It gets its own system prompt and the Agent tool's prompt string. It does not get the parent's conversation history, tool results or system prompt. So every file path, error message and decision it needs goes into that prompt. That is why the example above spells out the log path, the job name and the retry cap the main conversation already knew. The price-list subagent would need the folder path, the week's budget and the stop list. In the other direction, the parent receives only the subagent's final message. Ask for it in the shape the parent will use.
Isolation is not free. The documented line depends on the shape of the work rather than its size. Reach for a subagent when:
- the task "produces verbose output you don't need in your main context"
- you want to enforce specific tool restrictions or permissions
- the work is self-contained and can return a summary
Stay in the main conversation when:
- the task needs frequent back-and-forth or iterative refinement
- multiple phases share significant context
- you are making a quick, targeted change
- latency matters, since a subagent that is not a fork starts fresh and may need time to gather context
The price-list comparison fits the first list. Agreeing the week's orders with the manager fits the second. The same shape works without subagents as a multi-step workflow. Run the sprawling step as its own API call with its own message list. Keep the structured result. Start the next step from that result rather than from the transcript that produced it.
Where a Fact Should Live
A transcript records how you got here. Memory is the set of facts that must still be true tomorrow. Confusing the two produces a common anti-pattern: replaying an entire prior conversation into a new session so the model "remembers". That pays full input cost for everything that ever happened to recover a handful of facts, into the most crowded possible window, every session. Next Monday, the garden centre's agent needs only the supplier stop list and the herb-bed rule.
The memory tool is the documented alternative. It is generally available on the Messages API with no beta header. It is declared as a single tools entry and is available on all Claude 4 and later models:
message = client.messages.create(
model="claude-opus-5-5",
max_tokens=2048,
tools=[{"type": "memory_20250818", "name": "memory"}],
messages=[{"role": "user", "content": "Resume the vault-servicing schedule."}],
)The tool is client-side. Claude issues view, create, str_replace, insert, delete and rename commands against paths under a /memories prefix. Your handler maps that prefix onto whatever storage you run and returns the result in a tool_result block. When the tool is present, the API injects its own memory protocol into the system prompt. Its operative line states the design assumption. It reads: "ASSUME INTERRUPTION: Your context window might be reset at any moment, so you risk losing any progress that is not recorded in your memory directory".
The three techniques compose rather than compete, and the docs say how: "compaction keeps the active context small without client-side bookkeeping, and memory preserves the information that must survive summarization". Context editing clears specific tool results on the client's behalf. The no-bookkeeping claim holds for threshold compaction. On demand, the swap is bookkeeping your code does. For a long-running job, that is the whole stack. Prune the spent payloads and compact the settled transcript. Write anything that must outlive the compaction into memory before it fires. The garden centre's herb-bed rule goes into memory before the first compaction.
Ordering Is a Context Decision
With a long document and a question about it, the document goes first and the question and instructions go after. For inputs over about 20k tokens the guidance is explicit. It says: "Put longform data at the top: Place your long documents and inputs near the top of your prompt, above your query, instructions, and examples". It also makes a measured claim: "queries at the end can improve response quality by up to 30 percent in tests, especially with complex, multidocument inputs". The instruction the model acts on is the last thing it read. A question buried under 20k tokens of contract competes with everything after it. When the garden centre asks which clauses in a supplier contract cover unsold stock, the contract goes first.
Two structural refinements travel with the rule. Wrap each document in its own tags with metadata, so multi-document inputs stay individually addressable:
<documents>
<document index="1">
<source>annual_report_2023.pdf</source>
<document_content>{{ANNUAL_REPORT}}</document_content>
</document>
<document index="2">
<source>competitor_analysis_q2.xlsx</source>
<document_content>{{COMPETITOR_ANALYSIS}}</document_content>
</document>
</documents>
Analyse both documents. Identify strategic advantages and recommend Q3 focus areas.Then ground the answer in quotes. Ask Claude to quote the relevant parts of the documents first, before carrying out the task. That narrows attention to the passages that matter and leaves a string you can search for in the source. The garden centre gets the returns clause quoted before the answer.
In the exam
Items in this sub-skill test curation decisions on agentic runs. Half of them turn on telling bloat from drift. The bigger-window option is the standing distractor in every degradation item. The exam likes one anti-pattern: replaying a prior conversation into a new session so the model "remembers".
Dated current state, 30 September 2026
The type strings, headers and defaults above are current as of this date and have changed shape between releases. Remember the mechanism. The exact strings and figures live in the domain quick reference, where a rename is a one-line fix.
Exam Traps
Reading a degradation symptom as a capacity problem, and answering a slower, pricier, less accurate long run with a bigger context window or a stronger model.
Both postpone the ceiling and neither restores recall, because accuracy falls as the window fills regardless of where the ceiling sits. The keyed moves are pruning the spent tool payloads and compacting the settled transcript.
Treating bloat and drift as one fault, so a pruning answer is offered for wandering behaviour or a placement answer for a window that will not fit.
Format variation and skipped rules describe drift, fixed by moving the rules to a surface that is always present. Rising cost, latency and request size describe bloat, fixed by clearing and summarising. A long run can show shades of both at once, so follow the dominant symptom rather than expecting a clean split.
Believing compaction is lossless or reversible, so the original transcript can be consulted later and the default summary keeps everything important.
In both forms the summarised turns stop reaching the model: with threshold compaction the API ignores every content block before the compaction block, and with on-demand compaction your code removes them. A custom instructions string replaces the default summarisation prompt entirely rather than extending it, and compaction cost sits in usage.iterations, outside the top-level token counts.
Assuming an isolated context knows what the main one knows, so a subagent will pick the standing constraints up from the conversation.
A subagent inherits no parent history, tool results or system prompt. That option describes an impossible mechanism. The constraint reaches the subagent only if the Agent tool prompt states it.
Practice Scenario
An ice-house trust runs a long agentic job that plans a week of chiller servicing across sixty vaults. At step forty the harness compacts the transcript at a token threshold and the run continues from the summary. Three steps later the agent schedules a chiller isolation in vault 12, which it had itself recorded at step nine as holding a conservation deposit that must never lose refrigeration. The compaction summary names the vault but not the constraint. The trust is staying on its current model. Its constraint register for the sixty vaults is far too long to repeat on every step. What happened, and what is the fix?
Build Exercise
Instrument the Window, Then Take Three Things Out of It
What you'll learn
- How to measure where a context window actually fills up
- How context editing clears spent tool results and what it reports back
- What a compaction summary keeps by default and what a custom instructions string silently drops
- How an isolated context changes the cost and the handover burden
- Build a small agentic loop in Python or TypeScript that calls one real tool at least fifteen times, and log per step: input_tokens, output_tokens, wall time, and the character count of the tool result you appended
Why: You cannot curate a budget you have never measured, and the shape of the curve tells you which technique is worth applying.
You should see: A per-step table where the tool-result column grows far faster than anything else.
- Plot the per-step input token count and mark where the tool payloads overtake the rest of the window. That number is your baseline
Why: A named baseline is what turns each later change from an opinion into a measurement.
You should see: A crossover point, usually much earlier than expected.
- Add a clear_tool_uses_20250919 strategy behind the context-management-2025-06-27 beta header, set trigger and keep deliberately rather than by default, and read context_management.applied_edits back
Why: Setting the values yourself forces the judgement the defaults hide, and applied_edits is the only honest record of what was removed.
You should see: cleared_tool_uses and cleared_input_tokens on the steps where clearing fired, and a flattened input-token curve after it.
- Write down the three facts the run must not lose. Then add a compaction strategy, let it fire, read the compaction content block, and check whether all three survived
Why: Writing the contract before the summary exists is the discipline; checking it afterwards is the only way to know the default prompt kept what you assumed.
You should see: A summary that keeps some of your three facts and, very likely, quietly loses one.
- Re-run with an explicit instructions string and diff the two summaries, remembering that your string replaces the default prompt rather than adding to it
Why: The replacement behaviour is the trap: a focused instruction can preserve your three facts while no longer asking for what the default used to keep.
You should see: Your three facts present, and something the default summary had kept now missing.
- Move the sprawling half of the job into an isolated context, a subagent or a separate API call, and pass it deliberately only what it needs
Why: The handover constraint only becomes real when something you assumed was shared turns out not to be.
You should see: A first attempt that gets something wrong because you never told it, and a returned result the main context cannot use as-is.
- Write the durable facts to a memory store instead of the transcript, restart from an empty window plus that memory, and compare total input tokens and correctness against your baseline
Why: This is the whole sub-skill in one measurement: which intervention moved which number, and at what cost to correctness.
You should see: A three-row comparison naming what pruning, compaction and memory each bought you.
Sources
- Effective context engineering for AI agents — Anthropic engineering, the attention budget, context rot, just-in-time loading and the compaction risk
- Context editing — Claude Docs, clear_tool_uses_20250919, its parameters and applied_edits
- Compaction overview — Claude Docs, choosing between on-demand and threshold compaction
- Compaction on demand — Claude Docs, compact-2026-09-04, the compaction parameter, the swap, what the summary cannot carry, and the clash with context_management
- Compaction at a token threshold — Claude Docs, compact_20260112, its trigger, the instructions string, the compaction block and usage.iterations
- Context windows — Claude Docs, context awareness and the models that have it
- Memory tool — Claude Docs, memory_20250818, the client-side commands and the memory protocol
- Subagents in the SDK — Claude Docs, context isolation and what a subagent does and does not inherit
- Subagents — Claude Docs, choosing between a subagent and the main conversation (the reach-for/stay-in lists)
- Prompting best practices — Claude Docs, long-context prompting, document-first ordering, and context awareness near the limit
- Claude Certified Developer Foundations Exam Guide — Domain 6, Context Engineering — Anthropic