Context & Reliability
Context window management, compaction, handoff patterns, error propagation, and reliability patterns
Context window management, compaction, handoff patterns, error propagation, and reliability patterns
Every Claude model currently offers a 200K token context window. That sounds huge, but you need to understand what counts toward it and how output limits interact.
# What counts toward the 200K window
System prompt tokens
+ All conversation messages (user + assistant)
+ Tool call arguments & tool results
+ Current response being generated
= Total must stay โค 200,000 tokens
Output limitsโ Claude can generate up to 64K output tokens (Haiku 4.5) per response; other models vary. The output reservation reduces the space available for input.
Effective context= total window โ output reservation. If you reserve 16K for output, you have ~184K for input.
Just because 200K tokens fit doesn't mean every token is equally useful. Understanding how accuracy changes with context length is critical for production systems.
Accuracy degrades as conversation length grows. The model spreads attention over more tokens, diluting focus on any single fact.
Recent messages are weighted more heavily during generation. Information from 50 turns ago is harder to retrieve than the last 5 turns.
Information at the start (system prompt) and end (recent messages) is retrieved better than content in the middle โ the 'lost in the middle' effect.
Put critical instructions in the system prompt or the most recent messages. Don't rely on information buried in the middle of a long conversation.
# Summary + Recent implementation pattern
// 1. Separate older messages from recent
const cutoff = messages.length - RECENT_COUNT;
const older = messages.slice(0, cutoff);
const recent = messages.slice(cutoff);
// 2. Summarize older messages in a single call
const summary = await claude.summarize(older);
// 3. Rebuild context: system + summary + recent
const context = [
{ role: "system", content: systemPrompt },
{ role: "user", content: "Previous context summary: " + summary },
...recent
];
CLAUDE.md is the single most important file for persistent instructions. Unlike conversation messages, it survives context compaction because it is reloaded from disk every time the context is rebuilt.
# CLAUDE.md hierarchical loading order
~/.claude/CLAUDE.md # Global โ all projects
./CLAUDE.md # Project root
./src/CLAUDE.md # Subdirectory
./AGENTS.md # Subagent instructions
Rule of thumb: if an instruction matters across multiple conversations or must survive compaction, put it in CLAUDE.md rather than repeating it in conversation.
When extended thinking is enabled, Claude produces internal reasoning blocks. Here is how they interact with context:
When context transfers between agents or sessions, raw conversation is the wrong thing to pass along. Instead, transfer conclusions and decisions.
Context Handoff Flow
Agent A summarizes state โ human approves โ Agent B receives conclusions, not raw conversation
Production agents should signal uncertainty rather than always appearing confident. Uncalibrated confidence is a reliability anti-pattern.
# Structured uncertainty in tool results
{
"result": "The function likely causes the OOM",
"confidence": 0.72,
"reasoning": "Stack trace points here, but I haven't
confirmed with a memory profile",
"escalate": false
}
# Escalation trigger
if confidence < 0.5:
escalate_to_human(summary, evidence)
Anti-pattern:Agents that are always confident. If a model never says "I'm not sure," its outputs cannot be trusted without external verification.
Best practice: Attach confidence scores to tool results and define escalation triggers when confidence drops below a threshold.
When a subagent fails, the parent agent needs a strategy. The wrong choice cascades failures across the system.
Re-run the failed operation, optionally with modified parameters. Pass error details to the retry so the agent can adapt.
Mark the step as non-critical and continue. Works for optional enrichment steps that don't block the main flow.
Stop the entire pipeline and surface the error. Use when the failure is unrecoverable or data integrity is at risk.
Switch to an alternative approach. Example: if web search fails, use cached knowledge or a different data source.
# Circuit breaker pattern
// Stop cascading failures across agents
class CircuitBreaker {
failures = 0;
threshold = 3;
state = "CLOSED"; // CLOSED | OPEN | HALF_OPEN
async call(fn) {
if (this.state === "OPEN") throw new Error("Circuit open");
try {
const result = await fn();
this.failures = 0;
this.state = "CLOSED";
return result;
} catch (e) {
this.failures++;
if (this.failures >= this.threshold)
this.state = "OPEN";
throw e;
}
}
}
Observability: always log error details, the strategy chosen, and whether recovery succeeded. Without logs, debugging multi-agent failures is nearly impossible.
Conversations that exceed ~100 turns will degrade without active management. Compaction is no longer optional at that point โ it is essential.
# Practical guidelines
1. Monitor usage โ /context command shows token counts
2. Compact early โ after completing each subtask, not when you hit the wall
3. Persist state โ write to CLAUDE.md or external files, not conversation memory
4. Strategic cuts โ compact at natural boundaries (feature done, test passing)
Key insight: conversation memory is volatile. Anything that must survive compaction belongs in a file on disk.
You cannot improve what you cannot measure. Agent systems need the same observability rigor as any production service.
Agent testing requires layered strategies. Unit tests alone are not enough when behavior emerges from multi-turn conversations and tool interactions.
# Testing layers for agent systems
Unit tests โ Test individual tool implementations in isolation
Integration โ Test agent workflows end-to-end with mock tools
Eval datasets โ Curated input/output pairs to measure response quality
Regression โ Ensure fixes don't break other behaviors
# Example: eval-driven development
for (const case of evalDataset) {
const result = await agent.run(case.input);
assert(score(result, case.expected) > 0.8);
}
Domain 5 โข 15% of exam