← All craftbooks

Subtitle & Caption Generator

Media: audio and videoevalv1.0.0released 2026-06-05workflow: build-loop

Generate time-synced subtitles/captions for a video in a standard caption format (SRT or WebVTT), so the video is accessible and watchable without sound. Scopes the caption format and timing/reading-speed rules FIRST, transcribes the audio with precise word timings, then formats those into properly cued, line-length-limited caption cues. The transcribe-then-format split is deliberate: getting accurate text and timings is a different skill from chunking them into readable, on-screen-friendly cues that respect reading speed and never overlap.

Steps

Entry step: scope. Each step names the specialist role it wants; the full working prompt is expandable.

  1. Scope the captionsplannerentry

    format (SRT/VTT), timing rules, line limits, language

    Show working prompt
    Lock the caption rules BEFORE generating. Step 1: record the source video (path, duration) and the language. Step 2: pick the format — SRT (`HH:MM:SS,mmm`) or WebVTT (`HH:MM:SS.mmm` with a `WEBVTT` header). Step 3: set readability rules: max ~42 chars per line, max 2 lines per cue, min ~1s and max ~7s per cue, reading speed under ~17 chars/second, and a small gap between cues so none overlap. Step 4: decide how to handle non-speech (e.g. `[music]`, `[applause]`) and speaker IDs if multiple speakers. Write an acceptance-criteria checklist (valid SRT/VTT that a player can load, sequential cue numbering, monotonic non-overlapping timecodes, lines within the char limit, last cue ends near video duration) and decisions to `notes/scope.md` via write_task_note AND to the produces path.
  2. Transcribe with timingsdeveloper

    STT the audio into word/segment timestamps

    Show working prompt
    Produce timed text the formatter can chunk. Step 1: extract/take the audio track and run speech-to-text over the WHOLE recording to get segments with start/end timestamps (word-level if the engine supports it — it makes cue splitting far cleaner). Step 2: keep timestamps monotonic across any chunk boundaries. Step 3: mark non-speech events per the scope rules. Step 4: write the raw timed segments to `notes/timed-segments.json` (each: text, start, end) via write_task_note and the produces path so the format phase has structured input, not prose. Do not chunk into final cues yet — that is the next phase. On a loop-back from format, fix timing/coverage gaps here only if the issue is bad source timings.
  3. Format the caption filedeveloper

    chunk timed text into valid SRT/VTT cues

    Show working prompt
    Turn timed segments into a valid caption file. Step 1: emit the format header (none for SRT; `WEBVTT` for VTT). Step 2: walk the timed segments and pack words into cues that respect the scope's char/line/duration/reading-speed limits — split a long segment into multiple cues at natural pauses, splitting timecodes proportionally. Step 3: number cues sequentially (SRT) and write each cue's `start --> end` timecode in the EXACT format, then 1-2 text lines. Step 4: ensure no two cues overlap and the last cue ends at/just before the video duration. Step 5: write `captions.srt` (or `.vtt`) and validate it parses (try loading it, or re-parse the structure). write_task_note the caption path and cue count. On a loop-back, fix only the flagged cues (overlap, over-long lines, bad timecode format).
  4. Evaluatereviewer

    Grade the deliverable against every acceptance criterion. All pass → finish; any fail → loop back and fix the gap.

    Show working prompt
    Validate the caption file like a player would. Step 1: parse it — valid header (VTT), sequential numbering (SRT), and every timecode in the exact `HH:MM:SS,mmm`/`.mmm` format (PASS/FAIL). Step 2: confirm timecodes are monotonic and NO two cues overlap. Step 3: confirm cue durations and line lengths are within the scoped limits (sample several). Step 4: confirm the final cue ends within a small margin of the video duration (no dropped tail). Step 5: spot-check 3 cues against the audio if possible — text and timing align. Write PASS/FAIL per criterion.
    
    Then route — this is the whole point of the loop:
    
    - **Every criterion PASSES →** call `advance_task_step({ ref, stepId: "evaluate", next: "finish" })`.
    - **Any criterion FAILS →** write the specific gaps to notes, then call `advance_task_step({ ref, stepId: "evaluate", next: "format" })` to loop back. The builder fixes exactly those gaps.
    
    Never route to `finish` while any criterion is unmet. The build phase's completion gate already blocked a grossly-incomplete deliverable; your job is the judgment an automated check cannot make (does it actually work, read well, look right). After ~3 unproductive loops, stop and report DONE_WITH_CONCERNS so the user can step in.
  5. Finishdeveloper

    All acceptance criteria met. Stamp a short summary and report DONE.

    Show working prompt
    Every acceptance criterion passed. Write a one-paragraph DONE summary to task notes via `write_task_note`: what was built, the deliverable path(s), and a one-line confirmation that each criterion is met. Then report DONE.

Triggers

Phrases that suggest this craftbook to a crew.

Source

View this craftbook on GitHub · MIT license