Context Engineering for LLM Agents: Write, Select, Compress

Photo by Eilis Garvey on Unsplash
Context engineering is the discipline of curating and maintaining the optimal set of tokens an LLM sees during inference: the system prompt, tools, retrieved data, memory, and conversation history. For agents that run many turns, it manages the whole information state on every step, not just one prompt. Anthropic calls it the natural progression of prompt engineering.
Prompt engineering focuses on the wording of a single instruction written once before a call. Context engineering governs the entire token set assembled on every step, including tools, retrieved documents, memory, and history. Prompt engineering is now considered a subset of context engineering, because in a real agent the prompt is only one input among many.
It went mainstream in June 2025. Shopify CEO Tobi Lutke endorsed it on 19 June, and Andrej Karpathy amplified it on 25 June, calling it the art and science of filling the context window with the right information for the next step. Anthropic then published a formal engineering guide on it in September 2025.
Drew Breunig catalogues four modes: poisoning (an error is referenced repeatedly), distraction (the model over-focuses on a long context), confusion (superfluous tools or content lower quality), and clash (new information conflicts with existing). Anthropic separately describes context rot, where recall accuracy drops as the token count grows.
LangChain groups them as write, select, compress, and isolate. Write saves information outside the window (scratchpads, memory); select pulls in only relevant tokens via RAG and just-in-time loading; compress summarizes or trims tokens (Claude Code auto-compacts near 95% utilisation); isolate splits work across sub-agents that return condensed summaries.

Photo by Eilis Garvey on Unsplash
Key Takeaway
Context engineering is the discipline of curating exactly which tokens an LLM agent sees at each step: system prompt, tools, retrieved data, memory, and history. It superseded prompt engineering for production agents in 2025 because most agent failures are context failures, not model failures, and overloading the window degrades accuracy.
For two years the craft was called prompt engineering, and it mostly meant polishing one clever instruction until a chatbot behaved. That framing broke the moment I started shipping agents that run for hundreds of turns, call tools, and read documents. The wording of the prompt turned out to be a tiny fraction of what determined success. Everything else in the window, the retrieved chunks, the tool outputs, the conversation history, the memory, mattered far more.
In this post I walk through what context engineering actually is, why the term crystallised in 2025, the specific ways a context window fails, the four strategies I use to keep it healthy, and the published numbers that show the impact. Every figure here is drawn from a primary source linked at the end.
The label went mainstream in June 2025. On 19 June, Shopify CEO Tobi Lutke wrote that he preferred context engineering over prompt engineering because it describes the core skill better: the art of providing all the context for the task to be plausibly solvable by the model. Six days later, on 25 June, Andrej Karpathy endorsed it, calling context engineering the delicate art and science of filling the context window with just the right information for the next step. In September 2025 Anthropic published an engineering guide defining it as the strategies for curating and maintaining the optimal set of tokens during model inference.
The key mental shift is that prompt engineering is now a subset of context engineering. Writing a good instruction still matters, but in a real agent it is one input among many. Anthropic frames context engineering as the natural progression of prompt engineering: instead of crafting a single prompt, you manage the entire state of information the model sees across every turn.
| Dimension | Prompt engineering | Context engineering |
|---|---|---|
| Scope | One hand-written prompt | The whole token set across every turn |
| Unit of work | The wording of a single instruction | System prompt, tools, retrieved data, memory, history |
| When it runs | Once, before the call | Continuously, rebuilt on every step |
| Main failure risk | A vague or clumsy instruction | Overloading the window until recall degrades |
Longer context is not automatically better. Anthropic describes context rot: as the number of tokens grows, the model's ability to accurately recall information from that context decreases, because attention is stretched across more pairwise relationships. Drew Breunig catalogued four concrete ways contexts fail, each with evidence from public studies.
More context is not a free upgrade. A model with a million-token window can still lose the thread at a fraction of that limit, so treat every token you add as a cost, not a feature. If a chunk does not help the next step, leaving it out usually improves the answer.
LangChain groups the working techniques into four categories, using a useful analogy: the context window is like RAM, a finite resource an operating system curates. Almost everything I do in production maps onto one of these four verbs.
Here is the shape of a single agent turn when you treat context as a budget. It writes a small stable core, selects only the tools and documents that fit the goal, and compresses history the moment it nears the limit. The point is that context assembly is code you own, run on every step, not a one-off prompt.
# One agent turn: assemble context under a fixed token budget
MAX_TOKENS = 180_000
COMPACT_AT = 0.95 # Claude Code auto-compacts near 95% utilization
def build_context(state):
# WRITE once, keep it small: system prompt + a few canonical examples
ctx = [state.system_prompt, *state.canonical_examples]
# SELECT: RAG over tool specs and docs — pull the few that fit the goal,
# not all 40 tools (more tools measurably lowers tool-call accuracy)
ctx += select_relevant(state.tools, state.goal, top_k=5)
# SELECT just-in-time: keep lightweight IDs, load full docs only on demand
ctx += retrieve(state.query, top_k=5)
ctx += state.recent_messages
# COMPRESS: if we near the budget, summarize the oldest turns and
# keep decisions, open bugs, and file paths — then drop the raw history
if count_tokens(ctx) > MAX_TOKENS * COMPACT_AT:
summary = summarize(state.older_messages,
keep=["decisions", "open_bugs", "file_paths"])
ctx = replace(ctx, state.older_messages, summary)
return ctx # ISOLATE heavy sub-tasks in sub-agents that return ~1-2k tokens
Anthropic's practical advice: start with the smallest prompt on the best model you have, then add instructions only where you observe real failures. Prefer a few diverse, canonical examples over an exhaustive list of edge cases. A lean context you grow deliberately beats a bloated one you trim later.
The reason this stopped being optional is that the numbers are large and repeatable. A 39 percent multi-turn drop, an o3 score collapsing from 98.1 to 64.1, tool accuracy recovering when a set shrinks from 46 to 19, and correctness sliding at 32k tokens are not edge cases. They are the default behaviour of capable models fed poorly curated context.
So my rule when an agent misbehaves is to look at the context before I blame the model. Nine times out of ten the fix is fewer tools, a tighter retrieval query, a summary of the last twenty turns, or a sub-agent to isolate a noisy sub-task. Context engineering is unglamorous plumbing, and it is the single highest-leverage work in building agents that hold up in production.