Help us improve
Share bugs, ideas, or general feedback.
From hatch3r
Generates an in-chat session report from the active or named Claude Code transcript, showing every tool call, sub-agent delegation, and file edit with diagnostics for missed parallelism, redundant work, and over-serialization.
npx claudepluginhub hatch3r/hatch3rHow this skill is triggered — by the user, by Claude, or both
Slash command
/hatch3r:hatch3r-reportThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Render an in-chat report of what happened in a Claude Code session: every tool call, every sub-agent `Agent` delegation, every file edit, every hook event. Default = current session, executive summary, in-chat. Flags extend scope and depth. Two audiences: (a) users who want to understand the session end-to-end; (b) maintainers investigating runtime shape for framework-level optimizations.
Analyzes Claude Code session logs to extract tool usage stats, thinking blocks, error patterns, debug trajectories, and generate actionable productivity recommendations. Provides cc-session CLI for overviews, timelines, searches.
Analyzes current or recent agent sessions (GitHub Copilot CLI or Claude Code) and generates a diagnostic report. Useful for session feedback, debugging agent behavior, or reviewing build sessions.
Analyzes Claude Code JSONL transcripts to detect anti-patterns, tool misuse, user frustration signals, and workflow patterns using DuckDB SQL, 10 dimensions, and PM4Py mining.
Share bugs, ideas, or general feedback.
Render an in-chat report of what happened in a Claude Code session: every tool call, every sub-agent Agent delegation, every file edit, every hook event. Default = current session, executive summary, in-chat. Flags extend scope and depth. Two audiences: (a) users who want to understand the session end-to-end; (b) maintainers investigating runtime shape for framework-level optimizations.
Task Progress:
- [ ] Step 0: Detect ambiguity (P8 B1) — only if invocation arguments are ambiguous
- [ ] Step 1: Discover the session
- [ ] Step 2: Aggregate via jq
- [ ] Step 3: Compute diagnostics
- [ ] Step 4: Render executive summary
- [ ] Step 5: Render verbose timeline (--verbose only)
- [ ] Step 6: Save to disk (--save only)
This skill is read-only over local transcripts and produces no file mutations outside .hatch3r/reports/ (and only with --save). The platform-native question tool is invoked only when the user's --session <value> argument fails to resolve to a readable file or when --save would overwrite an existing report — see Error Handling. Otherwise the skill runs without an ASK gate.
| Flag | Effect |
|---|---|
--session <id|path> | Target a UUID under the project slug dir, or an absolute .jsonl path. Default = newest-mtime jsonl in current project slug. |
--list | Exclusive. Print the 5 most-recent sessions in this project (sessionId, mtime, first-user-message preview 60 chars). Skips all other rendering. |
--verbose | Append a chronological per-turn timeline after the executive summary. |
--save | After rendering in-chat, also write to .hatch3r/reports/{sessionId-short8}-{YYYYMMDD-HHMMSS}.md. |
--list takes precedence over --session, --verbose, --save. All other flags compose.
Compute the project slug from the working directory: SLUG="$(pwd | sed 's|/|-|g')". The transcript directory is ~/.claude/projects/${SLUG}. List *.jsonl files; the active session is the newest by mtime (ls -t *.jsonl | head -1). When --session <value> is provided, resolve a 36-char UUID against the slug dir as ${value}.jsonl, otherwise treat as an absolute path. When --list is set, enumerate the top-5 newest jsonl files; for each, parse the first type=user record and emit <short-id> <mtime> <first-60-chars-of-user-text>.
Run jq over the JSONL to produce a single structured JSON of counts. Persist to $(mktemp) so the LLM reads aggregated data only. Sample pipeline:
jq -s '
def tu: [.[] | select(.message.content?) | .message.content[] | select(.type=="tool_use")];
def tr: [.[] | select(.message.content?) | .message.content[] | select(.type=="tool_result")];
def asst_turns: [.[] | select(.type=="assistant" and (.message.content?))];
def thinks: [.[] | select(.message.content?) | .message.content[] | select(.type=="thinking") | .text];
{
sessionId: .[0].sessionId, firstTs: .[0].timestamp, lastTs: .[-1].timestamp,
cwd: .[0].cwd, gitBranch: .[0].gitBranch, records: length,
toolCounts: (tu | group_by(.name) | map({tool: .[0].name, count: length}) | sort_by(-.count)),
distinctReads: (tu | map(select(.name=="Read") | .input.file_path) | unique | length),
distinctEdits: (tu | map(select(.name=="Edit" or .name=="Write") | .input.file_path) | unique | length),
topReads: (tu | map(select(.name=="Read") | .input.file_path) | group_by(.) | map({path: .[0], count: length}) | sort_by(-.count) | .[0:3]),
agentCalls: (tu | map(select(.name=="Agent") | {sub: (.input.subagent_type // "general-purpose"), prompt: (.input.prompt[:80] // "")})),
bashCmds: (tu | map(select(.name=="Bash") | .input.command)),
turnLens: [asst_turns[] | (.message.content | map(select(.type=="tool_use")) | length)],
thinkingChars: ([thinks[] | length] | add // 0),
errorResults: (tr | map(select((.content | tostring) | test("error|failed"; "i"))) | length),
totalResults: (tr | length)
}' "$JSONL"
thinkingChars is the summed length of every thinking block's text — required input for D-LOOP-01 (thinking chars ÷ (tool_use count + 1) > 1200).
The LLM reads the resulting JSON, computes derived metrics (parallel-batch count = turns with ≥2 tool_use; sequential count = turns with exactly 1), and builds the rendered tables.
Apply each rule in §Diagnostic Heuristics over the aggregated structure. Each fired diagnostic produces a record {id, severity, turns:[...], evidence, suggestion}. Emit at most one fire per rule per session (consolidate same-rule fires across turns into one record). If zero rules fire, render None — execution shape is clean.
Always emit. Headings, order, and content per §Output Format. Mask obvious secret patterns (sk-..., ghp_..., xoxb-..., AIza..., Bearer ...) in any rendered tool_use input field. Truncate Bash commands and Agent prompts to ≤80 chars in tables.
Append ## Timeline. For each assistant turn containing ≥1 tool_use, emit a numbered block: turn index, ISO timestamp, elapsed-since-start, optional thinking: N chars summary, one line per tool_use (tool name + first 60 chars of primary input field), and a parallel/sequential marker — → {n} tool_use blocks ✓ parallel when n≥2, → 1 tool_use ⚠ sequential when n=1.
Create .hatch3r/reports/ if missing. Write the rendered markdown (executive summary + timeline if --verbose set) to .hatch3r/reports/{sessionId-short8}-{YYYYMMDD-HHMMSS}.md. Append a ## Raw Counts (machine-readable) section containing the jq-aggregated JSON in a fenced json block — this lets future tooling grep across sessions without re-parsing the source JSONL. Print the file path back to chat. The .hatch3r/ directory is gitignored.
## Session Report — a5d750f7
**Window:** 2026-05-12 09:14:03 → 09:47:21 (33m 18s, 272 records)
**Project:** hatch3r (release/1.7.1)
### Tool Activity (91 tool calls)
| Tool | Calls | Notable |
|------|------:|---------|
| Read | 47 | 12 distinct files; validate.ts read 4x |
| Bash | 21 | 6 parallel batches, 15 sequential |
| Edit | 18 | 9 distinct files |
| Task | 4 | 3 general-purpose, 1 explore — all sequential |
| Grep | 1 | — |
### Sub-Agent Delegation (4 Agent calls)
| # | Subagent | Prompt (first 60) | Files touched |
|---|----------|-------------------|---------------|
| 1 | general-purpose | "Find references to validateCommandOrch..." | 0 |
| 2 | Explore | "Map existing commands that overlap..." | 0 |
| 3 | Explore | "Find conversation transcript access..." | 0 |
| 4 | Plan | "Design hatch3r-report command..." | 0 |
### File Footprint
- 12 distinct files read; 9 distinct files edited
- Top 3 most-read: src/cli/commands/validate.ts (4x), skills/hatch3r-context-health/SKILL.md (2x), CHANGELOG.md (2x)
### Diagnostics
- WARN D-PAR-01 Missed parallelism: turns 7, 9, 11 each issued one Read on disjoint paths → batch into one assistant turn.
- WARN D-RED-01 Redundant Read: src/cli/commands/validate.ts read at turns 4, 8, 22, 31 with no Edit between turns 4 and 31.
- INFO D-PAR-02 Sub-agent fan-out: 4 Agent calls at turns 44, 53, 67, 78 — disjoint subsystems → eligible for parallel fan-out.
### Suggested Next Action
Re-run `/hatch3r-report --verbose` for the chronological timeline.
| ID | Heuristic | Trigger | Severity |
|---|---|---|---|
| D-PAR-01 | Missed parallelism (same-tool sequential) | ≥3 consecutive assistant turns each with exactly 1 tool_use of the same tool type targeting disjoint inputs | WARN |
| D-PAR-02 | Sub-agent fan-out missed | ≥2 Agent tool_use blocks within 10 turns where prompt subjects target disjoint path prefixes | WARN |
| D-RED-01 | Redundant Read | Same Read.file_path in ≥3 tool_use blocks with no intervening Edit/Write on that path | WARN |
| D-RED-02 | Re-Bash identical command | Same Bash.command (trimmed exact match) ≥2 times within 20 turns | INFO |
| D-LOOP-01 | High thinking-to-action ratio | Total thinking chars ÷ (tool_use count + 1) > 1200 AND tool_use count < 8 | WARN |
| D-LOOP-02 | Tool burst → stall | One turn with ≥5 tool_use blocks AND next turn with 0 AND ≥3 subsequent turns with 0 tool_use | INFO |
| D-ERR-01 | Tool-result error rate | tool_result.content matches /error|failed/i in >20% of results | WARN |
| D-PATH-01 | File staleness | Path read at turn N, edited at turn M, re-read at turn P>M+15 with no intervening edit on that path | INFO |
| D-SUB-01 | Sub-agent returning empty | Agent tool_result body <200 chars AND no subsequent Edit on any path the prompt referenced | WARN |
Each fired record: {id, severity, turns:[n,...], evidence, suggestion}. Consolidate same-rule fires into one record per session.
| Condition | Action |
|---|---|
~/.claude/projects/{slug} does not exist | Print: "No Claude Code transcripts found for this project. Slug: {slug}". Exit. |
Slug dir exists but contains no *.jsonl | Print: "Project directory empty — no sessions to report on." Exit. |
--session <id> does not resolve to a readable file | Print: "Session {id} not found under {slug}. Use --list to see available sessions." Exit. |
jq not installed | Print: "jq is required. Install via brew install jq (macOS) or your distro's package manager, then retry." Exit. |
| Malformed JSONL record encountered | Skip the record; increment a skipped counter; surface the count in the executive summary footer when non-zero. |
| Read access denied to a transcript file | Print: "Cannot read {path}: permission denied." Exit. |
$(mktemp) and are deleted at end-of-run.sk-, ghp_, xoxb-, AIza, Bearer ) in any rendered tool_use input — substitute {REDACTED-{prefix}}. The transcript may contain ephemeral tokens from user pastes..hatch3r/reports/. The --save target is fixed; do not honor flags or env vars that redirect output to other paths.rules/hatch3r-iteration-summary.md) at the end of the parent assistant turn that invoked this skill. The report content is not a substitute for the canonical Status / Outcome / Done block.