Native Pipeline CLI Skill
Run QCut's built-in TypeScript CLI (qcut, legacy name qcut-pipeline).
Active CLI Version
- Active native CLI version:
1.0.0 - Verify with:
qcut --version - Inventory on 2026-09-07: 280 registered commands in 14 groups (163 of them
under
editor). Checkqcut --help --jsonfor the live list.
Additional resources
- For standalone CLI commands (generate, analyze, transcribe, autoclip, models, help, output formats), see REFERENCE.md
- For audio/voice generation, Kling elements, analysis indexes, edit planning and cleanup, portrait, subtitles, sound/sticker search, Phota, Replicate, the newer ViMax stages,
system update/doctor/keys, andinstances, see reference-media-extras.md - For
compose,filter-lab,effect-lab,text-lab,sticker-lab,transition,draft(Jianying import/export), andedit deflicker, see reference-labs-compose.md - For YAML pipelines, API key management, project management, see reference-pipelines.md
- For ViMax commands (idea2video, script2video, novel2movie, scenes, portraits), see reference-vimax.md
- For editor core reference: connection, flags, batch limits, env vars, common workflows, see editor-core.md
- For editor media & project commands, project.json schema, see editor-media.md
- For editor timeline & editing commands, see editor-timeline.md
- For editor tracks, element patching, timeline manifests, stickers, transcript search, audio/caption export, keyboard, UI waits, demo runs, Moyin, and pointer automation, see editor-tracks-stickers-search.md
- For editor export, diagnostics, MCP, screen recording, UI, screenshots, state control, see editor-output.md
- For editor AI commands: video analysis, transcription, AI generation, Remotion, navigator, see editor-ai.md
- For editor state automation: snapshots, event streams, correlation IDs, transactions, capabilities, and notification bridge endpoints, see editor-state-control.md
- For agent automation: accessibility snapshots with refs, console capture, visual diffs, session persistence, and action policy, see editor-agent.md
- For source file locations by responsibility (core, output, handlers, state, auth), see reference-source-files.md
- For proxy mode, credit system, and admin tester management, see reference-proxy-credits.md
Step 1: Ensure QCut is Running
Before any editor command, check if QCut is running. If not, build and launch it.
# Check if QCut is running
qcut editor health --status-only --json || echo "NOT_RUNNING"
If NOT_RUNNING:
bun run build # Build first (source checkout)
bun run electron & # Launch in background
sleep 5 # Wait for startup
Only one QCut instance runs per user-data directory; a second launch exits
silently. With several editors open, pick the target with
qcut instances list --json and qcut instances use --port <port>.
Step 2: Find Project, Media & Timeline
Most editor commands need --project-id, --media-id, or --element-id. Run these to discover them.
# 1. List projects → get project-id
qcut editor navigator projects --json
# 2. Open a project (navigates the editor)
qcut editor navigator open --project-id <project-id> --json
# 3. Switch to editor panel (navigator open lands on the landing page, NOT the editor)
qcut editor ui switch-panel --panel video-edit --json
# 4. List media → get media-id values
qcut editor media list --project-id <project-id> --json
# 5. Export timeline → get track-id and element-id values
qcut editor timeline export --project-id <project-id> --json
Now you have the IDs needed for all other editor commands.
How to Run
qcut <group> <action> [options] # Group syntax (preferred)
qcut editor <area> <action> [options] # Editor commands are three-level
qcut <command> [options] # Legacy flat syntax (e.g. editor:timeline:export)
qcut-pipeline <group> <action> [options] # Legacy binary name, same CLI
Where the qcut binary comes from:
- Source checkout:
bun run qcut -- <args>runs the TypeScript entry directly;bun run buildproducesdist/electron/native-pipeline/cli/cli.js, whichpackage.jsonexposes as theqcutandqcut-pipelinebins. Rebuild after adding registry entries or handlers. - Packaged desktop app: the same
cli.jsships insideapp.asar. Run it withELECTRON_RUN_AS_NODE=1 "<QCut executable>" "<Resources>/app.asar/electron/native-pipeline/cli/cli.js" <args>; the agent plugin runner resolves this automatically and also honorsQCUT_CLI_PATH.
Output Directory Contract
For website Daytona Chat Agent sessions, uploaded files are under
/tmp/qcut-input and downloadable outputs must land under
/tmp/qcut-output.
For image generation, the CLI default model is gpt_image_2_ima. Do not pass
--model/-m unless the user explicitly requests a specific image model.
The CLI default output directory is $QCUT_OUTPUT_DIR or
~/Documents/QCut/exports. Override it with:
export QCUT_OUTPUT_DIR=/tmp/qcut-output
When running generation, analysis, transcription, music, translation, or
pipeline commands in that sandbox, use -o /tmp/qcut-output when a command
supports --output-dir/-o, or move final user-requested files into
/tmp/qcut-output before finishing. Keep scratch files and package installs
under /tmp/qcut-tools or /tmp.
Video Review / 审片
Use QCut's review mode when the user asks for video review, 审片, timestamped
feedback, CSV/JSON comments, or human-style short-drama notes. Do not use
generic aicp analyze-video for this workflow.
QCUT_DEBUG_OPENROUTER_VIDEO=1 \
QCUT_OUTPUT_DIR=/tmp/qcut-output \
qcut analyze video \
-i /tmp/qcut-input/video.mp4 \
--analysis-type review \
--review-language zh \
--max-tokens 16000 \
-m openrouter_gemini_3_5_flash_video \
--json \
-o /tmp/qcut-output
For English review comments, use --review-language en. The review output is
written under /tmp/qcut-output:
review-comments.json
review-comments.csv
review-feedback-browser.html
review-feedback-summary.html
review-agent-report.md
review-agent-prompts/
raw-analysis.json
review-split-manifest.json # only when the video is split
Long local videos are split automatically when the estimated base64 payload is
too large. If a part fails because OpenRouter returned truncated JSON, inspect
review-split-manifest.json and rerun the failed part rather than rerunning the
whole episode. The parser salvages complete comments from partial JSON arrays,
so non-empty raw-analysis.json with empty CSV usually means the model did not
emit complete comment objects.
In Daytona Chat Agent sessions, local host paths such as /Users/peter/... are
not available. First upload the file into the session, use its /tmp/qcut-input
path, or use a public/network URL that the model provider can read.
Command Groups
| Group | Description | Example |
|---|---|---|
editor |
Control the open editor, timeline, tracks, pointer, and export (three-level: editor <area> <action>) |
editor timeline export --project-id <id> --json |
gen |
Generate images, videos, avatars, speech, music, and voices | gen image -t "A cat" |
analyze |
Analyze, index, transcribe, translate, and query media | analyze transcribe -i audio.mp3 --srt |
edit |
Autoclip, upscale, motion, subtitles, cleanup, portrait, deflicker, stickers, sound search | edit upscale --image img.png |
compose |
Snapshot, plan, validate, apply, render, and package multi-resource edits | compose render --config edit.qcut-compose.json --output final.mp4 |
filter-lab |
Browse, render, stack, and verify locally cached filters; QCut's own Metal renderer | filter-lab render-independent --resource-id <id> -i in.png --output out.png |
effect-lab |
Search and render locally cached video effects | effect-lab render --effect "胶片框" --input in.mp4 --output out.mp4 |
text-lab |
Browse and render cached flower text and text animations | text-lab animations --slot loop --json |
sticker-lab |
Browse private local sticker reference batches | sticker-lab search --query "安排" --json |
transition |
Inspect and render transitions through the local Jianying runtime | transition render --preset <preset> --input-a a.mp4 --input-b b.mp4 |
draft |
Inspect, import, verify, and export Jianying Professional drafts | draft inspect --draft "<draft folder>" --json |
instances |
Discover running QCut apps and select the CLI target | instances list --json |
flow |
ViMax pipelines, YAML workflows, script/character generation | flow run -c pipeline.yaml -i "A sunset" |
system |
Update, auth, keys, models, cost, project setup, diagnostics | system doctor --json --skip-health |
Run qcut <group> --help for group details. qcut editor --help does not
list its actions; use the editor reference files above or
qcut editor <area> <action> --help --json.
Top-level commands (not in a group)
| Command | Description | Example |
|---|---|---|
update |
Check, download, verify, and install the latest QCut app (also system update) |
update --check --json |
record |
Standalone screen recording — spawns its own hidden QCut | record --record-duration 10 -o demo.mp4 |
record-daemon |
Inspect / stop / start the headless recorder daemon | record-daemon --status |
youtube:upload |
Upload a file to YouTube via Google OAuth | youtube:upload -i video.mp4 --title "demo" |
generate-grid |
Generate an image grid in one call | generate-grid -t "Seasons" --layout 2x2 |
create-element, list-elements, delete-element |
Reusable Kling V3 Omni character/object elements | list-elements --json |
moyin:parse-script |
Parse a screenplay file into structured data | moyin:parse-script --script screenplay.txt --json |
phota:edit, phota:enhance, phota:profile |
Phota image editing, enhancement, identity profiles | phota:enhance -i photo.jpg |
replicate, replicate:analyze, replicate:generate |
Replicate a video: analyze → recipe → generate | replicate:analyze --source input.mp4 --json |
vimax:list-models |
List ViMax-specific models | vimax:list-models --json |
record and record-daemon do not require QCut to be open — they
auto-launch a hidden recorder. See
editor-output.md
for flags and examples.
Project Setup & Organization
Use these commands for project setup, file categorization, and structure audits:
qcut system project-initqcut system project-organizeqcut system project-info
Standard structure:
{project-dir}/
├── input/
│ ├── images/
│ ├── videos/
│ ├── audio/
│ ├── text/
│ └── pipelines/
├── output/
│ ├── images/
│ ├── videos/
│ └── audio/
└── config/
Safe default workflow:
# 1) Create missing folders
qcut system project-init --directory ./my-project
# 2) Preview file moves first
qcut system project-organize \
--directory ./my-project \
--source ./incoming-media \
--recursive \
--dry-run
# 3) Execute organization
qcut system project-organize \
--directory ./my-project \
--source ./incoming-media \
--recursive
# 4) Verify final structure and counts
qcut system project-info --directory ./my-project --json
Safety rules:
- Run
--dry-runbefore moving user files. - Use
--sourcefor external ingest folders. - Use
--recursiveonly when nested scan is needed. - Avoid
--include-outputunless reorganizing output is intentional.
Quick Commands
qcut system models # List all models
qcut gen image -t "A cinematic portrait at golden hour"
qcut gen video -m kling_2_6_pro -t "Ocean waves at sunset" -d 5s
qcut gen avatar -m omnihuman_v1_5 -t "Hello world" --image-url avatar.png
qcut gen music -t "Upbeat pop, warm female vocal, 104 BPM"
qcut analyze video -i video.mp4 --analysis-type summary
qcut analyze transcribe -i audio.mp3 --srt
qcut edit portrait-filter --list-presets --json
qcut flow run -c pipeline.yaml -i "A sunset" --no-confirm
qcut system cost -m veo3 -d 8s
qcut record --record-duration 10 -o demo.mp4 # standalone screen recording, no editor needed
qcut filter-lab catalog-independent --json # filters QCut's own Metal renderer supports
qcut compose validate --config edit.qcut-compose.json --json
qcut draft inspect --draft "~/Movies/JianyingPro Drafts/my-draft" --json
qcut update --check --json
Auth Token Management
Get, set, or clear the QCut auth token directly from the CLI. No need for DevTools.
# Check the current token (masked) and whether the editor is authenticated
qcut editor auth token --json
# Set a token without putting it on the command line: hidden prompt on a
# TTY, or pipe it in
qcut editor auth token --from-stdin --json
printf '%s' "$QCUT_AUTH_TOKEN" | qcut editor auth token --from-stdin --json
# Activate the license on this device the same way
qcut editor auth activate --from-stdin --json
# Clear token (logout)
qcut editor auth logout --json
--set <token> and --token <token> still work but land in shell history
and process listings, and --reveal prints the full value; all three are
confirm-tier actions. Prefer --from-stdin and check authenticated in the
masked response instead of reading the token back.
| Command | Description |
|---|---|
editor auth token |
Get the masked token and authenticated flag; --from-stdin sets it from a hidden prompt or pipe (--set <val> / --reveal exist but expose the value) |
editor auth activate |
Activate the license on this device; --from-stdin reads the token hidden (or --token <val>) |
editor auth logout |
Clear the current auth token |
Never paste a revealed token into prompts, logs, or generated files.
YouTube Upload
Upload videos to YouTube after authenticating with Google OAuth.
Prerequisites:
- Logged in via Google OAuth in QCut app
- YouTube Data API v3 enabled in Google Cloud Console
- YouTube channel created on the Google account
- Auth token set (
qcut editor auth token --jsonreportsauthenticated)
# Set the auth token for CLI usage without exposing it (hidden prompt or pipe)
qcut editor auth token --from-stdin --json
# Upload a video (private by default)
qcut youtube:upload -i video.mp4 --title "My Video"
# Upload with all options
qcut youtube:upload \
-i video.mp4 \
--title "My Video" \
--text "Video description" \
--mode unlisted \
--data "tag1,tag2,tag3" \
--category 22 \
--image thumbnail.jpg \
--json
| Flag | Description |
|---|---|
--input, -i |
Path to video file (required) |
--title |
Video title (required) |
--text |
Video description |
--data |
Comma-separated tags |
--mode |
Privacy: public, unlisted, private (default: public) |
--category |
YouTube category ID (default: 22 = People & Blogs) |
--image |
Path to thumbnail image |
Auth flow: CLI token → license server /api/youtube/token → Google access token → YouTube Data API v3 resumable upload.
Key files:
- CLI handler:
electron/native-pipeline/cli/cli-handlers-youtube.ts - License server endpoint:
packages/license-server/src/routes/youtube.ts - Electron IPC handler:
electron/youtube-handler.ts
ViMax Quick Start
qcut flow idea2video --idea "A detective in 1920s Paris" -d 120
qcut flow script2video --script script.json
qcut flow novel2movie --novel book.txt --max-scenes 20
qcut flow scenes --novel book.txt -o /tmp/qcut-output --json
qcut flow storyboard --scenes /tmp/qcut-output/scenes.json --image-model gpt_image_2_ima --concurrency 3 --json
qcut flow novel2script --novel book.txt --project my-story # decomposed stage 3
qcut flow novel2video --project my-story --cost-gate # decomposed stage 4
API Key Setup
Keys stored in ~/.qcut/.env (mode 0600).
qcut system setup # Create .env template
qcut system set-key --name FAL_KEY # Set a key (interactive)
qcut system keys # Show configured and missing keys
qcut system check-keys # Check configured keys
qcut system sync-keys # Pull keys from the cloud vault (requires login)
Supported keys: FAL_KEY, GEMINI_API_KEY, GOOGLE_AI_API_KEY, OPENROUTER_API_KEY, ELEVENLABS_API_KEY, OPENAI_API_KEY, RUNWAY_API_KEY, HEYGEN_API_KEY, DID_API_KEY, SYNTHESIA_API_KEY, QCUT_AUTH_TOKEN
Unified JSON Output
All commands support --json for machine-readable output using a consistent envelope:
qcut gen image -t "A cat" --json
Three possible envelope shapes:
| Status | Shape | When |
|---|---|---|
ok |
{ "status": "ok", "command_id": "cmd-...", "duration_ms": 1234, "data": { ... } } |
Command succeeded |
error |
{ "status": "error", "command_id": "cmd-...", "duration_ms": 500, "error": "msg", "code": "cmd:failed" } |
Command failed |
pending |
{ "status": "pending", "jobId": "abc-123" } |
Async job started |
Every ok and error envelope includes:
command_id— unique correlation ID (cmd-{timestamp}-{random}) for tracingduration_ms— integer wall-clock execution time in milliseconds
See REFERENCE.md for full envelope docs.
3-Level Progressive Help (JSON)
The CLI provides structured help at three levels when using --help --json:
# Level 1: Root — list all groups, commands, global flags
qcut --help --json
# Level 2: Command — flags (required/optional), examples, usage
qcut gen image --help --json
# Level 3: Parameter — type, enum values, default, description
qcut gen image --help model --json
Each level returns a JSON envelope ({ "status": "ok", "data": { ... } }).
Flags that a handler accepts but the registry does not declare are not listed,
and --help <flag> --json exits 1 for them; prefer the declared spelling.
project.json — Agent-Readable Project State
Two CLI commands export the full project state as structured JSON:
# Minimal (~200 tokens): counts + settings only
qcut editor project info --project-id <id> --json
# Full (~2000 tokens): settings + media[] + subtitles[] + generated[] + exports[] + jobs[]
qcut editor project info --project-id <id> --full --json
# Dump to disk
qcut editor project export-state --project-id <id>
See editor-media.md for the full project.json schema.
Global Options
| Flag | Short | Description |
|---|---|---|
--output-dir |
-o |
Output directory (default: $QCUT_OUTPUT_DIR or ~/Documents/QCut/exports) |
--model |
-m |
Model key (e.g. gpt_image_2_ima, kling_2_6_pro) |
--json |
Output as JSON (includes command_id, duration_ms) |
|
--quiet |
-q |
Suppress progress and exit metadata |
--verbose |
-v |
Debug logging + JSONL debug events on stderr |
--force |
Bypass action-policy confirmations when the policy allows it | |
--policy |
Path to a JSON action policy file | |
--resume |
Resume and autosave a named CLI session | |
--focus |
Bring the editor window to the target project | |
--session |
Session mode: read commands from stdin | |
--skip-health |
Skip editor health check | |
--no-capability-check |
Skip per-request capability warnings | |
--host |
Editor API host (default 127.0.0.1) |
|
--port |
Editor API port (auto-selected when omitted; see instances use) |
|
--token |
Editor API bearer token; defaults to QCUT_API_TOKEN, then the token the running editor published for the port |
|
--help |
-h |
Print help |
--version |
Print the CLI version |
--stream is not a global flag; flow run and moyin:parse-script accept it
to emit JSONL progress events on stderr.
Exit Metadata
In non-JSON, non-quiet mode, every command appends to stderr:
[exit:0 | 1.2s]
Error Recovery Hints
When a command fails in non-JSON mode, actionable hints are printed below the error:
error: Missing API key for fal
hint: Set the key with: qcut system set-key --name <provider> --value <key>
Debug Event Stream
With --verbose (or --stream on the commands that support it), structured JSONL events are emitted to stderr:
{"event":"command:start","command_id":"cmd-1741830000-a1b2c3","command":"generate-image","timestamp":"2026-03-12T10:00:00.000Z"}
{"event":"command:end","command_id":"cmd-1741830000-a1b2c3","command":"generate-image","exit_code":0,"duration_ms":3200,"timestamp":"2026-03-12T10:00:03.200Z"}
Programmatic API (run / runChain)
For agent or programmatic use, import run() or runChain() directly instead of spawning a process:
import { run, runChain } from "./cli-runner/index.js";
// Single command
const result = await run("generate-image -t 'A cat'");
// → { success, exit_code, duration_ms, command_id, outputPath?, ... }
// Chained commands (output piped as --input to next)
const results = await runChain([
"generate-image -t 'A sunset'",
"upscale-image --target 2160p",
]);
Key Source Files
See reference-source-files.md for the full source file map organized by responsibility (core, output, handlers, state, auth).