Exit 0 is not a finished video.
ffmpeg exits 0 when it writes a file, not when the file is the video you planned. video-editor takes a shot list and its finished assets and hands back one video: cut to the plan, the music ducked under the voice, captions burned in where the platform buttons will not cover them, loudness set for where it will play. Then four gates read the file and print PASS or FAIL with the numbers.
For anyone whose agent assembles video, and who has posted a render that finished cleanly and was still wrong.

opvs-skills install @di-atomic/video-editorThen say: “cut the clips and the voiceover into one video” or “check this video before we post it”.
Why a render that finishes can still be wrong
type an ffmpeg command, run it exit 0, file written, post it → xfade offsets ignore overlap: 9.5 s for 13 → one clip ran short: 11 s for 13 → the voiceover runs past the last frame → a compressor "ducks" and pumps between words → captions sit under the platform buttons → loudnorm defaults land at -24 LUFS (nothing errors, so nobody checks)
Every one of those exits 0. The file plays, the length looks plausible, and the last six words of the voiceover are gone.
runtime detected: local ffmpeg or SpiderVideo timeline gated BEFORE render, refuses what won't fit graph computed from the shot list, never typed duck speech envelope, -12 dB, with a hold captions safe zone, font checked per character poster baked in as frame 0 loudness two-pass, set for the destination gates 4, on the finished file, with numbers
A video you can hand to someone with the numbers that prove it, because every check reads the file itself.
Exit code 0 proves nothing.
Four gates, and each one reads the file
verify-timelineBefore render. The plan adds up to the target, every clip is long enough for its slot, and no spoken word falls past the last frame.verify-renderffprobe on the output: codec, size, frame rate, duration, black and frozen runs, the poster on frame 0, loudness and true peak.verify-duckingThe music's own share of the mix, solved against the voice and music tracks. Depth, balance and pumping. Never the mix gap.verify-captionsThe same frame with and without captions. Text at every spoken word, nothing in the pauses, nothing under the buttons.emit-spidervideoNo ffmpeg on the agent? The SpiderVideo job, plus every field that path cannot honour, printed before you spend a render.What you actually get
Ducking you can prove
The voice is in the mix while it speaks, so the mix is louder during speech whether the music moved or not: a 9.96 dB gap on a render with no ducking. The gate solves out = a·voice + b·music every 50 ms instead. It also catches pumping: the first sidechain recipe a search returns ducks 17.77 dB and climbs back 6.37 dB between words.
Captions checked in pixels
Two moments of one video always differ, so the quick test passes a video with no captions at all (1.24% of pixels changed). The editor compares the same frame with and without captions instead. It checks the font first, too: a request for Noto Sans Hebrew quietly resolved to Verdana, which covers 1 of 11 Hebrew characters.
Runs where your agent runs
In Claude Code, Codex or Antigravity it renders on your machine with the local ffmpeg, from a graph computed off the shot list. On an OPVS agent with no ffmpeg it writes the SpiderVideo job and lists what that path drops. It complements SpiderVideo. It does not replace it.
One 13-second render, gated
> "cut the clips and the voiceover into one video"
detect-runtime ....... local_ready ffmpeg 8.0.1 · captions via coretext
mode ................. single_video (asked, never guessed)
FIRST PLAN, the picture is shorter than the voiceover
verify-timeline.mjs plan.json
FAIL vo_inside_picture speech ends 12.69 s / picture 11.00 s
FAIL captions_inside_picture 6 words lost: "checked the mix before it shipped."
RESULT ............... FAIL, nothing rendered
CORRECTED PLAN
Σlen 14 − overlap 1.00 = 13.00 s
compose.mjs plan.json out.mp4 --reference out.ref.mp4
verify-render.mjs .... PASS h264 High · 1080x1920 · 30 fps · 13.000 s
-14.1 LUFS · TP -1.7 · poster PSNR 44 dB
verify-ducking.mjs ... PASS depth 12.02 · balance 12.01 · pump 0.43
verify-captions.mjs .. PASS 31/31 words · 0.0000 % in pauses
The first plan would have rendered with exit 0 and cut the last six words. The timeline gate refuses it before a single frame is encoded, and every line above is the scripts' own output.
Two tests that pass when they should fail


What it will tell you it cannot do
- It assembles, it does not plan or generate. The cut comes from video-director, the footage and voice from media-generator. This bundle ships no font, no music and no audio of its own.
- Local rendering is per machine, not a service. An OPVS agent on a gateway gets the SpiderVideo path, with its losses printed: one global fade, a fixed duck depth, no per-scene trim, fit, mute or frame rate.
- Zoom-out transitions are refused. ffmpeg has no matching transition, so the editor says so instead of substituting one.
- The pump measurement is untested on drum-heavy music. The test bed was a sustained chord. Percussive beds may need a different threshold.
- A Mac cannot show you a missing glyph. Captions render through CoreText there, which quietly substitutes. The font check runs before render for exactly that reason; on Linux a missing letter becomes a box that a pixel test would accept.
- It will not guess the mode. One video or a batch of separate posts? If the shot list does not say, it asks.
I wanted proof, not an exit code.
video-editor is one skill in the system behind Di-Atomic, the marketing and compliance agency that runs cognitoAI, SpiderIQ and OPVS. If you want video produced on a pipeline that checks its own output, in any of my team's seven languages and including regulated categories, that is the day job.
Book a call with Di-AtomicJust want the skill? Get @di-atomic/video-editor free.