Skip to content

Back to the catalog

kajisho5/ffmpeg-skill
github.comrepo

kajisho5/ffmpeg-skill

ffmpeg-skill is an Agent Skill (SKILL.md plus 42 stdlib-only Python tools) that lets Claude Code, Cursor, Codex and other agents edit video and audio with local ffmpeg/ffprobe. It enforces a probe → edit losslessly → check → verify workflow, and every tool takes --dry-run, --json and --plan. A machine-readable contract, whose input schemas are derived at run time from each script's argparse parser (the author's "SPEC" pattern), drives an MCP server that lists a core 12 tools by default. The repo also ships per-platform render templates, a doctor capability check, a test suite and evals. It is useful as a worked example of a deterministic, verifiable skill/tool layer in which the agent supplies judgement and the tools do the work.

TL;DR Agent Skill and MCP server that gives coding agents 42 local FFmpeg video/audio tools with a probe-edit-verify workflow and a contract derived from argparse.
Document

How to use it

Install targets differ by agent. The npx installer copies files, and a copy does not update itself (re-run npx ffmpeg-skill to refresh it).

npx ffmpeg-skill              # Claude Code   → ~/.claude/skills/ffmpeg-skill
npx ffmpeg-skill --cursor     # Cursor        → ~/.cursor/skills/ffmpeg-skill
npx ffmpeg-skill --codex      # Codex         → ~/.agents/skills/ffmpeg-skill (Cursor reads this location too)
npx ffmpeg-skill --all        # all three
npx ffmpeg-skill --project    # this project  → ./.claude/skills/ffmpeg-skill
claude plugin install kajisho5/ffmpeg-skill   # plugin route, no Node, updates with claude plugin update

After installing, check the machine and inspect what an agent framework will see:

npx ffmpeg-skill doctor
npx ffmpeg-skill contract --json

MCP client config:

{"mcpServers": {"ffmpeg-skill": {"command": "python3", "args": ["/Users/you/.claude/skills/ffmpeg-skill/mcp/server.py"]}}}

The scripts also run directly from a shell:

S=~/.claude/skills/ffmpeg-skill/scripts
python3 $S/probe.py input.mp4 --compact
python3 $S/fit.py input.mp4 --duration 60 --aspect 9:16 --dry-run
python3 $S/render.py talk.mp4 --template tiktok --cues cues.txt

Requirements

  • FFmpeg 5.0+ and Python 3.9+. Node 16+ is needed only for the installer.
  • Always required: libx264, aac, and the filters drawtext, subtitles (libass), loudnorm, xfade, acrossfade, scdet, silencedetect and tile.
  • The apt and gyan.dev builds have everything. Some Homebrew bottles lack libass, libfreetype or libzimg.
  • On macOS, ffmpeg-full is keg-only. The skill picks it up automatically only when the lean Homebrew ffmpeg is the one on PATH.

Interface facts worth knowing before integrating

  • Failures: they come back as {"status": "failed", "error": {"kind": "input | ffmpeg | output | missing_tool | timeout | verification | interrupted", ...}}.
  • Timeouts: the default is 1800 s, set with --timeout or FFMPEG_SKILL_TIMEOUT. A timeout exits with code 124 and removes the partial output.
  • Smaller output: --json-brief returns roughly a third of the bytes of --json.
  • Doctor exit codes: 0 means all required components are present, 1 means something required is missing, 2 means nothing is proven missing but something is unknown.
  • Doctor's overall ok is not per-tool readiness. A plain Homebrew ffmpeg can be ok while caption reports usable: "no" because the subtitles filter is missing. Read doctor --json's tools field instead.
  • MCP surface:
  • tools/list shows 12 tools by default; FFMPEG_SKILL_MCP_FULL=1 lists all 42.
  • All 42 are callable by name through tools/call either way.
  • The server also exposes five prompt recipes: reel, podcast, multicam, delivery_check, hdr.
  • Plans: --plan FILE saves a dry run with fingerprinted inputs. render.py FILE executes it later and refuses if an input has changed.
  • Caching: render.py --cache DIR reuses unchanged stages. Cache keys include the ffmpeg, skill and contract versions.
  • Stability: 2.x promises that no tool name, CLI argument, JSON key or exit code is removed or renamed until 3.0. A snapshot test enforces this.
  • 2.0.0 already removed --crf in favour of --quality.
  • 2.0.0 also made writing to an existing output path a refusal unless --overwrite is passed.
  • Pinning: dependents should pin a tag or npm version, not main. Releases are auto-cut from PR labels after merge.

