Analyze Claude Code session transcripts to debug plugins, understand context usage, and trace execution flow
View on GitHubbfreis/claude-mart
transcript-analyzer
January 20, 2026
Select agents to install to:
npx add-skill https://github.com/bfreis/claude-mart/blob/main/plugins/transcript-analyzer/skills/transcript-analyzer/SKILL.md -a claude-code --skill transcript-analyzerInstallation paths:
.claude/skills/transcript-analyzer/# Transcript Analyzer Skill
Use this skill when you need to analyze Claude Code session transcripts for:
- Debugging plugin behavior
- Understanding context/token usage patterns
- Tracing tool execution flow
- Finding sources of context bloat
- Investigating errors or unexpected behavior
## Transcript Location
Claude Code stores session transcripts at:
```
~/.claude/projects/-PATH-TO-PROJECT/*.jsonl
```
The path uses dashes instead of slashes. For example:
- Project: `/Users/bfreis/dev/myproject`
- Transcripts: `~/.claude/projects/-Users-bfreis-dev-myproject/*.jsonl`
## Transcript Structure
Transcripts use **JSONL format** (one JSON object per line).
### Record Types
| Type | Description |
|------|-------------|
| `summary` | Session metadata |
| `file-history-snapshot` | File change tracking |
| `user` | User messages (includes tool results) |
| `assistant` | Assistant messages (includes tool calls) |
### Message Structure
```json
{
"type": "user" | "assistant",
"uuid": "message-uuid",
"parentUuid": "parent-message-uuid",
"sessionId": "session-uuid",
"isSidechain": false,
"timestamp": "2025-12-06T...",
"message": {
"role": "user" | "assistant",
"content": [...],
"usage": { "input_tokens": N, "output_tokens": N }
}
}
```
### Content Block Types
**In assistant messages:**
- `text` - Regular text response
- `tool_use` - Tool invocation with `.id`, `.name`, `.input`
- `thinking` - Extended thinking blocks
**In user messages:**
- `text` - User input
- `tool_result` - Tool output with `.tool_use_id`, `.content`
### Critical Gotchas
1. **Content is ALWAYS an array** - Even single text blocks
2. **Tool result `.content` can be string OR array** - Handle both:
```jq
if .content | type == "array" then
(.content | map(.text // "") | add)
else
.content
end
```
3. **Use `[]?` not `[]`** - Handles missing fields gracefully
4. **Sub-agents have `isSidechain: true`** - Filter these for main conversation only
5. **