/** * vclaw schema --json — the v3 introspection bundle. * * Returns the full CLI contract in one call: commands, flags, artifact * schemas, error codes, exit codes. Agents call this once to learn the * surface, then drive the CLI without further introspection. * * Stateless function — no fs writes, no env reads, no network. Pure * read of bundled JSON + reflection of the dispatch table. */ import { readFileSync, readdirSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { ALL_ERROR_CODES } from './errors.js'; import { ExitCode } from './cli-output.js'; import { listMultiShotPresets, type MultiShotPreset } from './multi-shot-prompt.js'; import { listMultiShotIssueExplanations, type PromptQualityIssueExplanation } from './prompt-quality.js'; export interface CommandFlag { name: string; /** "value" if it takes an argument, "boolean" if it's a switch. */ kind: 'value' | 'boolean'; description?: string; } export interface CommandSpec { name: string; usage: string; description?: string; flags?: CommandFlag[]; /** Backwards-compat aliases that dispatch to this command. */ aliases?: string[]; } export interface SchemaDump { version: string; generatedAt: string; exitCodes: Record; errorCodes: ReadonlyArray; commands: CommandSpec[]; artifactSchemas: Record; multiShot: { presets: readonly MultiShotPreset[]; issueExplanations: readonly PromptQualityIssueExplanation[]; }; } /** * Hand-curated list of subcommands covering the FULL VIDEO_DISPATCH table in * src/cli/vclaw.ts (back-compat aliases — execution-plan/execute/preflight — * are listed via their canonical entries only). cli-schema.test.ts asserts the * exact count, cli-dispatch-table.test.ts asserts every advertised command + * alias resolves to a dispatch entry, and cli-schema-dispatch-sync.test.ts * asserts the REVERSE: every dispatch key is either listed here or an alias of * a listed command — so `vclaw schema --json` can never silently drift behind * the dispatch again (it drifted to 40 missing public commands once). */ export const COMMANDS: CommandSpec[] = [ // --- core lifecycle --- { name: 'video providers', usage: 'vclaw video providers [--workspace-root ]' }, { name: 'video verify-env', usage: 'vclaw video verify-env [--root ] [--workspace-root ]' }, { name: 'video init', usage: 'vclaw video init [--root ] [--mode storyboard|director]' }, { name: 'video brand-extract', usage: 'vclaw video brand-extract --project --url [--root ] [--gemini-endpoint ]' }, { name: 'video brief', usage: 'vclaw video brief --project --title --intent <intent> [--root <path>] [--mode storyboard|director] [--platform <name>] [--aspect-ratio 16:9|9:16|1:1] [--quality fast|quality] [--resolution 720p|1080p] [--audio on|off] [--outputs 1-4] [--from-brand-dna]', flags: [{ name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video storyboard', usage: 'vclaw video storyboard --project <slug> (--scene <text> [--scene <text> ...] | --template <template-id>) [--reset-assets] [--root <path>] [--mode storyboard|director]', description: 'Write the storyboard artifact. Rewriting it never touches the asset-manifest (bindings key on a bare sceneIndex), so a changed scene count silently orphans or shifts prior asset bindings — this emits an assetWarnings list flagging at-risk bindings; --reset-assets clears scene-bound bindings for a clean re-bind.', flags: [{ name: '--environment', kind: 'value' }, { name: '--character-a', kind: 'value' }, { name: '--character-b', kind: 'value' }, { name: '--scene-character', kind: 'value' }, { name: '--scene-color', kind: 'value' }, { name: '--scene-voice', kind: 'value' }, { name: '--scene-ref-video', kind: 'value' }, { name: '--scene-first-frame', kind: 'value' }, { name: '--reset-assets', kind: 'boolean' }] }, { name: 'video assets', usage: 'vclaw video assets --project <slug> (--asset <kind:path[:sceneIndex][:backend]> [--asset ...] | --text-only) [--root <path>]', description: 'Write the asset-manifest artifact, the last artifact readiness requires before a render. <kind> must be one of image | video | audio | subtitle | other, and a local path must exist (URL and Asset:// paths are exempt) — an unknown kind or a missing file is an invalid_flag_value error, not a silent coercion to kind "other". --text-only declares a project that legitimately has no assets (pure text-to-video): it writes an empty manifest with textOnly: true and cannot be combined with --asset.', flags: [{ name: '--project', kind: 'value' }, { name: '--asset', kind: 'value' }, { name: '--text-only', kind: 'boolean' }, { name: '--root', kind: 'value' }] }, { name: 'video review', usage: 'vclaw video review --project <slug> --verdict pass|retry|fail [--finding <text> ...] [--root <path>]' }, { name: 'video publish', usage: 'vclaw video publish --project <slug> --status ready|published|blocked [--final-output <path>] [--note <text> ...] [--root <path>]' }, { name: 'video stock-search', usage: 'vclaw video stock-search --query <text> [--provider pexels] [--page <n>] [--per-page <n>]', description: 'Search licensed stock videos through the Pexels API. Search is transient and does not write project artifacts; PEXELS_API_KEY is read from the environment and never returned.', flags: [{ name: '--query', kind: 'value' }, { name: '--provider', kind: 'value' }, { name: '--page', kind: 'value' }, { name: '--per-page', kind: 'value' }] }, { name: 'video stock-import', usage: 'vclaw video stock-import --project <slug> --selection <stock-result.json> --rendition <id> [--scene <index>] [--root <path>]', description: 'Download one selected stock rendition into a project asset, write an immutable stock-import receipt, and register provenance in asset-manifest.', flags: [{ name: '--project', kind: 'value' }, { name: '--selection', kind: 'value' }, { name: '--rendition', kind: 'value' }, { name: '--scene', kind: 'value' }, { name: '--root', kind: 'value' }] }, { name: 'video publish-metadata', usage: 'vclaw video publish-metadata --project <slug> --title <text> --visibility private|unlisted|public --synthetic-media yes|no [--description <text>] [--tag <tag> ...] [--captions <path>] [--thumbnail <path>] [--root <path>]', description: 'Write explicit local publish metadata for reviewed export packages. This has no external side effects and never invents title, visibility, or synthetic-media disclosure.', flags: [{ name: '--project', kind: 'value' }, { name: '--title', kind: 'value' }, { name: '--description', kind: 'value' }, { name: '--tag', kind: 'value' }, { name: '--visibility', kind: 'value' }, { name: '--synthetic-media', kind: 'value' }, { name: '--disclosure', kind: 'value' }, { name: '--captions', kind: 'value' }, { name: '--thumbnail', kind: 'value' }, { name: '--root', kind: 'value' }] }, { name: 'video publish-package', usage: 'vclaw video publish-package --project <slug> --platform youtube-shorts|tiktok|instagram-reels [--final-output <path>] [--metadata <path>] [--captions <path>] [--thumbnail <path>] [--root <path>]', description: 'Build a versioned local upload package for a publish-ready reviewed project. Writes final.mp4, metadata.json, optional captions/thumbnail, manifest.json, and SHA256SUMS without uploading.', flags: [{ name: '--project', kind: 'value' }, { name: '--platform', kind: 'value' }, { name: '--final-output', kind: 'value' }, { name: '--metadata', kind: 'value' }, { name: '--captions', kind: 'value' }, { name: '--thumbnail', kind: 'value' }, { name: '--root', kind: 'value' }] }, // --- creator-mode pipeline drivers --- { name: 'video create', usage: 'vclaw video create "<intent>" [--project <slug>] [...]', flags: [{ name: '--slug', kind: 'value' }, { name: '--production-mode', kind: 'value' }, { name: '--runtime', kind: 'value' }, { name: '--color-grading', kind: 'value' }, { name: '--import-library-characters', kind: 'boolean' }, { name: '--auto-create-characters', kind: 'value' }, { name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video auto', usage: 'vclaw video auto "<intent>" [--project <slug>] [...]', flags: [{ name: '--slug', kind: 'value' }, { name: '--production-mode', kind: 'value' }, { name: '--runtime', kind: 'value' }, { name: '--color-grading', kind: 'value' }, { name: '--import-library-characters', kind: 'boolean' }, { name: '--auto-create-characters', kind: 'value' }, { name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video iterate', usage: 'vclaw video iterate "<intent>" [--project <slug>] [...]', flags: [{ name: '--slug', kind: 'value' }, { name: '--production-mode', kind: 'value' }, { name: '--runtime', kind: 'value' }, { name: '--color-grading', kind: 'value' }, { name: '--import-library-characters', kind: 'boolean' }, { name: '--auto-create-characters', kind: 'value' }, { name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video run-pipeline', usage: 'vclaw video run-pipeline "<intent>" [--project <slug>] [...]', flags: [{ name: '--slug', kind: 'value' }, { name: '--production-mode', kind: 'value' }, { name: '--runtime', kind: 'value' }, { name: '--color-grading', kind: 'value' }, { name: '--import-library-characters', kind: 'boolean' }, { name: '--auto-create-characters', kind: 'value' }, { name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video approve', usage: 'vclaw video approve --project <slug> [--root <path>] [--mode storyboard|director] [--dry-run]' }, // --- readiness + execution --- { name: 'video readiness', usage: 'vclaw video readiness --project <slug> [--root <path>] [--mode storyboard|director]' }, { name: 'video plan', usage: 'vclaw video plan --project <slug> [--root <path>] [--mode storyboard|director]', aliases: ['video execution-plan'] }, { name: 'video produce', usage: 'vclaw video produce --project <slug> [--root <path>] [--mode storyboard|director] [--dry-run] [--scene <sceneIndex> ...] [--auto-chain [--chain-fallback] [--enqueue]]', aliases: ['video execute'], description: 'Execute selected scenes, or use --auto-chain to compile sequential continuity into the canonical dependency queue; --enqueue remains an alias. Later scene payloads carry one explicit active selected-video policy, only one render runs at a time, and paid tasks remain awaiting-quote/blocked. --chain-fallback advances only after an authoritative provider failure by preserving the dead-letter attempt, replacing its untouched tail at the next declared rung, and requiring a fresh exact quote/approval. The former immediate auto-chain --execute loop is retired.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--mode', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--scene', kind: 'value' }, { name: '--auto-chain', kind: 'boolean' }, { name: '--chain-fallback', kind: 'boolean' }, { name: '--continuity-feedback', kind: 'boolean' }, { name: '--enqueue', kind: 'boolean' }, { name: '--execute', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }] }, { name: 'video execute-status', usage: 'vclaw video execute-status --project <slug> [--root <path>] [--mode storyboard|director]' }, { name: 'video execute-cancel', usage: 'vclaw video execute-cancel --project <slug> [--root <path>] [--mode storyboard|director]' }, { name: 'video pool', usage: 'vclaw video pool --project <slug> [--root <path>] [--mode storyboard|director] [--max-concurrent <N>] [--scenes <csv>] [--enqueue | --dry-run]', description: 'Defaults to compiling independent pending scenes into the shared durable Cinema queue, preserving the exact execution tasks and concurrency cap as one LaneQueue lane; --enqueue remains an explicit alias. Tasks remain awaiting-quote and no provider is called. Resumable: selected scenes are skipped; --dry-run prints the plan only. The former immediate --execute path is retired and fails before provider access.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--mode', kind: 'value' }, { name: '--max-concurrent', kind: 'value' }, { name: '--scenes', kind: 'value' }, { name: '--enqueue', kind: 'boolean' }, { name: '--execute', kind: 'boolean' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }] }, { name: 'video render-scenes', usage: 'vclaw video render-scenes --project <slug> [--root <path>] [--mode storyboard|director] [--method <route>] [--fallback-chain] [--continue-from <i>] [--scenes <csv>] [--dry-run] [--confirm-spend]', description: 'Render a project\'s pending scenes SEQUENTIALLY, walking a FALLBACK ROUTE LADDER per scene: try the primary route; if the provider rejects it, escalate to the next route, and so on. The distinguishing driver vs. produce --auto-chain (sequential + chained) and pool (parallel + independent) — it productizes the hand-written voice-render.mjs / chain.mjs loops (render one scene, on rejection escalate to a fallback method, resumable across crashes). --method picks the primary route; --fallback-chain appends the project routePreference / mode defaults as fallback rungs (without it the ladder is just the primary, i.e. a plain sequential render). Resumable: --continue-from <i> skips scenes below i, and scenes that already have a selected candidate are skipped. SPEND path: refuses without --dry-run unless --confirm-spend; --dry-run prints the plan (scenes, the route ladder, continueFrom) without rendering.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--mode', kind: 'value' }, { name: '--method', kind: 'value' }, { name: '--fallback-chain', kind: 'boolean' }, { name: '--continue-from', kind: 'value' }, { name: '--scenes', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }] }, { name: 'video assemble', usage: 'vclaw video assemble --project <slug> [--root <path>] [--brand-profile <path>] [--from-clips] [--allow-missing-scenes] [--music-volume <0..1>] [--drop-clip-audio] [--mute-clip-audio <i,j>] [--on-twos] [--sharpen] [--film-grain [0..100]] [--dry-run]', description: 'Assemble the final video: PDF slides -> title card -> per-slide animation -> TTS narration -> music bed -> stitched MP4 (dry-run plans the whole pipeline without ffmpeg/keys). --from-clips stitches the per-scene rendered clips instead (a storyboard scene with NO rendered clip is a hard gate on real runs — pass --allow-missing-scenes to stitch a deliberately partial master); --music-volume overrides the clip-stitch soundtrack bed level (default 0.55 is tuned for narration-led films — use ~0.12-0.20 when dialogue lives inside the clip audio); --drop-clip-audio discards the rendered clip audio entirely, leaving the score and explicit layers — the remedy when an audio-native route (veo-useapi cannot be asked for silence) has generated speech into a no-dialogue film, at the cost of any diegetic ambience; --mute-clip-audio <i,j> is the surgical form, silencing only the named scenes so every other shot keeps its ambience. Finishing look (all default off, omitting them leaves output byte-identical): --on-twos holds every second frame so motion steps at 12fps on a 24fps timebase (the hand-drawn "animated on twos" cadence — AI video is smooth at 24fps in a way drawn animation never is); --sharpen and --film-grain are the binding pass that pulls separately-generated clips into one cohesive piece.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--brand-profile', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--from-clips', kind: 'boolean' }, { name: '--allow-missing-scenes', kind: 'boolean' }, { name: '--music-volume', kind: 'value' }, { name: '--drop-clip-audio', kind: 'boolean' }, { name: '--mute-clip-audio', kind: 'value' }, { name: '--on-twos', kind: 'boolean' }, { name: '--sharpen', kind: 'boolean' }, { name: '--film-grain', kind: 'value' }] }, { name: 'video diagnose', usage: 'vclaw video diagnose [--symptom <text>] [--retry-pattern]', description: 'Diagnose a Seedance output-quality failure (generic/morphing/jittery/blocked/off-prompt): match a symptom to its root cause, the first repair, and the vclaw tool that fixes it. Read-only/free. Without --symptom lists the whole tree; --retry-pattern also emits the conservative retry template. Continuation/sequence failures live in the continuation-handoff failure-atlas. Harvested from the MIT Emily2040/seedance-2.0 troubleshoot tree.', flags: [{ name: '--symptom', kind: 'value' }] }, { name: 'video animation-styles', usage: 'vclaw video animation-styles [--style <id>]', description: 'List the slide-animation styles from the shared registry — 11 subtle (broadcast/tabloid/minimal/comic/indian-tv/neon-esports/cinematic-film/gold-luxe/retro-vhs/stadium-live/chalkboard) + 4 BOLD with camera/element motion (slow-push/hero-pop/light-sweep/energetic) — or show one style\'s full Veo motion prompt with --style <id>. Read-only/free. These styles drive bunty_animate_slides.py for animated decks; bold styles suit hero/title slides, subtle styles suit text-dense scorecards.', flags: [{ name: '--style', kind: 'value' }] }, { name: 'video soundtrack', usage: 'vclaw video soundtrack --project <slug> (--prompt "<text>" [--duration <seconds>] [--backends suno,lyria] [--dry-run] [--confirm-spend] | --select <backendId>) [--root <path>]', description: 'Generate A/B soundtrack candidates from every available music backend (Suno/Lyria) and persist soundtrack.json; --select <backendId> marks the human-chosen candidate and writes its path into the project manifest soundtrack field for the preview portal. The generate path is paid: it refuses without --dry-run unless --confirm-spend is passed.', flags: [{ name: '--project', kind: 'value' }, { name: '--prompt', kind: 'value' }, { name: '--duration', kind: 'value' }, { name: '--backends', kind: 'value' }, { name: '--select', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--root', kind: 'value' }, { name: '--lyrics', kind: 'value' }, { name: '--instrumental', kind: 'boolean' }] }, { name: 'video narrate', usage: 'vclaw video narrate --project <slug> (--text "<script>" | --text-file <path>) [--voice <name>] [--backend gemini-tts] [--video-duration-ms <ms>] [--dry-run] [--confirm-spend] [--root <path>]', description: 'Synthesize a narration clip via a TTS backend (Gemini TTS) to artifacts/audio/narration.wav and persist narration.json; --video-duration-ms embeds a planNarrationFit() timing plan (atempo / loop-video) for the assemble step. Paid: refuses without --dry-run unless --confirm-spend is passed.', flags: [{ name: '--project', kind: 'value' }, { name: '--text', kind: 'value' }, { name: '--text-file', kind: 'value' }, { name: '--voice', kind: 'value' }, { name: '--backend', kind: 'value' }, { name: '--video-duration-ms', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--root', kind: 'value' }] }, { name: 'video dialogue', usage: 'vclaw video dialogue --project <slug> --turns "Name: line || Name2: line2" [--voice <name>] [--backend gemini-tts] [--dry-run] [--confirm-spend] [--root <path>]', description: 'Synthesize one TTS clip per dialogue turn (each "Name: line" split on "||") to artifacts/audio/dialogue-<i>-<name>.wav and persist dialogue.json; --voice applies to every turn. Paid: refuses without --dry-run unless --confirm-spend is passed.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--turns', kind: 'value' }, { name: '--voice', kind: 'value' }, { name: '--backend', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }] }, { name: 'video sfx', usage: 'vclaw video sfx --project <slug> --prompt "<text>" [--duration <seconds>] [--prompt-influence <0..1>] [--backend elevenlabs-sfx] [--dry-run] [--confirm-spend] [--root <path>]', description: 'Generate one sound-effect clip from a text prompt via an SFX backend (ElevenLabs Sound Effects) to artifacts/audio/sfx-<n>.mp3 and append it to sfx.json. Paid: refuses without --dry-run unless --confirm-spend is passed.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--prompt', kind: 'value' }, { name: '--duration', kind: 'value' }, { name: '--prompt-influence', kind: 'value' }, { name: '--backend', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }] }, { name: 'video voice-clone', usage: 'vclaw video voice-clone --project <slug> --name <name> --audio <sample> [--character <name>] [--description <text>] [--slice-seconds <n>] [--width <px>] [--height <px>] [--execute | --dry-run] [--root <path>]', description: 'Build the "blank video with audio" voice reference (the cartoon-show voice-cloning trick) and persist it as a reusable voice clone in artifacts/voice-clones.json. Given an --audio sample, renders a black-frame MP4 carrying that voice (MP3 references do not lock a voice in Seedance/Veo; a black-frame video carrying the same audio does). --character binds the clone to a character so any scene featuring that character locks the cloned voice (routed into Seedance reference_videos on the seedance-direct route); an explicit @<voice-name> tag also resolves a voice. --slice-seconds chops the recording into N-second clips (drift fix). Local ffmpeg only — no provider spend. Default-safe: plans only unless --execute is passed.', flags: [{ name: '--project', kind: 'value' }, { name: '--name', kind: 'value' }, { name: '--audio', kind: 'value' }, { name: '--character', kind: 'value' }, { name: '--description', kind: 'value' }, { name: '--slice-seconds', kind: 'value' }, { name: '--width', kind: 'value' }, { name: '--height', kind: 'value' }, { name: '--execute', kind: 'boolean' }, { name: '--dry-run', kind: 'boolean' }, { name: '--root', kind: 'value' }] }, { name: 'video gen-image', usage: 'vclaw video gen-image --project <slug> --prompt "<text>" --kind prop|screen|overlay [--backend gobananas|openai|flow] [--scene <i>] [--out <path>] [--aspect <ratio>] [--model <id>] [--ref <path|mediaGenerationId>]... [--character <name|ref>]... [--count <1-4>] [--seed <n>] [--character-id <id>] [--style-preset-id <id>] [--dry-run] [--confirm-spend] [--root <path>]', description: 'Generate a diegetic still (prop / on-screen UI dashboard / overlay graphic) and write it under assets/props/. PAID: a real run requires --confirm-spend (exit-3 spend_confirmation_required otherwise); --dry-run plans without spending. Backends: gobananas (default, Go Bananas image API), openai (gpt-image), flow (Google Flow images, through your Google Flow account: nano-banana-2-lite / nano-banana-2 / nano-banana-pro, auto-selected by reference count unless --model pins one). Flow-only flags (rejected on other backends): repeated --ref (reference_1..10 slots; local paths are uploaded first), repeated --character (character_1..7 slots; names resolve via flow-characters.json), --count (images per generation, default 1), --seed. Inline @reference_N/@character_N prompt markers are validated against the provided slots before any upload or spend. Weaves a per-kind render directive into the prompt; screens and overlays keep text (they are UIs/alerts), props suppress it. --dry-run prints the composed request without spending. Register the result into a scene with vclaw video assets.', flags: [{ name: '--project', kind: 'value' }, { name: '--prompt', kind: 'value' }, { name: '--kind', kind: 'value' }, { name: '--backend', kind: 'value' }, { name: '--scene', kind: 'value' }, { name: '--out', kind: 'value' }, { name: '--aspect', kind: 'value' }, { name: '--model', kind: 'value' }, { name: '--ref', kind: 'value' }, { name: '--character', kind: 'value' }, { name: '--count', kind: 'value' }, { name: '--seed', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--root', kind: 'value' }] }, { name: 'video overlay', usage: 'vclaw video overlay --input <video> --output <path> (--graphic <png> | --alert "<text>" | --lower-third "<text>") [--position top-left|top-center|top-right|center|bottom-left|bottom-center|bottom-right|full] [--start <s>] [--end <s>] [--fade-in <s>] [--fade-out <s>] [--opacity <0..1>] [--pulse-hz <n>] [--font-size <n>] [--color <c>] [--dry-run]', description: 'Composite a motion-graphics overlay onto a video via FFmpeg. --graphic overlays a PNG/alpha image (time-gated, faded, positioned) — pairs with gen-image to drop a generated SYSTEM COMPROMISED/dashboard screen onto a clip. --alert burns a pulsing alert and --lower-third a boxed caption (both drawtext, require an ffmpeg built with libfreetype). --dry-run prints the planned ffmpeg command without running it.', flags: [{ name: '--input', kind: 'value' }, { name: '--output', kind: 'value' }, { name: '--graphic', kind: 'value' }, { name: '--alert', kind: 'value' }, { name: '--lower-third', kind: 'value' }, { name: '--position', kind: 'value' }, { name: '--start', kind: 'value' }, { name: '--end', kind: 'value' }, { name: '--fade-in', kind: 'value' }, { name: '--fade-out', kind: 'value' }, { name: '--opacity', kind: 'value' }, { name: '--pulse-hz', kind: 'value' }, { name: '--font-size', kind: 'value' }, { name: '--color', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }] }, { name: 'video mograph-sheet', usage: 'vclaw video mograph-sheet --project <slug> (--from-json <path> [--write] | --show | --master-prompt | --families) [--aspect <w:h>] [--force] [--root <path>]', description: 'Validate + persist the project motion sheet (artifacts/motion-sheet.json) — the single style authority for the motion-graphics lane; the mograph skill authors the JSON. Enforces the ≤120-word style lock (which must carry the do-NOT-copy-the-sheet-layout guard), a negative ending in the five audio bans (no music/soundtrack/voice-over/narration/lyrics), a described stage when locked, and a known style family. --master-prompt composes the deterministic art-direction-board prompt for the sheet reference image (render it via gen-image at the DELIVERY aspect — providers inherit aspect from the attached reference); --families lists the style-family register. A locked sheet refuses overwrite without --force (regenerating a sheet re-styles every future clip).', flags: [ { name: '--project', kind: 'value' }, { name: '--from-json', kind: 'value' }, { name: '--write', kind: 'boolean' }, { name: '--show', kind: 'boolean' }, { name: '--master-prompt', kind: 'boolean' }, { name: '--families', kind: 'boolean' }, { name: '--aspect', kind: 'value' }, { name: '--force', kind: 'boolean' }, { name: '--root', kind: 'value' }, ], }, { name: 'video mograph-pack', usage: 'vclaw video mograph-pack --project <slug> [--init-from <srt|vtt|whisper-json> --video <title> [--sheet <id>] [--aspect <w:h>] [--duration <sec>] [--force] | --check | --stats [--cost-per-clip <usd>] | --assemble <blockId> | --list [--priority P1|P2|P3]] [--root <path>]', description: 'Operate on the motion pack (artifacts/motion-pack.json) — one video\'s coverage map + action-only blocks. --init-from seeds a coverage-only skeleton from a timed transcript (pause-aware ~5s beats grouped into topic-chunk coverage rows; every second gets a decision, blocks stay a creative authoring step). Default / --check is the anti-drift lint gate: unique B### ids, forward time ranges, v2v-requires-videoSource, action ≤90 words (>120 fails), hex codes and style vocabulary banned from actions, quoted on-screen text ≤4 words (≤2 strings), SFX-never-music, one camera behavior, VO-not-in-action, coverage gap/overlap checks — exits non-zero on errors. --stats prints scope counts + cost tiers (P1 / P1+P2 / all); --assemble prints one block\'s exact submitted prompt (style lock + SHOT + AUDIO + AVOID, assembled by code).', flags: [ { name: '--project', kind: 'value' }, { name: '--init-from', kind: 'value' }, { name: '--video', kind: 'value' }, { name: '--sheet', kind: 'value' }, { name: '--aspect', kind: 'value' }, { name: '--duration', kind: 'value' }, { name: '--force', kind: 'boolean' }, { name: '--check', kind: 'boolean' }, { name: '--stats', kind: 'boolean' }, { name: '--cost-per-clip', kind: 'value' }, { name: '--assemble', kind: 'value' }, { name: '--list', kind: 'boolean' }, { name: '--priority', kind: 'value' }, { name: '--root', kind: 'value' }, ], }, { name: 'video mograph-render', usage: 'vclaw video mograph-render --project <slug> [--priority P1|P2|P3] [--block <id> ...] [--route runway-useapi|dreamina-useapi|seedance-direct|veo-useapi|prompt-only] [--enqueue | --plan-only] [--emit-batch <manifest-path>] [--write-sidecars <dir>] [--stitch] [--root <path>]', description: 'Lint-gates and emits the exact per-block contract, then defaults to a canonical render -> hash-verified local post-process DAG in the shared durable Cinema queue; --stitch adds a dependency-ordered local assemble task, --enqueue remains an explicit alias, and --plan-only is non-writing inspection. Provider routes remain awaiting-quote and unclaimable until exact authorization. Refs are transport-aware: Omni image refs are omitted while Seedance-family routes keep the sheet ref. --emit-batch only compiles a legacy-compatible manifest. The former immediate --execute renderer is retired and refuses before provider access.', flags: [ { name: '--project', kind: 'value' }, { name: '--priority', kind: 'value' }, { name: '--block', kind: 'value' }, { name: '--route', kind: 'value' }, { name: '--emit-batch', kind: 'value' }, { name: '--write-sidecars', kind: 'value' }, { name: '--enqueue', kind: 'boolean' }, { name: '--plan-only', kind: 'boolean' }, { name: '--execute', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--stitch', kind: 'boolean' }, { name: '--root', kind: 'value' }, ], }, { name: 'video mograph-logos', usage: 'vclaw video mograph-logos --project <slug> --brand <name> [--brand <name> ...] [--domain <domain>] [--source clearbit|simpleicons|favicon] [--color <tint>] [--size <px>] [--root <path>]', description: 'Fetch real brand marks as reference assets into projects/<slug>/assets/logos/ (keyless source ladder: Clearbit domain PNG -> SimpleIcons SVG -> Google-favicon fallback). Models drawing logos from memory produce mangled near-logos — attach the fetched file as a block reference and prompt "the attached <brand> logo, flat, unmodified" instead. Trademark clearance stays your call; exits non-zero when no source has any requested mark.', flags: [ { name: '--project', kind: 'value' }, { name: '--brand', kind: 'value' }, { name: '--domain', kind: 'value' }, { name: '--source', kind: 'value' }, { name: '--color', kind: 'value' }, { name: '--size', kind: 'value' }, { name: '--root', kind: 'value' }, ], }, { name: 'video motion-overlay', usage: 'vclaw video motion-overlay --input <video-path> (--project <slug> | --output-dir <path>) [--layout split|overlay|motion-only|avatar-host] [--style apple-clean|editorial-dark|knowledge-tool] [--accent <hex>] [--lang <code>] [--max-take-seconds 10] [--transcript <path>] [--render local|v2v] [--delivery local|flow-web|flow-api] [--kicker <label>] [--animate] [--headlines] [--icons] [--emit-flow-pack] [--restitch <dir>] [--gb-character <Name:ID>] [--gb-character-image <path>] [--gb-voice <name>] [--host-engine omni-r2v|veo-i2v] [--host-retries <n>] [--v2v-retries <n>] [--host-look <id>] [--no-host-chain] [--preview] [--root <path>] [--execute] [--dry-run] [--confirm-spend]', description: 'Turn an existing talking-head video into a motion-graphics reel synced to the speech. Plan/dry by default: ingest (ffmpeg) -> Gemini STT (or --transcript) -> sentence-boundary slice into <=10s takes -> per-take Omni V2V prompt composition -> writes a work folder (source/ takes/ frames/ prompts/), README, and motion-overlay-plan.json manifest. No provider spend in plan mode. --execute (Omni Flash V2V render) is gated behind --confirm-spend (exit-3 spend_confirmation_required otherwise). Render transports: Omni Flash V2V (default), local per-frame render (--render local with --animate/--headlines/--icons/--kicker), and avatar-host (--layout avatar-host with --gb-character / --host-engine). --delivery / --emit-flow-pack drive the Flow hand-off loop; --restitch re-stitches an existing work folder.', flags: [ { name: '--input', kind: 'value' }, { name: '--project', kind: 'value' }, { name: '--output-dir', kind: 'value' }, { name: '--layout', kind: 'value' }, { name: '--style', kind: 'value' }, { name: '--accent', kind: 'value' }, { name: '--lang', kind: 'value' }, { name: '--max-take-seconds', kind: 'value' }, { name: '--transcript', kind: 'value' }, { name: '--render', kind: 'value', description: 'Render transport: local (per-frame motion graphics) or v2v (Omni Flash). Default v2v.' }, { name: '--delivery', kind: 'value', description: 'Delivery target: local | flow-web | flow-api.' }, { name: '--kicker', kind: 'value', description: 'Brand label burned into local-render overlays.' }, { name: '--animate', kind: 'boolean', description: 'Local render: per-frame motion graphics (word reveal, count-up, gauge fill).' }, { name: '--headlines', kind: 'boolean', description: 'Local render: kinetic-typography headlines.' }, { name: '--icons', kind: 'boolean', description: 'Local render: stat-bug icons.' }, { name: '--emit-flow-pack', kind: 'boolean', description: 'Emit a Flow hand-off pack instead of rendering.' }, { name: '--restitch', kind: 'value', description: 'Re-stitch an existing work folder at the given path.' }, { name: '--gb-character', kind: 'value' }, { name: '--gb-character-image', kind: 'value', description: 'avatar-host: explicit go-bananas character still path.' }, { name: '--gb-voice', kind: 'value', description: 'avatar-host: voice preset (default Puck).' }, { name: '--host-engine', kind: 'value', description: 'avatar-host engine: omni-r2v (default) or veo-i2v.' }, { name: '--host-retries', kind: 'value', description: 'avatar-host: max retries on probabilistic Flow moderation.' }, { name: '--v2v-retries', kind: 'value', description: 'split/overlay V2V: per-take attempts on probabilistic Flow moderation (default 10; a blocked draw is free).' }, { name: '--host-look', kind: 'value', description: 'avatar-host: look/style preset id.' }, { name: '--no-host-chain', kind: 'boolean', description: 'avatar-host: disable pin+chain identity carry across takes.' }, { name: '--preview', kind: 'boolean', description: 'Emit a preview artifact without spending.' }, { name: '--root', kind: 'value' }, { name: '--execute', kind: 'boolean' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, ], }, { name: 'video music-video', usage: 'vclaw video music-video --config <music-video-config.json> [--work-dir <path>] [--output <path>] [--execute] [--dry-run] [--verify-lip-sync] [--sync-min <0..1>] [--sync-offset-advisory] [--ffmpeg-bin <path>] [--ffprobe-bin <path>]', description: 'Vocal-synced, beat-exact music-video assembler. Reads a config you write (song + clip registry + B-roll pools + an explicit vocal map or a transcript to auto-classify), pins each performer to their own vocal range time-aligned across B-roll cutaways, cuts every segment frame-exact (-frames:v, no drift), then concats + grades + muxes the song. Fully local (ffmpeg only, no provider/spend). PLAN/DRY by default; --execute renders and asserts zero drift.', flags: [ { name: '--config', kind: 'value' }, { name: '--work-dir', kind: 'value' }, { name: '--output', kind: 'value' }, { name: '--execute', kind: 'boolean' }, { name: '--dry-run', kind: 'boolean' }, { name: '--verify-lip-sync', kind: 'boolean' }, // the wrong-words correlation floor (default 0.6): a relaxed-bar lane passes // 0.5 instead of switching verification off entirely. { name: '--sync-min', kind: 'value' }, // right words on the wrong beat: report it instead of refusing to write // the master. `re-render` (wrong words) still blocks. { name: '--sync-offset-advisory', kind: 'boolean' }, { name: '--ffmpeg-bin', kind: 'value' }, { name: '--ffprobe-bin', kind: 'value' }, ], }, { name: 'video stitch-ad', usage: 'vclaw video stitch-ad --clip <path> [--clip <path> ...] --out <path> [--dissolve <sec>] [--width <px>] [--height <px>] [--fps <n>] [--bed <track>] [--bed-level <0-1>] [--sfx <track>] [--sfx-at <sec>] [--sfx-level <0-1>] [--dry-run]', description: 'Assemble ordered scene clips into a short ad: cross-dissolves (xfade video + acrossfade native audio) between shots, with an optional instrumental music bed laid UNDER the native voice (--bed, low --bed-level, fades in/out) and an optional one-shot --sfx at --sfx-at. The native character-ad finishing recipe — pair it after flow-r2v scenes and before title-card / make-vertical. Clips are normalized to a common WxH/fps. Fully local FFmpeg, no spend. --dry-run prints the planned ffmpeg command.', flags: [ { name: '--clip', kind: 'value' }, { name: '--out', kind: 'value' }, { name: '--dissolve', kind: 'value' }, { name: '--width', kind: 'value' }, { name: '--height', kind: 'value' }, { name: '--fps', kind: 'value' }, { name: '--bed', kind: 'value' }, { name: '--bed-level', kind: 'value' }, { name: '--sfx', kind: 'value' }, { name: '--sfx-at', kind: 'value' }, { name: '--sfx-level', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, ], }, { name: 'video title-card', usage: 'vclaw video title-card --input <video> --output <path> (--lower-third "<a||b>" | --end-card "<a||b>" | both) [--lt-start <s>] [--lt-end <s>] [--end-hold <s>] [--title-font <alias|path>] [--body-font <alias|path>] [--title-color <#hex>] [--sub-color <#hex>] [--accent-color <#hex>] [--no-accent] [--python <bin>] [--dry-run]', description: 'Burn music-video TITLE overlays — a faded lower-third early in the cut and/or a centred end card that holds to EOF — onto a finished video. Text is rasterized via Pillow + RAQM (transparent PNG, measure-ink-and-stack), so it works on ANY ffmpeg build (no libfreetype) and ANY script (Devanagari/Arabic). Each PNG is a looped input so delayed alpha fades animate. Fully local, no spend. PLAN/DRY by default; omit --dry-run to render.', flags: [ { name: '--input', kind: 'value' }, { name: '--output', kind: 'value' }, { name: '--lower-third', kind: 'value' }, { name: '--end-card', kind: 'value' }, { name: '--lt-start', kind: 'value' }, { name: '--lt-end', kind: 'value' }, { name: '--end-hold', kind: 'value' }, { name: '--title-font', kind: 'value' }, { name: '--body-font', kind: 'value' }, { name: '--title-color', kind: 'value' }, { name: '--sub-color', kind: 'value' }, { name: '--accent-color', kind: 'value' }, { name: '--no-accent', kind: 'boolean' }, { name: '--python', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, ], }, { name: 'video finish', usage: 'vclaw video finish (--input <video> | --media-id <flow-media-id>) --output <path> [--backend topaz-proteus|topaz-gaia|topaz-starlight|magnific-precision|runway-topaz-free|topaz-local|google-flow] [--scale 1..4] [--target-resolution 720p|1k|2k|4k] [--flow-resolution 720p|1080p|4K] [--grain 0..0.1] [--noise 0..1] [--recover-detail 0..1] [--sharpen] [--normalize] [--topaz-cli <path>] [--dry-run] [--confirm-spend]', description: 'Upscale/finish a rendered video to a clean HD master. Hosted Topaz (Proteus default / Gaia / Starlight) runs through the apiz/xskill service; magnific-precision runs the Magnific Video Upscaler Precision on Magnific\'s own API (needs MAGNIFIC_API_KEY) with --target-resolution 1k|2k|4k — it accepts MP4/MOV/AVI/WebM/MKV and enforces Magnific limits (<=15s, <=450 frames, <=150MB, <=4K input), failing fast unless --normalize re-encodes the clip to fit; topaz-local shells a local Topaz CLI. The anti-plastic detail-not-sharp recipe (noise/sharpen off, grain kept) is on by default; --sharpen disables it. --grain accepts 0..0.1 — Topaz\'s REAL ceiling (its published 0..1 schema lies); out-of-range values are rejected, not silently clamped. Hosted backends are PAID -> refuses without --confirm-spend (exit-3 spend_confirmation_required); --dry-run plans for free. topaz-local is free. google-flow runs GOOGLE\'s own Veo upsampler and is FREE at 720p/1080p (no --confirm-spend needed; --flow-resolution 4K costs 50 credits + Ultra and IS gated) — it takes --media-id instead of --input because Google upscales only a clip Flow GENERATED (an uploaded or stitched file returns 400 INVALID_ARGUMENT), and 720p promotes a clip generated at resolution 360p. Needs APIZ_API_KEY (or XSKILL_API_KEY) for Topaz hosted backends, MAGNIFIC_API_KEY for magnific-precision, USEAPI_API_TOKEN for google-flow.', flags: [ { name: '--input', kind: 'value' }, { name: '--media-id', kind: 'value' }, { name: '--flow-resolution', kind: 'value' }, { name: '--output', kind: 'value' }, { name: '--backend', kind: 'value' }, { name: '--scale', kind: 'value' }, { name: '--target-resolution', kind: 'value' }, { name: '--grain', kind: 'value' }, { name: '--noise', kind: 'value' }, { name: '--recover-detail', kind: 'value' }, { name: '--sharpen', kind: 'boolean' }, { name: '--normalize', kind: 'boolean' }, { name: '--topaz-cli', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, ], }, { name: 'video image-ops', usage: 'vclaw video image-ops --op upscale --input <image> --output <path> [--backend magnific] [--scale 2..16] [--flavor sublime|photo|photo_denoiser] [--sharpen 0..100] [--smart-grain 0..100] [--ultra-detail 0..100] [--logo-safe] [--dry-run] [--confirm-spend]', description: 'Still-image post-processing via Magnific. --op upscale runs the Magnific image upscaler (/v1/ai/image-upscaler-precision-v2, verified live; a different service from the video upscaler) — a local image is base64-encoded inline, an http(s) URL is passed through. --scale 2..16 (default 4), --flavor sublime (default) | photo | photo_denoiser, plus --sharpen/--smart-grain/--ultra-detail (0..100). --logo-safe is the flat-graphics/text preset (sharpen 10, smart-grain 0, ultra-detail 0) so logos do not get hallucinated texture. PAID -> refuses without --confirm-spend (exit-3 spend_confirmation_required); --dry-run plans for free. Needs MAGNIFIC_API_KEY.', flags: [ { name: '--op', kind: 'value' }, { name: '--input', kind: 'value' }, { name: '--output', kind: 'value' }, { name: '--backend', kind: 'value' }, { name: '--scale', kind: 'value' }, { name: '--flavor', kind: 'value' }, { name: '--sharpen', kind: 'value' }, { name: '--smart-grain', kind: 'value' }, { name: '--ultra-detail', kind: 'value' }, { name: '--logo-safe', kind: 'boolean' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, ], }, { name: 'video lipsync', usage: 'vclaw video lipsync --image <path> --audio <path> --output <path> [--resolution 720p|1080p] [--prompt "<text>"] [--turbo] [--no-normalize] [--fps <n>] [--dry-run] [--confirm-spend]', description: 'Audio-driven lip-sync: a still/keyframe + a vocal track -> a lip-synced talking-head clip via OmniHuman v1.5 (apiz/xskill). Uploads image+audio -> submits -> awaits -> downloads -> NORMALIZES to CFR fps (default 24) + even dimensions (OmniHuman returns 25fps/odd dims that break frame-accurate seeking in the assembler). Audio length is checked against the model cap (1080p<=30s, 720p<=60s) up front. Drives an EXTERNAL vocal (unlike motion-overlay avatar-host, which speaks in its own generated voice). PAID -> refuses without --confirm-spend (exit-3); --dry-run plans free. Needs APIZ_API_KEY (or XSKILL_API_KEY).', flags: [ { name: '--image', kind: 'value' }, { name: '--audio', kind: 'value' }, { name: '--output', kind: 'value' }, { name: '--resolution', kind: 'value' }, { name: '--prompt', kind: 'value' }, { name: '--turbo', kind: 'boolean' }, { name: '--no-normalize', kind: 'boolean' }, { name: '--fps', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, ], }, // --- director gate --- { name: 'video director-preflight', usage: 'vclaw video director-preflight --project <slug> [--root <path>] [--apply-content-fixes]' }, { name: 'video storyboard-review', usage: 'vclaw video storyboard-review --project <slug> [--root <path>] [--mode storyboard|director] [--apply-content-fixes]' }, // --- creator / review UI --- { name: 'video creator-ui', usage: 'vclaw video creator-ui [--root <path>] [--host 127.0.0.1] [--port <port>] [--dry-run]', description: 'Launch the secure local Creator UI product shell. It binds loopback only, uses a one-time tokenized URL plus HttpOnly session cookie, and exposes closed typed APIs for canonical Studio planning, project inspection, Pexels stock search/import, and Studio execution bound to a plan digest. Mutations require same-origin proof; execution is dry by default and spend-gated when confirmed. There is no arbitrary command endpoint.', flags: [ { name: '--root', kind: 'value' }, { name: '--host', kind: 'value' }, { name: '--port', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, ], }, { name: 'video creator-demo', usage: 'vclaw video creator-demo --project <slug> [--intent <text>] [--platform generic|youtube-shorts|tiktok|instagram-reels] [--aspect-ratio 16:9|9:16|1:1] [--duration <seconds>] [--root <path>]', description: 'Create a complete zero-key local demo: project, brief, three-scene storyboard, portrait placeholder media, asset manifest, readiness and cost artifacts, plus browser-ready review/preview/run portals. Makes no provider or network calls and does not render a final MP4.', flags: [ { name: '--project', kind: 'value' }, { name: '--intent', kind: 'value' }, { name: '--platform', kind: 'value' }, { name: '--aspect-ratio', kind: 'value' }, { name: '--duration', kind: 'value' }, { name: '--root', kind: 'value' }, ], }, { name: 'video review-ui', usage: 'vclaw video review-ui --project <slug> [--root <path>] [--host <host>] [--allow-remote] [--port <port>] [--ui-path <path>] [--dry-run]', description: 'Launch the authenticated local human-review station. Non-loopback hosts require --allow-remote; wildcard bind addresses are rejected.', flags: [ { name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--host', kind: 'value' }, { name: '--allow-remote', kind: 'boolean' }, { name: '--port', kind: 'value' }, { name: '--ui-path', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, ], }, { name: 'video review-autopilot', usage: 'vclaw video review-autopilot --project <slug> [--root <path>] [--template <template-id>] [--character <name>] [--run-id <id>]' }, { name: 'video portal', usage: 'vclaw video portal --project <slug> [--root <path>] [--client <name>] [--run <id>] [--surface edit|review|client-review|preview|compare|index|run]' }, { name: 'video portal-index', usage: 'vclaw video portal-index [--root <path>] [--client <name>] [--output <path>]' }, { name: 'video publish-preview', usage: 'vclaw video publish-preview --project <slug> --client <name> --bucket <bucket> [--root <path>] [--run <id>] [--surface review|preview|run|index] [--public-base-url <url>] [--wrangler-bin <path>] [--dry-run]' }, { name: 'video publish-portal-index', usage: 'vclaw video publish-portal-index --bucket <bucket> [--root <path>] [--client <name>] [--public-base-url <url>] [--wrangler-bin <path>] [--dry-run]' }, // --- character management --- { name: 'video character-add', usage: 'vclaw video character-add --project <slug> --name <name> [--gb-id <id>] [--description <text>] [--costume <text>] [...] [--root <path>]', flags: [{ name: '--description', kind: 'value' }, { name: '--costume', kind: 'value' }] }, { name: 'video character-auto-create', usage: 'vclaw video character-auto-create --project <slug> --input <json-path> [--root <path>] [--api-url <url>] [--no-sheet] [--reuse-existing] [--sheet-preset <id>] [--dry-run]' }, { name: 'video environment-auto-create', usage: 'vclaw video environment-auto-create --project <slug> --input <json-path> [--root <path>] [--api-url <url>] [--dry-run]' }, { name: 'video show-bible', usage: 'vclaw video show-bible --project <slug> [--title <t>] [--premise <p>] [--style <s>] [--add-episode "id|title|logline"]... [--from-json <path>] [--show] [--root <path>]', description: 'Derive or persist the cartoon-SHOW asset-library index (artifacts/show-bible.json): the repeatable production system that ties the project’s characters + locations + voice clones into one reusable world and tracks the episode list. By default the bible is DERIVED from the project’s existing artifacts and written; --show prints it without writing; --from-json validates+persists a bible you wrote; --add-episode (repeatable) merges episodes by id. Deterministic — no provider calls. Distinct from story-bible (per-project continuity) and director-blueprint (visual direction).', flags: [{ name: '--project', kind: 'value' }, { name: '--title', kind: 'value' }, { name: '--premise', kind: 'value' }, { name: '--style', kind: 'value' }, { name: '--add-episode', kind: 'value' }, { name: '--from-json', kind: 'value' }, { name: '--show', kind: 'boolean' }, { name: '--root', kind: 'value' }] }, { name: 'video show-preflight', usage: 'vclaw video show-preflight --project <slug> [--root <path>] [--mode storyboard|director]', description: 'Fail-fast gate that ENFORCES the cartoon-show method per route. Given the project’s show-bible + storyboard, it confirms every cast/speaking subject in every scene has the references the resolved provider route actually needs — on the Seedance family (seedance-direct / runway-useapi / dreamina-useapi) each cast member’s character sheet + the scene’s location plate + each speaking character’s bound voice clip, plus a specific visual descriptor (not "the man"); on Google Veo (veo-useapi) a character you registered in your Google Flow account. Read-only: prints a JSON blocker report and exits 3 (GATE) when any piece is missing so an && chain or the studio runner halts before a render. A project with no show-bible.json is inert (ready, exit 0). produce/execute apply the same gate when a show-bible exists.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--mode', kind: 'value' }] }, { name: 'video character-import-library', usage: 'vclaw video character-import-library --project <slug> --intent "<text>" [--root <path>] [--api-url <url>]' }, { name: 'video character-list', usage: 'vclaw video character-list --project <slug> [--root <path>]' }, { name: 'video character-show', usage: 'vclaw video character-show --project <slug> --name <name> [--root <path>]' }, { name: 'video character-consistency', usage: 'vclaw video character-consistency --project <slug> [--root <path>]' }, { name: 'video consistency-audit', usage: 'vclaw video consistency-audit --project <slug> [--root <path>] [--json]', description: 'Automated character identity/costume vision audit of the project’s rendered scenes (artifacts/consistency-audit.json). Extracts a representative mid-frame per rendered scene and asks a Gemini-Vision client whether each registered scene character still matches its locked reference face/hair AND costume/colours, plus a deterministic dark-border check and an extra-figure flag. Catches identity/wardrobe drift (e.g. a dhoti rendering crimson in some scenes and tan in others) BEFORE a render is presented as done. Requires a Gemini vision key (GEMINI_API_KEYS / GOOGLE_API_KEY).', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--json', kind: 'boolean' }] }, { name: 'video motion-qc', usage: 'vclaw video motion-qc --project <slug> [--root <path>] [--samples <2-24>]', description: 'Dense-frame motion-artifact vision QC of the project’s rendered clips (artifacts/motion-artifact-qc.json) — the defect classes a still-frame + whisper QC pass is BLIND to. Samples K frames per clip (default 9, denser than consistency-audit) and runs two lanes: a per-frame lane for breath-vapour condensation puffs and film-grain rendering as drifting fog over dark regions, and an adjacent-pair lane (anchored on the scene keyframe when bound) for objects/faces MORPHING between moments, solid props VANISHING mid-clip, and TEMPORAL vapour wisps that only read as a difference between frames. Complements consistency-audit (identity/costume drift), whose prompt deliberately excludes vapour/fog and which never compares adjacent samples. Conservative prompts; transport failures degrade to advisory. Requires a Gemini vision key (GEMINI_API_KEYS / GOOGLE_API_KEY).', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--samples', kind: 'value' }] }, { name: 'video clip-qc', usage: 'vclaw video clip-qc --project <slug> [--samples <2-24>] [--root <path>]', description: 'Per-second headcount over every rendered scene clip. Samples N frames per clip (default 8 - one per second of a standard 8s clip), counts the people in each, and flags headcount-variance (the count CHANGES mid-clip: someone walked into frame) and headcount-exceeds-cast (more people than the scene names: the model invented or duplicated cast). Fills the gap between consistency-audit (ONE mid-frame, identity only) and motion-qc (nine frames, morph/vanish only) - neither counts people, so a figure entering at t~4s is invisible to both. Also writes a per-clip filmstrip contact sheet to projects/<slug>/qc/, which needs no vision key and is the artefact a human actually reads. Emits artifacts/clip-qc.json. Headcount findings are ADVISORY (warning severity): vision counts are approximate, so the value is triage - it points you at the few filmstrips worth opening rather than all of them. A +/-1 spread is treated as boundary noise (calibrated on a live 37-clip run); the real defect signature was a spread of 4.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--samples', kind: 'value' }] }, { name: 'video keyframe-qc', usage: 'vclaw video keyframe-qc --project <slug> [--root <path>] [--cast] [--json]', description: 'Fail-fast PRE-RENDER keyframe readiness gate (artifacts/keyframe-qc.json) — deterministic and offline (pure Node PNG IHDR header parse; no vision model, no spend). Given the storyboard’s scene count it verifies every scene has references/scene<i>-keyframe.png, that each is a readable PNG, and that all keyframes share the dominant WxH; a missing storyboard, missing/unreadable keyframe, or dimension mismatch is an error → status \'fail\' and exit 3 (GATE) so an && chain or driver halts BEFORE produce spends on drifted keyframes (the mechanical half of the Garden Days keyframe-drift lesson: wrong crown / mixed dimensions / missing keyframes shipped because nothing machine-checked them). A uniform-but-non-1280x720 set is advisory-only (pass). Keyframes are resolved through the ASSET MANIFEST (the same mapping buildExecutionPayload uses to pick the start frame for each scene), falling back to the legacy references/scene<i>-keyframe.png name, and both PNG and JPEG are read — before this the gate could not see keyframes named any other way. Opt-in --cast adds a Gemini-Vision pass asking whether every character a shot LISTS is actually visible in the keyframe for that shot: on an image-to-video route the keyframe IS the identity lock, so a listed-but-absent character gets invented by the model (finding code keyframe-cast-missing); a missing key or failed call is an advisory, never a silent pass.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--cast', kind: 'boolean' }, { name: '--json', kind: 'boolean' }] }, // --- reference sheets --- { name: 'video reference-sheet-add', usage: 'vclaw video reference-sheet-add --project <slug> --type <type> --name <name> [...]', flags: [{ name: '--description', kind: 'value' }, { name: '--character-name', kind: 'value' }, { name: '--gb-ref', kind: 'value' }, { name: '--binding', kind: 'value' }] }, { name: 'video reference-sheet-list', usage: 'vclaw video reference-sheet-list --project <slug> [--type <sheet-type>] [--root <path>]' }, { name: 'video reference-sheet-show', usage: 'vclaw video reference-sheet-show --project <slug> --id <sheet-id> [--root <path>]' }, { name: 'video reference-sheet-bind', usage: 'vclaw video reference-sheet-bind --project <slug> --id <sheet-id> --scene <sceneIndex> [...]' }, { name: 'video reference-sheet-validate', usage: 'vclaw video reference-sheet-validate --project <slug> [--root <path>]' }, // --- candidates --- { name: 'video candidates-list', usage: 'vclaw video candidates-list --project <slug> [--scene <sceneIndex>] [--root <path>]' }, { name: 'video candidates-show', usage: 'vclaw video candidates-show --project <slug> --candidate-id <id> [--root <path>]' }, { name: 'video select-candidate', usage: 'vclaw video select-candidate --project <slug> (--scene <sceneIndex> --candidate-id <id> [--notes <text>] | --auto-select [--ref <imagePath> ...] | --adopt-sole [--scene <sceneIndex>]) [--root <path>]' }, { name: 'video reject-candidate', usage: 'vclaw video reject-candidate --project <slug> --scene <sceneIndex> --candidate-id <id> [--notes <text>] [--root <path>]' }, { name: 'video reroll-scene', usage: 'vclaw video reroll-scene --project <slug> --scene <sceneIndex> [--void] [...]', flags: [{ name: '--chain-from-prev', kind: 'value' }, { name: '--void', kind: 'boolean' }, { name: '--verdict', kind: 'value' }, { name: '--flaw', kind: 'value' }, { name: '--changed', kind: 'value' }, { name: '--seed', kind: 'value' }, { name: '--evidence', kind: 'value' }, { name: '--attempt-budget', kind: 'value' }] }, { name: 'video chain-from', usage: 'vclaw video chain-from --project <slug> --scene <sceneIndex> --from <sourceSceneIndex> [...]' }, { name: 'video unchain', usage: 'vclaw video unchain --project <slug> --scene <sceneIndex> [...]' }, // --- templates + clone --- { name: 'video template-list', usage: 'vclaw video template-list [--root <path>]' }, { name: 'video template-show', usage: 'vclaw video template-show --name <template-name> [--root <path>]' }, { name: 'video clone-plan', usage: 'vclaw video clone-plan --template <template-name> --project <slug> --intent <text> [--root <path>]' }, // --- authoring aids --- { name: 'video multi-shot', usage: 'vclaw video multi-shot (--presets | --plan [--shots N] [--seed N] [--genre <id>] [--format default|seedance-paragraph|per-shot|timecoded] [--lang en|zh|en+zh] [--category <id>] [--location <text>] [--time <text>] [--constraints [<text>]] [--shot-line <N>:<prose>] [--hook <patternId>] [--dialogue "<speaker>: <line> [emotion] [|| <speaker>: <line> [emotion]]"] [--emotion-cues] [--vfx <id>] [--optical <id>] [--fov <degrees>] [--cuts oner|sequential|timed|freestyle] [--lipsync [--vocal-ref <slot>]] | --validate [--file <path>] [--explain-issues] | --fix [--file <path>] | --auto --image <path> [--dry-run] [--retry-invalid N] [...]) [--preset <name>] [--provider <name>] [--route <name>] [--from-storyboard --project <slug> --scene <sceneIndex>] [--total-seconds N] [--max-chars N] [--root <path>] [--raw]', description: 'Scaffold, validate, and Gemini-author timecoded multi-shot cinematic prompts, including project storyboard scene hydration.', flags: [ { name: '--style-line', kind: 'value' }, { name: '--audio-line', kind: 'value' }, { name: '--location', kind: 'value' }, { name: '--time', kind: 'value' }, { name: '--action', kind: 'value' }, { name: '--character', kind: 'value' }, ], }, { name: 'video filmmaking-prompts', usage: 'vclaw video filmmaking-prompts --project <slug> [--root <path>] [--duration <seconds>] [--storyboard-grid <path>] [--category <id>] [--genre <id>] [--phase storyboard|video] [--detail terse|standard|rich] [--register prose|numeric] [--aspect-ratio 16:9|9:16|1:1] [--sheet 8-shot|6-panel|3-panel] [--realism] [--no-realism] [--wet] [--haze thin|light|heavy] [--background mid-gray|white|black] [--flat-grade] [--dynamic composed|elevated|kinetic|violent] [--strobe <bpm>] [--lighting <id>] [--grade <id>] [--dialogue "<speaker>: <line> [emotion] [|| <speaker>: <line> [emotion]]"] [--dialogue-scene "<sceneIndex>:<speaker>: <line>"] [--emotion-cues] [--no-faces] [--write]', description: 'Generate ai-filmmaking prompt packets: character sheet prompts, optional attached 9-panel storyboard grid, reference map, and Seedance Variant A/B/C packets. Default is the full photoreal treatment (rich + realism + prose); dial down with --detail/--register/--no-realism or a project cinema-profile.', flags: [{ name: '--checklist', kind: 'boolean' }], }, { name: 'video director-blueprint', usage: 'vclaw video director-blueprint --project <slug> (--from-json <path> [--write] | --show) [--root <path>]', description: 'Validate + persist an AI-Director Project Blueprint (the ai-director skill authors the JSON): visual identity, master color system, lighting grammar, per-character blueprint (silhouette/palette/voice/power-vulnerability-signature framing), environment blueprint (5 sensory words), project camera bible (dominant + forbidden movements + the one rule), and performance rules. The filmmaking-prompts composer reads it back to enrich every scene packet.', }, { name: 'video brand-definition', usage: 'vclaw video brand-definition --project <slug> (--from-json <path> [--write] | --show) [--root <path>]', description: 'Validate + persist the locked brand system (the brand-agency skill authors the JSON): brand name, positioning, taglines, voice rules, 6-color hex palette, typography hierarchy, 12-week theme map, and the vision-verified master asset (go-bananas product ref + Flow character name). The filmmaking-prompts composer reads it back to append a prose BRAND line to every scene packet.', }, { name: 'video prompt-lint', usage: 'vclaw video prompt-lint (--project <slug> | --file <path>) [--storyboard] [--root <path>] [--register prose|numeric] [--cast <Name:descriptor> ...] [--brand <token> ...]', description: 'Pure validator over a filmmaking-prompts artifact: per-packet 13-block order, word-count window, brand/proper-name scrub, grid-guard presence, required SUBJECT LOCK/CAPTURE REALISM/CAMERA CAPTURE blocks, and no Kelvin/hue tokens in a prose-register packet. Storyboard-grid panels get advisory annotation-slug-format (2-6 word uppercase strips) and framing-progression (wide -> medium -> close, climax in the final third) checks; in --project mode each stored character description is checked against the 30-60 word identity budget (>100 errors). Emits {packets:[{sceneIndex,issues}],grid?,characters?,ok} and exits non-zero when not ok. --storyboard switches to a headcount lint over the STORYBOARD scene descriptions instead: unbounded-crowd (error) for phrasings like "four more women behind them" that make the model invent and duplicate people, plus advisory missing-explicit-count and wide-multi-subject.', }, { name: 'video cinema-profile', usage: 'vclaw video cinema-profile --project <slug> [--detail terse|standard|rich] [--register prose|numeric] [--realism on|off] [--no-realism] [--haze thin|light|heavy] [--capture cinema|phone] [--root <path>]', description: 'Set the project-level cinematic look profile (persisted on project.json). Photorealism is the universal default; this dials it down by exception across every subsequent filmmaking-prompts run.', }, { name: 'video cinema-create', usage: 'vclaw video cinema-create --project <slug> --logline <text> [--hero <name>] [--runtime MM:SS|seconds] [--genre <text>] [--tone <text>] [--audience <text>] [--format <text>] [--dialogue none|sparse|dialogue-led] [--budget exploration|controlled|premium] [--boundary <text> ...] [--root <path>]', description: 'Compile and atomically persist the provider-free Cinema planning package: creative contract, story bible, visual/sound law, ten-condition hero recognition plan, geography, five-shot editorial coverage, rights registry and voice registry. The result is intentionally non-executable and records every unresolved gate; it never generates media, calls a provider or authorizes spend.', flags: [ { name: '--project', kind: 'value' }, { name: '--logline', kind: 'value' }, { name: '--hero', kind: 'value' }, { name: '--runtime', kind: 'value' }, { name: '--genre', kind: 'value' }, { name: '--tone', kind: 'value' }, { name: '--audience', kind: 'value' }, { name: '--format', kind: 'value' }, { name: '--dialogue', kind: 'value' }, { name: '--budget', kind: 'value' }, { name: '--boundary', kind: 'value' }, { name: '--root', kind: 'value' }, ], }, { name: 'video cinema-migrate', usage: 'vclaw video cinema-migrate --from-direct-ai-film <path> --project <slug> [--dry-run | --write] [--root <path>]', description: 'Dry-run by default. Inventories and hashes a Direct AI Film project, translates its source shots/assets into native Cinema planning contracts, snapshots canonical text metadata only, and never copies bulk media or imports approvals. --write persists an immutable import receipt while keeping rights, voices, recognition, execution and spend blocked.', flags: [ { name: '--from-direct-ai-film', kind: 'value' }, { name: '--project', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }, { name: '--write', kind: 'boolean' }, { name: '--root', kind: 'value' }, ], }, { name: 'video cinema-history-import', usage: 'vclaw video cinema-history-import --from-direct-ai-film <path> --project <slug> [--clip <id>] --write [--root <path>]', description: 'After the matching metadata migration, reconcile one existing Direct AI Film clip as bounded historical Cinema lineage. Re-hashes source request/job/cost/media/QC evidence, independently probes and copies exactly the clip/contact-sheet/end-frame, appends an unpromoted attempt/outcome, and explicitly authorizes no new work or spend. Requires --write; never contacts a provider.', flags: [ { name: '--from-direct-ai-film', kind: 'value' }, { name: '--project', kind: 'value' }, { name: '--clip', kind: 'value' }, { name: '--write', kind: 'boolean' }, { name: '--root', kind: 'value' }, ], }, { name: 'video cinema-status', usage: 'vclaw video cinema-status --project <slug> [--receipt <compatibility-receipt-id>] [--root <path>]', description: 'Read and validate the current immutable Cinema planning package, or project every task in an immutable compatibility receipt from the current shared durable queue with --receipt. Read-only; never contacts a provider or authorizes spend.', flags: [{ name: '--project', kind: 'value' }, { name: '--receipt', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-approve', usage: 'vclaw video cinema-approve --project <slug> --gate character-sheet|recognition|rights|voice --decision-id <id> --reviewer <id> --reason <text> [--artifact <sheet.json> --evidence <path> ... | --verdict <gate-verdict> --asset <id> --version <id> --condition <id> --evidence <path> ... | --verdict <gate-verdict> --asset <id> --owner <name> --scope <text> --evidence <path> ... | --verdict <gate-verdict> --character <id> --voice-id <id> --audition-evidence <path> ... --release-evidence <path> ...] [--decided-at <iso>] [--root <path>]', description: 'Append one immutable authority decision against the exact current Cinema plan. Evidence paths are read and content-hashed before the decision is accepted. Character-sheet approval validates the single-face/headless-body contract and rehashes every referenced media file; recognition targets one planned condition; rights clearance requires owner/scope evidence; a speaking voice lock requires both audition and release evidence. No media generation and no spend.', flags: [ { name: '--project', kind: 'value' }, { name: '--gate', kind: 'value' }, { name: '--decision-id', kind: 'value' }, { name: '--reviewer', kind: 'value' }, { name: '--reason', kind: 'value' }, { name: '--verdict', kind: 'value' }, { name: '--artifact', kind: 'value' }, { name: '--asset', kind: 'value' }, { name: '--version', kind: 'value' }, { name: '--condition', kind: 'value' }, { name: '--evidence', kind: 'value' }, { name: '--owner', kind: 'value' }, { name: '--scope', kind: 'value' }, { name: '--character', kind: 'value' }, { name: '--voice-id', kind: 'value' }, { name: '--audition-evidence', kind: 'value' }, { name: '--release-evidence', kind: 'value' }, { name: '--decided-at', kind: 'value' }, { name: '--root', kind: 'value' }, ], }, { name: 'video cinema-preflight', usage: 'vclaw video cinema-preflight --project <slug> [--root <path>]', description: 'Persist and return a content-addressed, provider-free readiness report. Character sheet, ten-condition recognition, rights and voice/release are compile gates; route discovery, exact quote and spend authorization remain separate external gates. Never submits media.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-compile', usage: 'vclaw video cinema-compile --project <slug> [--root <path>]', description: 'Compile immutable state-safe per-shot reference packs and five content-addressed shot manifests only after every evidence gate passes. Provider route remains null, submissionAuthorized remains false, and no provider is contacted. Exits with gate code cinema_evidence_required while evidence is unresolved.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-console', usage: 'vclaw video cinema-console --project <slug> [--root <path>]', description: 'Export a self-contained static HTML5 Cinema review console and canonical JSON sidecar from the real persisted project. Shows actual character-sheet media, full-clip filmstrips, all ten recognition conditions, rights/voice evidence, continuity/timed-audio bindings, blockers, detailed queue/lane/lease/retry state and zero-spend status. Read-only; never contacts a provider or authorizes generation.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-console-live', usage: 'vclaw video cinema-console-live --project <slug> --reviewer <id> --role reviewer|editor|director|producer --authority-evidence <path> [--role <role> ...] [--root <path>] [--host <host>] [--allow-remote] [--port <port>] [--dry-run]', description: 'Serve the real Cinema production console through an authenticated session. Live candidate review requires four evidence-bearing lanes and role-scoped authority; promotion requires director or producer authority. The server exposes no provider execution or spend-authorization action and records the launch authority evidence hash with every response.', flags: [{ name: '--project', kind: 'value' }, { name: '--reviewer', kind: 'value' }, { name: '--role', kind: 'value' }, { name: '--authority-evidence', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--host', kind: 'value' }, { name: '--allow-remote', kind: 'boolean' }, { name: '--port', kind: 'value' }, { name: '--dry-run', kind: 'boolean' }], }, { name: 'video cinema-discover', usage: 'vclaw video cinema-discover --project <slug> [--root <path>] [--higgsfield-bin <path>]', description: 'Probe the explicit official Higgsfield CLI route, persist an immutable short-lived capability snapshot when authenticated, and report account balance evidence. Read-only provider discovery only: never quotes, creates, submits, downloads, authorizes spend, installs software, or handles credentials.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--higgsfield-bin', kind: 'value' }], }, { name: 'video cinema-quote', usage: 'vclaw video cinema-quote --project <slug> [--model <id>] [--workflow <id>] [--operation <id>] [--resolution <value>] [--balance-tolerance <amount>] [--higgsfield-bin <path>] [--root <path>]', description: 'Discover the explicit official Higgsfield CLI route, compile byte-exact provider projections for every immutable Cinema shot, request cost only, and persist one expiring all-shot quote. Never invokes generate create, submits work, authorizes spend, mutates provider state, or downloads media.', flags: [{ name: '--project', kind: 'value' }, { name: '--model', kind: 'value' }, { name: '--workflow', kind: 'value' }, { name: '--operation', kind: 'value' }, { name: '--resolution', kind: 'value' }, { name: '--balance-tolerance', kind: 'value' }, { name: '--higgsfield-bin', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-authorize', usage: 'vclaw video cinema-authorize --project <slug> --quote <id> --quote-hash <sha256> --authorization-id <id> --approver <id> --approved-at <iso> --expires-at <iso> --maximum-spend <amount> --evidence <path> ... [--root <path>]', description: 'Persist a separate evidence-bearing approval for every and only job in one immutable quote, then attach its exact per-job caps to the shared durable queue. Requires you to repeat the quote hash and maximum spend. Performs zero provider calls and never submits generation.', flags: [{ name: '--project', kind: 'value' }, { name: '--quote', kind: 'value' }, { name: '--quote-hash', kind: 'value' }, { name: '--authorization-id', kind: 'value' }, { name: '--approver', kind: 'value' }, { name: '--approved-at', kind: 'value' }, { name: '--expires-at', kind: 'value' }, { name: '--maximum-spend', kind: 'value' }, { name: '--evidence', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-execute', usage: 'vclaw video cinema-execute --project <slug> --quote <id> --quote-hash <sha256> --authorization <id> --confirm-spend [--task <queue-task-id>] [--worker <id>] [--higgsfield-bin <path>] [--root <path>]', description: 'Claim and submit exactly one ready task from the shared durable queue through the explicit official Higgsfield CLI route. Revalidates the immutable quote, authorization, projection, balance envelope and LaneQueue ownership; persists submitting before generate create and records the provider job ID before returning. A lost response becomes reconciliation-required and is never blindly resubmitted. Paid and provider-mutating.', flags: [{ name: '--project', kind: 'value' }, { name: '--quote', kind: 'value' }, { name: '--quote-hash', kind: 'value' }, { name: '--authorization', kind: 'value' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--task', kind: 'value' }, { name: '--worker', kind: 'value' }, { name: '--higgsfield-bin', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-sync', usage: 'vclaw video cinema-sync --project <slug> --task <queue-task-id> [--output <path>] [--worker <id>] [--higgsfield-bin <path>] [--root <path>]', description: 'Reconcile one previously submitted official Higgsfield CLI job with generate get. Processing jobs hand off their lease for a later poll; completed video jobs download atomically, verify actual cost under the exact authorization, and automatically enter the existing candidate/selection stores with an immutable lineage receipt. Never creates or resubmits generation.', flags: [{ name: '--project', kind: 'value' }, { name: '--task', kind: 'value' }, { name: '--output', kind: 'value' }, { name: '--worker', kind: 'value' }, { name: '--higgsfield-bin', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-work', usage: 'vclaw video cinema-work --project <slug> --task <queue-task-id> [--worker <id>] [--confirm-provider-call] [--quote <id> --quote-hash <sha256> --authorization <id> --quote-adapter <executable> --confirm-spend] [--root <path>]', description: 'Run or synchronize one batch/pool/chain/mograph task through the shared durable queue. Free Runway Explore submission requires --confirm-provider-call and refuses credits/custom submit overrides. Paid submission requires a bound authorization, repeated exact quote/hash, explicit --confirm-spend and a fresh quote-adapter observation matching the authorized cost, balance, capability, exact payload and source hashes. Later calls reconcile only the persisted provider job ID and require provider-reported actual cost; completion re-hashes media and appends canonical lineage/candidate state.', flags: [{ name: '--project', kind: 'value' }, { name: '--task', kind: 'value' }, { name: '--worker', kind: 'value' }, { name: '--confirm-provider-call', kind: 'boolean' }, { name: '--quote', kind: 'value' }, { name: '--quote-hash', kind: 'value' }, { name: '--authorization', kind: 'value' }, { name: '--quote-adapter', kind: 'value' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-work-quote', usage: 'vclaw video cinema-work-quote --project <slug> --task <queue-task-id> --quote-adapter <executable> [--root <path>]', description: 'Request one authoritative read-only quote for an awaiting paid compatibility task. For veo-useapi the shipped adapter is dist/cli/flow-quote-adapter.js (prices from the account\'s own Flow model table; the free model quotes at 0). The adapter must return exact cost, maximum cost, balance envelope, capability TTL and transport identity; VideoClaw binds those facts to the canonical queue payload, exact execution payload and local reference hashes in the existing immutable snapshot/quote/projection artifacts. This command never submits generation and never authorizes spend.', flags: [{ name: '--project', kind: 'value' }, { name: '--task', kind: 'value' }, { name: '--quote-adapter', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-ingest', usage: 'vclaw video cinema-ingest --project <slug> --task <queue-task-id> [--root <path>]', description: 'Bridge one succeeded Cinema video task into the existing VideoClaw scene-candidate and selection stores. Re-hashes downloaded bytes, preserves queue/attempt/shot/provider/cost lineage in an immutable receipt, and leaves the completed candidate pending for review. Idempotent and provider-free; never generates media or authorizes spend.', flags: [{ name: '--project', kind: 'value' }, { name: '--task', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-review', usage: 'vclaw video cinema-review --project <slug> --task <queue-task-id> --review-id <id> --reviewer <id> --authority-evidence <path> --decision pass|reject|redesign --lane <lane>=pass|fail ... --reason <lane>=<text> ... --evidence <lane>=<path> ... [--story-purpose-verified] [--changed-variable <field>] [--reviewed-at <iso>] [--root <path>]', description: 'Record one immutable human review of a completed Cinema candidate across exactly four independent lanes: technical, identity-continuity, performance and editorial. The reviewer requires separately byte-hashed authority evidence; every lane requires its own evidence and reason. Pass additionally requires explicit story-purpose verification. Reject/redesign updates the existing selection store but never mutates generation history. Provider-free.', flags: [{ name: '--project', kind: 'value' }, { name: '--task', kind: 'value' }, { name: '--review-id', kind: 'value' }, { name: '--reviewer', kind: 'value' }, { name: '--authority-evidence', kind: 'value' }, { name: '--decision', kind: 'value' }, { name: '--lane', kind: 'value' }, { name: '--reason', kind: 'value' }, { name: '--evidence', kind: 'value' }, { name: '--story-purpose-verified', kind: 'boolean' }, { name: '--changed-variable', kind: 'value' }, { name: '--reviewed-at', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video cinema-promote', usage: 'vclaw video cinema-promote --project <slug> --review <id> --promotion-id <id> --reviewer <id> --editorial-slot <slot> --evidence <path> ... [--supersedes <promotion-id>] [--decided-at <iso>] [--root <path>]', description: 'Promote only an all-lane passed, story-verified Cinema review into an append-only generation-ledger promotion and the existing VideoClaw scene selection. Requires separate byte-hashed authority evidence, preserves asset-manifest inputs, and requires an exact superseded promotion when replacing a select. Provider-free and idempotent.', flags: [{ name: '--project', kind: 'value' }, { name: '--review', kind: 'value' }, { name: '--promotion-id', kind: 'value' }, { name: '--reviewer', kind: 'value' }, { name: '--editorial-slot', kind: 'value' }, { name: '--evidence', kind: 'value' }, { name: '--supersedes', kind: 'value' }, { name: '--decided-at', kind: 'value' }, { name: '--root', kind: 'value' }], }, { name: 'video storyboard-grid', usage: 'vclaw video storyboard-grid --project <slug> [--root <path>] [--output <path>] [--width <px>] [--height <px>] [--image <path> ...] [--images <a,b,c>] [--dry-run]', description: 'Render a deterministic storyboard story-sheet PNG from the filmmaking-prompt panels — each cell shows the shot beat plus a CAM/MOVE/MOOD slug strip. Pass --image (repeatable, panel order) or a comma-separated --images list to embed the actual keyframe stills into the cells; omitted cells stay empty placeholders. Marks the grid reference ready for execution.', }, { name: 'video seedance-register-assets', usage: 'vclaw video seedance-register-assets --project <slug> --character <name>:<imageUrl> [--character ...] [--group <name>] [--root <path>]', description: 'Register character reference images as xskill Asset Library avatars (Asset:// URIs) for ark/seedance-2.0 character consistency; writes artifacts/seedance-assets.json.', }, { name: 'video flow-register-characters', usage: 'vclaw video flow-register-characters --project <slug> --input <json-path> [--root <path>]', description: 'Register reusable Google Flow characters (locked identity + optional bundled voice) from a JSON array of {name,images,voice?}; writes artifacts/flow-characters.json. Scene characters then resolve to character_1..7 on veo-useapi. R2V-routed; the Veo 3.1 reference-to-video path now clears photoreal human faces (live-proven), so register real people directly and render scenes with vclaw video flow-r2v.', }, { name: 'video flow-r2v', usage: 'vclaw video flow-r2v --prompt "<text>" --character <name|ref> [--character ...] --out <path> [--project <slug>] [--root <path>] [--duration 8] [--aspect landscape|portrait] [--keep-music] [--allow-reverb] [--no-upscale] [--retries <n>] [--cooldown <sec>] [--dry-run]', description: 'Render ONE Google Flow Reference-to-Video (R2V) scene directly from saved Flow characters — the native character-ad workflow. Each --character is a friendly name (resolved via artifacts/flow-characters.json when --project is set) or a raw character ref → character_1..7 (lock the person AND the product in one scene). Dialogue lives inline in --prompt; Veo generates the voice + lip-sync natively. Uses veo-3.1-fast (R2V; no startImage) at 8s — the only length Veo reference-to-video generates. The finished clip is upscaled to 1080p through Google\'s own free upsampler unless --no-upscale is passed. By default applies the dry-voice (close-mic, no reverb) + no-baked-music hygiene so a post music bed sits cleanly under the native voice — opt out with --keep-music / --allow-reverb. A 403 reCAPTCHA throttle is cooled-down-and-retried (--retries / --cooldown). --dry-run prints the composed request without spending.', }, { name: 'video flow-register-voices', usage: 'vclaw video flow-register-voices --project <slug> --input <json-path> [--root <path>]', description: 'Register reusable Google Flow custom voices from a JSON array of {name,basePreset,dialog,voicePerformance}; writes artifacts/flow-voices.json.', }, // --- overnight batch video queue --- { name: 'video batch-submit', usage: 'vclaw video batch-submit --manifest <path> --project <slug> [--enqueue] [--out <dir>] [--route runway-useapi|dreamina-useapi|seedance-direct] [--root <path>]', description: 'Compiles the exact per-job execution tasks/profile into the shared durable Cinema queue for --project, without requiring --out, calling a provider or authorizing spend; --enqueue remains an explicit alias and paid tasks remain awaiting-quote. The former --execute submit path is retired and fails before provider access.', flags: [{ name: '--manifest', kind: 'value' }, { name: '--out', kind: 'value' }, { name: '--project', kind: 'value' }, { name: '--route', kind: 'value' }, { name: '--enqueue', kind: 'boolean' }, { name: '--execute', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--root', kind: 'value' }], }, { name: 'video batch-monitor', usage: 'vclaw video batch-monitor --out <dir> [--once] [--interval <sec>] [--max-minutes <n>] [--stall-minutes <n>] [--fail-wedged]', description: 'Historical compatibility monitor: poll an already-submitted batch, download completed clips to <dir>/clips/<jobId>.mp4, and refresh <dir>/batch-status.json. --once does a single pass; without --once it loops until terminal/deadline with throttle backoff. --stall-minutes flags wedged scenes and --fail-wedged can mark them failed. The former auto-resubmit mutation is retired and fails before provider access.', flags: [{ name: '--out', kind: 'value' }, { name: '--once', kind: 'boolean' }, { name: '--interval', kind: 'value' }, { name: '--max-minutes', kind: 'value' }, { name: '--stall-minutes', kind: 'value' }, { name: '--fail-wedged', kind: 'boolean' }, { name: '--auto-resubmit', kind: 'boolean' }, { name: '--max-resubmits', kind: 'value' }], }, { name: 'video batch-status', usage: 'vclaw video batch-status --out <dir>', description: 'Print the current batch queue-state rollup (done/pending/failed) without polling (read-only).', }, // --- portfolio + status --- { name: 'video list', usage: 'vclaw video list [--root <path>]' }, { name: 'video index', usage: 'vclaw video index [--root <path>] [--output <path>]' }, { name: 'video monitor', usage: 'vclaw video monitor [--port <n>] [--root <path> ...]' }, { name: 'video migrate-home', usage: 'vclaw video migrate-home [--confirm] [--root <home>]', description: 'Consolidate scattered projects (~/.videoclaw-* roots) into the one canonical workspace home (~/videoclaw): mv each project in, leave a symlink at the old path so old absolute paths still resolve. Dry-run by default (prints the move plan); --confirm performs the moves. Collision-safe (slug clashes get a -2/-3 suffix) and idempotent (already-symlinked dirs are skipped).' }, { name: 'video lane', usage: 'vclaw video lane <acquire|await|heartbeat|release|receipt|status|history> --route <routeId> [--account <id>] [--project <slug>] [--scene <i>] [--ticket <id>] [--limit <n>] [--ttl <sec>] [--max-wait <sec>] [--prompt <text>] [--prompt-hash <hash>] [--outcome <completed|failed|timeout|lease-lost|not-submitted|slot-busy|abandoned> [--job <id>] [--note <text>]] [--receipt-id <id> --phase <phase> --payload <json> [--content-hash <hash>]]', description: 'Local development or Cloudflare-shared multi-computer provider lanes. Lane key is route:account (limits are per account). With VCLAW_SHARED_QUEUE_REQUIRED=1, missing/unreachable remote coordination fails before provider access and never falls back to SQLite. Enforced acquire/await requires a stable prompt identity; receipts append immutable reference/submission evidence to an exact shared ticket; leases expire so a dead holder cannot wedge the queue.', flags: [{ name: '--route', kind: 'value' }, { name: '--account', kind: 'value' }, { name: '--project', kind: 'value' }, { name: '--scene', kind: 'value' }, { name: '--ticket', kind: 'value' }, { name: '--limit', kind: 'value' }, { name: '--ttl', kind: 'value' }, { name: '--max-wait', kind: 'value' }, { name: '--prompt', kind: 'value' }, { name: '--prompt-hash', kind: 'value' }, { name: '--receipt-id', kind: 'value' }, { name: '--phase', kind: 'value' }, { name: '--payload', kind: 'value' }, { name: '--content-hash', kind: 'value' }] }, { name: 'video metrics', usage: 'vclaw video metrics [--root <path>] [--mode storyboard|director]' }, { name: 'video next-actions', usage: 'vclaw video next-actions [--root <path>] [--mode storyboard|director]' }, { name: 'video report', usage: 'vclaw video report [--root <path>] [--mode storyboard|director]' }, { name: 'video status', usage: 'vclaw video status --project <slug> [--root <path>] [--mode storyboard|director]' }, { name: 'video doctor-project', usage: 'vclaw video doctor-project --project <slug> [--root <path>] [--mode storyboard|director]' }, { name: 'video doctor-portfolio', usage: 'vclaw video doctor-portfolio [--root <path>] [--mode storyboard|director]' }, // --- export + obsidian --- { name: 'video export-csv', usage: 'vclaw video export-csv [--root <path>] [--output-dir <path>] [--mode storyboard|director]' }, { name: 'video export-obsidian', usage: 'vclaw video export-obsidian --project <slug> [--root <path>] [--output-dir <path>] [--mode storyboard|director]' }, { name: 'video sync-obsidian', usage: 'vclaw video sync-obsidian [--root <path>] [--output-dir <path>] [--mode storyboard|director]' }, // --- veo (Bun bridge for Google Flow) --- { name: 'veo status', usage: 'vclaw veo status [batchId]', description: 'Show status of current or specific Veo batch.' }, { name: 'veo list', usage: 'vclaw veo list', description: 'List all Veo batches.' }, { name: 'veo history', usage: 'vclaw veo history [--limit <n>]', description: 'Show recent Veo job history.' }, { name: 'veo resume', usage: 'vclaw veo resume [batchId]', description: 'Resume a paused Veo batch.' }, { name: 'veo reset', usage: 'vclaw veo reset', description: 'Reset failed Veo jobs to pending.' }, { name: 'veo cancel', usage: 'vclaw veo cancel', description: 'Cancel current Veo batch.' }, { name: 'veo useapi:accounts', usage: 'vclaw veo useapi:accounts list|add [--cookies <path>]', description: 'Manage useapi.net accounts (via Bun bridge).' }, { name: 'veo useapi:captcha', usage: 'vclaw veo useapi:captcha list | --provider <name> --key <key>', description: 'Manage useapi.net CAPTCHA providers.' }, { name: 'veo useapi:health', usage: 'vclaw veo useapi:health', description: 'useapi.net account health + history.' }, { name: 'veo useapi:image', usage: 'vclaw veo useapi:image --image-prompt "<text>" [--image-model nano-banana-2-lite|nano-banana-2|nano-banana-pro] [--ref <url> ...] [--yes]', description: 'Generate images via useapi.net (the Nano Banana family; Google removed Imagen from Flow in July 2026 and the imagen-4 id is now an alias for nano-banana-2-lite).' }, { name: 'veo useapi:image:upscale', usage: 'vclaw veo useapi:image:upscale --media-id <id> --resolution 2k|4k', description: 'Upscale a nano-banana-pro image.' }, { name: 'veo useapi:gif', usage: 'vclaw veo useapi:gif --media-id <id> --output-file <path>', description: 'Convert a Veo video to GIF (free, no CAPTCHA).' }, { name: 'veo useapi:upscale', usage: 'vclaw veo useapi:upscale --media-id <id> --resolution 720p|1080p|4k', description: 'Upscale a Flow-generated video. 720p and 1080p are FREE on a paid plan (720p promotes a clip generated at --video-resolution 360p); 4k costs 50 credits and needs Ultra.' }, // --- mcp server --- { name: 'mcp serve', usage: 'vclaw mcp serve', description: 'Start the videoclaw MCP server (stdio) exposing read-only project introspection to MCP-aware agent hosts.' }, // --- human-friendly studio planner --- { name: 'studio', usage: 'vclaw studio [--dry-run] [--goal create-video|creator-demo|copy-reference|presenter-video|music-video|ugc-campaign|existing-project|review-regenerate|publish-deliver|brand-campaign|character-video] [--project <slug>] [--title <title>] [--intent <text>] [--input <path-or-url>] [--client <name>] [--duration <seconds>] [--platform generic|youtube-shorts|tiktok|instagram-reels] [--aspect-ratio 16:9|9:16|1:1] [--source-mode original-ai|stock-assisted|local-media] [--audio-mode none|narration|music|narration-and-music] [--execution-intent plan|render|publish-package] [--write-session] [--execute] [--confirm-spend] [--auto-approve-storyboard] [--from-step <id>] [--root <path>]', description: 'Generate a guided Studio production plan from high-level goals. Includes creator-demo for zero-key local onboarding. Plan-only by default. With --execute it RUNS the emitted plan by shelling out to the same vclaw video commands (not a second orchestrator). Dry-by-default: spend steps run with --dry-run and a spend step lacking --dry-run is refused; the human checkpoint is the director storyboard gate, surfaced as a blocked step. --confirm-spend promotes the dry spend steps to REAL renders (storyboard approval still required out-of-band); add --auto-approve-storyboard for an unattended render (sets VIDEOCLAW_APPROVE_STORYBOARD in the child). --from-step <id> resumes after an approval. Reports an execution block with per-step status + mode (dry|confirm-spend|auto-render).', flags: [ { name: '--dry-run', kind: 'boolean' }, { name: '--goal', kind: 'value' }, { name: '--project', kind: 'value' }, { name: '--title', kind: 'value' }, { name: '--intent', kind: 'value' }, { name: '--input', kind: 'value' }, { name: '--client', kind: 'value' }, { name: '--duration', kind: 'value' }, { name: '--platform', kind: 'value' }, { name: '--aspect-ratio', kind: 'value' }, { name: '--source-mode', kind: 'value' }, { name: '--audio-mode', kind: 'value' }, { name: '--execution-intent', kind: 'value' }, { name: '--write-session', kind: 'boolean' }, { name: '--execute', kind: 'boolean' }, { name: '--confirm-spend', kind: 'boolean' }, { name: '--auto-approve-storyboard', kind: 'boolean' }, { name: '--from-step', kind: 'value' }, { name: '--root', kind: 'value' }, ], }, // --- keyframe tools --- { name: 'video outpaint-keyframe', usage: 'vclaw video outpaint-keyframe --input <path> --output <path> [--width <px>] [--height <px>] [--mask-dilation <frac>] [--fill gobananas|none] [--prompt <text>] [--size <WxH>] [--project <slug>] [--root <path>]', description: 'Pad a keyframe image onto a target canvas (default 1920×1080, centred letterbox) and build an RGBA alpha inpainting mask (transparent border = fill, opaque centre = preserve) for the border region. --fill none (the default) writes the padded letterbox only (deterministic, offline). --fill gobananas uploads the padded source + mask to go-bananas and runs a masked gpt-image-2 edit (requires GO_BANANAS_API_KEY).', flags: [ { name: '--input', kind: 'value', description: 'Source keyframe image path.' }, { name: '--output', kind: 'value', description: 'Output PNG path.' }, { name: '--width', kind: 'value', description: 'Target canvas width in pixels (default 1920).' }, { name: '--height', kind: 'value', description: 'Target canvas height in pixels (default 1080).' }, { name: '--mask-dilation', kind: 'value', description: 'Mask dilation as a fraction of the smaller canvas dimension (default 0.03).' }, { name: '--fill', kind: 'value', description: 'Fill backend: gobananas (uploads source + mask, runs a masked gpt-image-2 edit, requires GO_BANANAS_API_KEY) or none (default; writes the padded letterbox only).' }, { name: '--prompt', kind: 'value', description: 'Outpaint instruction for --fill gobananas (overrides the default extend-the-scene prompt).' }, { name: '--size', kind: 'value', description: 'Optional gpt-image-2 output size for --fill gobananas (e.g. 1536x1024).' }, { name: '--project', kind: 'value', description: 'Optional project slug for output-path resolution context.' }, { name: '--root', kind: 'value', description: 'Workspace root (default cwd).' }, ], }, // --- project metadata + estimation --- { name: 'video set-meta', usage: 'vclaw video set-meta --project <slug> [--root <path>] [--owner <name>] [--priority low|medium|high|critical] [--due YYYY-MM-DD] [--tag <value> ...]', flags: [{ name: '--blocked-by', kind: 'value' }, { name: '--blocked-reason', kind: 'value' }] }, { name: 'video set-execution-profile', usage: 'vclaw video set-execution-profile --project <slug> [--root <path>] [--aspect-ratio 16:9|9:16|1:1] [--quality fast|quality] [--resolution 720p|1080p] [--audio on|off] [--outputs 1-4] [--veo-model fast|quality|lite|free|omni-flash] [--veo-resolution 360p|720p|none]', flags: [{ name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video cost-estimate', usage: 'vclaw video cost-estimate [--project <slug>] [--root <path>] [--scenes <count>] [--clip-duration <seconds>] [--new-characters <count>]', flags: [{ name: '--narration', kind: 'value' }] }, { name: 'video archive-project', usage: 'vclaw video archive-project --project <slug> [--root <path>] [--archive-dir <path>] [--cleanup]' }, { name: 'video artifact-history', usage: 'vclaw video artifact-history --project <slug> --artifact <name> [--root <path>]' }, // --- character / prompt library --- { name: 'video list-library', usage: 'vclaw video list-library [--name-regex <pattern>] [--root <path>]' }, { name: 'video find-library', usage: 'vclaw video find-library --intent "<text>" [--api-url <url>]' }, { name: 'video library', usage: 'vclaw video library find --intent "<text>" [--api-url <url>]' }, { name: 'video prompt-lib-list', usage: 'vclaw video prompt-lib-list' }, { name: 'video prompt-lib-show', usage: 'vclaw video prompt-lib-show --name <reference-name> [--root <path>]' }, { name: 'video playbook-list', usage: 'vclaw video playbook-list [--root <path>]' }, { name: 'video playbook-show', usage: 'vclaw video playbook-show --name <playbook-name> [--root <path>]' }, // --- templates + clone-from-template --- { name: 'video template-save', usage: 'vclaw video template-save --project <slug> --name <template-name> [--root <path>]' }, { name: 'video template-create', usage: 'vclaw video template-create --project <slug> --name <template-name> [--root <path>]' }, { name: 'video template-validate', usage: 'vclaw video template-validate --name <template-name> [--root <path>]' }, { name: 'video storyboard-template-list', usage: 'vclaw video storyboard-template-list' }, { name: 'video storyboard-template-show', usage: 'vclaw video storyboard-template-show --name <template-id>' }, { name: 'video clone-init', usage: 'vclaw video clone-init --template <template-name> --project <slug> --intent <text> [--root <path>] [--mode storyboard|director] [--platform <name>]', flags: [{ name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video clone-execute', usage: 'vclaw video clone-execute --template <template-name> --project <slug> --intent <text> [--root <path>] [--mode storyboard|director] [--platform <name>]', flags: [{ name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video clone-ad', usage: 'vclaw video clone-ad --template <template-name> --project <slug> --intent <text> [--root <path>] [--mode storyboard|director] [--platform <name>]', flags: [{ name: '--veo-model', kind: 'value' }, { name: '--veo-resolution', kind: 'value' }] }, { name: 'video storyboard-from-clone', usage: 'vclaw video storyboard-from-clone --project <slug> [--root <path>] [--mode storyboard|director]' }, { name: 'video import-legacy', usage: 'vclaw video import-legacy --source <path> [--root <path>]' }, // --- scene-candidate maintenance --- { name: 'video storyboard-still-add', usage: 'vclaw video storyboard-still-add --project <slug> --scene <sceneIndex> --image-url <url> [--image-id <id>] [--prompt <text>] [--notes <text>] [--root <path>]', flags: [{ name: '--image-id', kind: 'value' }, { name: '--prompt', kind: 'value' }, { name: '--notes', kind: 'value' }] }, { name: 'video candidates-migrate-from-assets', usage: 'vclaw video candidates-migrate-from-assets --project <slug> [--root <path>]' }, // --- portfolio reporting + analysis --- { name: 'video workload', usage: 'vclaw video workload [--root <path>] [--mode storyboard|director]' }, { name: 'video dependencies', usage: 'vclaw video dependencies [--root <path>] [--mode storyboard|director]' }, { name: 'video report-snapshot', usage: 'vclaw video report-snapshot [--root <path>] [--mode storyboard|director]' }, { name: 'video report-history', usage: 'vclaw video report-history [--root <path>]' }, { name: 'video report-diff', usage: 'vclaw video report-diff [--root <path>] [--from <snapshot-path>] [--to <snapshot-path>]' }, { name: 'video trends', usage: 'vclaw video trends [--root <path>]' }, { name: 'video analyze', usage: 'vclaw video analyze --project <slug> --source <path-or-url> [--auto] [--root <path>]', flags: [{ name: '--pacing', kind: 'value' }, { name: '--motion', kind: 'value' }, { name: '--beat', kind: 'value' }, { name: '--keep', kind: 'value' }, { name: '--change', kind: 'value' }, { name: '--var', kind: 'value' }] }, { name: 'video analyze-template', usage: 'vclaw video analyze-template --project <slug> --source <path-or-url> [--auto] [--root <path>]', flags: [{ name: '--pacing', kind: 'value' }, { name: '--motion', kind: 'value' }, { name: '--beat', kind: 'value' }, { name: '--keep', kind: 'value' }, { name: '--change', kind: 'value' }, { name: '--var', kind: 'value' }] }, // --- local media post-production --- { name: 'video remix-narrated', usage: 'vclaw video remix-narrated --project <slug> [--root <path>] [--output <path>]' }, { name: 'video verify-final', usage: 'vclaw video verify-final (--project <slug> | --file <path>) [--root <path>] [--output-dir <path>]' }, { name: 'video cinema-archive', usage: 'vclaw video cinema-archive --project <slug> [--root <path>] [--archive-dir <path>]', description: 'Create a byte-inventoried Cinema project archive with an immutable adjacent receipt. Rejects symbolic links and performs no provider call or generation.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--archive-dir', kind: 'value' }] }, { name: 'video cinema-restore', usage: 'vclaw video cinema-restore --archive <path> --destination-root <new-empty-path>', description: 'Restore a receipt-bound Cinema archive only into a new or empty workspace root, then re-hash every file and revalidate canonical Cinema planning, queue and lineage.', flags: [{ name: '--archive', kind: 'value' }, { name: '--destination-root', kind: 'value' }] }, { name: 'video cinema-deliver', usage: 'vclaw video cinema-deliver --project <slug> [--root <path>] [--ffmpeg-bin <path>]', description: 'Materialize every active evidence-promoted Cinema shot into the existing VideoClaw edit layout, assemble locally, run media/final verification, and persist a content-addressed delivery manifest. No provider calls or generation.', flags: [{ name: '--project', kind: 'value' }, { name: '--root', kind: 'value' }, { name: '--ffmpeg-bin', kind: 'value' }] }, { name: 'video qc', usage: 'vclaw video qc --project <slug> [--root <path>]' }, { name: 'video make-vertical', usage: 'vclaw video make-vertical (--project <slug> | --file <path>) [--write-plan-template <json> | --reframe-plan <json>] [--captions <srt|vtt|json>] [--caption-profile social-large|social-standard] [--strict | --quick-center-crop] [--root <path>] [--output <path>]', description: 'Create a 9:16 variant. --write-plan-template detects shot boundaries and writes unverified subject-anchor suggestions. A verified reframe plan enables shot-specific fixed/linear/contain crops, portrait-native captions, subject-anchor QC and automatic media QC. --strict requires a plan or explicit --quick-center-crop.', flags: [{ name: '--project', kind: 'value' }, { name: '--file', kind: 'value' }, { name: '--write-plan-template', kind: 'value' }, { name: '--reframe-plan', kind: 'value' }, { name: '--captions', kind: 'value' }, { name: '--caption-profile', kind: 'value' }, { name: '--strict', kind: 'boolean' }, { name: '--quick-center-crop', kind: 'boolean' }, { name: '--root', kind: 'value' }, { name: '--output', kind: 'value' }] }, { name: 'video make-square', usage: 'vclaw video make-square (--project <slug> | --file <path>) [--root <path>] [--output <path>]' }, { name: 'video make-loop', usage: 'vclaw video make-loop (--project <slug> | --file <path>) [--root <path>] [--output <path>]' }, { name: 'video thumbnail', usage: 'vclaw video thumbnail (--project <slug> | --file <path>) [--root <path>] [--output <path>] [--text <title>]' }, { name: 'video burn-subtitles', usage: 'vclaw video burn-subtitles (--project <slug> | --file <path>) --subtitle <path> [--root <path>] [--output <path>]' }, // --- exports --- { name: 'video scaffold-obsidian-vault', usage: 'vclaw video scaffold-obsidian-vault [--output-dir <path>]' }, // --- introspection --- { name: 'schema', usage: 'vclaw schema [--json]', description: 'Dump the full v3 contract (commands, flags, artifact schemas, error codes, exit codes) for agent introspection.' }, ]; function loadArtifactSchemas(): Record<string, unknown> { const here = dirname(fileURLToPath(import.meta.url)); const schemasDir = join(here, '..', '..', 'schemas', 'video', 'artifacts'); const out: Record<string, unknown> = {}; let entries: string[]; try { entries = readdirSync(schemasDir); } catch (err: unknown) { // Directory missing is expected in some test envs. Anything else // (permission denied, etc.) is genuinely unexpected. if ((err as NodeJS.ErrnoException).code === 'ENOENT') { return out; } throw err; } for (const file of entries) { if (!file.endsWith('.schema.json')) continue; const name = file.replace(/\.schema\.json$/, ''); const raw = readFileSync(join(schemasDir, file), 'utf-8'); // JSON.parse errors propagate — a corrupt schema should fail loudly. out[name] = JSON.parse(raw); } return out; } /** * The CLI's own version, read from the bundled package.json rather than * hardcoded — a literal here silently went 7 releases stale (alpha.1 while the * package was alpha.8), and `cli-schema.test.ts` only asserted it was a string. */ export function loadPackageVersion(): string { const here = dirname(fileURLToPath(import.meta.url)); const raw = readFileSync(join(here, '..', '..', 'package.json'), 'utf-8'); return (JSON.parse(raw) as { version: string }).version; } export function buildSchemaDump(): SchemaDump { return { version: loadPackageVersion(), generatedAt: new Date().toISOString(), exitCodes: { ...ExitCode }, errorCodes: ALL_ERROR_CODES, commands: COMMANDS, artifactSchemas: loadArtifactSchemas(), multiShot: { presets: listMultiShotPresets(), issueExplanations: listMultiShotIssueExplanations(), }, }; }