Skip to content
Back to skills

Cueframe Cli

ASecurity

Use when editing, clipping, or rendering video via the CueFrame CLI — e.g. "make a 9:16 short from this podcast", "pull the best moments out of this MP4", "render a clip", or any task that calls the `cueframe` binary. Also use when comparing CueFrame against direct-ffmpeg approaches.

  • 2 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added October 23, 2026
ai-agentsgoshellbashnodeapibackend

Works with

  • claude code
  • cursor
  • terminal
  • cli
  • api
  • mcp

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 3 files and shows the line behind each finding

Scanned November 11, 2026

npx -y skills add cueframe-ai/cueframe-mcp --skill cueframe-cli --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cueframe Cli?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cueframe Cli
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/cueframe-ai-cueframe-cli/badge)](https://www.skillsdirectory.com/skills/cueframe-ai-cueframe-cli)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cueframe-cli
description: Use when editing, clipping, or rendering video via the CueFrame CLI — e.g. "make a 9:16 short from this podcast", "pull the best moments out of this MP4", "render a clip", or any task that calls the `cueframe` binary. Also use when comparing CueFrame against direct-ffmpeg approaches.
---

# CueFrame CLI

Use the [project and capability policy](../composing-video/references/project-policy.md) for scope, current state and metered work.

## MCP is the primary surface — read this before using the CLI

**For a tool-driven workflow, prefer an existing supported MCP connection. For an explicitly requested terminal or CI workflow, use the CLI.** MCP is the supported, maintained integration surface: it hides transport and
contract details, its tools are generated from the same OpenAPI SSOT the CLI is, and it is where
new capability lands first. The `cueframe-connect` skill owns the setup for every host
(Claude Code, Claude/ChatGPT connectors, Cursor/Codex/VS Code/Windsurf/Zed, and the
no-account pay-per-call path) — load it rather than copying a connection command from here.

**Use this CLI when MCP is not available to you:** a terminal or CI job with no MCP host, a
scripted batch, or a human at a shell. It is a first-class path, not a deprecated one — but it is
the *second* thing to reach for.

**Do not hand-roll `curl` against `/v1`.** Raw REST is the fallback beneath the fallback: it is
where undocumented contract edges bite (components' runtime params were discovered that way), and
both MCP and this CLI exist so you do not have to.

## Overview

The `cueframe` CLI drives the CueFrame platform from the terminal. Optimized for agents — every command supports `--json` (NDJSON event stream) and the binary self-describes via `npx -y cueframe@0.12 describe --json`.

**Run it as `npx -y cueframe@0.12 …` — every command in this skill is written that way, and
that form is executable verbatim.** There is no `cueframe` on your PATH unless you put it
there: `npx -y cueframe@0.12 install` wires the MCP server and drops these skills, but npx
unpacks to an ephemeral cache, so it installs no binary. `npx` re-resolves the current
version on each call (~0.5s warm, ~5s cold), which also means these commands never go
stale. If you are running many in a row and want to skip that, `npm i -g cueframe` once
and drop the `npx -y ` prefix — but it needs a user-writable npm prefix (a default Linux
install fails `EACCES` on `/usr/local/lib/node_modules`), so it is an optimization, not
the documented path.

**The framework is three verbs:** `upload` (register media) → `composition put` (author the timeline) → `render` (→ MP4). The `Composition` is the contract — render takes the saved composition, nothing else. Everything domain-specific (AI clip suggestions, FCPXML/Premiere export) is a **use-case on-ramp** layered on top, not part of the core.

**Core principle — discover, don't guess.** Never author a composition from the
examples below alone. The live contract is `npx -y cueframe@0.12 schema composition` (prints
the real wire schema the server enforces); confirm any draft with
`npx -y cueframe@0.12 composition validate -b @file.json` BEFORE you render. Validation is
free and instant; a render is neither. The examples here are orientation — the
schema is the source of truth.

**Core principle:** once you are ON this path, drive everything through `cueframe` — never `curl` the v1 API around it, which invalidates the work and hides CLI bugs. (Choosing MCP over the CLI in the first place is not "going around it"; see the banner above.)

## Framework workflow (upload → compose → render)

The general path for any agent. Author the timeline yourself and render it — no
clip suggestion required.

For iteration, use `cueframe-compose-loop`'s [preview workflow](../cueframe-compose-loop/references/preview-workflow.md).
Validate first, then use `preview_card` / `preview_component` for isolated graphics,
`preview_frame` for composition stills, or `preview_clip` for a motion window. Use the available
MCP tools or the CLI's `api` escape hatch with the live request contract. Full `render` is for
delivery, not checking each edit. CLI validation does not replace visual evidence.

To compare a certified reference frame with an existing saved preview, use `compare`:

```bash
npx -y cueframe@0.12 compare <projectId> --reference-media <mediaId> --reference-representation <identity> --reference-frame 117 --candidate-job <jobId> --candidate-artifact <artifactId> --out ./comparison --json
```

The command calls the shared comparison operation; it does not rerender the composition. `--views overlay,difference` selects diagnostics and `--crop x,y,width,height` uses one common-coordinate crop. NDJSON contains source identities and image receipts, never base64 payloads. `--out` saves verified PNGs; without it, image receipts explicitly say `metadata_only`. Inspect those images and relevant motion before judging the film.

```bash
# 0. Always use --json for agent-driven runs (NDJSON to stdout, no spinners).
#    Commands run against production; auth is stored in ~/.cueframe/auth.json.

# 1. Register media (one or many — mixed video / image / audio).
npx -y cueframe@0.12 upload "/path/to/source.mp4" --json   # → mediaItemId (process_complete)

# 2. Create a project (sets aspect/format).
npx -y cueframe@0.12 project create -n "promo" -a 9:16 --json   # → projectId

# 3. Author the composition: tracks of clips (per-clip reframe/trim), optional
#    captions (captions.segments), brandKitId. The composition is the SSOT.
#    Discover the live schema, then validate the draft BEFORE saving/rendering:
npx -y cueframe@0.12 schema composition                                 # → live wire schema
npx -y cueframe@0.12 composition validate -b @composition.json          # → ✓ valid | per-field errors (no render)
npx -y cueframe@0.12 composition get <projectId> --json                  # → etag (not found = no composition yet)
npx -y cueframe@0.12 composition put <projectId> -b @composition.json --if-match <etag>
#    --if-match is required: a save made since your `get` fails with 409 stale_etag
#    instead of being overwritten. Re-`get`, re-apply your edit, retry. Use --create
#    only for the first composition of a project (refused 409 if one exists).

# 4. Render the saved composition to MP4. SSE-watches + downloads when done.
npx -y cueframe@0.12 render <projectId> -o ./out.mp4 --json
# → render_queued → render_progress* → render_complete
#
# `render` takes ONLY a projectId and renders the SAVED composition (tracks +
# captions). A clip suggestion is NOT required. Re-running the same command on an
# unchanged composition replays the same render (the Idempotency-Key hashes the
# project, the composition ETag and the request: --aspect/--fps/--resolution/
# --priority/--intent); editing the composition or changing a flag starts a new one.
# Without --aspect it renders the composition's own format. --aspect must match the
# composition's aspect (a new aspect is a `derive_composition`, not a render flag);
# pass it with --resolution hd|fhd|4k to change only the output resolution.
# Captions: render reads composition.captions — put caption words there to caption
# a hand-authored composition; if absent, the clip is rendered without captions.

# Reattach to an in-flight render later (e.g. after disconnect):
npx -y cueframe@0.12 render watch <renderId> -p <projectId> -o ./out.mp4 --json
```

## Anatomy of a composition.json

This section orients you to the shape; the authoritative contract is
`npx -y cueframe@0.12 schema composition` (the live wire schema) — run it when a field is
unclear, and `npx -y cueframe@0.12 composition validate -b @file.json` to check a draft.

`composition put` takes the **bare** `Composition` object (no wrapper; the CLI PUTs
the `@file` verbatim with your `--if-match` ETag). Minimal valid shape:

```json
{
  "v": 1,
  "format": { "aspectRatio": "9:16", "fps": 30 },
  "tracks": [
    { "id": "v1", "kind": "video", "contents": [
      { "id": "c1", "startTime": 0, "duration": 10, "source": { "kind": "media", "mediaId": "<mediaId>" } }
    ] }
  ]
}
```

- **Required**: `v: 1`, `format.aspectRatio` (`16:9` | `9:16` | `1:1` | `4:5`), `tracks`.
- Tracks hold **`contents`** (not `clips`); each clip wraps a `source`. A clip's
  `source.kind` must match the track `kind`: `media` → `video`/`image`/`audio`,
  `overlay` → `overlay`, `effect` → `effect`.
- `source.kind`s: `media` (`mediaId` + optional `trim`/`reframe`/`volume`), `overlay`
  (`primitiveId` + `params` + optional `zPlane`), `effect` (`primitiveId` + `params`).
- Times are **seconds** (`startTime`/`duration`/`trim`, and `reframe` `startSec`/`endSec`);
  caption word times are **milliseconds**. `region`/`fit` (PiP/inset) are clip-level.
- Clips on one track can't overlap — simultaneous layers go on separate tracks.
- Optional top-level: `captions` (`segments[].words[]`), `brandKitId`, `markers`.

For full per-video-type examples (auto-zoom demo, PiP, split-screen, captions,
behind-subject title), see the `cueframe-product-video` skill.

## Render resolves expensive intents automatically — author, don't pre-bake

You author *intent* on the composition; `render` materializes the expensive
artifacts it implies. Nothing to pre-bake, no compose step required:

- An overlay with `"zPlane":"behind-subject"` → the person **matte** is baked
  on-miss and the text is placed behind the speaker (shoulder-band anchor +
  occlusion handled). Author it and render — it just works.
- A clip whose `reframe.focus` is `{mode:"face",faceId}` / `{mode:"active-speaker"}`
  / `{mode:"all-faces"}` → **subject detection** runs on-miss so the crop tracks the
  real person. (`{mode:"point"}` / `{mode:"frame-center"}` need no detection.)

During this the SSE `render_progress` phases read
`resolving → baking-matte | detecting → rendering → complete` — the first behind/face
render of a source pays a one-time bake (cached after; re-renders are fast).

### Render error codes (fail-loud — render never ships a wrong frame silently)

| `code` | meaning | fix |
|---|---|---|
| `media_not_found` | a referenced `mediaId` doesn't exist or isn't your org's | reference media you uploaded |
| `media_not_ready` | the media has no file yet (still uploading/generating) | wait for `upload`'s `process_complete` |
| `source_dims_unknown` | a `reframe` clip's source has no width/height/fps yet | let the source finish processing before authoring a reframe |
| `content_anchor` | a clip's trim frames *different* footage than its captions show (wrong-footage) | align the trim window to the captioned moment |
| `behind_split_unsupported` | one media used under two *different* behind-subject windows | one behind window per media (split into separate clips/media) |
| `BehindMatteUnresolved` / `TrajectoryUnresolved` | the matte/detection bake produced no result for a behind/face clip | the source may have no detectable person; retry, or drop the behind/face intent |

## Clip-suggestion on-ramp ("podcast → short clip")

ONE use-case layered on the framework: the AI clip-finder picks a moment and
**authors a composition for you** (trim + speaker framing + captions sliced from
the transcript). Use it when you want CueFrame to choose the clip; otherwise author
the composition yourself (above).

```bash
# 1. Upload + chain the AI clip pass.
npx -y cueframe@0.12 upload "/path/to/source.mp4" --analyze --json   # mediaItemId + suggestions
# (or run it explicitly: npx -y cueframe@0.12 analyze <mediaItemId> --wait --json)

# 2. List clip suggestions (publicId sug_…, title, startMs/endMs, score).
npx -y cueframe@0.12 clips <mediaItemId> --json

# 3. Create a project AND author its composition from the chosen suggestion.
npx -y cueframe@0.12 project create -n "paul-klein-shorts" -a 9:16 --from-suggestion <sug_…> --json
#   (or, on an existing project: npx -y cueframe@0.12 composition from-suggestion <projectId> -s <sug_…>)

# 4. Render — same framework verb as above.
npx -y cueframe@0.12 render <projectId> -o ./out.mp4 --json
```

Both flows converge on `composition put` → `render`; the on-ramp just authors the
composition from a suggestion instead of you hand-writing it.

Pipe `--json` output through `jq -c 'select(.event=="…")'` to grab specific lifecycle events.

## Component authoring: scaffold your own

Own the motion-graphics components you render (shadcn-style): scaffold a native component as
editable source, customize it, and render it on CueFrame. The source lives in your repo under
version control; CueFrame bakes it to a transparent video and composites it (the shared
renderer never runs your code). The CLI does not fork built-ins: the maintained builtin
presets and recipes are placed as they are (list them with `list_catalog`
projection `component-library`).

```bash
# 1. Scaffold a workspace (writes cueframe.json + cueframe/components/). Idempotent.
npx -y cueframe@0.12 init --json

# 2a. Scaffold a component in cueframe/components/<id>/ as owned, editable source.
npx -y cueframe@0.12 new component my-badge --category ui-blocks --json

# The scaffold is a native (version 4) source: template.html + definition.json, with its
# manifest in cueframe.json.

# 3. Edit cueframe/components/<id>/template.html (one HyperFrames sub-composition ending in
#    __cfScene.mount(...)) and definition.json (inputs, defaults, timing, capabilities).

# 4. Publish to CueFrame so it can render (the server admits the source or names the rule it breaks).
npx -y cueframe@0.12 push my-badge --json            # one component
npx -y cueframe@0.12 sync --json                      # every component in the workspace

# 5. Reference the component id in your composition as a {kind:'component', componentId, props}
#    clip, then render with the same verb. Preview a single component first via the MCP
#    preview_component loop.
npx -y cueframe@0.12 render <projectId> -o ./out.mp4 --json
```

## Quick reference

| Need to… | Command |
|---|---|
| See every command + flags | `npx -y cueframe@0.12 describe --json` |
| Install/refresh managed skills | `npx -y cueframe@0.12 install` (shared `~/.agents/skills` and Claude `~/.claude/skills`; locally changed or untracked packages are preserved and reported) |
| List projects | `npx -y cueframe@0.12 list -n 50` |
| List your media | `npx -y cueframe@0.12 clips` (no mediaId arg) |
| Discover the live composition schema | `npx -y cueframe@0.12 schema composition` |
| Validate a draft (no save, no render) | `npx -y cueframe@0.12 composition validate -b @plan.json` |
| Read composition + ETag | `npx -y cueframe@0.12 composition get <projectId> --json` |
| Write composition | `npx -y cueframe@0.12 composition put <projectId> -b @plan.json --if-match <etag>` (`--create` for the first composition) |
| Export to Final Cut | `npx -y cueframe@0.12 export fcpxml <projectId> -s <sug> --wait -o cut.zip` |
| Export to Premiere | `npx -y cueframe@0.12 export premiere <projectId> -s <sug> --wait -o cut.zip` |
| Anything not wrapped | `npx -y cueframe@0.12 api GET /v1/...  -i` (escape hatch, like `gh api`) |
| Validate a composition without mutating | `npx -y cueframe@0.12 composition validate -b @plan.json` |

## Auth

Commands run against production. Authenticate once:

- `npx -y cueframe@0.12 login` — OAuth device flow (laptops).
- `npx -y cueframe@0.12 auth <cf_live_… key>` — save a static API key (CI / headless).

Creds are stored in `~/.cueframe/auth.json`; the key can also come from the `CUEFRAME_API_KEY` env var.

## NDJSON event shape

Every `--json` line:
```json
{"_":0,"schemaVersion":"v1","ts":1779250551614,"event":"<verb>_<phase>", ...payload}
```
Phase lifecycle: `<verb>_prepare` → `<verb>_ready` → `<verb>_progress` (0+) → `<verb>_complete` | `error`. The `_:0` field is a pino formatter placeholder — ignore it.

Errors come as `{"event":"error", "phase":"<step>", "message":"...", "code":"...", "exitCode":N}` *and* a non-zero process exit. Read both.

## Common mistakes

| Mistake | Reality |
|---|---|
| Reaching for `curl …/v1/...` because the CLI didn't have a command | Use `npx -y cueframe@0.12 api METHOD /v1/...` — same auth, same JSON pipeline. |
| Polling for render completion with a sleep loop | `npx -y cueframe@0.12 render` already SSE-watches and exits when done. Use `render watch <id>` to reattach. |
| Skipping `--json` and trying to parse human output | Human output is for humans. Agents always use `--json`. |
| Hand-editing the composition without an ETag | `composition put` refuses without `--if-match <etag>` from the `composition get` your edit started from. Don't fetch a fresh ETag right before the put: that overwrites anyone who saved in between. `--create` is only for a project's first composition; there is no unconditional overwrite. |
| Calling `npx -y cueframe@0.12 render <projectId> <suggestionId>` (old two-positional shape) | `render` takes ONLY a projectId; commander rejects the extra arg. It renders the SAVED composition — author it first via `composition put` (hand-author) or `project create --from-suggestion <sug>` (clip-finder on-ramp). |
| Assuming `render` needs a clip suggestion / that captions only come from a suggestion | No — `render` renders the saved composition directly; a suggestion is optional. Captions come from `composition.captions` (author them in the `put` JSON). The clip-suggestion on-ramp just fills those captions for you by slicing the transcript at author time. |

## When this skill applies (routing)

Use this skill for a requested terminal/CI workflow or when the available CLI is the supported path for the task. If supported MCP tools are already connected, use their narrow edit/preview guidance instead. A mechanical operation inside a creative task does not require a different project or new installation. If a required capability is absent, report the limitation and a supported alternative; do not invent a command or silently change lanes.

CLI development and internal backend inspection are outside this usage skill.

Files in this skill

  • SKILL.md18 KB
  • agents/openai.yaml473 B
  • assets/icon.svg1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.