--- name: shotstack description: | Render video, poll render status, and upload local source files via the Shotstack API. Use when generating clips, building automated video pipelines, uploading footage/audio/images to use in an Edit, or orchestrating cloud video renders from a script, agent, or CI workflow. NOT for: real-time streaming, or live broadcasting. license: Apache-2.0 --- # Shotstack CLI This skill loads in **terminal-based AI agents** (Claude Code, Cursor, Codex CLI, Gemini CLI, etc.). All operations here are shell commands. There is no embedded UI, no iframe, no inline canvas, no MCP tool surface — only `shotstack` invocations from a terminal. To hand off to a human, run `shotstack studio `; this opens the user's default browser to a `shotstack.studio` URL. Tell the user to click Render *in the browser tab*, not in any UI inside the terminal. ## Check versions once per session This skill is version **0.11.0** and needs `@shotstack/cli` **0.11.0** or later. Before the first `shotstack` command in a session: 1. Run `shotstack --version`. If it is older than 0.11.0, tell the user: what this skill documents, such as `analyze`, is missing until they run `npm install -g @shotstack/cli@latest`. 2. Run `npm view @shotstack/cli version`. If it is newer than this skill's version, tell the user an update is available and ask whether to install it. Only on a yes, run `npx skills update shotstack -y` and `npm install -g @shotstack/cli@latest`. Never update without asking. `npx skills check` is not a read-only check: it installs the update. If a check fails (no network, no npm, a sandbox), skip it and carry on. **Open-ended first render? Ask before composing.** If the ask doesn't state what the video is (subject, format or destination) — e.g. "render my first video", "make me a video", "set up Shotstack" — read [`references/onboarding.md`](references/onboarding.md) and ask its discovery questions, then WAIT for answers. Do not write an Edit first. An open-ended ask is not a specification, and a stray JSON file in the project doesn't make the user experienced. Compose without asking only when the user has stated what the video is, or explicitly says to just show anything. Commands for the Shotstack video rendering API. `render` submits an Edit JSON and returns a render ID; `status` polls a render until done. `ingest` uploads your own local files (or fetches remote URLs) and hosts them so they can be referenced from an Edit. `validate` lints an Edit — run it before every render. `studio` opens an edit in the browser editor for a human to preview, tweak, and render. `template list|get|create|update|delete` reads and writes templates saved to the account: `list` shows saved templates (id + name); `get ` fetches a saved template's Edit JSON (e.g. one the user designed in Studio) so you can render or remix it; `create --name ` saves an edit as a new template; `update ` overwrites one; `delete ` removes one. `models` lists the generation models for prompt-driven assets and whether this key can use each one; `models ` prints the options a model accepts. `generate ""` generates one asset on its own and prints its URL. `analyze ` measures a music track's tempo, beats, bars, drops and sections, free and without a key. **Default loop — no API key required:** compose → `validate` (offline lint) → `studio` (browser preview). Only the API-backed commands (`render`, `status`, `ingest`, `models`, `generate`) need a key. Reach for `render` when you specifically need a final MP4 exported in the cloud; reach for `studio` for everything else — it is the cheapest way to see an edit and the right default for any creative a human will review. ## Authentication Save your API key once with `shotstack login` — it's stored in `~/.shotstack/credentials.json` (chmod 600), per environment, so you don't re-enter it every session: ```sh shotstack login # prompts (hidden input); saves the v1 (production) key shotstack login --env stage # save the stage key (Shotstack keys are env-specific) echo "$KEY" | shotstack login # non-interactive (CI / agents): read the key from stdin shotstack logout --env stage # forget one env; shotstack logout --all forgets all ``` Or set an environment variable (overrides the saved key — best for CI): ```sh export SHOTSTACK_API_KEY=... ``` Resolution precedence: **`SHOTSTACK_API_KEY` env var → saved key for the target `--env` → error.** Get a key at . **`validate` and `studio` need no key** — only the API-backed commands (`render`, `status`, `ingest`, `models`, `generate`) require one; without a key *those* exit 1, while compose → validate → studio keeps working. ## Environments ``` --env stage → https://api.shotstack.io/edit/stage (test credits, free) --env v1 → https://api.shotstack.io/edit/v1 (production, default) ``` **The cheapest iteration path is `studio` — not `stage`.** `studio` previews client-side in the browser with no key and no credits (see the Studio section below); iterate there. `--env stage` gives a free cloud render (With watermark) for when you need a rendered video for review; v1 charges real credits. Override the target with the `SHOTSTACK_ENV` env var for the session. `ingest` commands hit the parallel `…/ingest/{env}` base automatically using the same key. ## Quickstart ```sh # 1 — Validate offline. Schema + same-track overlaps + fonts + URLs. No key, no credits. shotstack validate template.json # 2 — Preview in the browser. The DEFAULT next step: no key, no credits; a human hits Render. shotstack studio template.json # → opens https://shotstack.studio/s/ and prints the short URL # 3 — Export to MP4. Needs an API key and charges credits. Submit + poll in one command. shotstack render template.json --watch # → done https://shotstack-api-v1-output.s3.amazonaws.com/.../01ja7-x8m2k-39rzv-cmvxve.mp4 # Poll an existing render to a terminal state. shotstack status 01ja7-x8m2k-39rzv-cmvxve --watch # → done https://shotstack-api-v1-output.s3.amazonaws.com/.../01ja7-x8m2k-39rzv-cmvxve.mp4 ``` ## Uploading local files to use in an Edit An Edit can only reference media by **URL** — a local path in an `asset.src` will not render. To use a local file, host it first with `shotstack ingest upload`, then put the returned URL in your Edit. ```sh # Upload a local file and poll until it's hosted. --watch prints the URL. shotstack ingest upload ./clip.mp4 --watch --output json # → {"id":"zzytey4v-...","status":"importing"} # → {"id":"zzytey4v-...","status":"ready","source":"https://shotstack-ingest-api-v1-sources.s3...amazonaws.com/.../source.mp4",...} # Capture the hosted URL straight into a variable: SRC=$(shotstack ingest upload ./clip.mp4 --watch --output json | tail -n1 | jq -r .source) # …then reference "$SRC" as an asset.src in your Edit JSON and run `shotstack render`. ``` The bare command (no `--watch`) returns only an `id`; the hosted `source` URL does not exist until ingestion is `ready`. Always `--watch` (or follow up with `shotstack ingest status --watch`) when you need the URL. Other ingest subcommands: `ingest fetch ` (host a copy of a remote URL), `ingest status `, `ingest list`, `ingest delete `. **Read [`references/ingest.md`](references/ingest.md) for the full upload→render workflow, status values, and supported file types.** ## Generating assets An `image`, `video` or `audio` asset with a `prompt` and a `model` is generated by AI. `shotstack models` lists the models and whether this API key can use each one. `shotstack models ` adds the JSON Schema for that model's `options`. Read it before setting `options`, because values outside it are rejected. ```sh shotstack models --output json shotstack models seedance-2.0-text-to-video --output json ``` Offer only models marked available. `unavailable: AiCapabilityNotIncluded` means the plan doesn't include that kind of generation, `AiDisabled` means AI is turned off for the account, and `AiAccessUnavailable` means access couldn't be confirmed, so try again later. "availability unknown" means the check didn't run. It is not a yes. `shotstack generate ""` generates one asset without rendering an edit and prints its URL. Use it to try a prompt, a voice or a still before building it into a timeline. Inside an edit, set `prompt` and `model` on the asset instead and it is generated at render time. ```sh shotstack generate nano-banana-2 "A ceramic mug on a walnut desk, soft window light" \ --options '{"resolution":"2K","aspectRatio":"16:9"}' --watch --output json | tail -n1 | jq -r .url shotstack generate seedance-2.0-text-to-video "Waves break over black sand at dusk" --length 5 --watch ``` `--length` is the clip length in seconds. Models that generate to a duration use it in place of their own duration option. **Generation costs credits on stage as well as v1.** Before generating, run the same command with `--quote`, tell the user the model and the credits it prints (it says "up to" when the final charge can be lower), and wait for a yes. Identical requests share one job and its cached result: repeating a request while it runs, or after it finishes, returns the same job without charging again. That is also how to pick up a job started without `--watch`. Sending a failed generation again retries it, and that is charged. **Cutting or animating to music?** Measure the track with `shotstack analyze --output json` and follow [`references/beat-sync.md`](references/beat-sync.md): write every cut and keyframe in bars from the map, never from the BPM you asked for. **Read [`references/generation.md`](references/generation.md) before writing a prompt.** It covers what each model responds to, when to put text in a `rich-text` layer instead of the image, and how to size and chain generations inside an edit. ## Default workflow: preview in Studio (no key, no credits) **`shotstack studio ` is the default way to look at an edit** — prefer it over `render` unless you specifically need a cloud-exported MP4. It posts the JSON to https://shotstack.studio and opens `https://shotstack.studio/s/` in the browser — a short, shareable URL. No API key, no render credits charged; it previews client-side, so it works with no key. The human plays, edits, and decides whether to spend credits on a render. ```sh shotstack studio template.json # opens browser + prints short URL shotstack studio template.json --no-open # headless: just print the URL shotstack studio template.json --no-shorten # emit base64url URL inline (offline / debug) shotstack studio template.json --output json # piping: {"url":"...","shortened":true}, no browser ``` On headless systems (no `xdg-open`, no `$DISPLAY`) the browser launch silently no-ops; the URL is still printed. Safe to run anywhere. If the share API is unreachable, the command falls back to the inline base64url form automatically and prints a stderr warning. Shares expire after 30 days. **Default to `studio` for anything non-trivial** — multi-scene, multi-track, or any creative an interested human will review. It previews client-side, costs nothing, and lets the human hit Render when it's right. Use `render` directly only for single-shot/simple edits, automated pipelines, or when told "just render it". ## Four CLI rules 1. **Pipe → `--output json`.** Default output is human-readable. When parsing programmatically or piping to another command, always pass `--output json`. 2. **Use `--watch`, not a polling loop.** `shotstack render --watch` submits and polls in one shot; `shotstack status --watch` polls an existing render. Both exit when terminal: `done` (exit 0) or `failed` (exit 1). Don't write `while true; do ...; sleep 3; done`. 3. **Compose from `shared/agent-core.md`, then `shotstack validate`.** Its cheatsheet carries the property names, enums (transition/effect/position/fit) and rich-text fields you need — no schema download required. `shotstack validate ` then checks the JSON against the live schema offline and flags same-track overlaps, unloaded fonts and non-public URLs before you spend a credit. (For edge cases the full schema is at and the guide at .) 4. **Hand off to a human via `shotstack studio ` when uncertain.** Don't burn render credits iterating. Generate JSON → `shotstack studio file.json` (opens browser) → human reviews/tweaks → render only when right. ## REQUIRED: Read `shared/agent-core.md` before composing any Edit JSON Edit JSON does **not** follow CSS or web conventions, least of all the `rich-text` asset's styling fields (an `html5` asset's `css` is ordinary CSS). Composing Edit JSON from training-data instinct will produce silently invalid renders. **Read [`shared/agent-core.md`](shared/agent-core.md) first**, every time. The most-failed conversions: | You'd write (wrong) | API requires (right) | |---|---| | `alignment` | `align` | | `align.vertical: "center"` | `align.vertical: "middle"` | | `font.name` | `font.family` | | `duration` | `length` | | `transitions: [...]` (array) | `transition: { in, out }` (object) | | `fit: "cover"` (CSS instinct) | `fit: "crop"` | | `tracks[0]` is the bottom (z-index instinct) | `tracks[0]` is the **TOP** layer | The full ruleset (asset types, fonts, smart-string clip values, top-5 mistakes) lives in `shared/agent-core.md`. **Motion is yours to design.** Built-in motion (transitions, effects, keyframes, rich-text animation) takes fixed options from the schema; `html5` takes any seekable animation. [`references/motion.md`](references/motion.md) covers what each layer can animate (transitions, effects, keyframes, rich-text animation, `html5`), the easing available and recipes; the *Motion* section of `agent-core.md` summarises it. ## Exit codes | Code | Meaning | |---|---| | `0` | Success | | `1` | Permanent error — validation, missing key, 4xx, render `failed` | | `2` | Transient error — 5xx, network, timeout. Safe to retry. | ## References Authoritative sources, in order of preference: - `shotstack --help` and `shotstack --help` — current CLI flag listing - [`shared/agent-core.md`](shared/agent-core.md) — Edit JSON authoring conventions (shared with MCP server) - — OpenAPI Schema for the render API (machine-validatable) - — full API docs in LLM-friendly single file - — raw OpenAPI YAML, source of truth for property names and enums - — interactive HTML docs and guides - — interactive HTML API reference - — CLI source This skill ships sub-references for the gnarly bits: - [`references/onboarding.md`](references/onboarding.md) — first-render discovery interview for new users: what to ask, and how answers map to a first Edit - [`references/ingest.md`](references/ingest.md) — uploading local files (and fetching URLs) so they can be used in an Edit: the upload→render workflow, `--watch`, status values, supported types - [`references/timeline.md`](references/timeline.md) — track layering, transitions, background music via audio assets - [`references/positioning.md`](references/positioning.md) — coordinate model, `position`/`offset` (fraction of frame, +y up), clip bounding box & `fit`, text sizing, transform order - [`references/caption.md`](references/caption.md) — sizing per resolution, default style, the 5 named presets, alias pattern (asset type: `rich-caption`) - [`references/svg.md`](references/svg.md) — required attrs, supported elements - [`references/motion.md`](references/motion.md) — what moves on each layer (transitions, effects, keyframes, rich-text animation, `html5`), the easing available, GSAP/CSS recipes, and the brand kit through merge fields - [`references/html5.md`](references/html5.md) — HTML5 asset: fields, preloaded libs (GSAP and its plugins, d3, anime, lottie), browser harness and seek rules, 3D, sizing, worked examples - [`references/html5-effects.md`](references/html5-effects.md) — **the creative palette**: every effect an `html5` clip can do, by common motion-design name (per-character text, stroke write-ons, mattes, blend modes, noise displacement, speed ramps, 2.5D camera, particles), with one-line recipes and what to avoid. Read before designing an `html5` clip. - [`references/html5-snippets.md`](references/html5-snippets.md) — copy-paste motion-graphic clips: kinetic headline, value reveal, shine sweep, pulsing CTA, film grain - [`references/fonts.md`](references/fonts.md) — built-in fonts, Google Fonts URL pattern, custom-font workflow - [`references/generation.md`](references/generation.md) — per-model prompting craft for AI-generated video, images, speech and music, and what a timeline adds to a prompt. Read before writing any `prompt`. - [`references/beat-sync.md`](references/beat-sync.md) — cutting and animating to music: get the track first, analyse it, write every cue in bars, drive `html5` from the map, check frames at bar lines - [`references/asset-library.md`](references/asset-library.md) — placeholder videos, images, music - [`references/troubleshooting.md`](references/troubleshooting.md) — common errors and fixes If this skill and `--help` ever disagree, trust `--help`. If this skill and `llms-full.txt` ever disagree, trust `llms-full.txt`.