cut-mistakes
Agent 2 of the video editing pipeline. Finds and removes spoken mistakes — stutters, repeated words, false starts, and retakes (re-recorded lines) — from a talking-head recording. Use after cut-silences, when asked to cut mistakes, remove stutters / repeats / filler restarts, clean up flubs, or keep the best take. Works review-gated: it proposes every cut with context and a reason for approval, then renders only the approved cuts via ffmpeg. Requires a word-level transcript.
1How It Works & Mechanism
Splits spoken-mistake handling into a 3-step pipeline: mechanical candidate finding → mandatory review gate → rendering approved cuts only. Leaves judgment to LLM/humans and math to scripts.
### 1. Find candidates (mechanical) … ### 2. Review (the gate — REQUIRED) … ### 3. Apply approved cuts
Stutter detection = adjacent identical tokens with a gap <0.5s; defaults to deleting the former and keeping the latter.
const closeGap = b.start - a.end < 0.5; if (a.token === b.token && closeGap) { … // remove the first utterance, keep the second cut: { start: Number(a.start.toFixed(3)), end: Number(b.start.toFixed(3)) },
Retakes and false starts are detected not by enumerating rules, but by chunking via pauses/sentence ends/16s limits, then comparing stopword-filtered signatures via Jaccard similarity.
if (gap > 0.85 || (sentenceEnd && elapsed >= 7.5) || elapsed >= 16) { … const stop = new Set("a an and are as at be but by for from i if in is it of on or so that this to was we with you your they their there what when where why how like um uh".split(" ")); … const score = jaccard(sigs[i], sigs[j]); const sameOpening = sigs[i].slice(0, 4).filter((t, idx) => t === sigs[j][idx]).length >= 2; if (score >= 0.34 || (score >= 0.24 && sameOpening)) {
Identifies "short initial chunk + fast restart" as a false start, relabeling the type from retake to false_start.
const isFalseStart = sameOpening && firstLen < 6 && segments[j].start - segments[i].end < 12; … type: isFalseStart ? "false_start" : "retake",
The detector explicitly declares that it "makes no decisions", and SKILL.md mandates reading context case-by-case because emphatic repetition is mechanically isomorphic to flubs.
This is MECHANICAL detection only. It proposes candidate cut ranges with rich … context + a confidence + a default recommendation, but it does NOT decide.
The approved cuts list is converted into an EDL + retimed transcript via apply-cuts.mjs; renders via ffmpeg trim/atrim + concat only when --apply is passed, defaulting to a dry run.
if (approved.some(c => c.start < 0 || c.end > duration)) die('Cut range is outside source duration bounds'); … lines.push(`[0:v]trim=start=${r.start.toFixed(3)}:end=${r.end.toFixed(3)},setpts=PTS-STARTPTS[v${i}];`); … const ff = spawnSync("ffmpeg", ["-y", "-i", videoPath, "-/filter_complex", scriptPath, "-map", "[v]", "-map", "[a]", "-c:v", "libx264", "-preset", "medium", "-crf", "18", "-c:a", "aac", "-b:a", "192k", "-movflags", "+faststart", outputPath], { stdio: ["ignore", "ignore", "inherit"] });
2Core Capabilities
3External Dependencies
| Kind | Dependency / Endpoint |
|---|---|
| cli | Node.js(跑两个 mjs 脚本) |
| cli | ffmpeg(trim/atrim + concat 渲染,libx264/aac) |
| cli | ffprobe(转录未带时长时探源片时长) |
| cli | npx serve(只服务本地审查页 HTML,非上传) |
| cli | node scripts/build-edl-review.mjs(仓库级共享复核工具,不在本 skill 目录内) |
4Recommended Governance & Evidence
- scripts/: Local script or command execution: node .claude/skills/cut-mistakes/scripts/find-cut-candidates.mjs <transcrip
- 网络端点: External network access declaration: The sole HTTP surface is `npx serve . -p 8080 -n` during human review—a local static server that only serves generated review HTML without uploading media
- 本地工作目录: File I/O and artifact output: <stem>.cut-candidates.json / <stem>.cut-candidates.md (written alongside transcript by default, or to --out-dir)
5Second-Pass Verification
- [ok] 目录文件清单与产物对照 — 3 个文件(SKILL.md、find-cut-candidates.mjs、apply-cuts.mjs);SKILL.md 承诺的 *.cut-candidates.json/.md 与 *.mistakes-edl.json/transcript.json/decisions.md/filter.txt 均在两个脚本的 writeFileSync 目标中逐一定位到。
- [ok] 网络面反例搜索 — 目录内 0 处 fetch/https 导入;唯一 URL 形态字样是 SKILL.md 的本地命令 `npx serve . -p 8080 -n` 与仓库级脚本名,不构成执行期外发。
- [ok] 凭证面反例搜索 — 0 处 process.env/API_KEY/TOKEN/.env;spawnSync 列表仅 ffprobe/ffmpeg,环境变量未被子进程继承修改。
- [ok] 「只渲染已批准切点」是否被代码强制 — apply-cuts.mjs 第 49-51 行以 --cuts 文件为唯一输入并校验数组与非空范围;find-cut-candidates.mjs 不含任何写视频/批准逻辑,两脚本互不自动串接。
- [ok] 文档参数 vs 脚本 argv — find 脚本解析 <transcript> 与 --out-dir(Usage 行自述一致);SKILL.md 给的命令两种形态都能对上。apply-cuts 解析 --cuts/--video/--output/--out-dir/--apply,与 SKILL.md 的调用示例逐项一致。
- [ok] 上游转录服务是否被算作本 skill 行为 — SKILL.md 只写「Requires a word-level transcript」,未指名任何服务或 key;ElevenLabs helper 属仓库级 scripts/,故按『判级对象=skill 自身目录』记入 reason/risks 而不改档。
6Verdict & Scenarios
fca023adfb7af7d9…