video-digest — video in, working material out, $0
Python CLI pipeline 126 passing tests $0 / local dependency-injected I/O public repoThe problem
Claude can read images and text but not watch a video or listen to audio. Every "let Claude review this clip" workflow starts with a manual, repetitive extraction step — screenshot the interesting frames, transcribe or re-watch for the quotable lines — before the model can actually engage with the content. That extraction step is exactly the kind of mechanical work that should be a pipeline, not a person.
What I built
video-digest takes a video URL or a local mp4 path and produces keyframes, a
timestamped transcript, and a structured markdown digest — fully local, no cloud API calls
except yt-dlp fetching the URL you gave it.
- Five-stage pipeline —
acquire(yt-dlp download, or passthrough for a local path) →keyframes(ffmpeg scene-change detection,select='gt(scene,0.3)', plus a floor of 1 frame/N seconds, capped at ~20-40 frames) →audio(ffmpeg mono 16kHz wav) →transcript(faster-whisper, local, $0, timestamped) →digest(assembles the markdown template). - Honest about where synthesis stops — the digest-assembly step does not perform visual synthesis itself. It assembles a template with a TODO placeholder per keyframe; actually looking at the frames and writing the visual notes / ideas / action items is a human or Claude-in-the-loop step done after the pipeline runs, because that's the part of the workflow that can actually see the images.
- Optional local-vLLM first pass — if a local vLLM server is reachable at
localhost:8000, its model is asked for a mechanical, text-only first-pass summary of the transcript (the vLLM call never sees the keyframe images — that stays Claude/human-only). If the server isn't reachable, the pipeline falls back to the placeholder automatically; this is never a hard dependency.
Evidence you can check yourself
Public on purpose — every claim maps to a file you can open before you reply:
- Repo: github.com/jaimenbell/video-digest (MIT)
- Tests: global
python -m pytest -q(no repo-local venv) →126 passed(junitxml: 126 total, 0 failed, 0 errors, 0 skipped). Every subprocess call (yt-dlp,ffmpeg,ffprobe) and every model/HTTP call (faster-whisper'sWhisperModel, the local vLLM request) is dependency-injected behind arunner=subprocess.run/model_factory=/http_post=default argument — the suite never invokes a real binary, loads a real Whisper model, or makes a real network request. - One test file per module in
tests/, matching thevideo_digest/module layout 1:1 (acquire.py,keyframes.py,audio.py,transcript.py,vllm_summary.py,digest.py,cli.py).
The README leads with limitations, not features. Developed and tested on Windows —
ffmpeg/ffprobe invocation should be POSIX-compatible but is not
verified on macOS/Linux. Scene-change keyframe detection is a heuristic (ffmpeg's
scene filter plus a floor interval); it won't perfectly match every video's
actual cut points, especially on long or slow-paced source material. The optional vLLM
summary step requires you to already have a server running — this repo doesn't stand one
up for you. And there's no PyPI package yet — install from source.
What it shows about how I work
This is the same discipline as the MCP servers in this portfolio, applied to a plain CLI pipeline instead of an MCP surface: every external dependency (subprocess, model, HTTP) goes through an injectable seam so the test suite can prove the pipeline's logic without ever touching a real binary or a real network call, and the README says exactly where the tool's synthesis stops and a human's begins — no tool claims to do more than it does.