Skip to Content
AgentsRecipesGenerate video

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 download

In MCP: find_video_models → generate_video → get_video_job.

Steps

Find a connected video model

gavana model list --capability video.generate --jq '.models[].handle' -r

Narrow by provider if you need to:

gavana model list --provider PROVIDER_NAME --capability video.generate

Add a capability filter when the task needs one:

CapabilityNeeded for
video.generateAny 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 --pretty

Check. This is the step that saves money. Read:

  • parameters — the exact names, and for each one either an options list or a min and max.
  • Which of duration / duration_seconds, aspect_ratio, resolution, and generate_audio exist at all.
  • Whether first_frame is marked required.
  • The capabilities array.
  • 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:

FormNotes
node:NODE_IDRequires --canvas canvas:OWNER_UID:CANVAS_ID
asset:ASSET_IDDurable asset handle
https://…Public HTTPS only, no credentials in the URL
A local pathPNG, JPEG, WebP, or GIF, at most 50 MB — uploaded privately first
-Bytes from stdin
clipboardmacOS only

Rules the CLI enforces before spending:

  • --last-frame requires --first-frame.
  • --canvas is required when any frame or reference is a node: handle.
  • Up to nine --reference values, and they must be unique — identical local files are detected by content hash.
  • --prompt is required, at most 8,000 characters.
  • --duration is 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 \ --progress

Image 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 \ --progress

Frames 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 8

Queue 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 --yes

All 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.mp4

The 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 .mp4 file, if you downloaded one
  • Any node: or asset: 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

MistakeWhat happens
Guessing a model: handleNot found, or an ambiguity error naming the collision
Skipping model getA usage error on duration, ratio, or resolution — or a worse-shaped video than the user wanted
--last-frame without --first-frameUsage error before anything starts
A node: frame without --canvasUsage error before anything starts
Duplicate --reference valuesUsage error before anything starts
--download with --no-waitUsage error. Queue, then download
Retrying a paid failure automaticallyTwo charges for one intent
Calling a downloaded file a canvas nodeA 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.
Last updated on