Scripts & tooling
This is the operator and agent reference for videoclaw's own repo tooling — every npm script defined in package.json, and every helper under scripts/. These are the commands you run on the codebase itself: building it, testing it, smoke-proving the whole pipeline, and guarding against drift before changes land. (For commands you run to make videos, see the CLI reference — vclaw video ... — not this page.)
One command to remember
Before you change anything non-trivial, run npm run check:release-readiness-lite. It is the single pre-flight: it builds, runs every unit test, runs the main smokes, and runs the guardrails — in one shot. If it prints release-readiness-lite checks passed, you are clear.
Everything here is deterministic and offline by default. The smokes create throwaway projects in a temp directory, drive the real CLI end-to-end, assert the on-disk artifacts, and then delete the temp dir. None of them spend provider credits, call an API, or need a key — they stub providers and use --dry-run. The one exception (smoke:assemble-render) actually spawns FFmpeg locally and self-skips if FFmpeg is not installed.
How a run flows

Diagram source (live Mermaid)
Build & test
Run these constantly. build is a prerequisite for everything else — the smokes and test:node run against compiled dist/, never the TypeScript source.
| Script | Command | Purpose |
|---|---|---|
| build | npm run build | Wipe dist/, run tsc, then chmod +x the two CLI bins (vclaw, vclaw-provider-adapter). The clean rebuild every other script depends on. |
| dev | npm run dev | tsc --watch — incremental recompile while you edit. Leave it running in a terminal during development. |
| test | npm test | Full gate: build then test:node. The canonical "did I break the unit suite" command. |
| test:node | npm run test:node | Re-run the compiled node:test suite (dist/tests/*.test.js) without rebuilding. Use after dev has already recompiled, for a fast inner loop. Runs single-threaded (--test-concurrency=1). |
| demo | npm run demo | build then node scripts/demo-quickstart.mjs — runs the quickstart demo walkthrough against the freshly compiled CLI. |
| demo:record | npm run demo:record | bash scripts/record-demo.sh — records the demo walkthrough (does not rebuild first). |
Never edit dist/
dist/ is generated. Edit src/, then npm run build. Editing compiled output is silently discarded on the next build.
End-to-end smokes
Each smoke:* script runs npm run build first, then drives the real vclaw binary through a complete slice of the pipeline in an isolated temp project and asserts the resulting JSON artifacts. They are your proof that the wiring — CLI → domain modules → on-disk artifacts — actually holds together, not just that units pass in isolation. Run the relevant smoke after touching the area it covers; run them all via the release pre-flight before shipping.
| Script | Command | What it verifies |
|---|---|---|
| smoke:runtime | npm run smoke:runtime | The core happy path: init → brief → storyboard → assets → execution-plan → execute --dry-run → status → report → export-obsidian. Confirms the dry-run produces a plan, the portfolio report sees the project, and the Obsidian note is written. |
| smoke:native-veo | npm run smoke:native-veo | The native Veo (veo-useapi) transport. Stubs the local Bun vclaw-cli binary, runs a storyboard-mode execute, and captures the exact command the transport would have run — proving the Veo route assembles its submission correctly. |
| smoke:character-hydration | npm run smoke:character-hydration | Create-time cast hydration. Stands up a fake Go Bananas API server, runs vclaw video create with --import-library-characters and --auto-create-characters, and asserts imported character IDs land in the brief and the characters.json store. |
| smoke:execution-cancel | npm run smoke:execution-cancel | Adapter- and project-level cancellation. Wires a stub UseAPI adapter, submits, then execute-cancel, and asserts the execution-report.json and an execution.cancelled event were written. |
| smoke:portfolio | npm run smoke:portfolio | Portfolio visibility: index → report → export-csv. Confirms a project surfaces in the index, the report metrics, and a well-formed projects CSV. |
| smoke:reference-sheets | npm run smoke:reference-sheets | The role-tagged reference-sheet surface end-to-end: reference-sheet-add/list/show/bind/validate, role-vocabulary rejection (non-zero exit), palette collision detection, status summary, and the on-disk reference-sheets.json artifact. |
| smoke:scene-candidates | npm run smoke:scene-candidates | The candidate/take operator surface: select-candidate, reject-candidate, reroll-scene, candidates-list, candidates-show, plus the Candidates section rendered into storyboard.md and a clean doctor-project run. |
| smoke:story-bible-image | npm run smoke:story-bible-image | Image-only story-bible continuity: create builds a deterministic story bible, --apply-content-fixes regenerates scene text without going stale, doctor-project accepts it, and a --dry-run execute reaches dry-run-complete with zero video outputs through review → publish. Never submits a provider job. |
| smoke:assemble | npm run smoke:assemble | The FFmpeg assemble/stitch layer in dry-run. Asserts the plan threads narration (TTS) → slide-animation → final-video in order, records the stitch ffmpeg plan, and writes assemble-report.json. Needs no FFmpeg and no key. |
| smoke:assemble-render | npm run smoke:assemble-render | Real FFmpeg render validation (the only non-dry smoke). Synthesizes inputs with FFmpeg lavfi + sharp, then actually renders MP4s and ffprobes them for h264/aac, resolution, fps, stream counts, durations, MP4-validity, and both demuxer and filter stitch paths plus music mixing. Self-skips and exits 0 if FFmpeg/ffprobe are not on PATH. Validates plumbing/codecs only — aesthetic quality still needs a human. |
| smoke:multi-shot | npm run smoke:multi-shot | A plan→validate round-trip across every registered multi-shot preset (cinematic-15s, seedance-10s, veo-8s, runway-10s). Fixture-driven, fully offline, no Gemini. |
| e2e:image-storyboard | npm run e2e:image-storyboard | The image-storyboard workflow end-to-end, with --verify-server (exercises the review-station UI surface). |
| e2e:image-storyboard:examples | npm run e2e:image-storyboard:examples | The same workflow with --include-examples — runs the bundled example manifests in addition to the default. |
Running a single smoke
Every smoke is a standalone Node script. After one npm run build, you can re-run just the compiled CLI driver directly — e.g. node scripts/smoke-assemble.mjs — to iterate fast without rebuilding each time.
Guardrails (check:*)
The check:* scripts are drift guards. They don't test runtime behavior; they assert the repo's invariants stay true — docs don't reference dead paths, schemas and writers stay in sync, helper wrappers still parse, and verification artifacts stay gitignored. Run the relevant guard after editing docs, skills, schemas, or artifact writers.
| Script | Command | Purpose |
|---|---|---|
| check:movie-director-wrappers | npm run check:movie-director-wrappers | bash -n syntax-checks the six bundled movie-director helper scripts (auto, iterate, run-pipeline, verify, list-library, interview). Catches a broken wrapper before it ships. |
| check:cleanroom-docs | npm run check:cleanroom-docs | Scans README.md, docs/, and the movie-director / seedance-prompts skills for stale clean-room references — absolute home paths, retired CLI invocations, and other dead pointers — failing if any are found. |
| check:skill-frontdoor | npm run check:skill-frontdoor | Scans every skills/*/SKILL.md front door for retired script references, ensuring each skill's entry doc points at the current vclaw CLI surface. The ignore list (e.g. seedance-prompts/SKILL.md) is load-bearing — do not "fix" it. |
| check:artifact-schema-coverage | npm run check:artifact-schema-coverage | Advisory (always exits 0). Asserts every artifact written via the typed writeArtifact() helper has a matching JSON Schema under schemas/video/artifacts/, and every schema has a writer (with a documented allowlist for artifacts written by other paths). Prints any drift. |
| check:artifact-schema-coverage:strict | npm run check:artifact-schema-coverage:strict | The same coverage check in strict mode — exits 1 on drift. Use in CI or when you want a hard failure on writer/schema mismatch. |
Release pre-flight
| Script | Command | Purpose |
|---|---|---|
| prepublishOnly | (automatic) | npm test — npm lifecycle hook that runs the full build + test:node gate automatically before npm publish. You never invoke it directly. |
| check:release-readiness-lite | npm run check:release-readiness-lite | The one-shot local gate. It checks that the generated verification-artifact paths are gitignored, then runs, in order: build → test:node → the eight primary smokes (runtime, native-veo, character-hydration, execution-cancel, portfolio, reference-sheets, scene-candidates, assemble) → the e2e:image-storyboard workflow → all three doc/skill guardrails → the advisory schema-coverage check. Prints release-readiness-lite checks passed on success. |
What the pre-flight does not cover
By design, check:release-readiness-lite excludes smoke:assemble-render (needs real FFmpeg) and the :strict schema check (advisory drift is tolerated mid-flight). Run those two manually when the area is in scope.
When to run what
| Situation | Run |
|---|---|
| Actively editing TypeScript | npm run dev in a terminal, then npm run test:node to re-check |
| Quick "did I break units" check | npm test |
| Touched the assemble / FFmpeg layer | npm run smoke:assemble, then npm run smoke:assemble-render locally |
| Touched docs, skills, or schemas | the matching check:* guard |
| About to commit anything non-trivial | npm run check:release-readiness-lite |
| Wiring schema coverage into CI | npm run check:artifact-schema-coverage:strict |
For agents
Treat check:release-readiness-lite as the success signal: a clean run is evidence the change is safe. Prefer running the narrow smoke for the area you touched first (fast feedback), then the full pre-flight before declaring done. Smokes are self-cleaning and side-effect-free, so they are always safe to run.
