This is chengfeng-videocut 's first business entry point. The target output is only one thing:
一份已经人工复核过的删词账本(Cuts + EDL)
Do not cut media. Until this Skill ends, there is no new video file on disk—the original footage stays untouched, the ledger records which segments should play, and the preview stitches them together for a person to listen to. Physical cutting happens only in the next segment.
【本 Skill】──账本──▶ 导出 ──source_cut.mp4──▶ 字幕 ──subtitles.srt──▶ 分镜动画
Why not cut: Changing the ledger once takes tens of milliseconds; cutting once creates an irreversible file. By separating deletion decisions from media output, users can revise repeatedly until satisfied without paying the cost of cutting for every version.
The Skill performs semantic judgment and orchestration; the product Runtime is the sole writer of projects, Cuts, media cuts, and Studio state.
First read and execute the business Skill's stage contract. Every continuation run of this Skill must preserve its fixed stages, andstop only at review binding:preflight -> Product state readback -> proposal -> Product CAS -> project-level review binding. The latter three stages (user confirmation -> Product execution -> outcome verification) belong to the export Skill.
0. Always perform the Runtime preflight first
Obtain exactly from Codex's enabled Plugin list chengfeng-videocut 's source.path。SKILL_DIR is not a variable Codex guarantees to inject; do not rely on it, hardcode development machine paths, or use find to guess the installation directory:
PLUGIN_ROOT="$(codex plugin list --json | node -e 'let s=""; process.stdin.on("data", c => s += c); process.stdin.on("end", () => { const rows = JSON.parse(s).installed || []; const hit = rows.filter(x => x.enabled && x.name === "chengfeng-videocut" && x.source && x.source.path); if (hit.length !== 1) process.exit(1); process.stdout.write(hit[0].source.path); });')"
test -n "$PLUGIN_ROOT" && test -f "$PLUGIN_ROOT/.codex-plugin/plugin.json" || { echo "chengfeng-videocut enabled plugin root unavailable" >&2; exit 1; }
ENSURE="$PLUGIN_ROOT/scripts/ensure-runtime.cjs"
RUNNING="$PLUGIN_ROOT/scripts/ensure-running.cjs"
STUDIO="$PLUGIN_ROOT/scripts/ensure-studio.cjs"
VC="$PLUGIN_ROOT/scripts/videocut-cli.cjs"
node "$ENSURE" --install-if-missing --json
It must be made an inline step of the current task:
ready: Continue this Skill.missing: The script prompts only once that "it is installing from GitHub Release"; after verification completes, it automatically continues.runtime_unhealthy, installation failure, or doctor failure after installation: report structured diagnostics and stop. Stop means stop: do not continue the process with a self-made review page, player, timeline, or any substitute interface. Any output produced when the product is unavailable is untrustworthy (a real case: when Runtime was missing, the Agent hand-built a "screening console" webpage, and its review decisions were completely incompatible with the product's ledger format, so the user had to redo the work). The only correct action is: give the user the structured diagnostics and guide them to install or file an Issue.runtime_capability_missing: The current Runtime is healthy but lacks the editable EDL contract required by this process; stop and require an upgrade; do not fall back to the old editing chain.- During the preflight stage, it is forbidden to start services, open Studio, or create projects.
For the detailed protocol, see Runtime and Product Contracts。
1. preflight: accept real input and directly create the Product file
Accept only the real spoken-word video or existing real project provided by the user. If there is no real media, stop; it is forbidden to substitute examples, placeholder videos, or other projects in the browser.
[真实视频]
|
v
[云端逐词转录 + 稳定 wordIds]
|
v
[Product project create]
If the Runtime does not yet provide an original video transcription command, you may only use the currently approvedcloud ASR in the current environment to generate word-by-word candidates in the task directory; this process forbids falling back to local ASR. If no cloud ASR is available, clearly report missing_cloud_transcription_adapter, do not open Studio, and do not fabricate a transcript.
A new task is atomically created and prepared by Product; the Skill must not first write project.json:
node "$VC" project create "$jobDir" \
--video "$taskLocalVideo" \
--transcript "$taskLocalTranscript" \
--aspect-ratio "$aspectRatio" \
--json
--video and --transcript must be real files within the task directory;aspectRatio can only be 3:4 / 4:3 / 16:9, and when unspecified, use the product default 4:3. For an existing canonical project, first use inspect to confirm and reuse; do not recreate projectId. Only when restoring cut_prepare_running or explicitly refreshing an existing task should you use project prepare。
project create is the direct entry point for local real videos and cloud word-by-word transcripts into Product; it does not go through the asset library, material-library, upload session, import flow, or additional Skill. After creation succeeds, it is still in preflight: before all state readback and Cuts API, have Product declaratively ensure the resident service; the script only calls service ensure --json, and does not manage processes itself:
node "$RUNNING" --json
Only after the script confirms the service healthy=true、runtimeMode=launchd, version compatibility, valid PID, and that the URL is the canonical 5190 entry point, should you continue. On failure, pass through Product's structured error and stop; falling back to foreground, changing ports, or killing unknown processes is prohibited.
Then perform Product state readback, before generating any semantic candidates:
node "$VC" workflow get "$jobDir" --json
node "$VC" cuts get "$jobDir" --json
The two readbacks must point to the same projectIdreturned by Product, and save the current workflow stage, Project / Cuts / EditList revisions; if missing or inconsistent, stop, and do not guess or fill in with local files.
2. Fix words: put misheard proper nouns back
Do this before deciding what to delete, not after.
Transcription will mishear proper nouns, and will also write the same word in several ways. In a real project, among 39 words containing letters, there appeared
16 spellings:Grok was heard as Clock / Glock / Gokul,Codex written as CodeX / codex。
Deleting words cannot fix this. A misheard word is not extra speech—delete Clock , and that sentence is missing a word.
The product itself will do the dictionary step, so there is no need to manually produce a comparison table:
node "$VC" transcript dictionary "$jobDir" \
--dictionary "$PLUGIN_ROOT/references/ai-term-dictionary.md" --json
It changes directly, and lists which places were changed and the context of each.After the changes, look at that list—the dictionary does not look at context, so it will also change things incorrectly (for example, normalizing what the speaker actually said, "Skills", into "Skill"). If you see something wrong, change the dictionary; do not patch it elsewhere.
Only when the dictionary cannot solve it and the author has a manuscript on hand should you add one context alignment pass:
node "$VC" transcript align "$jobDir" --script "$scriptPath" --json # 只报不改
node "$VC" transcript correct "$jobDir" --file "$correctionFile" --json
Fixed principles:
- Only change text; do not change timing, do not change word count, do not change wordId. Product compares timestamps word by word, and if any is touched it rejects directly—timing is the foundation of all completed edits.
- Only change the spelling, not the meaning. If the speaker truly said it wrong and then said it again, that belongs to incomplete-sentence correction and is handled by the next step, word deletion.
- When it is not in the dictionary, and none of the spellings in the manuscript can confirm what is correct, do not guess. Report it and leave it for a human to add to the dictionary. Putting a made-up name into the user's video is worse than leaving a misheard name.
- Keep spoken Chinese as in the original. If the speaker says "叉", "大模型", or "智能体", that is what he said.
- Transcribe the same audio segment twice, and the results differ. In testing, the second pass heard
GrokasClock/Gokul/Glock,CodexasCodeX. So the dictionary is not "occasionally fixing a name or two"; it isa gate every transcription must pass through。
Why it must come before judgmentWhen the script is still wrong, judging what to delete means the judgment has to steer clear of the wrong names all the way through — that is where the criterion "a misheard proper noun is not grounds for deletion" comes from; it is a patch, not a solution. Once the text is fixed, that patch no longer needs to take effect.
The script is segmented by punctuation
In the transcript each word carries the punctuation that follows it (provided by Volcano); the script column is segmented by punctuation —one comma is one segment. So that column reads one sentence per line, not one big block.
我现在很少刷X了,
因为今天有什么值得研究已经被我外包给了Codex和Grok。
每天早上,
Codex都会调用Grok
The subtitle segment also consumes the same punctuation, so the sentence breaks on both sides are consistent.
Old projects may have no punctuation(transcribed before 2026-07-28). For projects whose segmentation rules changed but whose transcript did not, just run a re-segmentation once; there is no need to re-transcribe:
node "$VC" transcript regroup "$jobDir" --json
It verifies word by word that the id / time / text are unchanged, so it is safe for projects that have already been cut and subtitled. If you really want punctuation you still have to re-transcribe — the punctuation simply does not exist in the transcript and cannot be computed.
3. proposal → Product CAS: generate and submit word-deletion candidates
First read semantic deletion rules。
Before judging, you must fetch Product's playback-order view; you may not assemble it yourself from transcript.json :
node "$VC" transcript playback "$jobDir" --json
Judging "said it twice" relies onbeing adjacent in playback, not on being adjacent as stored in the file. In cut projects the segment numbers necessarily skip, and skipped numbers will be read as "there is content you did not show me", causing the judgment to be refused — on 2026-07-26 two correct judgments were wrongly rejected because of this. Assembling this view yourself has missed twice; for the wrong ways and consequences, see the "before judging" section of the criteria file.
Candidates reference only stable wordIds:
{
"schemaVersion": 1,
"cutWordIds": ["word-12", "word-13"],
"reasons": [
{ "wordIds": ["word-12", "word-13"], "kind": "repeat", "risk": "low" }
]
}
Fixed principles:
- Deletion has only two states, "deleted / not deleted"; an AI reason does not form a third state of "suggested deletion".
- Slips of the tongue, repetitions and fragmentary sentences are by default deleted keeping the earlier text; long sentences, whole sentences and branched re-sayings must be reviewed as high risk.
- Ordinary pauses are not computed by the Skill. Merging adjacent silences and
natural-pause-v2are performed deterministically by Product. - Candidate
cutWordIdslists only semantic word deletions; it is forbidden to read, copy or manually mergeinitialization.baselineCutWordIds。cuts setwill complete the merge inside the lock in Product via semantic-overlay. - "Lists only semantic word deletions" means the complete conclusion of this round of judgment, not the increment newly found this round. semantic-overlay is replace semantics: Product rebuilds the deletion set from "pause baseline ∪ this submission"; semantic words from the previous submission are not retained. On 2026-07-26 an increment was submitted, the deletion count fell from 430 to 394, the sound was still correct but the ledger regressed, while
changed: truelooked perfectly normal. reasonswill be persisted (since 2026-07-26), so write it truthfully. Product guarantees that a reason will not outlive the deletion it explains, and will also trim the parts that mention undeleted words.- Do not write directly to
cut-selection.json、project.jsonor the event log.
Read Cuts' own revision, then submit the candidate:
node "$VC" cuts get "$jobDir" --json
node "$VC" cuts set "$jobDir" \
--file "$proposalFile" \
--expected-revision "$latestCutsRevision" \
--json
cuts get.data.revision is cut-selection.json 's revision;workflow get.data.revision is project.json 's revision. The two must not be mixed.
cuts set itself will read back to verify the write result; on success the result carries readBackVerified: true; if the write and the read-back disagree it reports readback_mismatch instead of returning success.
After success you must look at noLongerCut: This is the word count and sample that will no longer be deleted this time. If it is not zero and was not an intentional retraction, that means an incremental submission was made; go back and submit the full version again. When the current state cannot be read, it is "unknown", and that must also be seen.
Afterward, it is still necessary to immediately again workflow get and cuts get, to confirm the Product readback's projectId、cut_review_ready, Project / Cuts / EditList revisions; if CAS returns or the readback is inconsistent, stop and re-review, and never directly write JSON or automatically overwrite.
4. project-level review binding: do not open Studio until manual review
Only when the transcript and Cuts have been persisted and the workflow has already entered cut_review_ready, prepare to open the review page. Even if the workflow starting point has already been ensured, before opening it is still necessary to idempotently ensure again, and then obtain the project URL returned by the product:
node "$RUNNING" --json
node "$VC" open "$jobDir" --json
Do not open this URL directly. First pass the returned URL to the capability gate:
node "$STUDIO" \
--url "$productUrl" \
--view koubo \
--json
The script will retain the project hash and confirm that the single 5190 product entry really registers the HyperFrames top-level koubo view. Only when it returns ok=true, use Codex's built-in browser to open studio.url, and then stop automatic progression, waiting for the user to select text, restore, and save. The public Skill does not switch to a second Studio port.
Before opening the browser, strictly compare the productUrl of #project/<projectId> with the just-obtained API/readback projectId , and bind stage=cut_review_ready、Project / Cuts / EditList revisions。ensure-studio of ok=true . This only proves product-side capability and cannot replace URL/hash project identity and project-level binding of the revision; if any item is inconsistent, read back again, and do not open or confirm.
studio_capability_missing must stop and explain that the version is incompatible; you may suggest using $chengfeng-report-videocut-bug to generate a redacted Issue draft. It is forbidden to assume the new interface exists merely because the URL contains ?view=koubo , and it is also forbidden to fall back to any old task panel without a capability manifest.
Do not:
- treat “opening the workbench” as the first step of the task;
- open an old Studio that has not passed
ensure-studio.cjs; - access the old
review.html, 8898 or 8899; - control the Studio DOM or directly modify media elements;
- create an independent audio track or placeholder subtitle track.
5. Handoff: up to the ledger
After the user indicates that review is complete,this Skill is finished. Do not pop up a confirmation card, and do not perform cuts.
Before ending, read back once and state the status clearly:
node "$VC" workflow get "$jobDir" --json
node "$VC" cuts get "$jobDir" --json
Write three things in the report, then tell the user to run export next:
删了多少词、少了多少秒
当前 stage(应为 cut_review_ready)
项目 / Cuts / EDL 三个 revision
return_cut_review: first node "$RUNNING" --jsonagain, then return to the same Studio to continue review.
Do not decide on the user's behalf, “let's just cut it while we're at it.” Physical cutting is irreversible, and its confirmation card belongs to the export Skill — the revision frozen by that card must be the one at the moment the user presses confirm, not the one at the moment review ends. Between these two moments, the user may make another cut at any time.
The report must be written separately: the Product structured revision is API/readback PASS; only real same-project browser-frame review counts as visual frame PASS; when no one has actually listened to the audio, it is always human listening UNVERIFIED, and playback, DOM, screenshots, or media probing must not be used as substitutes.
Recovery and failure
revision_conflict: re-read the state, explain the user's recent edit, and do not automatically overwrite.runtime_unhealthy: do not repeatedly reinstall.service_identity_mismatchorservice_port_conflict: Stop; do not roll back the foreground, do not change ports, do not kill unknown processes.- The page is closed but the service is still running: after reading the workflow, continue from the current state; do not create a new project.
- Under no failure may "the ledger has been written" be stated as "the edit is done".Up to this point no media file has been produced, so saying the edit is done is reporting something that did not happen.