Claude
Skills
Sign in
Back

session-replay

Included with Lifetime
$97 forever

Analyze claude-trace JSONL files for session health, patterns, and actionable insights. Use when debugging session issues, understanding token usage, or identifying failure patterns.

General

What this skill does


# Session Replay Skill

## Purpose

This skill analyzes claude-trace JSONL files to provide insights into Claude Code session health, token usage patterns, error frequencies, and agent effectiveness. It complements the `/transcripts` command by focusing on API-level trace data rather than conversation transcripts.

## When to Use This Skill

- **Session debugging**: Diagnose why a session was slow or failed
- **Token analysis**: Understand token consumption patterns
- **Error patterns**: Identify recurring failures across sessions
- **Performance optimization**: Find bottlenecks in tool usage
- **Agent effectiveness**: Measure which agents/tools are most productive

## Quick Start

### Analyze Latest Session

```
User: Analyze my latest session health
```

I'll analyze the most recent trace file:

```python
# Read latest trace file from .claude-trace/
trace_dir = Path(".claude-trace")
trace_files = sorted(trace_dir.glob("*.jsonl"), key=lambda f: f.stat().st_mtime)
latest = trace_files[-1] if trace_files else None

# Parse and analyze
if latest:
    analysis = analyze_trace_file(latest)
    print(format_session_report(analysis))
```

### Compare Multiple Sessions

```
User: Compare token usage across my last 5 sessions
```

I'll aggregate metrics across sessions:

```python
trace_files = sorted(Path(".claude-trace").glob("*.jsonl"))[-5:]
comparison = compare_sessions(trace_files)
print(format_comparison_table(comparison))
```

## Actions

### Action: `health`

Analyze session health metrics from a trace file.

**What to do:**

1. Read the trace file (JSONL format)
2. Extract API requests and responses
3. Calculate metrics:
   - Total tokens (input/output)
   - Request count and timing
   - Error rate
   - Tool usage distribution
4. Generate health report

**Metrics to extract:**

```python
# From each JSONL line containing a request/response pair:
{
    "timestamp": "...",
    "request": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "body": {
            "model": "claude-...",
            "messages": [...],
            "tools": [...]
        }
    },
    "response": {
        "usage": {
            "input_tokens": N,
            "output_tokens": N
        },
        "content": [...],
        "stop_reason": "..."
    }
}
```

**Output format:**

```
Session Health Report
=====================
File: log-2025-11-23-19-32-36.jsonl
Duration: 45 minutes

Token Usage:
- Input: 125,432 tokens
- Output: 34,521 tokens
- Total: 159,953 tokens
- Efficiency: 27.5% output ratio

Request Stats:
- Total requests: 23
- Average latency: 2.3s
- Errors: 2 (8.7%)

Tool Usage:
- Read: 45 calls
- Edit: 12 calls
- Bash: 8 calls
- Grep: 15 calls

Health Score: 82/100 (Good)
- Minor issue: 2 errors detected
```

### Action: `errors`

Identify error patterns across sessions.

**What to do:**

1. Scan trace files for error responses
2. Categorize errors by type
3. Identify recurring patterns
4. Suggest fixes

**Error categories to detect:**

- Rate limit errors (429)
- Token limit exceeded
- Tool execution failures
- Timeout errors
- API errors

**Output format:**

```
Error Analysis
==============
Sessions analyzed: 5
Total errors: 12

Error Categories:
1. Rate limit (429): 5 occurrences
   - Recommendation: Add delays between requests

2. Token limit: 3 occurrences
   - Recommendation: Use context management skill

3. Tool failures: 4 occurrences
   - Bash timeout: 2
   - File not found: 2
   - Recommendation: Check paths before operations
```

### Action: `compare`

Compare metrics across multiple sessions.

**What to do:**

1. Load multiple trace files
2. Extract comparable metrics
3. Calculate trends
4. Identify anomalies

**Output format:**

```
Session Comparison
==================
                    Session 1   Session 2   Session 3   Trend
Tokens (total)      150K        180K        120K        -17%
Requests            25          30          18          -28%
Errors              2           0           1           stable
Duration (min)      45          60          30          -33%
Efficiency          0.27        0.32        0.35        +7%
```

### Action: `tools`

Analyze tool usage patterns.

**What to do:**

1. Extract tool calls from traces
2. Calculate frequency and timing
3. Identify inefficient patterns
4. Suggest optimizations

**Patterns to detect:**

- Sequential calls that could be parallel
- Repeated reads of same file
- Excessive grep/glob calls
- Unused tool results

**Output format:**

```
Tool Usage Analysis
===================
Tool          Calls   Avg Time   Success Rate
Read          45      0.1s       100%
Edit          12      0.3s       92%
Bash          8       1.2s       75%
Grep          15      0.2s       100%
Task          3       45s        100%

Optimization Opportunities:
1. 5 Read calls to same file within 2 minutes
   - Consider caching strategy

2. 3 sequential Bash calls could be parallelized
   - Use multiple Bash calls in single message
```

## Implementation Notes

### Parsing JSONL Traces

Claude-trace files are JSONL format with request/response pairs:

```python
import json
from pathlib import Path
from typing import Dict, List, Any

def parse_trace_file(path: Path) -> List[Dict[str, Any]]:
    """Parse a claude-trace JSONL file."""
    entries = []
    with open(path) as f:
        for line in f:
            if line.strip():
                try:
                    entry = json.loads(line)
                    entries.append(entry)
                except json.JSONDecodeError:
                    continue
    return entries

def extract_metrics(entries: List[Dict]) -> Dict[str, Any]:
    """Extract session metrics from trace entries."""
    metrics = {
        "total_input_tokens": 0,
        "total_output_tokens": 0,
        "request_count": 0,
        "error_count": 0,
        "tool_usage": {},
        "timestamps": [],
    }

    for entry in entries:
        if "request" in entry:
            metrics["request_count"] += 1
            metrics["timestamps"].append(entry.get("timestamp", 0))

        if "response" in entry:
            usage = entry["response"].get("usage", {})
            metrics["total_input_tokens"] += usage.get("input_tokens", 0)
            metrics["total_output_tokens"] += usage.get("output_tokens", 0)

            # Check for errors
            if entry["response"].get("error"):
                metrics["error_count"] += 1

        # Extract tool usage from request body
        if "request" in entry and "body" in entry["request"]:
            body = entry["request"]["body"]
            if isinstance(body, dict) and "tools" in body:
                for tool in body["tools"]:
                    name = tool.get("name", "unknown")
                    metrics["tool_usage"][name] = metrics["tool_usage"].get(name, 0) + 1

    return metrics
```

### Locating Trace Files

```python
def find_trace_files(trace_dir: str = ".claude-trace") -> List[Path]:
    """Find all trace files, sorted by modification time."""
    trace_path = Path(trace_dir)
    if not trace_path.exists():
        return []
    return sorted(
        trace_path.glob("*.jsonl"),
        key=lambda f: f.stat().st_mtime,
        reverse=True  # Most recent first
    )
```

### Error Handling

Handle common error scenarios gracefully:

```python
def safe_parse_trace_file(path: Path) -> Tuple[List[Dict], List[str]]:
    """Parse trace file with error collection for malformed lines.

    Returns:
        Tuple of (valid_entries, error_messages)
    """
    entries = []
    errors = []

    if not path.exists():
        return [], [f"Trace file not found: {path}"]

    try:
        with open(path) as f:
            for line_num, line in enumerate(f, 1):
                if not line.strip():
                    continue
                try:
                    entry = json.loads(line)
                    entries.append(entry)
                except json.JSONDecodeError as e:
                    errors.appen

Related in General