venice-video-harness
v2.25.0
Published
Standalone consistency-first video production CLI powered by the Venice API
Maintainers
Readme
Venice Video Harness
A standalone, Venice-optimized CLI for consistency-first video creation at any length.
Install it, enter a Venice API key, and create films directly from the terminal. No coding agent, IDE extension, or MCP host is required. The same repository also includes optional orchestration material for agent-driven workflows.
If you are an AI agent driving this CLI, read Driving this from an agent before running any command. The pipeline is gated and the commands are order-dependent;
--helpalone is not enough to operate it, and several stages spend money at queue time.
Use it for:
- Character-consistent video projects (any genre, any length)
- Visual-style-locked series or campaigns
- Storyboard-to-video workflows
- Short-form and long-form narrative content (mini-dramas, documentaries, explainers)
- Branded cinematic sequences, trailers, and teasers
- Recurring-character social series
- Any multi-shot Venice workflow where continuity matters
- Text-first editing of existing footage — transcribe sources with local whisper.cpp, read the 12KB pack, propose a cut, render with 30ms audio fades, then self-eval at every cut boundary. Inspired by browser-use/video-use.
What This Is
Most Venice integrations are thin wrappers around API calls. This package is the higher-level production layer:
- Standalone
venice-videoCLI with setup, diagnostics, self-update, project creation, generation, QA, assembly, and export commands - Direct Venice API client with retries, rate limiting, deprecation warnings, and async media polling
- Persistent project state for characters, locations, episodes, references, recipes, and provenance
- Comprehensive model registry covering Venice video, image, audio, and music models
- Optional agent orchestration in
AGENTS.mdand.agents/for users who want natural-language operation
Installing the CLI
For a human at a terminal. (Driving it from an agent instead? See the next section.)
Prerequisites: Node 20+, and ffmpeg + ffprobe on PATH (used for video/audio processing; venice-video doctor checks all three).
Global install (recommended)
npm install -g venice-video-harness
venice-video setup # prompts for your Venice API key + default project workspace
venice-video doctor # verifies API key, ffmpeg, ffprobesetup prompts interactively (the API key prompt is hidden); for non-interactive use pass --api-key <key> and --workspace <dir>, or set VENICE_API_KEY in the environment. --skip-validation stores the key without contacting Venice.
The install puts three commands on PATH:
venice-video— the primary CLIvideo-harness— alias for the same CLIstoryboard— the legacy screenplay-ingestion CLI
From there:
venice-video pipeline # the ordered stages, their gates, and the command that advances each
venice-video shell # persistent interactive session: select a project once, background renders, /jobs
venice-video --help # everything elseFrom source (development)
git clone https://github.com/jordanurbs/venice-video-harness.git
cd venice-video-harness
npm install
npm run build
# Run via tsx during development, or the compiled CLI:
npm run dev -- pipeline
node dist/mini-drama/cli.js pipelinePut the API key in .env at the repo root (VENICE_API_KEY=...) — many scripts source it from there — or run setup as above.
Driving this from an agent
Instructions for a coding agent operating the harness — Claude Code, Cursor, Hermes Agent, OpenClaw, OpenCode, Codex, or anything else with a shell tool. Read this section in full before the first command.
Pick your surface, and know what it gives you
Three surfaces exist. They differ in how much of the harness's operating knowledge reaches you, which is the single largest predictor of output quality.
| Surface | How it runs | What you get | Use when |
|---|---|---|---|
| Repo-resident agent | Agent's cwd is a clone of this repo | Everything: AGENTS.md (55 rules, 31 anti-patterns), .agents/commands/, .agents/agents/, .agents/skills/, .cursor/rules/ | Authoring and iteration — the best results by a wide margin |
| MCP | venice-video-mcp (on npm) shells out to this CLI | 7 action-discriminated tools, structured JSON responses, progress notifications, plus 4 companion skills carrying the pipeline order | Any agent that supports MCP — Hermes, OpenClaw, Cursor, Claude — with no clone required |
| Bare global CLI | npm install -g, shell tool, --help | The compiled CLI, this README, AGENTS.md, .agents/skills/, and the self-describing commands below (agent-guide, pipeline) | When your runner has a shell but no MCP — start with venice-video agent-guide |
Quick start for Hermes and OpenClaw (no clone, no absolute paths)
Both packages are on npm, so an agent whose entire environment is a global install and a chat box has a complete, knowledge-bearing setup. Nothing here requires cloning a repo or hand-writing a path.
Tried the harness or MCP before and got poor results? Earlier global installs shipped only the compiled CLI — no
AGENTS.md, no skills, no MCP on npm — so the agent was guessing from--help. That is fixed now.HERMES-AGENT-SETUP.mdis a paste-ready prompt that upgrades a stale global, registers the MCP, installs the Hermes skills, and points the agent at the operating rules — run it once and re-set-up cleanly.
# 1. Install both globally. The harness ships AGENTS.md + .agents/skills/;
# the MCP ships its 7 tools and 4 companion skills.
npm install -g venice-video-harness venice-video-mcp --foreground-scripts
# 2. Point the harness at a workspace and confirm the environment.
export VENICE_API_KEY=vn_...
export VENICE_VIDEO_WORKSPACE=~/VeniceVideos
venice-video doctor # checks API key, ffmpeg, ffprobe
venice-video agent-guide # the core operating rules, inside the binary
# 3a. Hermes — register the MCP by its published bin (it is on PATH now):
hermes mcp add venice-video --command venice-video-mcp
hermes mcp test venice-video # confirm the handshake
venice-video-mcp-install-skills --target hermes # skills → ~/.hermes/skills/venice/
# 3b. OpenClaw / any MCP runner — same idea, using whatever the runner's
# "add MCP server" command is, with command `venice-video-mcp` and the
# env below. Install its skills into the runner's skills dir:
venice-video-mcp-install-skills --dir <that runner's skills dir>When both are installed globally, the MCP finds venice-video on your PATH
automatically — you do not need HARNESS_BIN or HARNESS_PATH. The only
required env for the MCP process is VENICE_API_KEY, plus VENICE_VIDEO_WORKSPACE
(or HARNESS_WORKSPACE) if you want projects somewhere other than the cwd. See
Registering the MCP server for the details and the
one case where you do set a path (pointing at a local build).
OpenClaw's exact MCP-registration and skills-directory conventions are not yet
verified here; the shapes above are what to adapt. venice-video-mcp-install-skills
--target openclaw currently errors on purpose rather than guessing a path — pass
--dir once you know it.
The bare-CLI trap, and how to check whether you are in it. Through version
2.9.0 the npm package published only dist, README.md, CHANGELOG.md,
LICENSE, and scripts/postinstall.mjs. AGENTS.md and .agents/ were left
out, so an agent working from a global install of those versions had no access to
the anti-patterns, the model-routing rules, or the pipeline playbooks. It saw a
flat list of 40-plus commands with no ordering information and no indication of
which stages were gated. That is the most common reason agent-driven runs produce
poor output, and it is a knowledge problem rather than a capability problem.
From 2.10.0 onward the package ships AGENTS.md plus the knowledge pack
(commands/, agents/, skills/ — under .claude/ through 2.13.x, under the
provider-neutral .agents/ from 2.14.0). Check what your install actually has:
ls "$(npm root -g)/venice-video-harness/AGENTS.md"If that file is present, read its "Agent Rules" and "Learned Anti-Patterns" sections before generating anything. If it is missing, you are on an older package and must do one of the following first:
- Upgrade, then read the shipped
AGENTS.md. - Register the MCP server (see below). It carries the pipeline order in its companion skills and returns JSON instead of prose.
- Clone this repo and work inside it, so
AGENTS.mdand.agents/load from the working tree. - Read
AGENTS.mdfrom GitHub and hold its rules in context for the session.
.cursor/rules/ is intentionally repo-only; it is IDE configuration, not
operating knowledge.
The CLI describes itself (start here on any surface)
From 2.11.0 the essential knowledge travels inside the binary, so even a bare
global install is not knowledge-free. Three things to run first, all of which
support --json for machine consumption:
venice-video agent-guide # the core rules: gates, queue-time billing, long-render handling
venice-video pipeline --json # the ordered stages, their gates, and the next command for each
venice-video status -p <dir> --json # where a project stands and the exact command to run nextagent-guide is the ~80/20 subset of AGENTS.md — read it before generating
anything, then reach for the full rules and playbooks when you need depth. The
same core rules are installable as a skill for runners that pull skills from
GitHub: hermes skills install jordanurbs/venice-video-harness/venice-agent-guide
(and any of the other .agents/skills/ by name).
From 2.15.0 the probe-verified model registry is also machine-readable:
venice-video capabilities # full capability manifest as JSON: model specs, capability sets, budgets, routing defaultsThe same manifest is committed as capabilities.json at the repo root
(regenerated on every release), so downstream clients — the Venice Video
Creator macOS app is the first — can fetch
https://raw.githubusercontent.com/jordanurbs/venice-video-harness/main/capabilities.json
and stay capability-synced between their own releases without shelling out to
the CLI.
Running the harness in a separate runtime (containers, remote backends)
Running long renders off the main machine is a real and useful capability. In Hermes it is the terminal backend, configured independently of any agent protocol:
# ~/.hermes/config.yaml
terminal:
backend: local # local | docker | ssh | modal | daytona | singularity
timeout: 180
lifetime_seconds: 300A remote or containerized backend is a good fit for this harness, because renders
are long, CPU-idle, and network-bound — exactly the work you want off a laptop.
But the harness keeps state on disk, so four things have to be true before a
non-local backend produces usable output:
| Requirement | Why |
|---|---|
| venice-video, ffmpeg, ffprobe installed in the runtime image | The default images are generic Node/Python; none of the three is present |
| VENICE_API_KEY reaches the runtime | Via the backend's env passthrough, not your shell |
| VENICE_VIDEO_WORKSPACE on a persistent volume | Renders land next to the process. On an ephemeral container they are deleted with it |
| A retrieval step back to the host | Nothing copies masters/ or output/ home for you |
The trap specific to this harness. pending-jobs.json — the record that makes
an interrupted render re-attachable instead of re-billable — is written to the
per-machine config directory (~/Library/Application Support/venice-video on
macOS, ~/.config/venice-video on Linux). In an ephemeral runtime that directory
dies with the container, so a render that was already queued and billed becomes
unrecoverable: the new runtime has no record to re-attach to. If you run renders
in a container, mount the config directory persistently, or keep generation on a
local/persistent backend and use the remote runtime only for assembly.
Long renders need a background invocation, not a longer timeout
This applies to every agent runner with a command timeout, and it is a common cause of half-finished runs that look like harness failures.
generate-videos, assemble-episode, produce-episode, finish, and
upscale routinely run 3–10 minutes. Hermes's terminal tool defaults to a
180-second timeout and hard-caps a foreground command at 600s, rejecting
anything higher with a note to use background=true with
notify_on_complete=true. A foreground render therefore gets killed partway
through on the default settings.
Because Venice bills at queue time, a killed render is already paid for. So:
- Run every generation or assembly stage as a background command with completion notification, not a foreground call with a raised timeout.
- If one does get killed, re-run the identical command — see below on re-attaching. Do not treat the kill as a failed render and start over.
- Raise
terminal.timeoutonly for the short commands (status,doctor,validate-*); it is the wrong tool for a 10-minute render.
Registering the MCP server
Published package (recommended — no clone, no absolute paths). The
venice-video-mcp bin is on your PATH after a global install, and it finds the
venice-video harness the same way:
npm install -g venice-video-harness venice-video-mcp
# Hermes Agent
hermes mcp add venice-video --command venice-video-mcp
hermes mcp test venice-video # confirm the handshake before relying on it
# Cursor / Claude Desktop / any runner that reads a JSON config:
# "venice-video": { "command": "venice-video-mcp", "env": { "VENICE_API_KEY": "vn_..." } }
# or, with no global install at all, run it on demand:
# "venice-video": { "command": "npx", "args": ["-y", "venice-video-mcp"], "env": { … } }Local build (development / running ahead of npm). Point the server at a built clone instead. This runs whatever you have checked out:
hermes mcp add venice-video --command node \
--args /ABS/PATH/venice-video-mcp/bin/venice-video-mcp.js
# plus HARNESS_BIN or HARNESS_PATH in the env, see belowEnvironment for the server process:
| Variable | Purpose |
|---|---|
| VENICE_API_KEY | Required. Forwarded to the harness |
| HARNESS_WORKSPACE | Where projects are created. Must already exist. Falls back to the cwd, which is rarely right for a GUI-launched runner — set it |
| HARNESS_BIN | Optional. Absolute path to dist/mini-drama/cli.js in a built clone. Set only to pin a specific local build |
| HARNESS_PATH | Optional. Absolute path to a built clone. Fallback for a local build — see below |
With both packages installed globally you set none of the three harness paths:
the server finds venice-video on PATH. You only reach for HARNESS_BIN /
HARNESS_PATH when you deliberately want a local checkout instead of the published
CLI.
Resolution order (fixed in venice-video-mcp 0.4.0). The server resolves the
harness as HARNESS_BIN, then HARNESS_PATH/dist/mini-drama/cli.js, then a
venice-video on PATH. An explicit HARNESS_PATH outranks an ambient global
install, because setting it is a statement of intent — the old order let a stale
global silently win over a clone you pointed at deliberately. The server also logs
the resolved binary once to stderr ([venice-video-mcp] harness: …) on the first
tool call, so the choice is never silent.
Every MCP response includes the exact command it ran, so you can confirm which binary answered:
{ "ok": true, "command": "node /path/to/harness/dist/mini-drama/cli.js list-series" }If that shows a path under a global npm prefix when you meant to use a clone,
HARNESS_BIN is missing.
Then install its companion skills, which carry the pipeline order the tool
descriptions deliberately leave out. From a global install the command is on
PATH (use node /ABS/PATH/venice-video-mcp/bin/install-skills.js … for a clone):
venice-video-mcp-install-skills --global # Claude/Cursor: ~/.claude/skills/
venice-video-mcp-install-skills --target hermes # Hermes: ~/.hermes/skills/venice/
venice-video-mcp-install-skills --dir <path> # any other runner's skills dirThe four skills are venice-mcp-pipeline (request-to-tool-call mapping and the
gate flowchart), venice-mcp-cookbook (one worked example per action),
venice-mcp-directing (shot-prompt quality), and venice-mcp-troubleshooting
(every known failure mode). Without them the MCP tools are thin per-command
wrappers and you will reconstruct the pipeline by trial and error. Claude Code and
Cursor read .claude/skills/ (their convention — the installer symlinks there);
Hermes reads ~/.hermes/skills/, so --target hermes installs a venice
category there. Any other runner: pass --dir with its skills path. This repo's
own knowledge pack lives provider-neutrally in .agents/.
Preflight: run these three checks first
venice-video --version # must match the docs you are reading
venice-video doctor # API key, ffmpeg, ffprobe
venice-video status -p <dir> # pipeline stage + the next command to runVersion-drift check is not optional. Releases can lag commits, so the
published npm latest may trail this repo. Documentation for a version newer
than your installed binary describes flags it rejects:
$ venice-video new --intelligence kimi-k3
error: unknown option '--intelligence'If --version does not match the version documented here, either upgrade or
work from the --help output of the binary you actually have. Never construct a
command from documentation you have not version-matched. When upgrading, pass
the prefix explicitly, because a global install can silently land in a different
Node prefix than the venice-video on your PATH:
npm install -g venice-video-harness@latest --prefix "$(npm prefix -g)" --foreground-scripts
command -v venice-video && venice-video --versionSet the workspace explicitly — always
The project workspace resolves to VENICE_VIDEO_WORKSPACE, then the stored
config value, then ./output relative to the current working directory. A
daemon-launched or GUI-launched agent has an arbitrary cwd, so projects get
created in unpredictable places and every later -p lookup fails.
export VENICE_VIDEO_WORKSPACE=~/VeniceVideosPass -p <project> and -e <episode> explicitly on every command. The
use / unuse selection is stored in user config and is meant for a human in
venice-video shell; an agent inheriting whatever the operator last selected is
a silent-wrong-project bug.
The pipeline is gated. This is the order
new -> workshop -> workshop --approve -> [references] -> storyboard-episode
|
v
qa-storyboard -> qa-approve
|
v
generate-videos -> qa-videos -> generate-music -> assemble-episode -> finish[references] = add-character / generate-location-references / generate-storyboard-refs.
Workshop approval materializes characters and locations as data only; storyboard-episode
blocks until each scripted character and location has reference images on disk.
Three gates block progress by design:
| Gate | Cleared by | Blocks |
|---|---|---|
| Script approval | workshop --approve or approve-script | storyboard-episode |
| Storyboard QA | qa-approve, after qa-storyboard reports no critical issues — the approval reads the report, and criticals/unchecked shots require --force | generate-videos |
| Video QA | qa-videos writing a passing video-qa-report.json (cross-unit identity, head glitches, boundary jumps) — a failing report blocks; a missing one warns | assemble-episode |
Do not route around a gate. --skip-approval and --skip-qa exist for
operators who have already reviewed the work by other means. An agent that hits
a gate error and retries with a skip flag is spending money to render
unreviewed panels, which is the exact outcome the gate prevents. When a gate
blocks you, run venice-video status -p <dir>, which reports the stage and
prints the next command in full copy-pasteable form, and clear the gate properly.
produce-episode runs the whole pipeline in one command. It is not a reliable
unattended path on a clean project, because it reaches stages that require a QA
approval artifact that does not exist yet. Prefer the explicit stage-by-stage
sequence.
Money is spent at queue time, so never blind-retry a render
Venice charges when a render is queued, not when it is downloaded. A lost
queue_id is money already spent.
- Every queued render is recorded in
pending-jobs.jsonkeyed by output path before the first poll. If a generation command is interrupted, re-run the identical command with the identical output path — the harness re-attaches to the in-flight job and resumes polling. Do not "start fresh." - Inspect in-flight work with
venice-video queue. Onlyqueue cleara record you know is dead. Do not delete a pending record to silence a warning. venice-video queueis Venice's side of the work; the shell's/jobsis only the current session's background commands. Different lists.- A render produces no output for long stretches. That is normal, not a hang. Do not kill and reissue a quiet command; see the timeout note above for how to invoke these stages in the first place.
- Use
POST /video/quote(surfaced by the CLI before paid steps) to price a run before committing.finishprints an estimate and requires--yesto proceed.
Parsing output
The CLI is written for humans reading a terminal, but the agent-facing commands now also emit JSON:
--jsonon the agent-facing commands —status,pipeline,agent-guide,doctor, andqueue(plus a globalvenice-video --json <command>) print exactly one JSON object on stdout, or use the MCP server, which returns{ ok, message, paths, data, warnings, ... }asstructuredContent. Commands without--jsonstill print prose — parse those conservatively.- Exit codes are honest (from 2.11.0).
venice-video statuswith no project now exits non-zero, not 0.$?is a reliable success signal for the agent-facing commands. - Ordinary errors are a clean
error:line, not a stack trace (from 2.11.0). A usage error in a non-TTY prints the message and exits 1; setVENICE_VIDEO_DEBUG=1to see the stack. - Deprecation warnings go to stderr, prefixed
⚠ MODEL DEPRECATION:, once per unique model/date pair. Surface them; they are the early signal that a model is about to start failing.
Interactive commands, and how to run them non-interactively
new and workshop prompt when attached to a TTY. In a non-TTY they require
their arguments up front. A complete non-interactive project creation:
export VENICE_VIDEO_WORKSPACE=~/VeniceVideos
venice-video new \
--type film \
--name "signal-drift" \
--concept "A radio astronomer starts hearing her own voice in the background noise" \
--genre "science fiction" \
--setting "a decommissioned desert array, present day" \
--audio-strategy native \
--video-family seedance
venice-video workshop -p ~/VeniceVideos/signal-drift \
--outcome "Leave viewers unsettled by the signal" \
--duration "3 minutes" \
--audience "science fiction short-film viewers"
venice-video workshop -p ~/VeniceVideos/signal-drift --status
venice-video workshop -p ~/VeniceVideos/signal-drift --approve
venice-video status -p ~/VeniceVideos/signal-driftnew requires at minimum --type, --name, and --concept without a TTY;
everything else falls back to a default rather than prompting.
The rules that most affect output quality
Full text lives in AGENTS.md > "Agent Rules" (55 rules) and "Learned
Anti-Patterns" (30 entries). If you can only carry a few, carry these:
- Direct the scene, don't decorate it. Name one intention for the beat and derive camera, light, blocking, performance, and sound from it. Stacking "cinematic / epic / 4k / masterpiece" adjectives gives the model nothing to serve.
- Prefer 15s shots. Two 15s shots beat five 6s shots on identity stability, motion completion, continuity, and cost. Reserve short durations for deliberate quick beats.
- Prefer Seedance native multi-shot for any 2–3 beat scene. One generation
with
Lens switch.separators holds identity, environment, and lighting across the beats and costs roughly 3× less than three separate renders. (Since 2026-08-05 the planner does this by default: multi-shot units render on Seedance R2V Enhanced with the full reference slot plan.) - Front-load style. Aesthetic descriptions go at the start of a prompt, not the end, or style drifts across angles.
- Keep Seedance prompts under 60 words, using Subject, Action, Camera, Style, Constraints.
- Never group shots with different characters into one multi-shot unit. Cuts between different speakers must be separate singles so each gets its own identity anchoring.
- Re-anchor every separately-rendered shot to the same locked references and restate the character's invariant traits — including relative size — in every prompt.
- State placement explicitly — spatial consistency is authored, not
inferred. Lock each location's landmark geography in
Location.spatialAnchorsand give every character shot ablockingfield: each subject's position relative to the named anchors, screen side, depth, and facing/eyeline. Keep screen sides and eyelines constant across a scene's shots unless a movement is scripted (180-degree rule). The harness injects both verbatim into panel, blocking-plate, and video prompts. - Pass
aspectRatioexplicitly on reference-to-video generation. - Never multi-edit close-up face shots on 16:9 panels. The square-to-16:9 crop removes roughly 25% top and bottom, losing foreheads and chins.
- Archive prior renders; never delete generated shot assets.
- Validate model capabilities before sending
elements,reference_image_urls,scene_image_urls,end_image_url, oraudio_url. The registry issrc/venice/models.tsin a clone; from a global install use.agents/skills/venice-video-model-routing/SKILL.mdor the model tables below. - Ask before burning in subtitles, and derive caption timings from
ffmpeg silencedetecton the rendered voiceover rather than estimating them.
Checkpoints where you should stop and ask
The harness is quality-first and several stages are expensive and hard to undo. Stop for confirmation before: rendering an EDL cut, replacing native dialogue with TTS, burning in subtitles, upscaling to a 4K master, and any run whose quote you have not shown the operator. Post a short summary of what you are about to do and wait.
Supported Venice Models
Video Models
Live catalog (synced against GET /api/v1/models?type=video — 103 entries). Families the harness routes to today; private / -video-to-video / -extend-video variants exist in the live catalog but aren't surfaced here.
| Family | Image-to-Video | Text-to-Video | Max Duration | Audio | Special Features |
|--------|---------------|---------------|-------------|-------|-----------------|
| Seedance 2.0 | i2v, R2V | t2v | 15s | Yes (stereo, lip-sync 8+ langs) | #1 ranked. R2V: flat reference_image_urls, @Image tags. Default routing target. |
| Seedance 2.0 Fast | i2v, R2V | t2v | 15s | Yes | Cheaper / faster Seedance 2.0 variant. Same 4-15s ladder, same provenance gate. |
| Seedance 1.5 Pro | i2v | t2v | 12s | Yes | Older Seedance line; kept for parity. |
| HappyHorse 1.1 | i2v, R2V (up to 9 refs) | t2v | 15s | Yes (joint single-pass, 7-lang phoneme lip-sync) | #1 blind-preference T2V + I2V (Alibaba 15B). 3-15s, 720p/1080p, nine aspect ratios. Best for talking characters + multilingual localization; SFW/commercial-leaning. The happyhorse video-family now routes here. |
| HappyHorse 1.0 | i2v, R2V | t2v | 15s | Yes | Prior line, kept for back-compat. Livelier hand-camera realism / cinematic grain vs Seedance. |
| MiniMax H3 | i2v, R2V (up to 9 refs) | t2v | 15s (5s floor) | Yes (native stereo, not toggleable) | Open-weight omni-modal model — one net covers T2V/I2V/reference. 2K is the only resolution (no draft tier) at ~1/3 the per-second cost of other families; 24fps, 2500-char prompts. The minimax-h3 video-family routes here. Sub-5s durations are a hard 400. |
| MiniMax H3 Max | i2v, R2V (up to 9 refs) | t2v | 15s (5s floor) | Yes (native, not toggleable) | Simple prompts — the model stages its own coverage. Registry promptStyle: 'simple', so the prompt builder strips blocking, locked location descriptions, and geography-hold clauses; say the intent in a sentence or two. Best for montages and beats where the model telling its own story is the point. 768P max — 2K is a hard 400, the inverse of base H3 (480P is the draft tier). private tier, uncensored, 10000-char prompts. $0.024/s. The minimax-h3-max video-family routes here. |
| MiniMax H3 Max Turbo | i2v | t2v | 15s (5s floor) | Yes (native, not toggleable) | Same model and constraints at $0.012/s — the cheapest lane in the registry, which makes 15s takes cheap enough to render several and pick. No R2V lane (-turbo-reference-to-video does not exist), so the minimax-h3-max-turbo family routes identity shots to minimax-h3-max-reference-to-video. |
| Wan 3.0 | i2v, R2V (up to 9 refs), Enhanced | t2v | 30s | Yes (always on, not toggleable) | Longest shots on Venice — 5/10/15/20/25/30s at 480p/720p/1080p, five aspect ratios plus adaptive, 5000-char prompts. The wan-3-0 video-family routes here. No audio input anywhere in the family, so it can't lip-sync to a supplied recording. *-enhanced-* variants are beta. |
| Wan 2.7 | i2v, R2V, V2V, Spicy | t2v | 15s | Wan i2v has no audio; lip-syncs via audio_url input | The audio-driven fallback for exact lip-sync. R2V exposes per-element audio_url for multi-speaker. Spicy = uncensored i2v variant. Seedance 2.x R2V and MiniMax H3 R2V also accept a top-level audio_url, so those families never route here. |
| Wan 2.6 | Standard, Flash, R2V | Standard | 15s | Yes (i2v/t2v); R2V capped at 10s | Now has R2V variant with audio_url input. 1080p. |
| Wan 2.5 Preview | i2v | t2v | 10s | Yes | audio_url input. |
| Wan 2.2 A14B | — | t2v | 5s | No | Legacy text-to-video. |
| Wan 2.1 Pro | i2v | — | 6s | No | Legacy. |
| Runway Gen-4.5 | Gen-4.5, Turbo, Aleph | Gen-4.5 Text | 10s | No (silent) | Strong motion physics; 7 aspect ratios. No R2V, no audio, no end-image. |
| Sora 2 | Standard, Pro | Standard, Pro | Standard 12s / Pro 20s | Yes | Pro now reaches 20s + true_1080p resolution. |
| Veo 3.1 | Fast, Full | Fast, Full | 8s | Yes | Up to 4K resolution. |
| Veo 3 | Fast, Full | Fast, Full | 8s | Yes | |
| Kling O3 | Pro, Standard, 4K + R2V variants | Pro, Standard, 4K | 15s | Yes | R2V: elements, reference_image_urls, scene_image_urls. 4K variants for delivery-grade output. |
| Kling V3 | Pro, Standard, 4K R2V | Pro, Standard, 4K | 15s | Yes | 4K variants added 2026-05+. end_image_url on R2V. |
| Kling 2.6 Pro | i2v | t2v | 10s | Yes | end_image_url. |
| Kling 2.5 Turbo Pro | i2v | t2v | 10s | No | end_image_url. |
| PixVerse C1 | i2v, R2V, Transition | t2v | 15s | Yes | Replaces v5.6: same four resolutions but 15s ladder + new R2V variant. |
| PixVerse v5.6 | Standard, Transition | Standard | 8s | Yes | Legacy; prefer C1 for new projects. |
| Grok Imagine | i2v, R2V, V2V | t2v | i2v/V2V/t2v 15s · R2V 5/8/10s | i2v/t2v: yes · R2V: no | R2V added 2026-05+ (no longer needs Kling fallback). 7 aspect ratios. |
| LTX Video 2.0 | Fast, Full, v2.3, 19B + V2V/extend | Fast, Full, v2.3, 19B | 20s (Fast/v2.3) · 10s (Full) · 18s (19B) | Yes | Up to 4K, longest durations. |
| Longcat | Standard, Distilled | Standard, Distilled | 30s | No | Longest single-shot for non-talking-head work. |
| Vidu Q3 | i2v | t2v | 16s | Yes | reference_image_urls. |
| OVI | i2v | — | 5s | Yes | |
Seedance face rule (removed 2026-07): Seedance 2.0 used to reject face-bearing input images that weren't produced by
seedream-v5-lite/seedream-v5-lite-edit. Venice removed that restriction — any image family now works for face-bearing inputs, so the harness usesnano-banana-2for all panels. See Image / Video Family Pairing below.
Image Models (28 entries)
nano-banana-pro, nano-banana-2, gpt-image-2 (high-quality alternative to nano-banana-pro), gpt-image-1-5, flux-2-pro, flux-2-max, grok-imagine-image, grok-imagine-image-quality, hunyuan-image-v3, imagineart-1.5-pro, qwen-image-2, qwen-image-2-pro, recraft-v4, recraft-v4-pro, seedream-v4, seedream-v5-lite, chroma, hidream, venice-sd35, lustify-sdxl, lustify-v7, lustify-v8, wai-Illustrious, z-image-turbo, ernie-image, ernie-image-turbo, wan-2-7-text-to-image, wan-2-7-pro-text-to-image, bria-bg-remover
New since the last sync: grok-imagine-image, grok-imagine-image-quality, lustify-v8, ernie-image, ernie-image-turbo, wan-2-7-text-to-image, wan-2-7-pro-text-to-image. Sunset: bare qwen-image (use qwen-image-2).
Multi-Edit Models
qwen-edit, qwen-image-2-edit, qwen-image-2-pro-edit, flux-2-max-edit, gpt-image-2-edit (high-quality alternative to nano-banana-pro-edit), gpt-image-1-5-edit, grok-imagine-edit, nano-banana-2-edit, nano-banana-pro-edit, seedream-v4-edit, seedream-v5-lite-edit
Audio / Music Models
- TTS:
tts-kokoro(50+ voices),tts-qwen3-0-6b,tts-qwen3-1-7b(style-prompted voices) - Music:
elevenlabs-music,minimax-music-v2,minimax-music-v25,minimax-music-v26,lyria-3-pro,ace-step-15,stable-audio-25 - Expressive speech / prompt-driven audio:
seed-audio-1-0(BytePlus Seed Audio 1.0 — 25 named voices, speed 0.5–2, up to a 2048-char prompt; premium prompt-directed narration/VO via the async audio queue). Usegenerate-audio --prompt … [--voice … --speed …]. - SFX:
elevenlabs-sound-effects-v2,mmaudio-v2-text-to-audio - TTS (ElevenLabs):
elevenlabs-tts-v3,elevenlabs-tts-multilingual-v2
The intelligence model
Three steps in the pipeline reason rather than render: the workshop develops
the project, workshop-script writes the shot script, and qa-storyboard
reads the rendered panels back and flags identity, wardrobe, setting and framing
drift. One model does all three, chosen when the project is created and stored on
series.intelligence. It generates none of the pixels or audio.
| Model | Tier | Reads panels | $/M out | |---|---|---|---| | Kimi K3 (default) | private | yes | 18.75 | | GLM 5.2 | private | no | 4.40 | | Grok 4.5 | private | yes | 6.80 | | Fable 5 | anonymized | yes | 60.00 | | Opus 5 | anonymized | yes | 30.00 | | GPT 5.6 Sol | anonymized | yes | 37.50 | | Qwen 3.8 Max | anonymized | yes | 7.50 |
Private means the prompt stays on Venice infrastructure. Anonymized means it is routed to an external provider with identifying metadata stripped.
A text-only model cannot do storyboard QA, so it is paired with a vision-capable companion from the same privacy tier — GLM 5.2 borrows Grok 4.5, never an anonymized model. The pairing is shown before you commit to it, in the wizard and on the treatment page.
venice-video new # asks, defaulting to Kimi K3
venice-video new --intelligence claude-opus-5 # or state it upfront
venice-video workshop -p <project> --model grok-4-5 # override one runGLM 5.2 needs a second attempt at valid JSON about one time in three; the client retries automatically, so the choice costs latency rather than a failed command.
What Makes It Venice-Optimized
- Image prompts tuned for Venice image generation models
- Two-pass panel generation with Venice multi-edit refinement
- Model-routing logic for action, atmosphere, and character-consistency tiers
- Support for reference-aware video generation (
elements,reference_image_urls,scene_image_urls) - Environment-aware prompt adaptation (daytime vs night scenes)
- Venice-native audio generation paths for TTS, SFX, and music
- Video quote endpoint for cost estimation before generation
- Model-aware parameter building (auto-skips unsupported params per model)
- Parallel editing pipeline — transcribe existing footage locally, read a 12KB pack, render with 30ms audio fades, self-eval at every cut boundary
Project Structure
AGENTS.md Agent orchestration hub
.agents/
commands/ 19 workflow playbooks (see below)
agents/ 6 specialized agent roles (see below)
skills/ 6 Venice and workflow knowledge packs (see below)
.cursor/rules/ IDE-level safety rules
src/
venice/ Venice API client layer
client.ts HTTP transport, retries, rate limiting
models.ts Complete model registry (50+ models)
video.ts Video queue/retrieve/quote/complete
generate.ts Image generation
multi-edit.ts Multi-image layered editing
edit.ts Upscale, background remove
audio.ts TTS, music, SFX, queued audio
voices.ts Voice catalog (Kokoro + Qwen3)
types.ts Full API type definitions
series/ Project state and character management
manager.ts Create/load/save series
types.ts Character, ShotScript, SeriesState types
mini-drama/ Reference narrative video implementation
cli.ts Commander CLI (25+ commands)
prompt-builder.ts Image + video prompt construction
video-generator.ts Video rendering with frame chaining
generation-planner.ts Single vs multi-shot planning
panel-fixer.ts Multi-edit character correction
subtitle-generator.ts SRT from script
assembler.ts Video assembly + audio mix
editing/ Parallel editing pipeline (inspired by browser-use/video-use)
types.ts WordTiming, Take, TakesPack, Edl, EditSession
packer.ts Collapse word streams -> takes_packed.md
aligner.ts Ground-truth script alignment for generated VO
providers/whisper-cpp.ts Local transcription provider
edl.ts EDL authoring + ffmpeg rendering
silence.ts silencedetect wrapper + filler-word detection
render.ts EDL -> final-edit.mp4 with 30ms audio fades
self-eval.ts Drive cut-qa agent, max 3 iterations
overlays.ts Overlay manifest types
storyboard/ Legacy screenplay storyboard pipeline
characters/ Character extraction and references
parsers/ Fountain + PDF screenplay parsing
assembly/ Remotion scaffold and manifest
scripts/ Utility scripts (.ts tracked, .mjs gitignored)
templates/ HTML storyboard viewer template
output/ Generated projects (gitignored)Getting Started
Requirements
- Node.js 20+
ffmpegandffprobeon your PATH- A Venice API key
- Optional (editing pipeline):
whisper-cppon PATH for local transcription
Standalone install
The CLI works directly against the Venice API. Cursor, Claude Code, OpenCode, MCP, and other agent harnesses are optional integrations, not runtime requirements.
npm install -g venice-video-harness --foreground-scripts
venice-video setup
venice-video doctor
venice-video newThe --foreground-scripts flag makes the package's PATH diagnostic visible;
modern npm otherwise suppresses successful post-install output. After installation,
verify that your shell can find the executable:
command -v venice-video
venice-video --versionIf npm reports a successful install but venice-video is not found, npm's global
bin directory is not on your shell PATH. The install output prints the exact
directory and an export PATH=... command when it detects this condition. You can
also inspect the directory manually:
NPM_BIN="$(npm prefix -g)/bin"
echo "$NPM_BIN"
export PATH="$NPM_BIN:$PATH"Add that export line to ~/.zshrc, ~/.bashrc, or the startup file for your
shell, then open a new terminal. Node version managers can create this mismatch
when the active npm installs globally somewhere different from the active
Node shim.
venice-video setup prompts for the API key without echoing it, validates it,
and stores it in the OS-appropriate user configuration directory with owner-only
permissions. It also records a default project workspace. Environment variables
still take precedence for CI or ephemeral use:
export VENICE_API_KEY=your_key
export VENICE_VIDEO_WORKSPACE=~/VeniceVideosAfter new, the CLI hands the project to one guided control center:
venice-video workshop -p ~/VeniceVideos/my-film
# Noninteractive: --outcome "Leave viewers exhilarated, then unsettled by the signal"The workshop develops the complete project—not only a shot list:
- audience outcome, audience, runtime, constraints, and optional dragged reference files/directories
- logline, synopsis, themes, acts/movements, and story beats
- visual aesthetic, palette, lighting, lens language, and texture
- characters, wardrobe, voices, and continuity anchors
- locations and environmental continuity
- dialogue/audio approach and exact-lip-sync decisions
- production-ready shot script, risks, and open questions
It writes a formatted WORKSHOP.html for browser review, WORKSHOP.md as a
portable text version, and workshop.json as the structured source. In an
interactive terminal, the HTML opens automatically in your default browser. Iterate without losing project context:
venice-video workshop -p ~/VeniceVideos/my-film --feedback "Make the middle more tense"
venice-video workshop -p ~/VeniceVideos/my-film --status
venice-video workshop -p ~/VeniceVideos/my-film --approveApproval materializes the accepted aesthetic, cast, locations, and script into the existing production pipeline.
The treatment page tracks the run
WORKSHOP.html is not written once and left to go stale. Every command that
produces an artifact rewrites it, so the browser tab you already have open is
one reload away from the current state. The page gains:
- a Production progress card: the pipeline stage, panel/clip/dialogue
counts, and the next command in full copy-pasteable form (
-pand-eincluded, so it works pasted into any terminal, not only the shell) - an Output column on the shot script: each shot's panel thumbnail, replaced by the clip's poster frame once the shot renders, with badges for panel, clip, voiceover and its QA verdict — hover a flagged verdict to read the issue
Images are embedded as WebP data URIs, so the page stays a single self-contained
file that survives being moved or emailed. Encoding is cached against each
file's mtime in .treatment-thumbs.json, so a refresh only re-encodes what
actually changed (a typical refresh is ~10ms). The refresh can never fail the
command that triggered it: an undecodable panel or a half-written QA report
just leaves that cell blank.
Commands that refresh the page: approve-script, storyboard-episode,
fix-panel, insert-shot, qa-storyboard, qa-approve, generate-videos,
generate-music, override-audio, assemble-episode, and finish.
The workshop also asks for the final delivery target. Choose 4K master to keep generation/drafts economical and upscale only the approved assembled cut:
venice-video finish -p ~/VeniceVideos/my-film
# Prints input, output, and cost estimate first; then:
venice-video finish -p ~/VeniceVideos/my-film --yesThe finishing command finds the assembled master, chunks large videos into
upload-safe segments, upscales them through topaz-video-upscale, resumes
already-finished chunks after interruption, concatenates without another video
encode, and remuxes the original audio. The 4K master lands in masters/ while
the original assembled master is preserved. Current rough estimate: about
$0.12 per input second; the CLI always shows the estimate before spending.
For a standalone file outside a project:
venice-video upscale --input final-cut.mp4 --factor 4
venice-video upscale --input final-cut.mp4 --factor 4 --yesIndividual commands such as
explore-aesthetic, add-character, and storyboard-episode remain available
for advanced manual control, but they are no longer the default onboarding path.
The new wizard starts with these production types:
- Film — a film of any length; there is no short-duration assumption
- Series
- Product video
- Music video
- Screenplay
Film projects use new-script and workshop-script terminology. Internally,
legacy JSON keys and directories still use episode for compatibility, but the
CLI and scriptwriter prompt call the work a Film and Part. Film scripts do not
inherit the series workflow's 60-second duration, one-location structure, or
next-episode cliffhanger.
A non-interactive Film can also be created explicitly:
venice-video new \
--type film \
--name "Long Horizon" \
--concept "A feature-length journey across a flooded world" \
--genre adventure \
--audio-strategy native \
--video-family autoUseful standalone commands:
venice-video config show
venice-video config set-workspace ~/VeniceVideos
venice-video config unset-api-key
venice-video list-series
venice-video update
venice-video --helpStaying up to date
venice-video update # install the latest published release
venice-video update --check # report what is available, install nothing
venice-video update --dry-run # print the npm command it would run
venice-video update --tag nextThe install goes to the prefix the running copy lives in, not to whatever npm
happens to be first on your PATH. Those are the same directory in a plain
install, but a Node version manager can leave them pointing at different
prefixes — in which case npm install -g reports success while the executable
you actually run stays on the old version. update reads the new version back
off disk afterwards and says so if they disagree.
A build that is ahead of the published tag — an unreleased local build, or a
dist-tag that was rolled back — is reported rather than downgraded; pass
--force to install the published version anyway.
Two installs update will not overwrite, because it does not own them:
- a copy in a project's
node_modules, whose version belongs to that project's lockfile (npm install venice-video-harness@latestthere instead) - a copy running from a git checkout, where npm would clobber local work
(
git pull && npm install && npm run build)
In both cases the command prints the right instructions and exits non-zero.
Interactive shell
Every command above also runs inside a persistent session:
venice-video shellThe shell keeps one warm process for the whole production, which changes three things that matter over a long session:
- A selected project and part.
use <project> [part]sets them once; after that-pand-eare optional on every command and the prompt shows what you are pointed at.unuseclears the selection. The selection persists across shell restarts and applies to one-shot commands too. - Warm rate limiting and caches. The Venice client's pacing state survives between commands instead of resetting on every invocation, so back-to-back generation stops tripping 429s.
- Background commands. Suffix any command with
&to detach it, then keep working./jobslists them with elapsed time and current progress detail,/jobs log <id>replays captured output,/jobs cancel <id>aborts one.
venice-video my-film · ep 01 › storyboard-episode
venice-video my-film · ep 01 › generate-videos &
[1] started in the background. Check with /jobs.
venice-video my-film · ep 01 › /jobs
[1] running 4m12s generate-videos — shot 3/12 pollingSession extras: Tab completes commands, flags, and project slugs; ↑/↓ walk
a persistent history file; Ctrl-C cancels the running command without killing
the session (Ctrl-D or /exit leaves); /help, /status, /jobs, /cd, and
/pwd are shell meta-commands; !<cmd> runs something in your system shell.
Loop mode — watch the whole plan while it renders, or iterate on real shots
Once a plan exists (an approved shot script), you can play the entire film as a live browser loop while the harness renders it, instead of waiting for the full gated pipeline:
venice-video loop -p ~/VeniceVideos/my-film -e 1 # asks the purpose
venice-video loop -p ~/VeniceVideos/my-film -e 1 --mode looping # or state it
venice-video loop -p ~/VeniceVideos/my-film -e 1 --mode productionPre-written beats: stream --beats-file
The stream writes every beat with a live writer model. To author the beats
yourself — or have an agent write them up front — pass --beats-file. The
first N beats of the stream are then served from the file and the writer model
is never called for them; only if the stream runs past the last scripted
beat does the live writer take over (defaulting to STREAM_DEFAULT_WRITER).
venice-video stream -p ~/VeniceVideos/my-film -e 1 \
--beats-file ~/VeniceVideos/my-film/beats.json \
--direction "live studio audience laugh track after every joke" \
--budget 2With --beats-file a new stream needs no --writer: the file IS the writer
decision for the beats it covers. A --writer still overrides the fallback
used past the file. On resume the scripted lane re-attaches the same way —
beats already rendered are never re-rendered, and a writer switch from the
Stream tab changes only the fallback.
The file is JSON and accepts two shapes:
// 1. A bare array of beats.
[
{
"description": "The bell jingles as JAKE strides in and takes the couch.",
"characters": ["JAKE KELLER", "MEL"],
"dialogue": { "character": "JAKE KELLER", "line": "The usual.", "delivery": "cheerful" },
"sfx": "door bell, live studio audience applause",
"cameraMovement": "slow dolly in to a wide of the cafe",
"summary": "Jake arrives at the cafe."
}
]// 2. The { "beats": [...] } shape of /stream/export.json — entries with an
// "authored" object are unwrapped, so an exported stream replays as-is.
{ "beats": [ { "n": 1, "authored": { "description": "…", … } } ] }Beat fields match AuthoredBeat in stream-engine.ts. Each entry is
normalized against the locked cast (names snap to the cast's spelling, missing
fields are completed), and a beat with no description fails at load — before
anything bills. The stream's continuity rules still apply to what you write:
each beat is one continuous shot that begins where the previous beat ended,
and every beat should END on a wide or medium-wide frame, never a human-face
close-up (the next beat chains off that frame, and MiniMax i2v dies on a
face-filled start frame — anti-pattern 31).
Loop mode starts with one required, deliberate decision — is this for
LOOPING or for PRODUCTION? — because it is a real quality-vs-flow tradeoff, not
a default to fall through. In a terminal it asks; non-interactively you must pass
--mode (it errors otherwise). You can state it in plain words —
--mode looping / loop / fun / creative, or --mode production / prod /
gather:
- Looping — creative flow, lower quality. The first generation is t2v, every shot after it chains i2v off the previous shot's last frame, and it never uses R2V (those renders are too slow for a loop). Turbo, 480P, fast. Not final-quality; it's for watching and riffing.
- Production — gather usable shots, higher quality. Max R2V + references at 768P, identity locked, each shot rendered independently. Slower, but the takes you pin are keepers.
Either way it boots the local web UI, opens the browser to a Loop tab, and
auto-starts a background engine that renders each shot into the episode's
loop/ directory and keeps regenerating fresh takes continuously (it does
not stop after a fixed number of takes — only a Pause or the budget stops it).
The plan plays on repeat and each shot hot-swaps in as its take finishes;
because the render outruns playback, the video keeps evolving. Pin the keepers,
regenerate the ones you don't, and watch a running spend meter. Both modes
skip the storyboard/QA gates and write only under loop/ — canonical
scene-001/shot-NNN.mp4 renders and series.json are never touched, so a loop
can run alongside real production.
Two behaviors make the loop play as one continuous piece:
- Last-frame chaining (default on). Shot 1 renders normally; every shot
after the first renders i2v using the previous shot's last frame as its first
frame, so the clips flow into each other. Turn it off with
--no-chainto render each shot independently (in create mode that keeps per-shot R2V identity locking). - Full-length takes. Every generation renders the model's full length
(15s by default — MiniMax H3 Max's max), for maximum footage and playback
per render. Override with
--duration.
Because the engine auto-starts, the Loop tab shows Pause while it's
running. It regenerates until you Pause or the budget is reached; when the budget
is reached it pauses and the button becomes Resume, which authorizes another
budget's worth and continues. (--max-takes is a ring buffer — the number of
candidate takes kept per shot — not a stop condition; older takes are pruned so
an infinite run can't fill the disk.)
The two modes differ in what they render:
| Purpose (--mode) | Model | Resolution | Identity | Use it to… |
|---|---|---|---|---|
| looping | MiniMax H3 Max Turbo t2v/i2v (~$0.012/s) | 480P | not locked (Turbo has no R2V lane) | keep a fast, continuous loop going for creative flow |
| production | MiniMax H3 Max R2V for character shots, i2v/t2v otherwise (~$0.024/s) | 768P | locked via the project's reference stack | gather real, usable shots and pin keepers |
Production mode uses the same reference-first routing as the real pipeline:
character shots render on minimax-h3-max-reference-to-video with the full
@Image reference stack (character sheets, location angles, blocking plates)
plus voice-donor audio, so identity holds. Shots with no references on disk
degrade to i2v (off a panel) or t2v, so generate your character/location
references first for the full effect.
Continuous regeneration spends money, so it is capped by default:
venice-video loop -p <dir> -e 1 \
--mode production \ # looping | production (required; also accepts loop/fun, prod/gather)
--resolution 768P \ # defaults: 480P (looping) / 768P (production)
--duration 15s \ # per-take length, snapped to the 5-15s ladder (default 15s)
--budget 2 \ # pause after ~$2; Resume/regenerate authorizes another budget
--max-takes 3 \ # candidate takes kept per shot (ring buffer, not a stop)
--no-chain \ # render shots independently instead of i2v last-frame chaining
--no-face-continuity \ # don't prompt chained shots to end on the character's face (see below)
--once # or: render one take per shot, then stop
# --unbounded # remove the budget cap (spends until you Ctrl-C)The loop is resumable: takes, pins, and spend are recorded in
loop/loop-manifest.json, so re-running loop picks up where it left off.
Ctrl-C stops the engine and the server.
A shot that keeps failing is given up on, not re-billed forever. After 3
consecutive render failures the engine marks the shot failed, stops scheduling
it, and moves on — so a server-side-doomed shot (e.g. a MiniMax i2v start frame
with a human face, which Venice bills at queue time then 500s on retrieve) can't
burn the whole budget one failed take at a time. A manual regenerate in the
UI revives it.
Face continuity (on by default, for smoother i2v transitions). In a chained
loop each shot's last frame becomes the next shot's i2v start frame, so
--face-continuity (default on) prompts each character shot to end on the
character's face, giving the next clip a clean anchor to continue from
(--no-face-continuity turns it off). One important caveat: MiniMax i2v renders
die server-side when the start frame shows a face (AGENTS.md anti-pattern
31), so on the MiniMax loop lanes this prompting is auto-suppressed — a
face-ending frame would kill the next chained render. It activates on any i2v
model that accepts face start frames. For smooth character-face loops today,
use production mode: R2V locks the face from the reference sheets across every
shot, with no i2v chaining involved (verified — MiniMax R2V accepts face-bearing
reference sheets; only i2v start frames die).
Stream mode — an infinite, live-authored story
loop cycles a fixed plan. stream never repeats. It writes the story forward
one beat at a time and never renders a beat twice:
venice-video stream -p ~/VeniceVideos/my-show \
--direction "90s multi-camera sitcom, live studio audience laugh track after every joke"How it works:
- You pick the writer. A new stream asks which model writes the beats (it is
the voice of the whole story, and its speed sets how far the stream lags
playback). Non-interactive runs must pass
--writer <model>(or--writer default=deepseek-v4-flash-0731-fast, the fastest reliable writer in the bakeoff); a resumed stream keeps the writer it last ran with. The writer and the per-beat cost print before beat 1 bills. - The writer writes beat 1 from the series bible: concept, setting, aesthetic, and cast.
- Beat 1 renders text-to-video on MiniMax H3 Max (the default; the faster, lower-quality Turbo lane is selectable).
- The writer reads
story-so-far.md(one line per prior beat) plus the last 6 beats verbatim, and writes beat 2 so it begins exactly where beat 1 ended. - Beat 2 renders image-to-video off beat 1's last frame.
- Repeat forever, until Pause or the budget.
There is no re-anchoring and no ring buffer. Every beat descends from the frame
before it, and every beat stays on disk in order under
episodes/episode-NNN/stream/ as beat-NNNNN.mp4 + beat-NNNNN.json, with
story-so-far.md and stream-manifest.json beside them. The browser's
Stream tab plays forward from beat 1; when it reaches the newest beat before
the next is ready, it holds and then continues. Nothing else is needed: no
script, no storyboard, no references. A locked aesthetic (set-aesthetic) and
a cast (add-character, --skip-images is fine) make the writer much better.
venice-video stream -p <dir> \
-e 1 \ # episode the stream lives under (default 1)
--direction "<text>" \ # standing direction folded into every beat's writer prompt
--writer <model> \ # writer; asked for a new stream, required non-interactively (see the bakeoff table)
--video-family <family> \ # minimax-h3-max (default) | minimax-h3-max-turbo | wan-3-0 | grok-imagine | seedance-2-0 | seedance-2-5 | kling-o3-standard
--resolution 480P \ # default: the family's draft tier
--duration 15s \ # per-beat length, snapped to the 5-15s ladder
--lookahead 15 \ # beats authored AHEAD of the render (0 = serial)
--budget 2 # stop after ~$2; Continue authorizes another budget
# --no-refill # fill the look-ahead buffer once, then author on demand
# --unbounded # no cap (streams until Ctrl-C)Look-ahead writer buffer
By default the writer runs ahead of the render. It is a producer/consumer
pair: the writer keeps up to --lookahead beats (default 15) authored and
waiting in a buffer, and the renderer pulls from it — so a render never blocks
on a writer-model call. While the stream is paused after priming, the writer is
already filling the buffer, so clicking Start renders back to back with no
writer latency between beats. It also lets you run a slower, better writer
without stalling playback, as long as the writer stays ahead of the render.
--lookahead <n>sets the depth.0is serial: each beat is authored just before it renders (the pre-2.24 behaviour), so every beat pays the writer latency.--no-refillfills the buffer once and then authors on demand as it drains; the default keeps it topped up to the depth as the renderer consumes it.- Both are switchable live from the Stream tab (the Look-ahead buffer
control — a depth field and a "keep topped up" toggle) and via
POST /stream/config. The tab shows a livebuffered / depthmeter. - Switching the writer drops the beats the old writer had queued (keeping only the one on the wire) so the new writer takes over from the next beat.
- The budget still bounds it — the writer never authors beats the budget cannot
render — and the buffer is saved in
stream-manifest.json(pendingBeats), so a resume renders the pre-authored beats without paying for them again.
The stream is resumable: re-running stream continues from the last beat on
disk and chains off it. After 3 consecutive failures (write, chain, or render)
the engine stops rather than skip a beat — a stream cannot have a hidden cut.
Identity drifts slowly over many hops, by design; that is the trade for a
continuous, unbroken picture.
Faces and the chain. MiniMax i2v accepts a start frame that is filled by a
human face, bills it, and then fails server-side (anti-pattern 31). Because
every beat chains off the previous last frame, one face-ending beat could stall
the whole stream. Three things keep it alive: the writer is told to end every
beat on a wide shot with no face close-up; a failed chained render first steps
the start frame back into the previous clip (0.5s, then 1.5s); and after
STREAM_CHAIN_FAILURES_BEFORE_RESET (2) chained failures on one beat, that beat
renders text-to-video as a soft reset (lane: "t2v-reset") — the prompt
restates the scene from the previous beat's summary, identity drifts for one
beat, and the story keeps going. The Stream tab shows the retry error while it
happens and marks reset beats in the story list.
Choosing Stream Models
A stream is a live broadcast whose producer must keep pace with the viewer. Each beat costs two latencies: the writer authors the beat, then the video model renders it. The viewer watches 15 s of video per beat. Nothing on Venice renders 15 s of video in under 15 s, so every stream eventually catches up to its newest beat and holds on the last frame. The two model choices decide how long that hold is. Both are dropdowns in the Stream tab; a change applies to the next beat, and the i2v chain survives a switch.
Why the stream does not use the project's intelligence model. The
intelligence model (series.intelligence, default kimi-k3) is picked for the
workshop, the shot script, and vision QA. Those tasks reward depth and reading
panels; a 35 s think is fine. A stream beat is a 100-word paragraph in
character, once every 30 s, forever. Latency is the whole game, so the stream
has its own default and its own list.
Why thinking is off. The harness never sent disable_thinking. On the same
model that flag is the difference between 35 s and 4 s per beat, and reasoning-
only models spend the entire token budget thinking and return nothing.
chatJson now takes disableThinking; the stream sets it per writer.
How the numbers were measured. `scripts/b
