Compaction

2026-01-12 Context Management ultrathink

How It Works

Claude Code automatically compacts conversation history when context approaches limits. This summarizes older turns while keeping recent context intact.

Trigger Thresholds

From our observations across 32+ sessions:

  • Auto-compaction triggers at roughly 155k-165k tokens
  • After compaction: ~5-6% context reduction (9k-13k tokens removed)
  • Example: 197,406 → 184,374 preTokens = 13,032 tokens removed

compact_boundary Event

Compaction is marked with a system message in session logs:

{ "type": "system", "subtype": "compact_boundary", "compactMetadata": { "trigger": "auto", "preTokens": 164975 }, "timestamp": "2025-12-15T19:59:17.126Z" }
Field Meaning
trigger"auto" or "manual"
preTokensToken count before compaction

Manual /compact Command

You can manually trigger compaction with /compact. The stream-json output shows:

  1. Status: {"type": "system", "subtype": "status", "status": "compacting"}
  2. Complete: {"type": "system", "subtype": "status", "status": null}
  3. Re-init: {"type": "system", "subtype": "init", ...}
  4. Boundary: {"type": "system", "subtype": "compact_boundary", "compact_metadata": {"trigger": "manual", "pre_tokens": 18875}}
  5. Auto-generated summary injected as user message

What's Preserved

After compaction:

  • Recent turns kept in full (thinking blocks, tool uses, tool results)
  • Older turns summarized/removed
  • Semantic content preserved, historical depth compressed

Cache Token Tracking

From the result message usage object:

{ "input_tokens": 2, "cache_creation_input_tokens": 5758, "cache_read_input_tokens": 13119, "output_tokens": 12 }
Field What it means
input_tokensNew tokens sent this call
cache_creation_input_tokensTokens written to cache
cache_read_input_tokensCache hits (reused, cheap)
Cache Expiration
Cache entries expire after 5 minutes of non-use. Cache reads don't count toward rate limits.

Detecting Compaction

// Check for compaction in session logs const compacted = messages.some(m => m.type === "system" && m.subtype === "compact_boundary" ); // Get pre-compaction size const preTokens = messages .find(m => m.subtype === "compact_boundary") ?.compactMetadata?.preTokens;