Agents that run for hours fail mostly from bloated or missing context, not from weak models; managing it is the core expert skill.
Prompt engineering is about writing a good prompt. Context engineering is the broader job of deciding, at every step of an agent, which tokens are in the window: instructions, tool definitions, history, retrieved data, tool results and memories. The goal, in Anthropic's words, is the smallest set of high-signal tokens that makes the right next action likely.
Why it matters: accuracy degrades gradually as the window fills (context rot), every token costs money and time, and a long-running agent can produce far more tool output than any window holds.
Core techniques:
- Lean, stable foundations. A clear system prompt at the right level of detail, and a small set of distinct tools with unambiguous descriptions. Overlapping tools confuse choice and waste tokens. Some platforms can load tool definitions on demand instead of all up front.
- Just-in-time retrieval. Keep references (file paths, record ids, queries) and let the agent fetch content with tools when needed, instead of preloading everything. Often a hybrid works best: preload a little, explore the rest.
- Trim tool results. Return concise, relevant output from tools (pages of results, not thousands of rows) and clear old tool results once used.
- Compaction. When the window nears its limit, summarise the history (decisions, open issues, key facts) and continue in a fresh window. Tune summaries to keep what later steps need. Some providers now compact automatically on the server.
- Structured notes. The agent keeps a progress file or to-do list outside the context and rereads it, so work survives compaction and new sessions.
- Sub-agents. Delegate deep exploration to sub-agents whose large contexts are thrown away, keeping only their short summaries.
Order matters too: stable content first (which also enables prompt caching), volatile content last. Measure all of this with evals on long tasks.
Example
def compact(messages, summarise, keep_last=6, max_tool_chars=500):
"""Shrink an agent's history before the next model call."""
old, recent = messages[:-keep_last], messages[-keep_last:]
trimmed = []
for m in recent: # trim bulky tool output in the recent turns
if m["role"] == "tool" and len(m["content"]) > max_tool_chars:
m = {**m, "content": m["content"][:max_tool_chars] + " ...[trimmed]"}
trimmed.append(m)
if not old:
return trimmed
summary = summarise(old) # a model call: decisions, open issues, key facts
return [{"role": "user", "content": "Summary of earlier work:\n" + summary}] + trimmed
history = [{"role": "tool", "content": "x" * 2000}] * 10
print(len(compact(history, summarise=lambda ms: f"{len(ms)} earlier steps"))) # 7Remember
- Context engineering = choosing the tokens in the window at every agent step
- Fetch just in time, trim tool output, compact history, keep notes outside the window
- Use sub-agents to isolate heavy exploration; keep stable content first