← cc-safe-setup

Claude Code Auto-Compact Death Spiral: How to Fix It

April 20, 2026 · 3 min read · by yurukusa

TL;DR: Auto-compact can loop infinitely and consume your entire token budget overnight. Install compact-circuit-breaker.sh to prevent it. Takes 30 seconds.

The Problem

You leave a Claude Code session running overnight. By morning, your entire token budget is gone — and no work was done.

The cause: auto-compact entered an infinite loop. Each compaction attempt failed to restore continuity (due to FileHistory errors), which triggered the next compaction immediately. The loop continued until every token was consumed.

This isn't theoretical:

Why Auto-Compact Has No Circuit Breaker

Auto-compact is designed as a stabilizing mechanism — when context gets too large, it compresses it. But it has no maximum frequency limit. When the underlying recovery system (FileHistory hard-linking) is degraded:

  1. Auto-compact fires because context is too large
  2. Compaction completes but FileHistory can't restore continuity
  3. The context appears "too large" again (continuity not restored)
  4. Auto-compact fires again — immediately
  5. Repeat until all tokens are consumed

The critical flaw: there's no check for "did the last compaction actually help?" Each iteration costs tokens, and the total cost is unbounded.

The Fix: Circuit Breaker Hook

30-second install:
npx cc-safe-setup --install-example compact-circuit-breaker

This hook acts as a circuit breaker for auto-compaction:

If you prefer to block all compaction entirely, use compact-blocker.sh instead.

Manual Installation

Save as ~/.claude/hooks/compact-circuit-breaker.sh:

#!/bin/bash
MAX_PER_HOUR="${CC_COMPACT_MAX_PER_HOUR:-3}"
MIN_INTERVAL="${CC_COMPACT_MIN_INTERVAL:-120}"
STATE_DIR="/tmp/.cc-compact-circuit-breaker"
STATE_FILE="$STATE_DIR/compaction-log"
mkdir -p "$STATE_DIR"
touch "$STATE_FILE"
NOW=$(date +%s)
ONE_HOUR_AGO=$((NOW - 3600))
[ -f "$STATE_FILE" ] && awk -v cutoff="$ONE_HOUR_AGO" '$1 >= cutoff' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
RECENT_COUNT=$(wc -l < "$STATE_FILE" | tr -d ' ')
LAST_TIME=0
[ -s "$STATE_FILE" ] && LAST_TIME=$(tail -1 "$STATE_FILE")
ELAPSED=$((NOW - LAST_TIME))
if [ "$RECENT_COUNT" -ge "$MAX_PER_HOUR" ]; then
  echo "CIRCUIT BREAKER: $RECENT_COUNT compactions in the last hour. Start a fresh session." >&2
  exit 2
fi
if [ "$ELAPSED" -lt "$MIN_INTERVAL" ] && [ "$LAST_TIME" -gt 0 ]; then
  echo "COOLDOWN: Last compaction was ${ELAPSED}s ago." >&2
  exit 2
fi
echo "$NOW" >> "$STATE_FILE"
exit 0

Add to ~/.claude/settings.json:

{
  "hooks": {
    "PreCompact": [{
      "matcher": "",
      "hooks": [{"type": "command",
        "command": "bash ~/.claude/hooks/compact-circuit-breaker.sh"}]
    }]
  }
}

Prevention Checklist

40 token drain symptoms diagnosed

The compaction death spiral is Symptom 39 of 40 documented in the Token Book. Each symptom includes root cause analysis, hook-based fix, and prevention checklist.

Token Book — $17 Details + Free Chapters Free Token Checkup (30 sec)

Related