Skip to content

Instantly share code, notes, and snippets.

@GGPrompts
Last active April 13, 2026 19:37
Show Gist options
  • Select an option

  • Save GGPrompts/8125321d4cd462da19769b04f43ee70a to your computer and use it in GitHub Desktop.

Select an option

Save GGPrompts/8125321d4cd462da19769b04f43ee70a to your computer and use it in GitHub Desktop.
Add cache health to statusline

Add a cache health indicator to your Claude Code statusline

If you're using a custom statusline script, you can add cache health monitoring to catch when your prompt cache is getting thrashed. Here's what to add and what it means.

What it tracks: The ratio between cache_read_input_tokens (cheap, reused from cache) and cache_creation_input_tokens (expensive, rebuilding cache). When cache reads drop to zero while creation stays high, you're paying full price every turn instead of getting the ~90% cache discount.

Step 1: Extract the token data

Add this near the top where you parse the statusline JSON input:

# Extract context_window data
context_window=$(echo "$input" | jq -c '.context_window // null')
current_usage=$(echo "$input" | jq -c '.context_window.current_usage // null')

# Calculate context percentage
context_pct=""
if [ "$context_window" != "null" ]; then
    context_window_size=$(echo "$context_window" | jq -r '.context_window_size // 0')
    if [ "$current_usage" != "null" ]; then
        input_tokens=$(echo "$current_usage" | jq -r '.input_tokens // 0')
        cache_creation=$(echo "$current_usage" | jq -r '.cache_creation_input_tokens // 0')
        cache_read=$(echo "$current_usage" | jq -r '.cache_read_input_tokens // 0')
        total_tokens=$((input_tokens + cache_creation + cache_read))
        if [ "$context_window_size" -gt 0 ]; then
            context_pct=$((total_tokens * 100 / context_window_size))
        fi
    fi
fi

Step 2: Add the cache health indicator

Add this where you build your status line segments:

# Cache Health Indicator
# Detects broken cache: cache_read stuck at 0 while cache_creation is high
if [ "$current_usage" != "null" ] && [ -n "$context_pct" ]; then
    STATE_DIR="/tmp/claude-code-state"
    mkdir -p "$STATE_DIR"
    CACHE_HEALTH_FILE="${STATE_DIR}/${SESSION_ID}-cache-health.json"

    # Track consecutive zero-read checks
    if [ -f "$CACHE_HEALTH_FILE" ]; then
        prev_checks=$(jq -r '.checks // 0' "$CACHE_HEALTH_FILE" 2>/dev/null)
        prev_zero_reads=$(jq -r '.zero_reads // 0' "$CACHE_HEALTH_FILE" 2>/dev/null)
    else
        prev_checks=0
        prev_zero_reads=0
    fi

    new_checks=$((prev_checks + 1))
    if [ "$cache_read" -eq 0 ] && [ "$cache_creation" -gt 0 ]; then
        new_zero_reads=$((prev_zero_reads + 1))
    else
        # Reset on any successful cache read
        new_zero_reads=0
    fi

    # Persist state across refreshes
    printf '{"checks":%d,"zero_reads":%d,"last_read":%s,"last_creation":%s,"timestamp":"%s"}\n' \
        "$new_checks" "$new_zero_reads" "$cache_read" "$cache_creation" \
        "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$CACHE_HEALTH_FILE" 2>/dev/null

    # Skip first 2 checks (cold start -- no cache exists yet, zero reads is normal)
    # After 3+ consecutive zero-read checks, warn about cache thrashing
    if [ "$new_checks" -gt 2 ] && [ "$new_zero_reads" -ge 3 ]; then
        status_parts+=("${RED}CACHE MISS${RESET}")
    elif [ "$new_checks" -gt 2 ] && [ "$cache_read" -gt 0 ]; then
        # Show cache hit ratio when healthy
        cache_total=$((cache_read + cache_creation))
        if [ "$cache_total" -gt 0 ]; then
            cache_hit_pct=$((cache_read * 100 / cache_total))
            dollar='$'
            if [ "$cache_hit_pct" -gt 80 ]; then
                status_parts+=("${GREEN}${cache_hit_pct}%${dollar}${RESET}")
            elif [ "$cache_hit_pct" -gt 50 ]; then
                status_parts+=("${YELLOW}${cache_hit_pct}%${dollar}${RESET}")
            else
                status_parts+=("${RED}${cache_hit_pct}%${dollar}${RESET}")
            fi
        fi
    fi
fi

What you'll see in the statusline

  • 92%$ in green -- healthy, 92% of tokens hitting cache (saving money)
  • 45%$ in red -- poor cache hit rate, you're overpaying
  • CACHE MISS in red -- cache is completely thrashed, zero reads for 3+ consecutive checks

Why this matters

A broken cache means you're paying full input token price every turn instead of getting the ~90% discount. It also increases latency. I found that certain workflows (like batch tool calls in quick succession) consistently thrash the cache, and was able to restructure them once I could actually see it happening in real time.

SESSION_ID should match however you identify your session -- tmux pane ID, env var, or a hash of the working directory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment