CLI Reference
Running the CLI
# After the current source install, or after the future npm release
gavana --helpgavana-canvas is the descriptive alias. craftboard and
craftboard-canvas remain backward-compatible aliases for existing scripts.
See Install the CLI for the current package
release status.
Output format
The CLI writes one JSON result to stdout by default:
{ "ok": true, "result": {} }Errors and progress events go to stderr, so a script or AI client can parse
stdout cleanly. Use --output markdown for a chat-ready result or
--output jsonl for one selected array item per line.
Use --jq to select a property path and -r to print strings or numbers
without JSON quotes:
gavana canvas list --limit 25 --jq '.canvases[].handle' -r
gavana asset list --jq '.assets[]' --output jsonlThe built-in selector supports property paths, non-negative array indexes, and
[] projections, such as .canvases[0].title or
.connections[].models[]. It intentionally does not execute arbitrary jq
programs, so it works without a separate jq installation.
Errors include a stable code and, when possible, the exact fields to fix:
{
"ok": false,
"error": {
"code": "input_validation_error",
"message": "baseRevision is required.",
"fields": [
{
"field": "baseRevision",
"message": "Read the canvas and pass its current revision."
}
],
"requestId": "7f8e0d9d-4bf8-4e6e-96e0-8bcd6a8f315a"
}
}The requestId is safe to share with support. Never share an Agent Access
Token. Fix validation and permission errors before retrying. A client may retry
safe read requests after a temporary error such as rate_limited,
service_unavailable, or upstream_timeout; for an image, workflow, video, or
other potentially paid write, ask for explicit approval before starting a new
attempt.
Exit codes
| Exit | Meaning |
|---|---|
0 | Success |
2 | Usage, configuration, or validation error |
3 | Authentication or authorization error |
4 | Revision conflict |
5 | Not found |
7 | Network error |
8 | Wait timeout — the Run can still be resumed |
9 | Recipe, image, or Action Run ended unsuccessfully |
Core commands
auth login|status|logout
config list|use
mcp install|config
canvas list|create|agent|get|render|apply
node get|create|update|move|resize|delete
connection list|create|delete
asset list|get|upload
provider list
model list|get
recipe search|get|fork|run
action list|get|run
image generate|edit|variations
video generate|download
run get|wait|cancel
job get|wait|cancel- Destructive commands require
--yes. - Recipe, image, and Action commands wait for durable persistence by default — pass
--no-waitto get the sharedrun:handle immediately and resume it later withrun wait. - Default waiting plus
run get|wait|cancelrequires the token’sjob:managescope. A start-only token can use--no-waitand a signed webhook instead. job get|wait|cancelremains an image and Action compatibility alias; it is never used for Recipe Runs.- Canvas, Recipe, asset, Action, model, and provider list commands accept
--limitand the opaque--cursorreturned aspage.nextCursor. Keep the same filters when requesting the next page.
Run results include estimatedSeconds, observed queue/execution timing, and a
stable failure.code plus failure.retryable when generation fails. A failed
provider request is returned as a terminal Run result, so run wait finishes
without hiding the reason behind a generic request error. The complete terminal
resource remains on stdout for automation, while recipe run, image ...,
action run, and run wait
return exit code 9 when the terminal state is failed, canceled, or
expired.
Image and Action run: handles and their legacy job: aliases address the
same temporary record and expire together. By default, unacknowledged results
expire after 24 hours; a successfully finalized result expires 15 minutes after
its first server finalization (from a Run GET or signed callback), and the
expired tombstone is deleted after seven days. Operators may override these
windows. Recipe Run records currently do not use this temporary TTL. Persist
the returned asset: and node: handles, which remain durable after the
observation handles expire.
To receive one signed callback instead of polling, keep the secret out of shell history:
read -rs 'GAVANA_WEBHOOK_SECRET?Webhook signing secret: '; printf '\n'
export GAVANA_WEBHOOK_SECRET
gavana image generate \
--destination agent-canvas \
--prompt "A studio product photograph" \
--webhook-url "https://automation.example.com/hooks/gavana" \
--no-wait
unset GAVANA_WEBHOOK_SECRETUse --webhook-secret-env MY_SECRET_VARIABLE to read a different environment
variable. The CLI sends the secret only in the authenticated Run-start body;
Gavana encrypts it and Run output reports only delivery state. Recipe and
Image Action starts accept the same webhook options. The always-on worker keeps
an authenticated Recipe moving after the original CLI process exits.
Successful Image and Action callbacks are sent only after their durable canvas,
node, and asset results are stored. Failed, canceled, or expired callbacks
describe the terminal state without requiring images.
Stable handles
Use handles returned by Gavana:
canvas:<ownerUid>:<canvasId>
node:<nodeId>
connection:<connectionId>
asset:<assetId>
asset:<ownerUid>:<assetId> (shared asset)
recipe:<recipeId>
action:<slug>
model:<opaqueModelKey>
run:<runId>
job:<jobId>Use the owner-qualified handle returned by asset list for a shared asset.
This lets Gavana read that exact asset directly without searching another
user’s library. Recipe and Action handles come from their catalogs. Model,
Run, and job IDs are opaque results: copy their complete returned handles and
do not decode, guess, or construct them.
Recipe Runs
Forking and running are deliberately separate. recipe fork adds a private,
editable Recipe card and never executes it. recipe run is the explicit action
that binds typed inputs, creates declared output nodes, and starts text or image
work:
gavana recipe run recipe:product-visual-direction \
--input product-context="A matte black travel bottle for a quiet premium campaign" \
--destination canvas:OWNER_UID:CANVAS_IDUse each exact input key returned by recipe get. Written ports accept inline
text, @path, a text/sticky node:, or an image reference when the Recipe
asks for “an image or written note.” For that flexible written port, upload a
local visual first and pass the returned asset: handle; @path reads the
file as text. Image ports accept node: or asset: handles, local raster
paths, stdin, or the macOS clipboard. All Recipe starts
currently require image:generate and its dependent scopes, including
text-only Recipes. The terminal Run returns typed outputs with durable node:
and, for images, asset: handles.
Use gavana model list --capability image.edit before choosing a model.
The result tells you which saved connection can run it, the exact valid
parameters, and its estimated duration. Then inspect one entry with
gavana model get model:<opaqueModelKey> and pass the same handle to an
image command with --model model:<opaqueModelKey>.
Deterministic Image Actions
Image Actions make precise raster changes without asking an AI model and without spending AI credits. The first stable set is resize, crop, change aspect ratio, side-by-side composite, add text, overlay image, color grade, and rotate.
Inspect the catalog before running an Action:
gavana action list
gavana action get action:resize
gavana action run action:resize \
--input ./product.png \
--destination agent-canvas \
--width 1080 \
--height 1350For two-input Actions, repeat --input in the order shown by action get:
gavana action run action:side-by-side-composite \
--input node:FIRST_IMAGE \
--input asset:SECOND_IMAGE \
--destination canvas:OWNER_UID:CANVAS_ID \
--direction horizontal \
--gap 24Inputs may be node: or asset: handles, a local PNG/JPEG/WebP/GIF path,
stdin (-), or clipboard on macOS. The CLI privately uploads local inputs,
creates one output node when --target is omitted, waits for durable asset and
node handles by default, and returns exit code 9 for a failed terminal Run.
Use repeatable --param NAME=VALUE for schema fields that do not have a
dedicated flag. Existing handles need only the Action scopes; local, stdin, and
clipboard inputs additionally require image:generate for the private upload.
Video generation
Video generation is an explicit potentially paid action. Discover the exact connected model and capability before starting; do not guess a model: handle or retry a failed paid request automatically.
gavana model list --capability video.generate
gavana model get model:OPAQUE_MODEL_KEY
gavana video generate \
--model model:OPAQUE_MODEL_KEY \
--prompt "A slow product turntable" \
--duration 15 \
--aspect-ratio 9:16 \
--download ./turntable.mp4For image-to-video, use --first-frame with a durable node:/asset: handle, public HTTPS URL, local image, stdin, or the macOS clipboard. A last frame requires a first frame. Add --no-wait to return the job: handle immediately, then use job get, job wait, job cancel, or video download job:JOB_ID --file ./result.mp4. Generation requires canvas:read, asset:read, and video:generate; waiting, downloading, and cancellation also need job:manage.
Concurrency
An operation that changes an existing canvas takes its latest baseRevision (from a prior read) and an idempotencyKey, so retries are safe and concurrent browser and agent edits do not clobber each other. Creating a new canvas or resolving the persistent Agent Canvas is a separate operation; use the exact contract for that command.