Scene candidates & selection

Every scene can have many takes — videoclaw keeps all of them, lets you pick the winner per scene, and re-rolls just the bad scenes without burning budget on the good ones. It is a director's selection desk for AI video: nothing is overwritten, every "which one did we ship?" question has a real answer, and you can re-run scene 3 alone while scenes 1, 2, and 4 stay locked.
What it does
- Keeps every take. Each time the runtime generates a scene, the result is appended as a new candidate (
scene-0-take-1,scene-0-take-2, …). Old takes are never overwritten, so you can compare take 1 to take 2 after the fact. - Separates "what was generated" from "what you chose." An append-only registry records every take; a separate mutable ledger records your pick, your rejections, pending takes, and re-roll requests per scene.
- Re-runs one scene at a time.
produce --scene 2regenerates only scene 2 and appends a fresh round; the scenes you didn't name keep their current winner. - Asks for several takes on demand. Re-roll the same scene a few times to get takes 1, 2, 3, then pick the best.
- Chains continuity between cuts.
chain-fromtells the runtime to feed scene N−1's selected clip into scene N so a provider like Seedance 2.0 carries identity, environment, and motion across the cut. - Gates downstream stages.
reviewandpublishrefuse to advance while any scene with candidates has no winner picked — so you can't ship an unselected scene by accident. - Migrates legacy projects. A one-shot command turns an old single-generation project into one pre-selected candidate per scene.
How to use it
All commands below use the form node dist/cli/vclaw.js video .... If you installed the package globally you can type vclaw video ... instead — they are identical.
node dist/cli/vclaw.js video candidates-list --project demoLists every take grouped by scene, plus a portfolio-wide summary (total / completed / pending / failed). Add --scene 0 to focus one scene.
node dist/cli/vclaw.js video candidates-show --project demo --candidate-id scene-0-take-1Prints one candidate looked up by id across all scenes as { sceneIndex, candidate }. Exits non-zero on an unknown id.
node dist/cli/vclaw.js video select-candidate --project demo --scene 0 --candidate-id scene-0-take-1 --notes "first take was perfect"Marks that take as the winner for scene 0. It is pulled out of the rejected/pending lists and any pending re-roll flag is cleared. --notes is optional.
node dist/cli/vclaw.js video reject-candidate --project demo --scene 2 --candidate-id scene-2-take-1Records a rejection. If that take was the current winner, the selection is cleared; the id is removed from pending if present.
node dist/cli/vclaw.js video reroll-scene --project demo --scene 2 --chain-from-prev onFlags scene 2 as needing a fresh generation and clears its winner so you must re-pick. --chain-from-prev on|off is optional and sets the chain flag at the same time.
node dist/cli/vclaw.js video produce --project demo --scene 2Regenerates only scene 2 and appends it as a new round/take. Pass --scene more than once (e.g. --scene 1 --scene 3) for a specific subset; scenes you omit keep their current candidate. produce ↔ execute are aliases.
node dist/cli/vclaw.js video chain-from --project demo --scene 5 --from 4Turns on chain-from-prev for scene 5, feeding scene 4's selected clip in as the upstream hint. v1 only supports the immediately previous scene — --from must equal --scene − 1 or it returns chain-from-unsupported.
node dist/cli/vclaw.js video unchain --project demo --scene 5Turns the chain-from-prev flag back off for that scene.
How it flows

Diagram source (live Mermaid)
Artifacts & outputs
Two canonical JSON artifacts live under projects/<slug>/artifacts/:
scene-candidates.json— append-only registry of every take, grouped bysceneIndex. Each candidate has a globally-unique idscene-<sceneIndex>-take-<n>, agenerationRound,status(pending | completed | failed | cancelled),outputs[](kind + path), and asourceblock recording the execution round, adapter, and anychainedFromCandidateId.scene-selection.json— mutable ledger, one entry per scene withselectedCandidateId,rejectedCandidateIds[],pendingCandidateIds[],rerollRequested,chainFromPrev, and optionalnotes. The three id sets are pairwise disjoint per scene (enforced by validation).
At publish time the selected candidates are projected into a canonical asset-manifest.json view, so the shipped assets match exactly what you picked. Per-scene Obsidian notes also surface candidate counts, the selected take, rejected/pending counts, and the chain flag.
Tips & gotchas
One scene, many takes — keep the good one
The whole point: re-run only the scene that's off. reject-candidate → reroll-scene → produce --scene <n> → select-candidate gives you a clean fix without re-rendering scenes that were already perfect.
Lock the upstream scene before chaining
chain-from-prev reads the previous scene's selectedCandidateId. If that scene has no winner, the runtime hard-fails with chain-from-prev-source-missing; if the upstream winner isn't completed, it fails with scene-chain-upstream-stale. Run select-candidate on the previous scene first, or unchain the downstream scene.
Pick a winner or you can't ship
readiness, review, and publish all block with scene-selection-missing when any scene has candidates but no selection. doctor-project / doctor-portfolio also flag scene-selection-stale (a newer completed take exists), scene-reroll-pending (a re-roll is still outstanding), and scene-chain-upstream-stale.
Migration is one-shot
candidates-migrate-from-assets synthesizes one pre-selected candidate per scene from an existing asset-manifest.json. It refuses with migrate-refused if scene-candidates.json already exists — there is no --force in v1. Use --dry-run to preview, and delete the artifact manually if you genuinely need to re-migrate.
Driving it from an agent
An AI agent (e.g. Claude Code) drives the full loop with plain shell calls: produce --scene <n> to generate, candidates-list --project <slug> to read back the JSON, then select-candidate/reject-candidate/reroll-scene to record the decision. Every command emits machine-readable JSON on stdout and follows the exit-code contract: 0 = ok, non-zero = validation or lookup error (candidates-show on an unknown id, chain-from with an unsupported source, etc.). Because selection is gated, an agent can loop produce → inspect → select until readiness stops returning scene-selection-missing, then advance to review/publish.
Related
- providers — which routes (Seedance, Veo, Runway) generate the takes a candidate captures.
- characters — identity bindings carried through each generated scene; chain-from-prev preserves identity across the cut.
- assemble — stitches the selected winners into the final master.
- Deep reference:
docs/SCENE_CANDIDATES.md— full data model, chain-from semantics, migration, readiness/doctor codes, and troubleshooting.
