vibeknow-create
TRIGGER
- User wants to generate a video from a document, URL, or file
- Check video task status or wait for completion
- Download a rendered video
- List available voice templates
SKIP
- Document upload/status only (no video) → use vibeknow-doc
- Auth, profile, config, diagnostics → use vibeknow-core
Run Contract
Applies from the moment a run starts. Every rule here exists because breaking it costs the user money or loses a run that was still going.
Never run vibeknow create twice for the same request. A second
create is a second billed render, always — it never recovers or resumes
the first one. If you have lost the ids, run vibeknow jobs list, then
vibeknow video list. Only start over when the CLI has told you in so many
words that it is safe (resend_safe: true, see exit 6 below).
One process owns the stream. create and video wait already poll the
backend, print progress, and collect the result. Do not start a second
video status loop alongside a running one, and do not wrap the command in
your own poller.
Do not resend because it went quiet. A render takes minutes and the pipeline is legitimately silent through some of them. Slowness, an empty patch of output, and a tool call that timed out on your side are all compatible with a run that is about to succeed.
Never merge the streams. 2>&1 destroys the contract: stdout is the
result and stderr is everything else. Redirect them to separate files if
you need to keep them.
Do not use tail -n 20 as a cursor. Events arrive in bursts. Read
stderr from a saved offset, or you will silently skip whole stages.
A finished process is not a finished run. The shell returning, a background job ending, or a notification arriving tells you nothing about the task. Read the exit code and stdout.
Never invent an --confirm value or add --yes on your own initiative.
When the CLI hands back a spend decision it has stopped precisely because
the choice is not yours to make. Relay it and wait.
Core Concepts
- Hero command:
vibeknow create --from <source>resolves input → uploads if needed → submits to figlens pipeline → streams progress → returns video URL. - Four ways to name the source:
--fromtakes adoc_id(used directly), a URL (auto-uploaded to vectoria), a local file path (auto-uploaded), or-to read the text from stdin.--texttakes the text itself, for a passage the user pasted rather than a file they pointed at. What it cannot do is invent material: a request with no source ("做个讲量子计算的视频") has no command — ask for it. - Creation modes mirror the product's five online modes: default (灵活创作),
--engine agent(一键成片),--mode image(图解视频),--mode replica(PPT 讲解),--mode handdraw(手绘动画). 原稿锁定 is the orthogonal--script-lockswitch, combinable with any mode. Style via--theme(browse withvibeknow theme list --mode <mode>), output language via--language. - Sync vs async: Default is sync (blocks until done).
--asyncreturns task_id + session_id immediately. - Waiting in bounded steps:
vibeknow video wait --for 90swatches the event stream for that long, then reports the stage it reached and exits 6 withreason: "wait_budget_expired". Run it again to keep waiting. Use it when your own tool times out sooner than a render takes —video statuscannot substitute, since the work row carries no progress until the export stage. - NDJSON event stream:
--output ndjsonemits structured progress events (schema_version: "1"). See events.md. - 4 pipeline stages:
outline→tts→render→publish. Not every node reports progress: parts of every run — and the entire middle of ahanddrawrun — are silent by design. Silence is not a hang; wait for a terminal event. - session_id: every
videosubcommand is addressed by a(task_id, session_id)pair, both returned bycreate. You do not have to carry them:createrecords the pair locally, sovibeknow video waitwith no arguments reattaches to the most recent run andvibeknow video wait <task_id>looks up the session for you. Passing--session-idexplicitly still works and always wins. - Run ledger:
vibeknow jobs listshows what this machine started. Use it instead of re-runningcreatewhen you have lost a task_id — a secondcreateis a second billed render. The ledger is per-machine; when it has nothing, the video commands fall back to the account's most recent run and say so on stderr. - stdout is the answer, stderr is the run: with
--output json, stdout carries exactly one JSON document and stderr carries live progress asvk_event={...}lines. You get both from one invocation — you do not have to choose between watching and parsing. SetVIBEKNOW_EVENTS=1to get the same lines in text mode,VIBEKNOW_EVENTS=0to suppress them. - Local artifacts:
share_urlis a hosted page you cannot show anyone from a terminal. Pass--preview-dir <dir>tocreate,video status,video wait, orvideo exportand the cover still (and the MP4, once exported) land on disk, each announced by aresource_readyevent carrying an absolutelocal_pathto a fully written file. Onstatusthis is the only route open to a caller that did not start the run — reattaching to someone else's task, or coming back after losing its own context. Hand each newlocal_pathto the user once. Unchanged content is not re-announced, so re-running into the same directory is safe. - Spending requires consent:
video exportrenders an MP4 and costs credits. Without a terminal it does not decide for you — see Spend Decisions below.
Quick Reference
| Command | Description |
|---|---|
vibeknow create --from <source> |
Generate a video (sync by default) |
vibeknow create --text "<text>" |
Same, from text the user pasted (--from - for stdin) |
vibeknow create --from <source> --preset <name> |
Same, with a saved style bundle; command-line flags still win |
vibeknow video status <task_id> --session-id <sid> |
Get task status (--preview-dir to also fetch the artifacts) |
vibeknow video wait <task_id> --session-id <sid> |
Stream progress, block until done |
vibeknow video wait <task_id> --for 90s |
Same, but come back after 90s with the stage reached (exit 6) |
vibeknow video download <task_id> --dest out.mp4 |
Download rendered video (--dest is the path; --output is the format) |
vibeknow jobs list [--active] |
Recorded runs, newest first |
vibeknow jobs get [task_id] |
One recorded run (default: most recent) |
vibeknow voice list [--language <locale>] |
Voices: public templates grouped by language + your cloned voices |
vibeknow theme list --mode <mode> |
Visual themes/styles usable with create --theme |
vibeknow avatar list |
Talking-head presenters (public presets + your trained ones) for create --avatar |
vibeknow subtitle fonts |
Font families video set --subtitle-font accepts (free) |
vibeknow subtitle presets |
Ready-made subtitle looks for video set --subtitle-preset (free) |
vibeknow video avatar-retry [task_id] |
Retry failed avatar scenes (unblocks a rejected export; no re-charge) |
vibeknow video script [task_id] |
Read what the video says, shot by shot (free) |
vibeknow video edit [task_id] --scene N --script "…" |
Rewrite one shot's narration (bills; confirmation gate) |
For full flags and output examples, see commands.md.
Common Tasks
Generate a video (sync, simplest path)
vibeknow create --from slides.pdf
# Blocks until done, prints video URL
Pick a creation mode
vibeknow create --from slides.pdf --mode replica # PPT 讲解: page-by-page replay (PDF/PPT only)
vibeknow create --from notes.md --mode image --pages 6 # 图解视频: one AI illustration per page
vibeknow create --from story.md --mode handdraw # 手绘动画 (silent mid-run is normal)
vibeknow create --from script.md --script-lock # 原稿锁定: narrate the document verbatim
vibeknow create --from doc.pdf --engine agent # 一键成片 (v2 agent engine)
Style, language, voice
vibeknow theme list --mode image # browse the mode's style catalog
vibeknow create --from notes.md --mode image --theme <theme_id>
vibeknow voice list --language en-US # voices are grouped by language
vibeknow create --from slides.pdf --voice <speech_voice_id> --language en-US
Reuse a saved style (--preset)
vibeknow create --from deck.pdf --preset brand-explainer # <config>/presets/brand-explainer.yaml
vibeknow create --from deck.pdf --preset ./team/shorts.yaml # or a path
vibeknow create --from deck.pdf --preset brand --mode replica # your --mode wins over the file's
A preset is a YAML file bundling style flags (mode, aspect, theme,
voice, language, bgm, pages, images, prompt, avatar*,
script-lock, engine). It supplies defaults only — every flag you also
pass on the command line wins.
A preset can never approve a spend: export, yes and confirm are refused
with exit 2, as are from/kb-id and async/preview-dir/output. Same
for any unknown key. All of it is checked before the first upload, so a bad
preset costs nothing — read the error, fix the file, re-run.
If the user asks what a run used, read the preset.applied event (or the
preset "<name>" applied: … stderr line): its keys list is exactly what
the file contributed, with command-line overrides already excluded. Do not
infer it from the file.
Fix a line of narration (video edit)
vibeknow video script 42 # free: read the shots and their numbers
vibeknow video edit 42 --scene 3 --script "换一种说法,更短一点。" # exit 8: shows the diff, asks
vibeknow video edit 42 --scene 3 --script "…" --confirm act_… # after the user agrees
The only content edit there is. One shot per call — three shots is three
confirmations and three charges. --scene uses the numbers video script
prints, counting from 1.
Add --script-only to regenerate just the voice-over (cheaper, layout
untouched). Leave it off — the default — to rebuild the shot's layout and
background image too, which is what a rewrite of a noticeably different
length needs, since nothing re-flows without it.
The block payload carries from and to. Show the user both: they are
approving a diff, and there is no undo — no endpoint returns a previous
version of a shot. The token is bound to that exact text, so reworded
attempts each get their own block.
Afterwards the preview and share link are current but the rendered MP4 is
not: the backend leaves the old file in place, so video download still
returns the previous narration until the next video export. The response
flags this as export_stale.
Exit 4 means another edit holds the lock on this work — wait a moment and retry the same command.
Make the subtitles readable (video set)
vibeknow subtitle presets # free: see the looks and what each one sets
vibeknow video set 42 --subtitle-preset 2 # apply one
vibeknow video set 42 --subtitle-preset 2 --subtitle-size 52 # that look, but bigger
Use a preset rather than assembling a look from the individual flags. Readability is a combination: the outlined looks also clear the background plate, and the plated looks also switch the outline off. Set one half without the other and the command still exits 0 — the video just looks wrong, and nothing reports it.
A preset touches only the fields that make up its look; size, vertical
position and entry animation stay as the work had them. Any --subtitle-*
flag you pass alongside wins over the preset.
For a font, vibeknow subtitle fonts lists every family that will be
accepted; pass the #. A guess is refused server-side with a message that
does not say what the alternatives are, so do not guess.
Free and immediate, like the rest of video set — but it still discards the
rendered MP4 (export_invalidated), so a re-export is needed to get a file
that matches.
Talking-head avatar
vibeknow avatar list # sys_<id> presets + your own ua_<id>
vibeknow create --from slides.pdf --avatar sys_7 --voice <its VOICE_ID>
vibeknow create --from slides.pdf --avatar ua_12 --avatar-position bottom-right --avatar-size 300
Not available with --mode handdraw or --engine agent (rejected with
exit 2 — the backend would silently render without the presenter). Each
public preset carries a paired VOICE_ID; using it keeps face and voice
matched. Export gating: video export is refused while any scene's
avatar is still rendering ("生成中") or has failed ("生成失败"). Failed
scenes stay failed until retried — run vibeknow video avatar-retry,
wait, then export again. The retry re-bills nothing.
Use text the user pasted
vibeknow create --text "季度复盘要点…" --async --output json
# Long or multi-line: stdin, so the shell never touches the text
vibeknow create --from - --script-lock --async --output json <<'EOF'
第一段讲稿…
第二段讲稿…
EOF
--script-lock on a paste is "照着我这段话念". Without it the text is source
material and a script gets written from it.
Async submit, then follow up
# Submit and exit immediately
vibeknow create --from https://example.com/doc --async
# Output: task_id=t_xxx session_id=s_yyy
# Later: check status
vibeknow video status t_xxx --session-id s_yyy
# Or: wait for completion
vibeknow video wait t_xxx --session-id s_yyy
Follow a run when you cannot block for minutes
vibeknow create --from report.pdf --async --output json
# → {"task_id":42,"session_id":"s_yyy"}
vibeknow video wait 42 --session-id s_yyy --for 90s --output json
# exit 6 + reason "wait_budget_expired" → report the stage, run it again
# exit 0 → done; the snapshot is on stdout
Each call comes back inside the budget with a stage worth repeating, instead
of one long block your own timeout would cut. Repeating the call costs
nothing: the run belongs to the backend, not to the process watching it.
Never answer a spent budget with a second create.
Agent mode (NDJSON streaming)
vibeknow create --from doc_abc --output ndjson
# Each line is a JSON event: task.submitted, stage.started, stage.progress, ...
# Terminal event: task.succeeded (with video_url) or task.failed
Find a run you lost track of
vibeknow jobs list --output json # every recorded run, newest first
vibeknow jobs list --active # only the ones still going
vibeknow video wait # reattach to the most recent
Reach for this before re-running create: re-creating a run that is
already going costs a second render.
Download the result
vibeknow video download t_xxx --session-id s_yyy
# Default destination: <session_id>.mp4
vibeknow video download t_xxx --session-id s_yyy --dest ./my-video.mp4
vibeknow video download t_xxx --session-id s_yyy --dest ./my-video.mp4 --overwrite
Exit Code Handling
| Exit | Meaning | Agent Action |
|---|---|---|
| 0 | Success | Extract video_url from output |
| 1 | General error | Read stderr |
| 2 | Invalid arguments | Fix and retry. Covers unknown/misspelled flags, unknown subcommands, missing required flags, stray positional args, and bad enum values. stderr names the valid values, and suggests the closest flag when you typo one. Never re-send the same command unchanged. |
| 3 | Auth error (missing/expired/replaced credential) — fires on every command, not just create |
Run vibeknow auth status to inspect credential source. Re-login with vibeknow auth login (interactive) or set VIBEKNOW_TOKEN. See vibeknow-core for profile/diagnostics if installed. |
| 4 | Retryable: rate limited, server error, or concurrency cap | Wait, then re-send the same command |
| 5 | Task failed, not retryable | Report error to user, do not retry |
| 6 | Stream interrupted, task status unknown | Read error.detail.resend_safe — see below. Default to reconnecting with vibeknow video wait, not re-submitting. |
| 7 | Partial success: preview is ready, the MP4 render failed | Report the preview share_url; retry only the export |
| 8 | Blocked on a decision only the user can make | Stop. Show the user the pending action, wait for an answer, then run its resume_command verbatim. |
| 130 | User interrupt (SIGINT) | — |
Exit 6: is a resend safe?
Exit 6 means the CLI could not observe the outcome. That is not the same as
the run having failed, and re-running blind is how you pay twice. The error
envelope's detail answers the question directly:
delivery |
resend_safe |
What it means | Do |
|---|---|---|---|
submitted |
false |
The backend has this run; it is likely still going | Reattach with the next_actions command |
not_submitted |
true |
The backend has no record; nothing was billed | Starting over is free |
indeterminate |
false |
The CLI could not find out | Check with vibeknow video list before deciding |
Branch on resend_safe. When it is absent or false, do not re-run create.
Minimum Evidence
Do not report a deliverable until you hold its evidence. These are not interchangeable — each row needs everything in it, and a nearby fact is not a substitute for the one you need.
| Deliverable | Minimum evidence |
|---|---|
| The video exists (previewable) | create or video wait exited 0, and the payload has preview.ready: true with a share_url |
| An MP4 was rendered | Exit 0 from video export, and export.status: "succeeded" with a video_path |
| An MP4 is on this machine | The row above, plus video download exited 0 and the file at --dest is non-empty |
| A local still to show the user | A resource_ready event, plus the file at its local_path reads back |
Specifically, none of these follow from one another:
preview.readydoes not mean an MP4 exists — export is a separate, separately billed step.export.status: "succeeded"does not mean a file is on disk. It means a file exists on the backend.- A
share_urlis not a video file. It is a web page. export-statusexiting 0 does not mean the render succeeded. It is a single-shot reading; the outcome is inexport.status, which may sayfailed. Only blocking commands (create,video wait,video export) put the outcome in their exit code.
Spend Decisions
video export costs credits. With no terminal attached the CLI will not
decide for you: it exits 8, having written the decision to stdout.
{ "status": "blocked",
"pending_actions": [{
"action_id": "act_9f3c…", "type": "export_confirmation", "blocking": true,
"message": "About to render MP4 …",
"payload": { "session_id": "s_x", "credits": 1, "operation": "render_mp4" },
"options": [{ "id": "confirm", "effect": "resume" },
{ "id": "cancel", "effect": "none" }],
"resume_command": "vk video export 42 --session-id s_x --confirm act_9f3c…" }] }
What to do:
- Show the user
messageandpayload— what it does and what it costs. - Wait for an actual answer. Do not pick a default.
- On confirm, run
resume_commandexactly as given. - On cancel (
effect: "none"), run nothing at all.
You cannot derive action_id; it is not guessable and it is bound to this
run and this price. If it is rejected (exit 2) the terms changed — re-run
without --confirm, show the user the new terms, and ask again.
--yes and VIBEKNOW_ASSUME_YES=1 still bypass the gate. Use them only
when the user has already authorised this spend in advance. Reaching for
either to get past a block you just received is the thing this exists to
prevent.
For detailed error handling and recovery, see errors.md and recipes.md.
NDJSON Event Summary
Events share common fields: schema_version, ts, type.
Key events (pipeline engine):
| Event | Extra Fields | Meaning |
|---|---|---|
node.started |
stage, node, message |
Pipeline node begins |
node.succeeded |
stage, node, message, metrics? |
Node done; metrics (when present) carries real outputs, e.g. script_chars, duration_sec |
node.failed |
stage, node, message |
Node failed (not necessarily terminal — wait for task.failed) |
task.succeeded |
session_id, video_url, duration_ms |
Terminal: video ready |
task.failed |
code, message, retryable |
Terminal: task failed (retryable=true → exit 4, false → exit 5) |
task.paused |
message |
Run paused (web editor's pause, or vibeknow video pause). Not a failure: continue it with vibeknow video resume <task_id> — never by creating the video again, which bills in full. The command exits 6. |
Agent engine (--engine agent) replaces node.started/succeeded/failed with node.progress carrying status + message, and omits duration_ms from task.succeeded.
The same events appear on stderr behind a vk_event= prefix whenever
--output json is in use, so you do not have to give up a parseable result
to watch a run. Two more types appear there when --preview-dir is set:
| Event | Extra Fields | Meaning |
|---|---|---|
resource_ready |
asset_kind, local_path, bytes |
A complete local file. Give it to the user once. |
resource_preview_warning |
asset_kind, code, message |
An artifact did not arrive. Not a failed run. |
asset_kind is cover_image or video_playback. local_path is absolute
and the file is fully written before the event fires. The remote URL is
deliberately never included — it is signed, and relaying one publishes a
credential.
See events.md for the complete field reference, engine differences, and parsing examples.
References
- commands.md — Full flag reference for all commands
- events.md — NDJSON task event schema
- errors.md — Exit codes, error codes, Error Object schema
- recipes.md — Advanced: retry, recovery, batch, NDJSON parsing