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;