Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Converts a Claude Code session JSONL file into an animated GIF terminal replay. Use when creating demos or visual evidence from past sessions.
.claude/skills/athola-session-replay/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-11 | ✗→✓ | ▲ Improved | -17% | 0% |
| case-16 | ✗→✓ | ▲ Improved | -28% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-08 | ✗→✓ | ▲ Improved | -5% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 26% | 0% |
Turn a Claude Code session JSONL file into an animated GIF that plays back the conversation as typed terminal output.
The skill orchestrates three steps: parse the session file into turns, generate a VHS tape from those turns, and hand off to scry for GIF rendering.
scribe:session-to-post)scribe:doc-generator)scry:vhs-recording directly)| Need | Skill | What it adds | |------|-------|-------------| | GIF rendering | scry:vhs-recording | Converts VHS tape to animated GIF | | Tutorial embedding | scribe:tech-tutorial | Embed GIF in tutorial markdown | | PR preparation | sanctum:prepare-pr | Attach replay as PR evidence |
When the user invokes /session-replay without a path argument, use scribe.session_parser.list_sessions() to discover recent session files from ~/.claude/projects/.
The function returns a list of SessionInfo objects sorted by modification time (most recent first), each containing:
path: full path to the .jsonl filemodified: mtime timestampfirst_user_message: preview of the first human messageturn_count: number of user turns in the sessionproject_name: parent directory namePresent the list to the user as a numbered menu:
Recent sessions:
1. [my-project] "implement auth module" (8 turns, 2h ago)
2. [api-server] "fix rate limiting bug" (3 turns, 5h ago)
3. [docs-site] "update installation guide" (12 turns, 1d ago)Ask the user to pick a number. Use the selected session's path for the remaining steps.
If list_sessions returns an empty list, report that no sessions were found and suggest providing a path directly.
Use scribe.session_parser.parse_session() to read the JSONL file. The parser:
Apply filters based on user options:
--turns selects specific turn ranges (e.g. 1-5)--show controls which layers appear: user, assistant,tools, thinking (thinking is excluded by default)
Use scribe.tape_generator.generate_tape() to convert the parsed turns into a VHS tape file. The generator:
$ prefix--speed multiplier--max-duration is exceededWrite the tape to a temp file: {tempdir}/session-replay-{timestamp}.tape
Invoke Skill(scry:vhs-recording) with the tape file path. Scry validates the tape, runs VHS, and produces the GIF at the path specified in the Output directive.
After successful rendering, delete the temp tape file.
| Error | Action | |-------|--------| | VHS not installed | Report: install via go install github.com/charmbracelet/vhs@latest | | Tape syntax error | Report VHS error output. Likely a string escaping bug. | | GIF generation fails | Report VHS error. Suggest --turns 1-5 to reduce scope. | | Scry skill not found | Report: scry plugin required for GIF rendering. |
bash# Pick from recent sessions interactively /session-replay # Replay a specific file directly /session-replay ~/.claude/projects/my-project/abc123.jsonl # First 5 turns only, faster playback /session-replay --turns 1-5 --speed 1.5 # Show only the conversation, no tool calls /session-replay --show user,assistant --output demo.gif
Output (interactive picker):
Recent sessions:
1. [my-project] "implement auth module" (8 turns, 2h ago)
2. [api-server] "fix rate limiting bug" (3 turns, 5h ago)
3. [docs-site] "update installation guide" (12 turns, 1d ago)
Pick a session [1-3]: 1
Parsed 42 turns from session (12 user, 15 assistant, 15 tools)
Generated tape: /tmp/session-replay-1711234567.tape
Rendering GIF via scry...
Done: session-replay.gif (18s, 960x540){tempdir}/session-replay-{timestamp}.tapebefore rendering is attempted
Outputdirective and its size reported (duration, dimensions)
go install github.com/charmbracelet/vhs@latest rather than silently failing
list_sessions() returns empty,user is told no sessions were found and directed to provide a path directly
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-11 | fail→pass | 13,477 | 2,138 | -84% | 1 | 1 | 0% | 2,099 | 1,748 | -17% | 0 | 0 | — |
case-01 | fail→fail | 16,982 | 6,782 | -60% | 1 | 1 | 0% | 3,162 | 1,767 | -44% | 0 | 0 | — |
case-02 | fail→fail | 7,471 | 6,545 | -12% | 1 | 1 | 0% | 1,220 | 1,690 | +39% | 0 | 0 | — |
case-16 | fail→pass | 15,229 | 2,825 | -81% | 1 | 1 | 0% | 2,538 | 1,825 | -28% | 0 | 0 | — |
case-03 | fail→fail | 31,820 | 7,320 | -77% | 1 | 1 | 0% | 6,140 | 1,833 | -70% | 0 | 0 | — |
case-04 | fail→pass | 9,008 | 5,457 | -39% | 1 | 1 | 0% | 1,457 | 2,306 | +58% | 0 | 0 | — |
case-05 | pass→pass | 9,083 | 3,505 | -61% | 1 | 1 | 0% | 1,592 | 1,942 | +22% | 0 | 0 | — |
case-06 | pass→pass | 15,304 | 7,672 | -50% | 1 | 1 | 0% | 2,518 | 2,741 | +9% | 0 | 0 | — |
case-07 | pass→pass | 9,174 | 1,694 | -82% | 1 | 1 | 0% | 1,345 | 1,618 | +20% | 0 | 0 | — |
case-08 | fail→pass | 11,024 | 2,048 | -81% | 1 | 1 | 0% | 1,765 | 1,669 | -5% | 0 | 0 | — |
case-09 | fail→pass | 9,352 | 1,720 | -82% | 1 | 1 | 0% | 1,259 | 1,592 | +26% | 0 | 0 | — |
case-10 | fail→pass | 14,700 | 2,220 | -85% | 1 | 1 | 0% | 2,188 | 1,648 | -25% | 0 | 0 | — |
case-12 | pass→pass | 14,388 | 5,194 | -64% | 1 | 1 | 0% | 2,138 | 2,238 | +5% | 0 | 0 | — |
case-13 | fail→fail | 12,175 | 4,100 | -66% | 1 | 1 | 0% | 1,915 | 2,013 | +5% | 0 | 0 | — |
case-14 | fail→pass | 10,223 | 5,334 | -48% | 1 | 1 | 0% | 1,602 | 2,277 | +42% | 0 | 0 | — |
case-15 | pass→pass | 8,243 | 4,075 | -51% | 1 | 1 | 0% | 1,245 | 1,984 | +59% | 0 | 0 | — |
case-17 | pass→pass | 6,627 | 2,590 | -61% | 1 | 1 | 0% | 1,030 | 1,797 | +74% | 0 | 0 | — |
case-18 | pass→fail | 4,746 | 1,418 | -70% | 1 | 1 | 0% | 687 | 1,629 | +137% | 0 | 0 | — |
case-19 | fail→pass | 11,340 | 7,702 | -32% | 1 | 1 | 0% | 1,116 | 2,736 | +145% | 0 | 0 | — |
case-20 | fail→pass | 9,200 | 6,216 | -32% | 1 | 1 | 0% | 1,467 | 2,337 | +59% | 0 | 0 | — |
case-21 | fail→fail | 9,272 | 8,549 | -8% | 1 | 1 | 0% | 1,380 | 2,747 | +99% | 0 | 0 | — |
case-22 | fail→pass | 6,796 | 3,170 | -53% | 1 | 1 | 0% | 981 | 1,967 | +101% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 19 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 19 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.