Editing agent playbook
The canonical behavior for an agent editing with OverlayMotion, written for the common case: the user hands over footage and a weak prompt such as "make this good," and for footage that carries spoken editing instructions.
You produce two artifacts. An edit decision plan records evidence,
assumptions, protected subjects, assets and QA checkpoints. An Edit Spec v1
describes the render. The plan explains judgment; the spec stays a deterministic
rendering input. Machine-readable defaults and the plan schema live in
src/agent/; tool contracts are in agent-toolkit.md.
This page is what applies to every edit. Anything that applies to one kind of request lives in its own file, and you open that file when the request names it.
Open only what the job asks for
| The request involves | Read this first |
|---|---|
| captions, subtitles, word-timed text | features/captions.md |
| removing, replacing or blurring a background | features/background-removal.md |
| face or head tracking, a corner bubble, a follow crop | features/tracking.md |
| noise, hum, room tone, "clean up the audio" | features/voice-cleanup.md |
| a music bed | features/music.md |
| sound cues on overlays | features/sound.md |
| a camera move | camera-motion-spec.md |
| color, HDR, or an unexplained shift in the delivered file | features/delivery-color.md |
| authoring any spec at all | edit-spec.md |
Nothing else is required reading. A caption job never opens the matting page. Each feature page carries the rules, the tools and the QA for that one job, so opening it late is worse than opening it first: several of those rules decide things before a render, and re-rendering is how they get paid for twice.
Prime directive
Improve comprehension without contradicting the speaker, hiding the important subject or fabricating facts. In priority order:
- explicit user request;
- observable transcript and visual evidence;
- subject, message, rights and platform safety;
- established brand and platform defaults;
- decorative style.
When an explicit request conflicts with subject safety, satisfy both through layout: split the screen and reframe the speaker into the open panel instead of placing secondary media over their face.
What you decide, and what you ask
Decide without interrupting the job: caption style, conservative motion, exact safe placement, crop focus, phrase grouping, and the shortest faithful copy. Record each one as an assumption.
Verify or ask before asserting identity, changing meaning, making a factual claim, selecting unlicensed media, publishing a quote whose wording or attribution is uncertain, or making an ambiguous destructive cut. A low-risk draft may keep an unresolved item as a clearly labeled placeholder.
When templates are the choice, show at most three options, each with title,
slug, a one-sentence tradeoff and a preview path such as /templates/speaker-card,
so a UI can render linked choice cards without being coupled to one interface.
The intake gate
Run this before writing the plan, once:
python3 scripts/check-intake.py --source talk.mp4 \
--request "add subtitles and cut it for reels" \
--asset logo=brand.svgIt probes the file and reads the request against the assets actually supplied.
Exit status is 2 when something blocks. The contract behind it is INTAKE in
src/agent/policy.ts; the script exists so the checks stop depending on an agent
remembering them at the end of a long session.
| verdict | what it means | what you do |
|---|---|---|
blocking |
the edit cannot be finished as asked | stop and say what is missing |
ask |
two or three legitimate answers, materially different | one question, options, default already chosen |
checkpoint |
a preview answers it faster than a question | show the cheap thing, keep going |
default |
reversible or decorative | choose from source evidence, record it |
Only three things block, each because the missing piece cannot be invented: captions asked of a source with no speech, brand treatment with no brand asset, and named b-roll with no media or license.
Questions come from facts about the file, never from a fixed questionnaire. A horizontal source going vertical raises "whose framing wins in the crop"; the same request over a source that already fits raises nothing. A round that asks what the file already answers teaches the user to skip the round.
Budget: one round, at most three questions, each with the default already
selected so silence means proceed. Record every one in the plan's
clarifications with resolution set to answered, defaulted or deferred.
validateEditDecisionPlan rejects a plan carrying an unanswered blocking
question, an answered question with no option named, or more than three open
questions, so the budget is enforced rather than requested.
Environment bootstrap
bash scripts/agent-bootstrap.sh # detect and reuse only, downloads nothing
bash scripts/agent-bootstrap.sh --need captions # transcriber AND forced aligner
bash scripts/agent-bootstrap.sh --need matting --need denoise
bash scripts/agent-bootstrap.sh --allIt is idempotent and reuse-first: it detects ffmpeg/ffprobe/whisper-cli (and
avconvert on macOS) and symlinks anything already present under
dev-assets/projects/* into canonical paths, so a warmed machine finishes in
seconds with zero network. Downloads happen only for groups named with --need;
fetch for the edits the footage actually asks for, not up front. Missing items
print a todo: line with the flag that fetches them, and anything listed ok is
safe to use while other items are missing.
The summary ends in CAPTIONS BLOCKED while the forced aligner is missing even
when the transcriber is ready, because a transcriber alone is not a caption
pipeline. Reading spoken instructions off a draft transcript is fine at any time;
timing captions from one is not.
Never pip install into an existing pinned venv without checking the imports
first. A bare pip install torchvision into a venv that already has torch
silently upgrades torch to the newest release (observed: 2.8.0 dragged to 2.13.0)
and breaks the denoise stack sharing that venv. The bootstrap installs matched
pairs only when the imports fail.
Source analysis before effects
Create one normalized source record before authoring the spec:
- probe container, codec, dimensions, rotation, frame rate, duration, color range and audio streams;
- transcribe speech with word start/end timestamps and language. Recognizer word times are a draft and can overrun the real media duration near the tail, so clamp them to the probed duration and confirm any time used as an edit beat against extracted frames;
- inspect a contact sheet across the full timeline;
- inspect frames around each named person, object, gesture, scene change and requested edit beat;
- note face, mouth, active-hand, demonstrated-object and platform-UI regions;
- preserve the original; use a rotation-correct proxy only when the renderer needs one.
Treat spoken edit commands as commands only when the context supports it. Keep the original words in the transcript either way.
Source fidelity
Preserve the source's perceived color and audio unless the user explicitly requests a creative change. Color grading, LUTs, exposure, contrast, saturation, white balance, filters and HDR/SDR conversion are not reversible aesthetic defaults.
- Preserve color primaries, transfer function, range, bit depth and HDR metadata through proxies and delivery when the output permits it.
- Never reinterpret or merely retag HDR footage as SDR. A required HDR-to-SDR conversion aims for a perceptual match, not a new look, and uses a color-managed path.
- Record every unavoidable conversion in the plan and the completion report. Ask before proceeding when the output needs a materially different look.
- Compare representative source and delivered frames through the same reference display transform, checking skin tones, neutral surfaces, shadows and highlights. Metadata alone does not prove color was preserved, and a delivery with an unexplained shift is not approved because its tags are compliant.
The renderer's master tags do not describe its pixels reliably, so the final encode has a verification step of its own: features/delivery-color.md.
The default edit for a weak prompt
For a spoken social video the useful default is deliberately modest:
- trim only obvious dead head and tail space; do not rewrite the speaker;
- add word-timed captions;
- apply brand tokens and real supplied brand assets;
- use restrained emphasis overlays only where the speech supplies a clear semantic beat;
- preserve faces, hands and demonstrated objects;
- keep source audio primary and avoid decorative sound under important speech;
- deliver a preview or checkpoints before paying for a full render.
Do not fill silence with effects. Do not turn every sentence into a card.
Captions, in one paragraph
Spoken video gets word-timed captions by default unless the user opts out, and
captions have exactly one route: scripts/align-words.py force-aligns,
scripts/build-caption-props.py phrases, scripts/check-caption-sync.py
verifies. Timing comes from forced alignment, never from a transcriber.
Whisper drafts the words; a phoneme/CTC aligner decides when each one is said,
and both downstream scripts refuse input that does not name a forced aligner. A
cue carries at most 4 words, the letters carry a black outline, and captions
start in the caption-zone region. Everything else, phrasing, presets, props and
caption QA, is in features/captions.md.
Protected subjects and the composed frame
Faces, mouths, eyes, active hands, a demonstrated object and the current gesture target are protected. Add padding; do not merely avoid their bounding boxes.
When showing an image or secondary video: decide which subject is primary at that
beat, choose the secondary media region, reframe the base source into the
complementary region with source.reframes (see
edit-spec.md), inspect the subject
at entrance, midpoint and exit, and place captions in the remaining safe region.
Prefer a stable crop with modest easing; unnecessary tracking looks nervous and
costs more to verify.
A spec has exactly one base source and it is the speaker, the one whose audio
survives to delivery. A screen recording, a demo capture, b-roll or a flat color
behind them all travel in props. Inverting that is the arrangement that loses the
speaker's audio, which is why the base source is defined by audio rather than by
whichever image is larger.
Gesture-aware placement
Words such as "here," "there," "this" and "right here" are spatial only when resolved with nearby frames.
- Find the transcript time of the deictic word.
- Inspect roughly 0.35s before through 0.65s after it.
- Identify the active hand, fingertip and direction of the pointing ray.
- Place the overlay just beyond the fingertip, usually about 3% of the frame past it, keeping hand, face and intended target visible.
- Inspect the entire overlay window. Track only if the anchor moves enough to break the meaning.
Use a custom percentage region for the resolved location. A named corner is only a fallback.
Camera moves
Only the preset grammar is implemented (preset, amount, inSec, outSec,
rest, focus, frequency, seed, time, easing). Keyframes, rotation and
crop are not; do not author them.
- Outside its window a camera sits at its resting zoom, which is identity unless
restsays otherwise. So "zoom in and stay zoomed" is either a window ending on the composition's final frame or areston a zoom preset. Do not leave a gap and expect the framing to persist. inSecandoutSecpin the approach and the return to exact seconds on the window, which is how a spoken "zoom in right now" becomes a camera rather than an approximation.- Choose the scope by semantics and text safety together. "Zoom in with the
camera" is the recording camera, so footage-only
source.camerafits, and it keeps text out of an animated scale (animated scale over text shimmers glyphs in Chromium renders; see recipe-scaled-text.md). - A footage push-in magnifies the subject toward locked overlay regions. Check overlay clearance against the zoomed subject at the overlay's exit time, using the camera's zoom value at that moment. Sequencing the beats usually resolves the collision without tracking.
- Camera windows in one scope never overlap, each move has one editorial intent, and repeating or alternating zooms are never generated unless asked.
Quotes, assets and logos
A quote is content, not decoration. Select wording that supports the nearby speech and fits the safe region at a readable size, verify it against an authoritative source, and preserve exact wording, author, work and translation/edition. Never pass an attractive paraphrase as a quotation: label it a paraphrase or drop the quote marks. Prefer a shorter verified excerpt over shrinking a long quote until it is unreadable. Record the source in the plan even when the design shows only a concise attribution.
Use assets in this order: user-supplied, brand library, licensed source, then a
generated asset when generation is appropriate and disclosed. Record source URL,
license and required credit; keep visible credit concise and full provenance in
the plan. Never reconstruct a real company logo when the asset is unavailable.
logo-sting accepts a real transparent logo; its monogram is an intentional
fallback, not an imitation.
Efficient QA
Quality comes from targeted checks, not repeated full renders.
- Validate the decision plan and the spec. If validation rejects a template slug
as unknown, check
src/templates/<slug>/before redesigning around it: a finished template may exist but be unwired, and registration is a three-line change. - Render low-cost stills just before the edit, at entrance, midpoint, exit and just after.
- Add a checkpoint for every spatial decision (face, split, gesture) and every semantic one (quote, number, name, attribution). When a fullscreen-first template sits in a custom region, verify its complete visual bounds; container clipping is not intentional scaling.
- Run the scripted checks before the visual ones.
check-caption-sync.pysettles onset, silences, cue windows and delivered audio offset without a frame being looked at, so your eyes are spent on what it cannot judge. - Compare the decoded delivery audio zero-point with the final cut-only audio and correct codec or container delay before approval. Re-measure after every remux, even a stream copy: edit lists and AAC priming shift on a container change. With no cuts, stream-copy the original track and verify the delivery is sample-identical at zero offset.
- Compare representative source and delivered frames through the same display transform. Fail unexplained changes in skin tone, neutrals, shadows or highlights.
- Watch one complete preview at normal speed. Full-render once after these pass.
Three frames may be enough for a stable static placement. A moving hand, crop, face or tracked anchor needs more. Spend QA where the uncertainty is.
Completion report
Report what was inferred, what was verified, asset provenance and credit, what the template system could not express, and which QA checks ran. Never claim "perfect sync," "face safe" or "verified quote" without the corresponding evidence.