Evidence

Apple VideoToolbox (--hw, opt-in), measured on an M4 Max

  • Speed: 2–7× faster than x264/x265 medium.
  • Size at matched SSIM: 1.1–2.9× the bytes on SDR and 1.9–3.5× on HDR.
  • That size cost is why it is not the default.

CI coverage

  • Every PR runs on FFmpeg 5.1.1 (static), 6.1 (Ubuntu), 7.1 (Debian trixie), 8.x (Homebrew macOS) and 9.x (gyan.dev Windows).
  • Python 3.9 and 3.13 are both exercised.
  • A test runs every tool under --dry-run behind a fake ffmpeg and asserts that ffmpeg was never called and no file was written.
  • Another test hashes every input after a run to confirm it was not modified.

Other material

  • The real-device corpus is a ~1.4 GB download (tests/corpus.py --fetch --verify).
  • There are benchmarks for sync, silence and scenes, plus regex-graded agent evals in evals/.
  • The page gives no numbers for any of these.

Limits

Platform coverage

  • The real-footage corpus has been run on Linux and macOS only.
  • Neither the full corpus nor a third-party install has been verified on Windows (tracked in issue #143).
  • Some fake-ffmpeg tests, including the dry-run test, are skipped on Windows.

No content understanding

  • look.py only renders a PNG. Nothing in the repo detects faces, subjects or interesting moments.
  • fit --fit crop centre-crops unless the caller supplies --crop-x/-y.
  • scenes.py --highlights ranks scenes by audio level or duration, not by content.
  • A non-visual caller has to make these choices itself.

Refusals by design

  • Filler-word removal needs measured word timings.
  • Beat-snapping refuses below --min-confidence.
  • Transcription is optional. Without an installed engine (Parakeet or a Whisper variant), it refuses rather than guessing. Those engines download model weights on their first run.

Other caveats

  • doctor's gpu_encoders field shows encoders compiled into ffmpeg. It does not prove the GPU or driver will accept a job.
  • Sync confidence below 0.3 is probably wrong. Separate-device recordings longer than 10 minutes need --fix-drift.
  • A stream-copy cut can start up to one GOP early. The tool re-encodes when the snap exceeds 0.5 s.
  • The page states no licence; check the repository before adopting.

Organisations named here

  • Claude Code
  • Cursor
  • kajisho5
  • Model Context Protocol

Technologies named here

  • ffmpeg-skill
  • FFmpeg
  • ffprobe
  • Claude Code
  • Cursor
  • Codex
  • Claude Desktop
  • MCP
  • doctor
  • contract --json
  • render.py
  • parakeet-mlx
  • faster-whisper
  • openai-whisper
  • whisper.cpp
  • AI-video-production-OS
  • Node.js
  • npm
  • Model Context Protocol
  • GitHub Actions
  • Whisper
  • Parakeet
  • Linux
  • macOS
  • Python
  • Windows

Techniques named here

  • SPEC
  • Probe-edit-verify agent workflow
  • Contract-derived MCP server
  • Plan before render
  • Beat-synced cuts
  • Filler word removal
  • Caption size fitting
  • Phrase-aware caption wrapping
  • Sync with drift correction
  • Capability detection with unknown state