oimiragieo/agent-studio

compaction-detector

Detect Claude Code context compaction events in session JSONL logs. Identifies compaction boundaries, measures token delta before/after, reports compaction events with timestamps and token impact.

First seen Apr 7, 2026

Installation

$ npx skills add oimiragieo/agent-studio --skill compaction-detector

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from oimiragieo/agent-studio · top by installs.

npx skills add oimiragieo/agent-studio

Browse all from oimiragieo/agent-studio

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 40
Default branch main
Open issues 501
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

Version1
Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,840 B
  • docs SUMMARY.md 223 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 5 installs

SKILL.md

Compaction Detector

<identity> Compaction Detector Skill - Detect Claude Code context compaction events in session JSONL logs. Identifies compaction boundaries, measures token delta before/after, reports compaction events with timestamps and token impact. </identity>

<capabilities>

  • Detect context compaction events in Claude Code session JSONL logs
  • Measure token delta (before/after) at each compaction boundary
  • Report compaction events with ISO timestamps, turn index, and token impact
  • Parse multi-session or single-session JSONL files
  • Output structured compaction report to stdout or file

</capabilities>

<instructions> <execution_process>

Step 1: Locate the Session Log File

Claude Code session logs are stored as JSONL files. Find the target log:

# Default log location (adjust path for your OS)
# macOS / Linux
ls -lt ~/.claude/projects/*/logs/*.jsonl | head -5

# Windows (Git Bash / WSL)
ls -lt "/c/Users/$USER/.claude/projects/"*/logs/*.jsonl 2>/dev/null | head -5

# Or search by project path hash
find ~/.claude/projects -name "*.jsonl" -newer /tmp/sentinel 2>/dev/null

Expected output: One or more .jsonl file paths with modification timestamps. Verify: File is non-empty — wc -l <path> should return > 0.

Step 2: Identify Compaction Boundary Lines

Each line in a Claude Code session JSONL is a JSON object. Compaction events are identified by a sharp drop in usage.input_tokens between consecutive turns — the context was summarised and reset to a smaller window.

Command — extract token counts with line numbers:

SESSION_LOG="<absolute-path-to-session.jsonl>"

grep -n '"input_tokens"' "$SESSION_LOG" \
  | awk -F'[":,]' '{
      for(i=1;i<=NF;i++) {
        if($i ~ /input_tokens/) { print NR, $(i+2); break }
      }
    }'

Simpler alternative using jq (if available):

jq -r 'select(.usage.input_tokens != null) | [.timestamp, .usage.input_tokens, .usage.output_tokens] | @tsv' \
  "$SESSION_LOG"

Expected output: Tab-separated rows: <timestamp> <inputtokens> <outputtokens>

Step 3: Detect Token Drop Events

A compaction event occurs when inputtokens[N] < inputtokens[N-1] * 0.5 (tokens dropped by more than 50%).

Command — detect drops with awk:

SESSION_LOG="<absolute-path-to-session.jsonl>"

grep '"input_tokens"' "$SESSION_LOG" \
  | grep -oP '"input_tokens"\s*:\s*\K[0-9]+' \
  | awk '
    NR > 1 {
      pct = ($1 / prev) * 100
      if (pct < 50) {
        printf "COMPACTION at line %d: %d -> %d tokens (%.1f%% retained)\n", \
               NR, prev, $1, pct
      }
    }
    { prev = $1 }
  '

Expected output:

COMPACTION at line 47: 98234 -> 8102 tokens (8.2% retained)
COMPACTION at line 203: 112450 -> 9341 tokens (8.3% retained)

Verify: Each reported line number corresponds to a real turn boundary. Cross-check with sed -n '<line>p' "$SESSION_LOG" | jq .timestamp.

Step 4: Extract Timestamps for Each Compaction

For each compaction line number identified in Step 3, extract the ISO timestamp:

SESSION_LOG="<absolute-path-to-session.jsonl>"
COMPACTION_LINE=47   # Replace with actual line number

# Extract timestamp from that JSONL line
sed -n "${COMPACTION_LINE}p" "$SESSION_LOG" \
  | grep -oP '"timestamp"\s*:\s*"\K[^"]+'

Alternative with jq:

sed -n "${COMPACTION_LINE}p" "$SESSION_LOG" | jq -r '.timestamp // "unknown"'

Expected output: 2026-03-21T14:32:07.441Z

Step 5: Compute Token Delta Per Compaction Event

For each compaction boundary, calculate:

  • tokensbefore: inputtokens on the line immediately before the drop
  • tokensafter: inputtokens on the compaction line
  • delta: tokensbefore - tokensafter
  • retentionpct: (tokensafter / tokens_before) \* 100

Full pipeline — produces structured TSV:

SESSION_LOG="<absolute-path-to-session.jsonl>"

paste \
  <(grep -n '"input_tokens"' "$SESSION_LOG" | grep -oP '^\d+') \
  <(grep '"input_tokens"' "$SESSION_LOG" | grep -oP '"input_tokens"\s*:\s*\K[0-9]+') \
  | awk '
    NR > 1 {
      delta = prev_tokens - $2
      pct   = ($2 / prev_tokens) * 100
      if (pct < 50) {
        printf "%s\t%d\t%d\t%d\t%.1f\n", \
               prev_line, $1, prev_tokens, $2, pct
      }
    }
    { prev_line = $1; prev_tokens = $2 }
  ' \
  | column -t -s $'\t' \
    -N "BOUNDARY_LINE,COMPACTION_LINE,TOKENS_BEFORE,TOKENS_AFTER,RETENTION_PCT"

Expected output:

BOUNDARY_LINE  COMPACTION_LINE  TOKENS_BEFORE  TOKENS_AFTER  RETENTION_PCT
46             47               98234          8102          8.2
202            203              112450         9341          8.3

Step 6: Produce Structured Report

Emit the compaction report as JSON to stdout or save to a file:

SESSION_LOG="<absolute-path-to-session.jsonl>"
OUTPUT_FILE=".claude/context/tmp/compaction-report-$(date +%Y%m%d-%H%M%S).json"

python3 - "$SESSION_LOG" "$OUTPUT_FILE" <<'PYEOF'
import json, sys, os, re
from datetime import datetime, timezone

log_path = sys.argv[1]
out_path  = sys.argv[2]

lines = open(log_path).readlines()
events = []
prev_tokens = None
prev_ts     = None

for i, raw in enumerate(lines):
    try:
        obj = json.loads(raw)
    except Exception:
        continue
    tokens = (obj.get("usage") or {}).get("input_tokens")
    ts     = obj.get("timestamp")
    if tokens is None:
        continue
    if prev_tokens is not None and tokens < prev_tokens * 0.5:
        events.append({
            "line_number":    i + 1,
            "timestamp":      ts or "unknown",
            "tokens_before":  prev_tokens,
            "tokens_after":   tokens,
            "delta":          prev_tokens - tokens,
            "retention_pct":  round(tokens / prev_tokens * 100, 1)
        })
    prev_tokens = tokens
    prev_ts     = ts

report = {
    "session_log":       log_path,
    "analyzed_at":       datetime.now(timezone.utc).isoformat(),
    "total_lines":       len(lines),
    "compaction_count":  len(events),
    "events":            events
}

os.makedirs(os.path.dirname(out_path), exist_ok=True)
with open(out_path, "w") as f:
    json.dump(report, f, indent=2)

print(json.dumps(report, indent=2))
PYEOF

Expected output (stdout + file):

{
  "session_log": "/home/user/.claude/projects/abc123/logs/session.jsonl",
  "analyzed_at": "2026-03-21T15:00:00.000Z",
  "total_lines": 312,
  "compaction_count": 2,
  "events": [
    {
      "line_number": 47,
      "timestamp": "2026-03-21T14:32:07.441Z",
      "tokens_before": 98234,
      "tokens_after": 8102,
      "delta": 90132,
      "retention_pct": 8.2
    },
    {
      "line_number": 203,
      "timestamp": "2026-03-21T14:58:33.117Z",
      "tokens_before": 112450,
      "tokens_after": 9341,
      "delta": 103109,
      "retention_pct": 8.3
    }
  ]
}

Verify: compaction_count matches the number of events in the events array.

</execution_process>

<best_practices>

  1. Always use absolute paths for SESSION_LOG — relative paths fail when the shell CWD differs.
  2. Check file size before parsing — files >10MB should be processed line-by-line (streaming), not loaded into memory.
  3. Threshold tuning — the default 50% drop threshold catches most compactions. Use 30% for aggressive detection or 70% for conservative (fewer false positives on large tool outputs).
  4. Handle missing timestamps gracefully — not all JSONL lines include timestamp; fall back to line number as the event identifier.
  5. Use python3 pipeline for production — the awk pipeline is fast for quick checks; the Python script is more reliable for malformed JSON or multi-byte characters.

</best_practices> </instructions>

<examples> <usage_example> Quick check — does this session have any compactions?

SESSION_LOG="$HOME/.claude/projects/$(ls -t ~/.claude/projects | head -1)/logs/session.jsonl"

grep '"input_tokens"' "$SESSION_LOG" \
  | grep -oP '"input_tokens"\s*:\s*\K[0-9]+' \
  | awk 'NR>1 && ($1/prev)<0.5 {print "Compaction found: "prev" -> "$1} {prev=$1}'

Full structured report:

Skill({ skill: 'compaction-detector' })
# Then supply the session log path when prompted

Pipe report into jq for summary:

node .claude/skills/compaction-detector/scripts/main.cjs --log "$SESSION_LOG" \
  | jq '{count: .compaction_count, events: [.events[] | {ts: .timestamp, delta: .delta}]}'

</usage_example> </examples>

Search Protocol

For code discovery and search tasks, follow this priority order:

  1. \pnpm search:code "<query>"\ (Primary intent-based search).
  2. \ripgrep\ (for exact keyword/regex matches).
  3. semantic/structural search via code tools if available.

Memory Protocol (MANDATORY)

Before starting: \\\bash cat .claude/context/memory/learnings.md cat .claude/context/memory/decisions.md \\\

After completing:

  • New pattern -> \.claude/context/memory/learnings.md\
  • Issue found -> \.claude/context/memory/issues.md\
  • Decision made -> \.claude/context/memory/decisions.md\

ASSUME INTERRUPTION: Your context may reset. If it's not in memory, it didn't happen.