How to Stop Context Rot in 1M-Token AI Coding Agents: A Practical Guide to Memory Budgeting and Session Discipline
Massive context windows do not guarantee recall. Use compaction, hard session budgets, and ruthless prompt pruning to keep long-running coding agents accurate and cheap.
Accept That 1M Tokens Won't Prevent Forgetting
Agents forget requirements even with a 1 million token context window. In practice, an agent may lose track of what you asked 10 minutes ago after 20 requests. Research shows model performance degrades consistently—and catastrophically—as context grows, with the effect appearing around 10K tokens for some models and accelerating past 50K. Bigger windows without engineering simply produce expensive hallucination at scale.
Treat the context window as a budget, not a warehouse. A 1M-token ceiling does not mean you have 1M tokens of reliable working memory. Once usage crosses the threshold where degradation begins, recall precision drops regardless of the theoretical limit. Monitor live token counts and enforce hard cutoffs before quality collapses. Expecting the model to retain fine-grained details across hundreds of thousands of tokens ignores the observed failure pattern.
A common approach is to set an automated guardrail at 50K tokens:
def within_context_budget(current_tokens: int) -> bool:
# Hard stop before catastrophic degradation zone
return current_tokens < 50_000
When the budget is exhausted, archive or summarize rather than appending more text. Conservative practice suggests starting fresh or triggering comprehensive summarization once you reach 50% of the available window. If you treat the full window as free storage, you are paying for tokens that actively increase error rates. Cap your sessions, measure actual usage, and assume that anything beyond your budgeted threshold is already forgotten. The window size is a resource limit, not a guarantee of retention.
Cap Every Session at 50% of the Window
Conservative memory budgeting demands resets before the limit is reached. Complete a major task, then start fresh, or enforce a hard stop when the session reaches 50% of the available window. This threshold ensures you never allow context to grow large enough that quality collapses. When the limit trips, spawn a new conversation thread, instantiate a clean agent, or trigger a comprehensive summarization that effectively reboots the context.
Monitor token count in the orchestration layer and trigger a handoff immediately after crossing the boundary. A common approach is to wrap the agent loop with a guard that checks cumulative usage before every turn:
def run_turn(agent, messages, limit: int):
used = count_tokens(messages)
if used > limit // 2:
summary = compress_history(messages)
return agent.reset(context=summary)
return agent.step(messages)
For terminal-driven workflows, enforce the same cap with a shell pre-flight check against the provider’s usage payload:
USED=$(cat session.json | jq '.usage.total_tokens')
HALF=$(($CONTEXT_LIMIT / 2))
if [ "$USED" -gt "$HALF" ]; then
echo "Session budget exceeded; rotating context."
exit 1
fi
Treat the second half of the window as protected emergency reserve, not usable capacity. Forcing a reset at the halfway mark preserves response accuracy and prevents the quality collapse that follows full-window bloat.
Compact History Instead of Hoarding It
Raw message logs are the fastest way to burn tokens and trigger context rot. Every turn appends hundreds or thousands of tokens, so a long coding session quickly exceeds the effective recall threshold even in a 1M-token window. The fix is context compaction: collapse older exchanges into dense summaries while preserving recent turns in full detail. This keeps the working set small without losing the thread of the conversation, and it directly lowers API costs on long threads because billed tokens drop after each compression.
A common approach is to run compaction after each completed sub-task. At that point you store only the generated summary, the current file state, and the last few user-assistant exchanges in active memory. Everything earlier is archived or discarded. Treat the summary as a system-level message so the agent retains the decisions and constraints from earlier steps.
def compact_turns(history, keep_last=3):
stale = history[:-keep_last]
recent = history[-keep_last:]
summary = model.summarize(
f"Condense these {len(stale)} turns into key decisions and file changes.",
messages=stale
)
return [{"role": "system", "content": summary}] + recent
If you also inject the current file tree or key snippets at the same time, the next prompt stays grounded in accurate state without dragging along obsolete edits. This mirrors the conservative practice of resetting context once a major milestone is reached rather than letting it grow indefinitely. By compacting instead of hoarding, you maintain accuracy without token bloat and keep the agent responsive across extended sessions.
Strip Skill Files and System Prompts to the Bone
Every token in a skill file loads into the active context on each invocation, so bloat directly accelerates rot. Treat 200 lines as a hard ceiling for any skill definition; if a file crosses that threshold, split it by sub-task or extract reusable helpers into separate modules. Begin by stripping the file to the three essentials: the tool schema, the minimal parameter definition, and one concise usage example. Remove background theory, verbose inline comments, multi-page tutorials, and decorative metadata. If the agent needs a schema, give it the JSON skeleton rather than a fully annotated OpenAPI specification. The goal is to give the model just enough structure to invoke the tool correctly and nothing else. Every extra comment or unused property is a token that crowds out user code later in the session.
# Bad: 400+ line monolithic skill
description: |
This tool handles user authentication...
examples:
- code: |
// 50-line story about login flows
# Good: under 200 lines, schema + one example
name: auth_user
parameters:
type: object
properties:
username: {type: string}
password: {type: string}
required: [username, password]
example: auth_user({"username":"alice","password":"secret"})
System prompts should follow the same austerity. Instead of dumping every global instruction into a single monolithic block, gate context behind task-type flags. A common approach is to maintain a dictionary of prompt fragments and inject only the fragment that matches the current operation. Avoid restating project-wide conventions that the agent already loaded at session start.
TASK_PROMPTS = {
"refactor": "Follow existing style. Do not rename public APIs.",
"test": "Use pytest. Mock external HTTP calls.",
"docs": "Output Markdown. Keep headings under 60 chars."
}
system_msg = TASK_PROMPTS.get(current_task, "")
This ensures the agent receives exactly the constraints it needs without paying the recurring token tax for irrelevant guidance on every turn.
Reboot on Major Task Boundaries
End sessions deliberately instead of letting them drift. Reset immediately after completing a major task—such as merging a feature branch, closing a pull request, or finishing a code review—before you begin the next unit of work. This boundary prevents stale assumptions, abandoned variable names, and outdated file contents from bleeding into unrelated logic.
Mark the boundary in your repository first:
git checkout main
git merge --no-ff feature/payments
git branch -d feature/payments
Once the task is closed, start a new conversation thread or spawn a fresh agent instance. Carrying the full transcript forward guarantees cross-task pollution because the model continues to weight earlier implementations and rejected approaches. Treat each major deliverable as a discrete boot context with its own clean slate.
If you must preserve continuity between sessions, pass a compact handoff document rather than dumping the entire chat history into the next window. The handoff should contain only architectural decisions, critical file pointers, and outstanding action items. Create it as a small markdown file:
cat > handoff.md << 'EOF'
Decision: Adopt async job queue for invoice generation
Files: src/jobs/invoice.ts, src/queue/redis.ts
Pending: Add dead-letter handling (issue #88)
Blockers: None
EOF
Feed only that file into the new session. By rebooting the context at major boundaries and importing just the distilled state, you keep the agent’s working memory focused on the current task and avoid the compounding noise that produces context rot.
Operationalize Context Engineering in Your Control Loop
Context engineering beats context inflation. Treat your agent’s context window as a strict memory budget with runtime guardrails. Before any skill executes, validate its payload: assert that loaded skill files stay under 200 lines. If a file exceeds the limit, refuse to load it until the author splits the logic or prunes non-essential examples. This single check eliminates a major source of token bloat at the entry point.
Next, instrument the control loop to monitor session depth continuously. Auto-trigger summarization at the 50% session threshold. This prevents silent accumulation and forces a compress-and-continue checkpoint before retrieval quality degrades. Treat the midpoint as a hard circuit breaker rather than a soft suggestion.
Tool outputs are another common vector for unplanned growth. Reject or truncate any response that would push the window over budget. A lightweight pre-insertion filter keeps the agent from drowning in verbose logs:
def insert_tool_output(ctx, output, limit=1_000_000):
projected = ctx.token_count + estimate_tokens(output)
if projected > limit * 0.5:
output = compress(output, target_ratio=0.5)
ctx.append(output)
Finally, apply code-review discipline to prompt templates. Review them the same way you review functions: if a block does not directly serve the current task, remove it. Strip introductory fluff, redundant XML wrappers, and off-topic few-shot examples. Every token must earn its place. The result is an agent that stays within budget and retains what actually matters.
References for further reading
Sources consulted while researching this guide, included so you can verify the details and go deeper. Listing them is not a claim that every line was independently fact-checked.
- Context Rot in AI Coding Agents: What It Is and How to Prevent It
- Stop Stuffing Your LLM's Context Window, by César Soto Valero
- The Context Window Trap: Why 1M Tokens Won't Save Your AI Agent
- AI agents forget even with 1 million token context window - LinkedIn
- Deep dive into context engineering for AI agents | by clara | May, 2026 | Code Like A Girl
I packaged the setup above into a ready-to-use kit — **Context That Doesn't Rot (12 Templates)* — for anyone who'd rather copy-paste than wire it from scratch: https://unfairhq.gumroad.com/l/vszzu.*
Top comments (0)