MCP·Engineering
← All case studies

video-digest — video in, working material out, $0

// data-pipeline category · 126 passing tests · fully local, $0 cloud cost · public repo
Python CLI pipeline 126 passing tests $0 / local dependency-injected I/O public repo

The 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 pipelineacquire (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's WhisperModel, the local vLLM request) is dependency-injected behind a runner=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 the video_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.

Book a scoping call  Next case study →