Lesson 4: Compaction and Notes: Context Management for Long Tasks
Learning goals:
- State what compaction is and how it's implemented: when a conversation nears the window's limit, hand the message history to the model to summarize, then reinitiate a fresh window from that summary
- Write the summarize instruction and the keep/drop list for one compaction, following the rule: preserve architectural decisions and unresolved bugs, discard redundant tool output
- Tell the roles of compaction and structured notes apart, and design a write-as-you-go note scheme for a long-task agent
Prerequisites: You've finished Lessons 1 through 3 of this course, and you can hand-write the harness loop from course 7 of this series, "Agent Harness Fundamentals: Loops and Control" | Prev: Lesson 3 << | Next: Lesson 5 >>
A Task One Window Can't Hold
Start with a scene you'll hit soon enough. You take the harness you hand-wrote in course 7 of this series, "Agent Harness Fundamentals: Loops and Control," and point it at a debugging task: fixing a race condition that only shows up under concurrency. The agent reads files, runs tests, edits code, runs the tests again — forty-some turns in, the task still isn't done, but the message history has swollen past a hundred thousand tokens and the window is about to fill.
The four control valves from course 7 (max turns, budget, idle-spin detection, the approval valve) are no help here. They govern "don't let the loop run away," but the loop is behaving fine — the task itself is just long. That's not a mishap; it's the loop's nature: "An agent running in a loop generates more and more data that could be relevant for the next turn of inference"1 — tool output, intermediate conclusions, failed attempts, all piling into the message history.
And the window isn't free. A model parsing large volumes of context draws on an "attention budget," and "Every new token introduced depletes this budget by some amount."1 The more tokens pile up, the worse the model gets at accurate recall: "as the number of tokens in the context window increases, the model's ability to accurately recall information from that context decreases"1 — a gentle downhill slope rather than a cliff, but downhill all the same, so "context, therefore, must be treated as a finite resource with diminishing marginal returns."1 The Claude Code best-practices doc puts it more bluntly — "Claude's context window fills up fast, and performance degrades as it fills," and "The context window is the most important resource to manage."2
When a task runs too long for one window to hold, you have two weapons: compaction and structured notes. This lesson works both through.
Compaction: Summarize, Then Open a New Window
Compaction is exactly what the name says: "taking a conversation nearing the context window limit, summarizing its contents, and reinitiating a new context window."1 Notice the last part — you don't stuff the summary back into the old conversation and keep cramming; you reinitiate. The old window is abandoned whole, and the new one travels light, carrying only the system prompt and the summary.
The implementation is plainer than it sounds: it's "passing the message history to the model to summarize and compress the most critical details."1 Which means compaction is itself one extra model call. In code it looks roughly like this (formatHistory just joins the message array into readable plain text; implementation omitted):
Splicing it into that course 7 loop takes just one more idea: at the start of each turn, check the message history's token usage, and once it nears the limit, call compact() and replace the entire messages array with the return value. Actually building this into the harness — how to set the trigger threshold, what to do when compaction fails — is the hands-on material of Lesson 6; for now, just get the mechanism straight.
The Art of Compaction: What to Keep, What to Drop
The hard part of compaction isn't "how to summarize" — it's "what to keep, what to drop." The direction is actually clear: "preserves architectural decisions, unresolved bugs, and implementation details while discarding redundant tool outputs."1
Why that trade-off? Imagine the agent "waking up" in the new window; that summary is its entire memory. The cost of compressing in the wrong direction is concrete: say your summarize instruction just says "briefly summarize the conversation content," and the model casually drops "there's an unfinished race condition in orders/service.js" — the agent wakes up seeing only records marked "complete," so it either declares the job done or picks through things you already fixed. One compaction, forty turns of work just went off the rails.
Flip it around: redundant tool output is the fattest target. One grep returns 200 matching lines; the useful signal is already captured in the next step's conclusion, "narrowed to the updateStatus function." The raw 200 lines sticking around just burn attention budget, adding nearly no decision value to the next move.1
A practical self-check: after you write the summarize instruction, take a real long conversation and compact it once, then answer three questions from the summary alone — "what should happen next," "what decisions are locked in," "what holes are still unfilled." If all three come out clean, your instruction's keep/drop rules pass; if any blank out, go back and patch that keep rule.
Compaction in Production: Auto-Compaction and /clear
The tool you use every day has a ready-made reference. Claude Code "automatically compacts conversation history when you approach context limits, which preserves important code and decisions while freeing space"2 — the same mechanism as the hand-written compact() above, just productized with the triggering and keep/drop rules done for you.
But compaction isn't the only option. If you're switching to an unrelated new task, the old context is not just useless — it's harmful, because "Long sessions with irrelevant context can reduce performance."2 At that point the docs say "Run /clear between unrelated tasks to reset the context window entirely"2 — no summarizing, no preserving, just a full reset. The reasoning is simple: compaction costs one model call and carries the risk of getting the keep/drop judgment wrong; for an unrelated task, clearing outright is cheaper and cleaner. Compaction serves "the same task isn't done yet," while /clear serves "now I'm doing something else."
That doc also has a line worth keeping at hand: "A clean session with a better prompt almost always outperforms a long session with accumulated corrections."2 Translation: when a session's history is mainly "no, try again" and "still wrong," the historical value for the next step is likely negative — reopening a session and baking the lesson directly into a new prompt often beats dragging all that baggage forward.
Structured Notes: Write Key State Outside the Window
Compaction has one built-in weakness: it's reactive. You wait until the window is nearly full before you look back and summarize, so what survives depends entirely on that moment's judgment — and judgment can fail. Is there a way to preserve information while it's fresh?
Yes, and it's plain: "the agent regularly writes notes persisted to memory outside of the context window."1 "Like Claude Code creating a to-do list, or your custom agent maintaining a NOTES.md file."1 Take that opening race-condition task again; a passing-grade set of notes looks roughly like this:
Wiring is something you learned in course 7: give the agent a file-writing tool, then add one requirement to the system prompt — "whenever you make an important decision, discover a new problem, or finish a stage, update NOTES.md first, then continue." From now on, the window's key state has a backup copy outside the window. No matter how the window compacts or restarts, the notes sit on disk; the first thing the new window does is read them back.
This trick isn't specific to coding tasks. "Claude playing Pokémon demonstrates how memory transforms agent capabilities in non-coding domains."1 Anthropic's multi-agent research system does the same for long tasks: "agents summarize completed work phases and store essential information in external memory."3
Division of Labor: Compaction Backstops, Notes Run Daily
Put both weapons side by side and the division of labor becomes clear. Compaction is passive: it fires when the window nears its limit, timing not your choice, and it's lossy — what survives depends on that moment's keep/drop judgment. Notes are active: you write key state the moment it's born, content is lossless, and the cost is just a few lines of file writes each time. One sentence: notes are daily routine, compaction is the backstop.
The two don't clash; they reinforce. The more diligent your notes, the lighter the consequence of compaction dropping something — if the summary misses a detail, the notes still have it. Going the other way, having compaction as the backstop means notes don't have to be exhaustive, just the few categories "the agent must know when waking up."
Proportion matters too. Not every task earns this machinery: Anthropic's guidance is "you should consider adding complexity only when it demonstrably improves outcomes."4 Note the verb — consider. That's a posture of weighing, not a prohibition. For a task that finishes in ten turns, both compaction and notes are spare parts; start with the simplest loop and add them when you actually hit the ceiling.
Two final boundaries, so you don't waste time hunting for answers this lesson doesn't cover:
- Cross-session persistence of note files — how to organize them, how to recover them in a new session, long-term maintenance — is the subject of course 5 of this series, "Agent Memory and State." This lesson only cares about how notes lighten the window's load within one long task.
- Handling long-horizon tasks actually has three moves: "compaction, structured note-taking, and multi-agent architectures,"1 all aimed at letting agents "maintain coherence, context, and goal-directed behavior over sequences of actions."1 The first two are done; the third — splitting the task across subagents carrying clean windows — is Lesson 5.
Recap
- Compaction = when a conversation nears the window limit, "passing the message history to the model to summarize and compress the most critical details,"1 then "reinitiating a new context window"1 from that summary — reinitiate, not append back into the old conversation
- The art of compaction is in the keep/drop choice: "preserves architectural decisions, unresolved bugs, and implementation details while discarding redundant tool outputs";1 compress in the wrong direction and the agent wakes up forgetting what it was doing
- Claude Code "automatically compacts conversation history when you approach context limits, which preserves important code and decisions"2; between unrelated tasks use
/clearfor a full reset — "A clean session with a better prompt almost always outperforms a long session with accumulated corrections"2 - Structured notes: "the agent regularly writes notes persisted to memory outside of the context window" (to-do list,
NOTES.md);1 compaction is passive backstop and lossy, notes are active externalization and write-as-you-go - The three moves for long-horizon tasks are "compaction, structured note-taking, and multi-agent architectures";1 the first two are in hand, the third is Lesson 5. Cross-session note persistence is the subject of course 5 of this series, "Agent Memory and State"
>> Lesson 5: Subagents and Context Isolation
Footnotes
-
Effective context engineering for AI agents — Anthropic Engineering — https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18
-
Best practices for Claude Code — Claude Code Docs — https://code.claude.com/docs/en/best-practices ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
How we built our multi-agent research system — Anthropic Engineering — https://www.anthropic.com/engineering/multi-agent-research-system ↩
-
Building Effective AI Agents — Anthropic Engineering — https://www.anthropic.com/engineering/building-effective-agents ↩
Exercises
Someone wrote this "compaction" function for the harness, calling it when the window is nearly full:
Level 2: Diagnose "Amnesia After Compaction"After hooking it in, the agent triggered compaction at turn 45. You then observed two symptoms: first, at turn 47 it restarted debate over "should the test framework be node:test or vitest," a question already decided at turn 3 as vitest; second, it never mentioned the unresolved race bug recorded at turn 5, and declared the task done a few turns later. Explain the cause of both symptoms, and give a two-layer fix.