Subtitles
This is one task, not a step in a flow. Do it whenever the user asks—right after clipping, or after they delete two sentences and want subtitles redone.
It has only one prerequisite: the edit list already exists. Not because subtitles come after clipping in a sequence, but because without the edit list there is no way to know which words remain and at what second they appear in the final video.
Requires edit-list.json, transcript.json
Produces subtitles.json
Once done, stop. Do not guide the user to the next step.
First read and execute the Business Skill Phase Contract. Criteria in Subtitle Correction Rules. Proper noun forms follow the AI Term Dictionary.
Who Decides What
This is the foundation; everything else is derived from it.
Clip talking head decides "what words stay and at what time" ← sole source of truth for timing
Subtitles decides "what text appears on screen" ← sole source of truth for display
Each subtitle screen stores a list of word IDs + display text, not seconds. Time is computed on the fly from the edit list every time. This way the two ledgers never drift—there is no second copy of timing to go stale. Failures become precise: "The 7th and 12th screens have their words clipped out" instead of a vague "subtitles may be out of date."
Storing the subtitle text separately is intentional. The transcript answers "what was said," while subtitles answer "what the viewer should read"—punctuation, removed filler words, proper noun spelling. These should be different. Forcing a single string to do both jobs means commas can never be added.
0. Readiness
First run the Update Check's readiness check—are skills up to date, is the Runtime compatible. The plugin root is also located there (all <pluginRoot> paths in this file use that literal directory). Only proceed on "ready"; for "new session needed" or "stop," follow its handling (including the "no custom alternative UI" ban). Do not embed environment logic in the business skill.
If the readiness result is runtime.kind=desktop-managed, directly reuse the stable CLI already installed by the desktop app and its existing launchd/windows-task service. Do not resolve Electron paths, install extra dependencies, or start a second Runtime.
1. Entry Assertions
node "<pluginRoot>/scripts/ensure-running.cjs" --json
node "<pluginRoot>/scripts/videocut-cli.cjs" inspect "<projectDir>" --json
| Assertion | If not met |
|---|---|
edit-list.json exists and has segments | Say the edit list is missing and ask the user to clip first. Do not clip yourself. |
transcript.json exists | The project is not ready; stop. Do not create one yourself. |
Do not assert source_cut.mp4, do not transcribe. Subtitles need neither—see next section.
2. Correct Words: First Dictionary, Then Script
No re-transcription needed. The existing word-level transcript already has timestamps; the edit list knows which segments survived. Each word's position in the final video is computed, not re-listened to:
The word's time in the source clip — the transcript has it
Which segments survive — the edit list has it
The word's time in the final video — compute from the two
Sending the audio through ASR again just re-listens to the same speech—costly, time-consuming, and worse at proper nouns (they need to be corrected again). (transcript retranscribe is a relic of an earlier design where subtitles got their timeline from re-transcribing the clipped video. Since subtitles switched to word ID anchors, that problem is gone. Do not use it for subtitles.)
Two different tools, both to be used:
# Dictionary: fixed spelling for this speaker, no evidence needed
node "<pluginRoot>/scripts/videocut-cli.cjs" transcript dictionary "<projectDir>" --dictionary "<pluginRoot>/references/ai-term-dictionary.md" --json
# Script: only when the author has a manuscript, evidence required per instance
node "<pluginRoot>/scripts/videocut-cli.cjs" transcript align "<projectDir>" --script "<scriptFile>" --json
Dictionary always write it this way applies globally, no context check — lists which words were changed
Script only write it this way if context matches requires evidence per instance — reports "not sure" otherwise, does not guess
Why the dictionary is necessary and the script alone is insufficient: Talking heads often re-record. In real projects the same sentence was recorded four times, so context like "connector X" and "X is" appears multiple times. The align tool reports "not sure" for all of them because it follows the rule not to guess—a name written wrong is worse than a mis-recognition. It might only dare to change one out of three occurrences. The dictionary has no such problem: in this speaker's work, "X" is "X."
There is only one dictionary, located at the plugin-level references/ai-term-dictionary.md: it corrects the transcript, and both clipping and subtitles use the same transcript. Do not create a separate dictionary under this skill.
Review the list of changes. The dictionary applies globally without context, so it can also make mistakes—for example, normalizing "Skills" (Claude Skills, a plural proper noun) to "Skill." If you spot a mistake, fix the dictionary, not the command.
transcript align only reports changes; it does not apply them. To apply its proposals, convert the corrections to [{wordId, text}] and run:
node "<pluginRoot>/scripts/videocut-cli.cjs" transcript correct "<projectDir>" --file "<correctionFile>" --json
After correcting the transcript, subtitle screens that reference these words are updated in the same step, reported as subtitles.updated. Screens that could not be updated (because the line was manually overwritten) go into needsAttention—report them for human review, do not guess.
When neither the dictionary nor the script can confirm a correct spelling, do not guess. Report it so the user can add to the dictionary—once it's in the dictionary, the next video will get it right automatically. Guessing once means you will have to guess again next time.
3. Split Screens
node "<pluginRoot>/scripts/videocut-cli.cjs" subtitle build "<projectDir>" --json
Four rules, applied in order:
① Deleted words two sides of a deletion are adjacent on the timeline but unrelated in meaning.
Deleting silence does not count—if the silence is inside a sentence, don't split the sentence.
② Any punctuation Ashburn period or comma counts—same granularity as clip splits.
Both split at the same boundary. Punctuation beats any timing evidence:
a speaker can say two sentences without a breath, or pause in the middle of one.
③ Paragraph boundary + pause **Only used when the word lacks punctuation.** It's for guessing
a sentence ended based on paragraph breaks. If punctuation exists, rule ② and its
comma logic should handle it—they consider screen length, rule ③ does not.
(Triggering rule ③ on a punctuated boundary can increase screen count from 40 to 43,
creating too many tiny screens.)
④ Long pause for the audience Inside a sentence, need a longer silence to qualify.
Clipping and subtitles use the same punctuation and the same granularity: one comma = one segment / one screen.
Fragments (one or two characters) are merged, but not across periods—"You see" starts a new sentence, it is not the tail of the previous one. Merging it backward would produce "…call Grok CLI you see," gluing two sentences together.
Short sentences spoken quickly are kept (in a real project, "Every morning" and "execute tasks" each came in at 0.6 seconds). That is how the speaker actually spoke; do not issue a warning. One-comma-per-screen naturally produces such screens. Warning about them means warning about normal speech—too many warnings become noise.
For screens longer than one line, split them evenly into multiple screens, one line per screen. If a line splits into a single-character fragment, that means rule ②'s boundary is not really a period—merge the fragment back into the previous screen.
The command reports four things, all to be reviewed:
stale screens affected by a change in the edit list — precise: which screen, which words were lost
tooFast too many characters, not enough reading time
transcriptMoved the transcript is no longer the original one
When Subtitles Already Exist — Stop and Ask
Without --replace it will immediately refuse. This is the only place in this skill where user consent is required, because --replace discards human-made screen splits and phrasing that the product itself cannot recover.
The user wants to change a few words Do not build. Let them edit directly in the Studio, or tell you which screens to modify.
The user wants to start over Confirm, then add --replace.
4. Review: Screen by Screen in the Studio
node "<pluginRoot>/scripts/videocut-cli.cjs" open "<projectDir>" --json
After opening, switch to the left panel's "Subtitles" tab. One line per screen: left side shows the screen number and timing, right side shows the text. Click to edit directly.
- Enter = split at cursor into a new screen
- Backspace at start of line = merge with previous screen
- Right panel "Parameters > Subtitles" → choose one of four presets for the entire clip
- You can see subtitles on the preview canvas—position and font size are proportional to the canvas. Preview and final export use the same numbers.
During review, at least ask the user to confirm: proper nouns correct, no swallowed words, line breaks read naturally, each screen stays long enough to be read.
5. Ends at subtitles.json
This task is done. Do not perform physical cuts, storyboard, animation, or final rendering. Do not push the user to the next step.
Reports must clearly separate: Product structured readback = API/readback PASS; actual same-project browser frame review = visual frame PASS; if no human has ever watched the subtitles against the video, the report is human listening UNVERIFIED. Do not substitute with DOM inspection, screenshots, or file probing.
Boundary: Burning into the Video is Not This Task
The output format decided is burn into the video, but burning happens during the export phase. The subtitle skill's output is subtitles.json—all dimensions are percentages of the canvas. Export converts pixels using the output resolution; both use the same numbers.
Today's exported mp4 has no subtitles. That step has not been done yet. The report must clearly state this consequence; do not say "subtitles are done" as if the final video contains them—the user will assume they do.
Recovery and Failure
subtitles_exist: Subtitles already present. Ask first, do not--replacedirectly.revision_conflict: Another process is writing. Re-read, do not auto-overwrite.- Dictionary says "row N unreadable": a malformed table row. Only table rows (
| Correct Spelling | Common Misrecognition |) are parsed; prose and lists are silently ignored. transcript correctsays "must not change any word id, time or gap flag": the proposal mixed timing changes into a word-correction request. Word corrections only change text.runtime_unhealthy: Do not loop on reinstallation.- Any failure must not claim "transcription is done" as "subtitles are ready." ASR output is raw material, not the final product.