sessionreel 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sessionreel-0.1.0/.claude-plugin/marketplace.json +12 -0
- sessionreel-0.1.0/.claude-plugin/plugin.json +10 -0
- sessionreel-0.1.0/.gitguardian.yaml +6 -0
- sessionreel-0.1.0/.gitignore +16 -0
- sessionreel-0.1.0/DESIGN.md +122 -0
- sessionreel-0.1.0/LICENSE +24 -0
- sessionreel-0.1.0/PKG-INFO +164 -0
- sessionreel-0.1.0/README.ko.md +80 -0
- sessionreel-0.1.0/README.md +140 -0
- sessionreel-0.1.0/commands/reel.md +12 -0
- sessionreel-0.1.0/docs/launch/posts.md +50 -0
- sessionreel-0.1.0/pyproject.toml +48 -0
- sessionreel-0.1.0/scripts/make_demo_session.py +147 -0
- sessionreel-0.1.0/skills/sessionreel/SKILL.md +71 -0
- sessionreel-0.1.0/src/sessionreel/__init__.py +7 -0
- sessionreel-0.1.0/src/sessionreel/board.py +101 -0
- sessionreel-0.1.0/src/sessionreel/cli.py +193 -0
- sessionreel-0.1.0/src/sessionreel/demo/demo-session.jsonl +25 -0
- sessionreel-0.1.0/src/sessionreel/fonts/Inter-Regular.ttf +0 -0
- sessionreel-0.1.0/src/sessionreel/fonts/Inter-SemiBold.ttf +0 -0
- sessionreel-0.1.0/src/sessionreel/fonts/InterDisplay-Bold.ttf +0 -0
- sessionreel-0.1.0/src/sessionreel/fonts/JetBrainsMono-Bold.ttf +0 -0
- sessionreel-0.1.0/src/sessionreel/fonts/JetBrainsMono-Regular.ttf +0 -0
- sessionreel-0.1.0/src/sessionreel/fonts/NotoEmoji.ttf +0 -0
- sessionreel-0.1.0/src/sessionreel/fonts/OFL-Inter.txt +92 -0
- sessionreel-0.1.0/src/sessionreel/fonts/OFL-JetBrainsMono.txt +93 -0
- sessionreel-0.1.0/src/sessionreel/fonts/OFL-NotoEmoji.txt +93 -0
- sessionreel-0.1.0/src/sessionreel/fonts/OFL-Pretendard.txt +94 -0
- sessionreel-0.1.0/src/sessionreel/fonts/Pretendard-Bold.otf +0 -0
- sessionreel-0.1.0/src/sessionreel/fonts/Pretendard-Regular.otf +0 -0
- sessionreel-0.1.0/src/sessionreel/ingest.py +237 -0
- sessionreel-0.1.0/src/sessionreel/models.py +79 -0
- sessionreel-0.1.0/src/sessionreel/redact.py +139 -0
- sessionreel-0.1.0/src/sessionreel/render.py +736 -0
- sessionreel-0.1.0/src/sessionreel/story.py +507 -0
- sessionreel-0.1.0/src/sessionreel/voice.py +74 -0
- sessionreel-0.1.0/tests/conftest.py +83 -0
- sessionreel-0.1.0/tests/test_board.py +72 -0
- sessionreel-0.1.0/tests/test_ingest.py +61 -0
- sessionreel-0.1.0/tests/test_redact.py +154 -0
- sessionreel-0.1.0/tests/test_render.py +95 -0
- sessionreel-0.1.0/tests/test_story.py +232 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sessionreel",
|
|
3
|
+
"owner": { "name": "Youngmin Ko", "url": "https://github.com/mandu5" },
|
|
4
|
+
"plugins": [
|
|
5
|
+
{
|
|
6
|
+
"name": "sessionreel",
|
|
7
|
+
"source": "./",
|
|
8
|
+
"description": "Turn a Claude Code session into a short recap video. Local, redacted, no API key.",
|
|
9
|
+
"version": "0.1.0"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "sessionreel",
|
|
3
|
+
"description": "Turn this Claude Code session into a 30-60 second recap video: the ask, the failing test, the fix, green, shipped. Rendered locally, secrets redacted, no API key. /reel writes the storyboard, rewrites the captions from what actually happened, and renders an mp4.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": { "name": "Youngmin Ko", "url": "https://github.com/mandu5" },
|
|
6
|
+
"homepage": "https://github.com/mandu5/sessionreel",
|
|
7
|
+
"repository": "https://github.com/mandu5/sessionreel",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"keywords": ["video", "recap", "session", "demo", "share", "changelog", "ffmpeg"]
|
|
10
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# sessionreel — design
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
A coding agent can work for two hours and leave behind a 30 MB JSONL log. The work is real, but
|
|
6
|
+
nobody else can see it: a teammate will not scrub a transcript, a client will not open a replay
|
|
7
|
+
viewer, and a link on X is not a video. The existing tools (claude-devtools, claude-code-log,
|
|
8
|
+
claude-replay, mindwalk, zoetrope) are *viewers* — the audience has to come to them and spend
|
|
9
|
+
minutes. None of them produces the one artifact people actually share: a short video that plays
|
|
10
|
+
inline and tells what happened.
|
|
11
|
+
|
|
12
|
+
## Goal
|
|
13
|
+
|
|
14
|
+
`sessionreel` turns one agent session into a 30–60 second video that is
|
|
15
|
+
|
|
16
|
+
1. **true** — every frame is derived from the log (the real prompt, the real diff, the real
|
|
17
|
+
test output); nothing is invented, including by an LLM;
|
|
18
|
+
2. **interesting** — it tells the story (goal → the failure → the fix → green → shipped), not a
|
|
19
|
+
random sample of 400 tool calls;
|
|
20
|
+
3. **safe to post** — secrets, tokens, emails and home paths are redacted before anything is
|
|
21
|
+
drawn, and the report says what was removed;
|
|
22
|
+
4. **free and local** — no API key, no upload, no Node/Chromium; one `uvx` command.
|
|
23
|
+
|
|
24
|
+
Non-goals for v1: live capture, Codex/Cursor logs (adapter interface is in place; Codex is next),
|
|
25
|
+
music, voices other than the OS voice.
|
|
26
|
+
|
|
27
|
+
## Pipeline
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
session.jsonl ──ingest──▶ Session(events) ──redact──▶ Session' ──story──▶ Storyboard ──render──▶ mp4
|
|
31
|
+
▲
|
|
32
|
+
optional: captions rewritten by the host agent
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Every stage is a pure function with a JSON boundary, so `plan` and `render` can run separately
|
|
36
|
+
and a user (or the agent in plugin mode) can edit `storyboard.json` in between.
|
|
37
|
+
|
|
38
|
+
### ingest (`ingest/claude.py`)
|
|
39
|
+
|
|
40
|
+
Claude Code writes one JSON object per line. We keep only the main thread
|
|
41
|
+
(`isSidechain == false`) and normalise to five event kinds:
|
|
42
|
+
|
|
43
|
+
| event | source |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `Prompt(text)` | `type=user`, string content, not a command/caveat/system-reminder wrapper |
|
|
46
|
+
| `Say(text)` | assistant `text` block |
|
|
47
|
+
| `Tool(name, input, output, error, patch)` | assistant `tool_use` joined to the next `tool_result` by id; `patch` from `toolUseResult.structuredPatch` (Edit/Write/MultiEdit) |
|
|
48
|
+
| `Usage(in, out, cache)` | assistant `message.usage` |
|
|
49
|
+
| timestamps | every entry's `timestamp` |
|
|
50
|
+
|
|
51
|
+
Malformed lines are skipped and counted, never fatal: logs are written live and may be truncated.
|
|
52
|
+
|
|
53
|
+
### redact (`redact.py`)
|
|
54
|
+
|
|
55
|
+
Runs on the normalised session, before the storyboard exists, so no later stage can leak.
|
|
56
|
+
Patterns: provider keys (`sk-…`, `sk-ant-…`, `ghp_/gho_/github_pat_`, `AKIA…`, `xox[abpr]-`,
|
|
57
|
+
`AIza…`), JWTs, `Bearer …`, `KEY=value` where KEY names a secret, URL credentials and token query
|
|
58
|
+
params, e-mail addresses, and the user's home directory (→ `~`). Contents of `.env*`, `*.pem`,
|
|
59
|
+
`id_rsa*` files are never shown. User-supplied `--redact REGEX` adds patterns. The count per
|
|
60
|
+
category is printed and stored in the storyboard; `render` refuses a storyboard whose
|
|
61
|
+
`redacted` flag is false.
|
|
62
|
+
|
|
63
|
+
### story (`story.py`)
|
|
64
|
+
|
|
65
|
+
Deterministic. Beats are detected, scored and packed into the time budget:
|
|
66
|
+
|
|
67
|
+
- **goal** — the first substantive prompt (the ask).
|
|
68
|
+
- **explore** — reads/greps/globs collapsed into one montage ("read 14 files").
|
|
69
|
+
- **red** — a test/build command whose output shows failure (pytest/jest/go/cargo/tsc summary
|
|
70
|
+
lines, non-zero exit, `is_error`).
|
|
71
|
+
- **fix** — the edits between a red and the next green of the *same* command family.
|
|
72
|
+
- **green** — that command passing.
|
|
73
|
+
- **ship** — `git commit`/`git push`/`gh pr create`/publish commands that succeeded.
|
|
74
|
+
- **result** — the agent's final message, first sentence.
|
|
75
|
+
- **stats** — duration, prompts, tool calls, files changed, lines ±, tests, tokens.
|
|
76
|
+
|
|
77
|
+
The red→fix→green arc is the spine: if the session has one, the reel is built around the most
|
|
78
|
+
recent complete arc. Otherwise the largest edits carry the middle. Captions are templated from the
|
|
79
|
+
data ("3 tests failing", "fixed in `parser.py`", "12 passed"); they never claim what the log does
|
|
80
|
+
not show.
|
|
81
|
+
|
|
82
|
+
### captions
|
|
83
|
+
|
|
84
|
+
Default: templates (offline, zero cost). Plugin mode: the agent that did the work rewrites the
|
|
85
|
+
captions in `storyboard.json` — it has the context, and it runs inside the user's own session, so
|
|
86
|
+
no extra API key or upload exists. The renderer does not care who wrote a caption; `plan` stores
|
|
87
|
+
the template caption as `fact` next to it so a rewrite can be checked against the source.
|
|
88
|
+
|
|
89
|
+
### render (`render/`)
|
|
90
|
+
|
|
91
|
+
Pillow draws each frame; frames stream as raw RGB into ffmpeg (system binary, else the static
|
|
92
|
+
binary from `imageio-ffmpeg`) → H.264 yuv420p, CRF 20, 30 fps. Formats: `square` 1080×1080
|
|
93
|
+
(feeds), `wide` 1920×1080, `tall` 1080×1920. Scenes: title, prompt (typewriter), montage,
|
|
94
|
+
terminal (typed command, output reveal, exit badge), diff (hunks, line-by-line reveal, syntax
|
|
95
|
+
colour via Pygments), stats (counters), end card. Crossfades between scenes. Static layers are
|
|
96
|
+
drawn once per scene and cached; per-frame work is only what moves. Optional `--voice` speaks
|
|
97
|
+
each caption with the OS voice (`say` on macOS, `espeak-ng` on Linux) and stretches scenes to fit.
|
|
98
|
+
|
|
99
|
+
Fonts are bundled (OFL): JetBrains Mono for code, Inter for UI, Pretendard for Hangul, with
|
|
100
|
+
per-character fallback so a Korean prompt renders correctly.
|
|
101
|
+
|
|
102
|
+
## Interfaces
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
sessionreel # latest session for the current directory → reel.mp4
|
|
106
|
+
sessionreel list # recent sessions: id, when, project, prompts, tool calls
|
|
107
|
+
sessionreel plan [SESSION] -o storyboard.json
|
|
108
|
+
sessionreel render storyboard.json -o reel.mp4 [--format square|wide|tall] [--voice] [--gif]
|
|
109
|
+
sessionreel demo # bundled sample session → demo.mp4 (no logs needed)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Claude Code plugin: `/reel` plans, lets the agent rewrite captions from its own context, renders,
|
|
113
|
+
and prints the path.
|
|
114
|
+
|
|
115
|
+
## Quality bar
|
|
116
|
+
|
|
117
|
+
- Fixture sessions (synthetic, no personal data) covering: red→green arc, no tests, only
|
|
118
|
+
exploration, errors without recovery, Korean prompt, secrets in commands and outputs.
|
|
119
|
+
- Unit tests per stage; a render smoke test that decodes the output with ffprobe (duration,
|
|
120
|
+
resolution, codec) and samples frames for non-blank content.
|
|
121
|
+
- Redaction tests are adversarial: every pattern has a positive and a near-miss negative.
|
|
122
|
+
- `ruff`, CI on macOS + Ubuntu, Python 3.10–3.13.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Youngmin Ko
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
The fonts in src/sessionreel/fonts/ are distributed under the SIL Open Font License 1.1;
|
|
24
|
+
see the OFL-*.txt files next to them.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sessionreel
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Turn a Claude Code session log into a 30-60 second recap video. Local, redacted, no API key.
|
|
5
|
+
Project-URL: Homepage, https://github.com/mandu5/sessionreel
|
|
6
|
+
Project-URL: Issues, https://github.com/mandu5/sessionreel/issues
|
|
7
|
+
Author: Youngmin Ko
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: claude-code,coding-agent,ffmpeg,recap,session,video
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Multimedia :: Video
|
|
15
|
+
Classifier: Topic :: Software Development
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: imageio-ffmpeg>=0.5
|
|
18
|
+
Requires-Dist: pillow>=10.0
|
|
19
|
+
Requires-Dist: pygments>=2.15
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
22
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# sessionreel
|
|
26
|
+
|
|
27
|
+
**Your agent worked for two hours. Here is the 35-second version.**
|
|
28
|
+
|
|
29
|
+
`sessionreel` reads a Claude Code session log and renders a short recap video: the ask, the
|
|
30
|
+
test that went red, the diff that fixed it, the run that went green, what shipped. It runs
|
|
31
|
+
locally, redacts secrets before anything is drawn, and needs no API key.
|
|
32
|
+
|
|
33
|
+
<p align="center"><img src="docs/demo.gif" width="600" alt="sessionreel demo: 2 failed → 14 passed in 35 seconds"></p>
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
uvx sessionreel # newest session in this directory → reel.mp4
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
[한국어](README.ko.md)
|
|
40
|
+
|
|
41
|
+
## Why
|
|
42
|
+
|
|
43
|
+
Agent sessions are real work that nobody else can see. A teammate will not scrub a 30 MB
|
|
44
|
+
transcript, a client will not open a replay viewer, and a link on X is not a video. The tools
|
|
45
|
+
that exist are viewers (you go to them); sessionreel makes the thing you send.
|
|
46
|
+
|
|
47
|
+
What a reel is built from — all of it straight from the log:
|
|
48
|
+
|
|
49
|
+
| scene | source in the log |
|
|
50
|
+
|---|---|
|
|
51
|
+
| the ask | the prompt that started this piece of work |
|
|
52
|
+
| exploring | files read and searches run before the first change |
|
|
53
|
+
| red | a test/build command whose output shows failures (`pytest`, `jest`/`vitest`, `go test`, `cargo test`, `tsc`, `ruff`, `mypy`, `make <target>`) |
|
|
54
|
+
| the fix | the diffs Claude Code recorded between that red run and the next green run of the same check |
|
|
55
|
+
| green | the same check passing |
|
|
56
|
+
| shipped | a successful `git commit` / `git push` / `gh pr create` / publish, with the commit message |
|
|
57
|
+
| numbers | active time (breaks over 15 min don't count), tool calls, files and lines changed, tests |
|
|
58
|
+
|
|
59
|
+
No arc in the session? The reel is built from the largest edits instead. A long session with
|
|
60
|
+
many unrelated tasks? The reel tells one episode — from the ask that led to the fix up to the
|
|
61
|
+
next ask — so it doesn't end on another task's summary (`--whole` to override).
|
|
62
|
+
|
|
63
|
+
## Install
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
uvx sessionreel # run without installing
|
|
67
|
+
pipx install sessionreel # or install
|
|
68
|
+
uvx --from git+https://github.com/mandu5/sessionreel sessionreel # latest main
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Python 3.10+. ffmpeg is used if it's on your PATH, otherwise the bundled static build from
|
|
72
|
+
`imageio-ffmpeg`. Fonts are bundled (JetBrains Mono, Inter, Pretendard for Hangul, Noto Emoji).
|
|
73
|
+
|
|
74
|
+
**As a Claude Code plugin** — the agent that did the work writes the captions:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
/plugin marketplace add mandu5/sessionreel
|
|
78
|
+
/plugin install sessionreel@sessionreel
|
|
79
|
+
/reel
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`/reel` plans the storyboard, rewrites the captions from its own context (only claims the
|
|
83
|
+
scene data supports), and renders. Or `npx skills add mandu5/sessionreel`.
|
|
84
|
+
|
|
85
|
+
## Use
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
sessionreel # this session inside Claude Code; else the newest one for this directory
|
|
89
|
+
sessionreel 5e55a0d0 # a session id prefix, or a path to a .jsonl
|
|
90
|
+
sessionreel list # recent sessions: id, time, prompts, tool calls, project
|
|
91
|
+
sessionreel demo # a bundled sample session — no logs needed
|
|
92
|
+
|
|
93
|
+
sessionreel --format wide # 1920×1080 (square 1080×1080 is the default; tall 1080×1920)
|
|
94
|
+
sessionreel --lang ko # Korean captions
|
|
95
|
+
sessionreel --voice # narrate with the OS voice (say / espeak-ng), no cloud TTS
|
|
96
|
+
sessionreel --gif # also write a GIF
|
|
97
|
+
sessionreel --redact 'ACME-\d+' # extra pattern to scrub (repeatable)
|
|
98
|
+
sessionreel --project "client app" # name shown on frames instead of the directory; --no-branch hides the branch
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Edit before rendering:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
sessionreel plan -o storyboard.json # the story as JSON: scenes, captions, durations
|
|
105
|
+
$EDITOR storyboard.json # rewrite captions, drop a scene, change timing
|
|
106
|
+
sessionreel render storyboard.json -o reel.mp4
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
A 35-second 1080×1080 reel renders in about 30 seconds on an M1 Pro and is ~1 MB.
|
|
110
|
+
|
|
111
|
+
## Privacy
|
|
112
|
+
|
|
113
|
+
Redaction runs on the parsed session **before** the storyboard exists, so no later stage ever
|
|
114
|
+
sees the original strings, and it runs **again at render time** over every string in the
|
|
115
|
+
storyboard, so a caption edited by you or by an agent is checked too. It removes:
|
|
116
|
+
|
|
117
|
+
- provider keys and tokens (Anthropic, OpenAI, Stripe, GitHub, GitLab, npm, PyPI, AWS, Slack,
|
|
118
|
+
SendGrid, Twilio, Google, Hugging Face), JWTs, bearer/basic auth, private-key blocks — also
|
|
119
|
+
when they span lines inside a diff — webhook URLs, credentials and tokens in URLs;
|
|
120
|
+
- `SECRET=value`, `"api_key": "…"`, `--password …`, `mysql -p…`, `curl -u user:pass`;
|
|
121
|
+
- long high-entropy strings that look like credentials;
|
|
122
|
+
- your identity: home directory (→ `~`, including Claude Code's `-Users-you-…` form), username,
|
|
123
|
+
hostname, `user@host` prompts, e-mail addresses;
|
|
124
|
+
- the contents of `.env*`, `*.pem`, `*.key`, `*.p12`, `*.tfvars`, `.git-credentials`,
|
|
125
|
+
kube/docker/AWS credential files — never shown at all.
|
|
126
|
+
|
|
127
|
+
`plan` prints how many items were removed, by kind. `--project NAME` replaces the directory name
|
|
128
|
+
shown on every frame and `--no-branch` hides the git branch. Captions whose numbers do not appear
|
|
129
|
+
in the scene's data are flagged at render time.
|
|
130
|
+
|
|
131
|
+
Redaction is pattern-based. **Watch the video before you post it.** Nothing is uploaded
|
|
132
|
+
anywhere; sessionreel makes no network calls.
|
|
133
|
+
|
|
134
|
+
## FAQ
|
|
135
|
+
|
|
136
|
+
**Isn't this just a screen recording?** No recording happens. Every frame is drawn from the
|
|
137
|
+
log: the real command, the real output, the real diff hunks Claude Code stored. You can make a
|
|
138
|
+
reel of a session from last month.
|
|
139
|
+
|
|
140
|
+
**Does an LLM write the story?** No. The planner is deterministic and every caption is built
|
|
141
|
+
from numbers in the log. In plugin mode the agent may reword captions, but the skill forbids
|
|
142
|
+
claims the scene data doesn't support, and each scene keeps its original `fact`.
|
|
143
|
+
|
|
144
|
+
**Codex / Cursor / other agents?** Claude Code first. The ingest layer normalises to five event
|
|
145
|
+
kinds, so another log format is one adapter; Codex is next. PRs welcome.
|
|
146
|
+
|
|
147
|
+
**How is this different from claude-replay, mindwalk, zoetrope, claude-code-log?** Those are
|
|
148
|
+
viewers — interactive pages or TUIs you open and explore. sessionreel produces a 30–60 second
|
|
149
|
+
video that plays inline wherever you post it.
|
|
150
|
+
|
|
151
|
+
## How it works
|
|
152
|
+
|
|
153
|
+
`ingest` (JSONL → prompts, messages, tool calls joined to their results, diff hunks, token
|
|
154
|
+
usage) → `redact` → `story` (finds the red→fix→green arc, scopes the episode, packs scenes into
|
|
155
|
+
a time budget) → `render` (Pillow draws each frame; frames stream into ffmpeg as raw RGB →
|
|
156
|
+
H.264). Design notes: [DESIGN.md](DESIGN.md).
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
python -m pytest -q # 140 tests: ingest, adversarial redaction, check parsing, arcs, storyboard safety, rendering, CLI
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT. Bundled fonts are under the SIL Open Font License 1.1 (see `src/sessionreel/fonts/`).
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# sessionreel
|
|
2
|
+
|
|
3
|
+
**에이전트는 두 시간 일했고, 보여줄 건 35초면 됩니다.**
|
|
4
|
+
|
|
5
|
+
`sessionreel`은 Claude Code 세션 로그를 읽어 짧은 리캡 영상을 만듭니다. 요청이 무엇이었는지,
|
|
6
|
+
어떤 테스트가 빨간불이 됐는지, 어떤 diff가 그걸 고쳤는지, 다시 초록불이 된 실행, 그리고 배포까지.
|
|
7
|
+
모두 로컬에서 돌고, 그리기 전에 비밀값을 가리며, API 키가 필요 없습니다.
|
|
8
|
+
|
|
9
|
+
<p align="center"><img src="docs/demo.gif" width="600" alt="sessionreel 데모: 2 failed → 14 passed, 35초"></p>
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
uvx sessionreel # 이 디렉터리의 최신 세션 → reel.mp4
|
|
13
|
+
uvx sessionreel --lang ko # 한국어 자막
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 왜 만들었나
|
|
17
|
+
|
|
18
|
+
에이전트 세션은 분명한 작업인데 다른 사람은 볼 방법이 없습니다. 동료는 30 MB 트랜스크립트를
|
|
19
|
+
넘겨보지 않고, 고객은 리플레이 뷰어를 열지 않으며, X에 올린 링크는 영상이 아닙니다. 지금 있는
|
|
20
|
+
도구들(claude-replay, mindwalk, zoetrope, claude-code-log)은 **뷰어**라서 사람이 찾아가야 합니다.
|
|
21
|
+
sessionreel은 **보내는 물건**을 만듭니다.
|
|
22
|
+
|
|
23
|
+
영상의 모든 장면은 로그에서 그대로 옵니다.
|
|
24
|
+
|
|
25
|
+
| 장면 | 로그의 출처 |
|
|
26
|
+
|---|---|
|
|
27
|
+
| 요청 | 이 작업을 시작한 프롬프트 |
|
|
28
|
+
| 탐색 | 첫 수정 전에 읽은 파일과 검색 |
|
|
29
|
+
| 실패 | 실패가 찍힌 테스트/빌드 명령 (`pytest`, `jest`/`vitest`, `go test`, `cargo test`, `tsc`, `ruff`, `mypy`, `make <target>`) |
|
|
30
|
+
| 수정 | 그 실패와 같은 검사의 다음 통과 사이에 Claude Code가 기록한 diff |
|
|
31
|
+
| 통과 | 같은 검사의 성공 |
|
|
32
|
+
| 배포 | 성공한 `git commit`/`git push`/`gh pr create`/publish와 커밋 메시지 |
|
|
33
|
+
| 숫자 | 실제 작업 시간(15분 넘는 공백은 제외), 도구 호출, 바뀐 파일·줄, 테스트 |
|
|
34
|
+
|
|
35
|
+
실패→수정→통과 흐름이 없으면 가장 큰 수정으로 영상을 만듭니다. 여러 작업이 섞인 긴 세션이면
|
|
36
|
+
그중 **한 에피소드**(수정으로 이어진 요청부터 다음 요청 전까지)만 보여줘서, 다른 작업의 요약으로
|
|
37
|
+
끝나지 않게 합니다. 전체를 원하면 `--whole`.
|
|
38
|
+
|
|
39
|
+
## 설치
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
uvx sessionreel # 설치 없이 실행
|
|
43
|
+
pipx install sessionreel # 설치
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Claude Code 플러그인으로 쓰면, 작업한 에이전트가 직접 자막을 씁니다:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
/plugin marketplace add mandu5/sessionreel
|
|
50
|
+
/plugin install sessionreel@sessionreel
|
|
51
|
+
/reel
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 사용법
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
sessionreel list # 최근 세션 목록
|
|
58
|
+
sessionreel 5e55a0d0 # 세션 id 앞자리 또는 .jsonl 경로
|
|
59
|
+
sessionreel demo # 내장 샘플 세션 (로그 없어도 됨)
|
|
60
|
+
sessionreel --format tall # 1080×1920 (쇼츠/릴스), wide = 1920×1080
|
|
61
|
+
sessionreel --voice # OS 음성으로 내레이션 (say / espeak-ng, 클라우드 TTS 없음)
|
|
62
|
+
sessionreel plan -o storyboard.json # 스토리보드를 JSON으로 → 자막 수정 → sessionreel render storyboard.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
M1 Pro 기준 35초 1080×1080 영상 렌더링에 약 30초, 파일 크기 약 1 MB입니다.
|
|
66
|
+
|
|
67
|
+
## 개인정보
|
|
68
|
+
|
|
69
|
+
가리기(redaction)는 스토리보드가 만들어지기 **전에**, 파싱된 세션 전체에 적용됩니다. 이후 단계는
|
|
70
|
+
원문을 볼 수 없습니다. Anthropic·OpenAI·GitHub·AWS·Slack·Google·Hugging Face 키, JWT, Bearer
|
|
71
|
+
토큰, 개인 키, `SECRET=값` 형태의 할당, URL 속 자격증명·토큰, 이메일, 홈 디렉터리(→ `~`)를
|
|
72
|
+
지우고, `.env*`, `*.pem`, `*.key`, `id_*` 같은 파일의 내용은 아예 보여주지 않습니다. 몇 개를
|
|
73
|
+
지웠는지 종류별로 출력합니다.
|
|
74
|
+
|
|
75
|
+
패턴 기반이라 완벽하지 않습니다. **올리기 전에 영상을 꼭 한 번 보세요.** 어디에도 업로드하지
|
|
76
|
+
않고 네트워크 호출도 없습니다.
|
|
77
|
+
|
|
78
|
+
## 라이선스
|
|
79
|
+
|
|
80
|
+
MIT. 포함된 폰트는 SIL Open Font License 1.1 (`src/sessionreel/fonts/`).
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# sessionreel
|
|
2
|
+
|
|
3
|
+
**Your agent worked for two hours. Here is the 35-second version.**
|
|
4
|
+
|
|
5
|
+
`sessionreel` reads a Claude Code session log and renders a short recap video: the ask, the
|
|
6
|
+
test that went red, the diff that fixed it, the run that went green, what shipped. It runs
|
|
7
|
+
locally, redacts secrets before anything is drawn, and needs no API key.
|
|
8
|
+
|
|
9
|
+
<p align="center"><img src="docs/demo.gif" width="600" alt="sessionreel demo: 2 failed → 14 passed in 35 seconds"></p>
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
uvx sessionreel # newest session in this directory → reel.mp4
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
[한국어](README.ko.md)
|
|
16
|
+
|
|
17
|
+
## Why
|
|
18
|
+
|
|
19
|
+
Agent sessions are real work that nobody else can see. A teammate will not scrub a 30 MB
|
|
20
|
+
transcript, a client will not open a replay viewer, and a link on X is not a video. The tools
|
|
21
|
+
that exist are viewers (you go to them); sessionreel makes the thing you send.
|
|
22
|
+
|
|
23
|
+
What a reel is built from — all of it straight from the log:
|
|
24
|
+
|
|
25
|
+
| scene | source in the log |
|
|
26
|
+
|---|---|
|
|
27
|
+
| the ask | the prompt that started this piece of work |
|
|
28
|
+
| exploring | files read and searches run before the first change |
|
|
29
|
+
| red | a test/build command whose output shows failures (`pytest`, `jest`/`vitest`, `go test`, `cargo test`, `tsc`, `ruff`, `mypy`, `make <target>`) |
|
|
30
|
+
| the fix | the diffs Claude Code recorded between that red run and the next green run of the same check |
|
|
31
|
+
| green | the same check passing |
|
|
32
|
+
| shipped | a successful `git commit` / `git push` / `gh pr create` / publish, with the commit message |
|
|
33
|
+
| numbers | active time (breaks over 15 min don't count), tool calls, files and lines changed, tests |
|
|
34
|
+
|
|
35
|
+
No arc in the session? The reel is built from the largest edits instead. A long session with
|
|
36
|
+
many unrelated tasks? The reel tells one episode — from the ask that led to the fix up to the
|
|
37
|
+
next ask — so it doesn't end on another task's summary (`--whole` to override).
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
uvx sessionreel # run without installing
|
|
43
|
+
pipx install sessionreel # or install
|
|
44
|
+
uvx --from git+https://github.com/mandu5/sessionreel sessionreel # latest main
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Python 3.10+. ffmpeg is used if it's on your PATH, otherwise the bundled static build from
|
|
48
|
+
`imageio-ffmpeg`. Fonts are bundled (JetBrains Mono, Inter, Pretendard for Hangul, Noto Emoji).
|
|
49
|
+
|
|
50
|
+
**As a Claude Code plugin** — the agent that did the work writes the captions:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
/plugin marketplace add mandu5/sessionreel
|
|
54
|
+
/plugin install sessionreel@sessionreel
|
|
55
|
+
/reel
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`/reel` plans the storyboard, rewrites the captions from its own context (only claims the
|
|
59
|
+
scene data supports), and renders. Or `npx skills add mandu5/sessionreel`.
|
|
60
|
+
|
|
61
|
+
## Use
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
sessionreel # this session inside Claude Code; else the newest one for this directory
|
|
65
|
+
sessionreel 5e55a0d0 # a session id prefix, or a path to a .jsonl
|
|
66
|
+
sessionreel list # recent sessions: id, time, prompts, tool calls, project
|
|
67
|
+
sessionreel demo # a bundled sample session — no logs needed
|
|
68
|
+
|
|
69
|
+
sessionreel --format wide # 1920×1080 (square 1080×1080 is the default; tall 1080×1920)
|
|
70
|
+
sessionreel --lang ko # Korean captions
|
|
71
|
+
sessionreel --voice # narrate with the OS voice (say / espeak-ng), no cloud TTS
|
|
72
|
+
sessionreel --gif # also write a GIF
|
|
73
|
+
sessionreel --redact 'ACME-\d+' # extra pattern to scrub (repeatable)
|
|
74
|
+
sessionreel --project "client app" # name shown on frames instead of the directory; --no-branch hides the branch
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Edit before rendering:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
sessionreel plan -o storyboard.json # the story as JSON: scenes, captions, durations
|
|
81
|
+
$EDITOR storyboard.json # rewrite captions, drop a scene, change timing
|
|
82
|
+
sessionreel render storyboard.json -o reel.mp4
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
A 35-second 1080×1080 reel renders in about 30 seconds on an M1 Pro and is ~1 MB.
|
|
86
|
+
|
|
87
|
+
## Privacy
|
|
88
|
+
|
|
89
|
+
Redaction runs on the parsed session **before** the storyboard exists, so no later stage ever
|
|
90
|
+
sees the original strings, and it runs **again at render time** over every string in the
|
|
91
|
+
storyboard, so a caption edited by you or by an agent is checked too. It removes:
|
|
92
|
+
|
|
93
|
+
- provider keys and tokens (Anthropic, OpenAI, Stripe, GitHub, GitLab, npm, PyPI, AWS, Slack,
|
|
94
|
+
SendGrid, Twilio, Google, Hugging Face), JWTs, bearer/basic auth, private-key blocks — also
|
|
95
|
+
when they span lines inside a diff — webhook URLs, credentials and tokens in URLs;
|
|
96
|
+
- `SECRET=value`, `"api_key": "…"`, `--password …`, `mysql -p…`, `curl -u user:pass`;
|
|
97
|
+
- long high-entropy strings that look like credentials;
|
|
98
|
+
- your identity: home directory (→ `~`, including Claude Code's `-Users-you-…` form), username,
|
|
99
|
+
hostname, `user@host` prompts, e-mail addresses;
|
|
100
|
+
- the contents of `.env*`, `*.pem`, `*.key`, `*.p12`, `*.tfvars`, `.git-credentials`,
|
|
101
|
+
kube/docker/AWS credential files — never shown at all.
|
|
102
|
+
|
|
103
|
+
`plan` prints how many items were removed, by kind. `--project NAME` replaces the directory name
|
|
104
|
+
shown on every frame and `--no-branch` hides the git branch. Captions whose numbers do not appear
|
|
105
|
+
in the scene's data are flagged at render time.
|
|
106
|
+
|
|
107
|
+
Redaction is pattern-based. **Watch the video before you post it.** Nothing is uploaded
|
|
108
|
+
anywhere; sessionreel makes no network calls.
|
|
109
|
+
|
|
110
|
+
## FAQ
|
|
111
|
+
|
|
112
|
+
**Isn't this just a screen recording?** No recording happens. Every frame is drawn from the
|
|
113
|
+
log: the real command, the real output, the real diff hunks Claude Code stored. You can make a
|
|
114
|
+
reel of a session from last month.
|
|
115
|
+
|
|
116
|
+
**Does an LLM write the story?** No. The planner is deterministic and every caption is built
|
|
117
|
+
from numbers in the log. In plugin mode the agent may reword captions, but the skill forbids
|
|
118
|
+
claims the scene data doesn't support, and each scene keeps its original `fact`.
|
|
119
|
+
|
|
120
|
+
**Codex / Cursor / other agents?** Claude Code first. The ingest layer normalises to five event
|
|
121
|
+
kinds, so another log format is one adapter; Codex is next. PRs welcome.
|
|
122
|
+
|
|
123
|
+
**How is this different from claude-replay, mindwalk, zoetrope, claude-code-log?** Those are
|
|
124
|
+
viewers — interactive pages or TUIs you open and explore. sessionreel produces a 30–60 second
|
|
125
|
+
video that plays inline wherever you post it.
|
|
126
|
+
|
|
127
|
+
## How it works
|
|
128
|
+
|
|
129
|
+
`ingest` (JSONL → prompts, messages, tool calls joined to their results, diff hunks, token
|
|
130
|
+
usage) → `redact` → `story` (finds the red→fix→green arc, scopes the episode, packs scenes into
|
|
131
|
+
a time budget) → `render` (Pillow draws each frame; frames stream into ffmpeg as raw RGB →
|
|
132
|
+
H.264). Design notes: [DESIGN.md](DESIGN.md).
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
python -m pytest -q # 140 tests: ingest, adversarial redaction, check parsing, arcs, storyboard safety, rendering, CLI
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## License
|
|
139
|
+
|
|
140
|
+
MIT. Bundled fonts are under the SIL Open Font License 1.1 (see `src/sessionreel/fonts/`).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Turn this session into a 30-60 second recap video (local, redacted, no API key)
|
|
3
|
+
argument-hint: "[--lang en|ko] [--whole] [--project NAME] [--no-branch] [--format square|wide|tall] [--voice] [--gif]"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Make a recap video of this session by following [`skills/sessionreel/SKILL.md`](../skills/sessionreel/SKILL.md). That file is the source of truth; do not reimplement its steps here.
|
|
11
|
+
|
|
12
|
+
Arguments: `$ARGUMENTS` — pass `--lang`, `--whole`, `--project`, `--no-branch`, `--redact` to `plan`, and `--format`, `--voice`, `--gif` to `render`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Launch copy — sessionreel 0.1.0
|
|
2
|
+
|
|
3
|
+
Rules learned from 2026 data (see the author's research notes): the video is the post; the
|
|
4
|
+
number goes in line one; post where the audience already is; answer the three standard attacks
|
|
5
|
+
("what's the use case", "it's a screen recording", "prove it") in the first reply.
|
|
6
|
+
|
|
7
|
+
## X / Threads (English) — attach docs/demo.mp4 natively, not a link
|
|
8
|
+
|
|
9
|
+
> My coding agent fixed a bug in 2 minutes. Showing someone took 20.
|
|
10
|
+
>
|
|
11
|
+
> So I built sessionreel: one command turns a Claude Code session log into a 35-second video —
|
|
12
|
+
> the ask, the failing test, the diff, green, shipped. Local, secrets redacted, no API key.
|
|
13
|
+
>
|
|
14
|
+
> uvx sessionreel
|
|
15
|
+
> github.com/mandu5/sessionreel
|
|
16
|
+
|
|
17
|
+
Reply 1 (answer the attacks up front):
|
|
18
|
+
> Not a screen recording — every frame is drawn from the log Claude Code already writes
|
|
19
|
+
> (~/.claude/projects). You can make a reel of a session from last month. Nothing is uploaded;
|
|
20
|
+
> redaction runs before anything is drawn. Watch it before you post it.
|
|
21
|
+
|
|
22
|
+
## GeekNews (Show GN) — first-person, story first
|
|
23
|
+
|
|
24
|
+
Title (site prepends "Show GN:"):
|
|
25
|
+
> sessionreel – Claude Code 세션 로그를 35초 영상으로 만드는 도구
|
|
26
|
+
|
|
27
|
+
Body:
|
|
28
|
+
> 에이전트가 두 시간 동안 버그를 고쳤는데, 그걸 팀에 보여주려면 30 MB짜리 로그를 넘겨줄 수밖에
|
|
29
|
+
> 없더라고요. 기존 도구(claude-replay, mindwalk 등)는 뷰어라서 상대가 직접 열어봐야 합니다.
|
|
30
|
+
>
|
|
31
|
+
> 그래서 로그를 읽어서 "요청 → 실패한 테스트 → 고친 diff → 통과 → 커밋"을 30~60초 영상으로
|
|
32
|
+
> 만드는 CLI를 만들었습니다.
|
|
33
|
+
>
|
|
34
|
+
> - `uvx sessionreel` 한 줄. 로컬에서 Pillow로 그리고 ffmpeg로 인코딩, 네트워크 호출 없음
|
|
35
|
+
> - 그리기 전에 API 키·토큰·이메일·홈 경로를 가리고, .env 같은 파일 내용은 아예 안 보여줌
|
|
36
|
+
> - 실패→수정→통과 흐름을 로그에서 찾아서 스토리를 짬 (LLM이 지어내는 부분 없음)
|
|
37
|
+
> - 긴 세션은 그중 한 에피소드만, 한국어 자막(`--lang ko`), 쇼츠용 세로(`--format tall`), OS 음성 내레이션
|
|
38
|
+
> - Claude Code 플러그인으로 쓰면 작업한 에이전트가 자막을 직접 다듬음 (`/reel`)
|
|
39
|
+
>
|
|
40
|
+
> 로그만 있으면 한 달 전 세션도 영상으로 만들 수 있습니다. 올리기 전에 한 번은 꼭 보세요 —
|
|
41
|
+
> 가리기는 패턴 기반입니다.
|
|
42
|
+
|
|
43
|
+
## Hacker News — NOT from the author's account (karma 1, auto-flagged before)
|
|
44
|
+
|
|
45
|
+
If someone else posts: title
|
|
46
|
+
> sessionreel: turn a Claude Code session log into a 35-second video
|
|
47
|
+
|
|
48
|
+
## r/ClaudeAI / r/ClaudeCode — video post
|
|
49
|
+
|
|
50
|
+
> I made a CLI that turns a Claude Code session into a 35-second recap video (local, redacted)
|