Generate Video
Video is the most expensive thing an agent can start in Gavana and the easiest to get wrong, because every model accepts a different set of durations, aspect ratios, and resolutions. The discovery step is not optional politeness — it is how you avoid paying for a rejected request.
Video generation charges the AI provider connected to the account. Start it only when the user’s current message explicitly asks for it, and never retry a failure automatically.
Scopes. Generation requires canvas:read, asset:read, and video:generate. Waiting, downloading, and cancelling additionally require job:manage. Note that video generation does not require canvas:write — it can produce a downloadable Job output without writing a node.
Call sequence
model list --capability video.generate
→ model get model:…
→ [approval]
→ video generate
→ job wait (or --download inline)
→ video downloadIn MCP: find_video_models → generate_video → get_video_job.
Steps
Find a connected video model
gavana model list --capability video.generate --jq '.models[].handle' -rNarrow by provider if you need to:
gavana model list --provider PROVIDER_NAME --capability video.generateAdd a capability filter when the task needs one:
| Capability | Needed for |
|---|---|
video.generate | Any video generation |
video.generate.fromImage | --first-frame |
video.generate.fromFrames | --last-frame |
video.generate.fromReferences | --reference |
Check. You need one exact model: handle. Never invent one, and never assume a provider model name will resolve — the same model can exist on more than one saved connection, and video generate refuses an ambiguous bare id and tells you to use the handle.
Listing models requires image:generate or video:generate on the token; a purely read-only credential cannot see the catalog.
Read the model’s exact parameters
gavana model get model:OPAQUE_MODEL_KEY --prettyCheck. This is the step that saves money. Read:
parameters— the exact names, and for each one either anoptionslist or aminandmax.- Which of
duration/duration_seconds,aspect_ratio,resolution, andgenerate_audioexist at all. - Whether
first_frameis markedrequired. - The
capabilitiesarray. - The estimated duration, so you can tell the user how long they will wait.
The CLI validates your options against exactly this data before starting paid work. If a duration is not in the model’s supported set, you get a usage error listing the supported values — not a charge.
Prepare frames and references
Frames and references accept any of:
| Form | Notes |
|---|---|
node:NODE_ID | Requires --canvas canvas:OWNER_UID:CANVAS_ID |
asset:ASSET_ID | Durable asset handle |
https://… | Public HTTPS only, no credentials in the URL |
| A local path | PNG, JPEG, WebP, or GIF, at most 50 MB — uploaded privately first |
- | Bytes from stdin |
clipboard | macOS only |
Rules the CLI enforces before spending:
--last-framerequires--first-frame.--canvasis required when any frame or reference is anode:handle.- Up to nine
--referencevalues, and they must be unique — identical local files are detected by content hash. --promptis required, at most 8,000 characters.--durationis a whole number from 1 through 120, and must additionally be a value the model supports.
Get explicit approval
Name the model, the duration, the aspect ratio, roughly how long it will take, and that it uses the connected provider. Then wait for a yes in the same turn.
Generate once
Text to video, streamed straight to disk:
gavana video generate \
--model model:OPAQUE_MODEL_KEY \
--prompt "A slow product turntable on a matte grey surface" \
--duration 15 \
--aspect-ratio 9:16 \
--download ./turntable.mp4 \
--progressImage to video from a canvas node:
gavana video generate \
--model model:OPAQUE_MODEL_KEY \
--prompt "Animate the fabric naturally, keep the product identical" \
--first-frame node:PRODUCT_STILL \
--canvas canvas:OWNER_UID:CANVAS_ID \
--idempotency-key hero-clip-2026-08-04 \
--progressFrames to video:
gavana video generate \
--model model:OPAQUE_MODEL_KEY \
--prompt "Dissolve between the two states" \
--first-frame asset:START_ASSET \
--last-frame asset:END_ASSET \
--duration 8Queue and hand off:
gavana video generate \
--model model:OPAQUE_MODEL_KEY \
--prompt "Animate the fabric naturally" \
--first-frame ./product.png \
--no-wait--download cannot be combined with --no-wait — you cannot stream a file that has not finished. Queue it, then download separately.
Audio: --audio or --no-audio, only on models that declare a generate_audio parameter. Passing both, or passing a value to either, is a usage error.
Supply your own --idempotency-key (8–200 characters) for anything you might need to resume. Without one the CLI generates a UUID, which is fine for a one-shot command and useless for a retry.
Wait
By default the CLI waits up to 30 minutes — longer than the 15-minute default elsewhere, because video is slower. --progress streams state transitions to stderr, including a percentage when the provider reports one.
If you queued with --no-wait:
gavana job get job:JOB_ID --jq '.status' -r
gavana job wait job:JOB_ID --progress
gavana job cancel job:JOB_ID --yesAll three require job:manage.
Exit 8 means you stopped waiting — the job is still running and can be resumed with job wait. Exit 9 means the job reached a terminal failed, canceled, or expired state.
Download
If you did not use --download:
gavana video download job:JOB_ID --file ./result.mp4The CLI refuses to overwrite an existing file unless you pass --yes. It writes through a temporary file created with mode 0600 and cleans it up if the stream fails, so a partial download never masquerades as a finished one.
Returns job, the resolved file path, bytes, and contentType.
Report honestly
A video Job may return a protected download without materialising a native video node on any canvas. Report exactly what the server returned. Do not describe a downloaded file as a canvas node, and do not claim canvas durability you did not observe.
Report the job: handle, the terminal status, and the downloaded file path with its byte count. If a node was created, report the node: handle too — after reading the canvas back to confirm it.
What you end up with
- A terminal
job:handle with its final status - A downloaded
.mp4file, if you downloaded one - Any
node:orasset:handle the server actually returned — not one you assumed
The job: record expires. The file on disk and any durable handles do not.
Common mistakes
| Mistake | What happens |
|---|---|
Guessing a model: handle | Not found, or an ambiguity error naming the collision |
Skipping model get | A usage error on duration, ratio, or resolution — or a worse-shaped video than the user wanted |
--last-frame without --first-frame | Usage error before anything starts |
A node: frame without --canvas | Usage error before anything starts |
Duplicate --reference values | Usage error before anything starts |
--download with --no-wait | Usage error. Queue, then download |
| Retrying a paid failure automatically | Two charges for one intent |
| Calling a downloaded file a canvas node | A durability claim you did not verify |
Cheaper alternatives
Before generating, check whether the user actually needs generation:
- Deterministic Image Actions — resize, crop, aspect-ratio change, composite, add text, overlay, colour grade, rotate — cost no AI credits and cover a lot of “make this fit the format” work. See the CLI reference.
- An existing asset may already be on the canvas. Read it first.