MontajMontajdocs

CLI Reference

Complete command reference for the Montaj CLI — every operation the UI performs is available from the terminal.

CLI Reference

Every operation is available from the terminal. montaj is the full command, mtj is the short alias.

Version

montaj --version    # or: montaj -v
# montaj 2.0.6

Global Output Flags

Available on all commands:

--json        # output result as JSON (for scripting and agent use)
--out <path>  # specify output path (default: workspace/)
--quiet       # suppress progress output, result only on stdout

Tier 1 — Workflow Commands

The primary interface for most users.

montaj run ./clips --prompt "tight cuts, remove filler, 9:16"
# Runs default workflow against all clips in the directory

montaj run ./clips --workflow tight-reel --prompt "..."
# Runs a named workflow

montaj run --workflow animations --prompt "60s animated explainer, dark theme"
# Animation project — no source footage required

montaj serve
# Start local HTTP server + open UI at http://localhost:3000

montaj serve --network
# Bind to all network interfaces — accessible to other devices on the local network.
# WARNING: only use on trusted networks.

montaj render
# Render project.json [final] → final.mp4

montaj render --project ./workspace/project.json --out ./output/final.mp4
# Explicit paths

montaj render --clean
# Delete intermediate files after compositing

montaj run works headlessly — no UI, no montaj serve required.

Render Pipeline

montaj render runs three stages:

  1. Normalize + base video — normalize all sources to the project's working color space (settings.colorSpace), then trim and prepare source clips
  2. Overlay segments — each JSX overlay is bundled with esbuild, rendered frame-by-frame in headless Chromium, and encoded to lossless FFV1/MKV
  3. Compose — segment-based pipeline encodes each timeline segment independently, concats via -c:v copy, then mixes audio tracks. Codec follows the project's color space — H.264 for SDR projects, HEVC 10-bit for HDR projects.

Tier 2 — Workflow Management

montaj workflow list
# List all available workflows (native + custom)

montaj workflow new <name>
# Scaffold a new workflow file at workflows/<name>.json

montaj workflow edit <name>
# Open workflow in the node graph UI

montaj workflow run <name> ./clips --prompt "..."
# Run a specific workflow (alias for: montaj run --workflow <name>)

Tier 3 — Steps

montaj step is the interface for running any step directly. Steps are discovered automatically across three scopes: built-in, user-global (~/.montaj/steps/), and project-local (./steps/).

montaj step --help                  # list all available steps
montaj step <name> --help           # show params for a specific step
montaj step <name> --input <file>   # run a step

montaj create-step <name>           # scaffold steps/<name>.py + .json

montaj validate step <filename>     # validate a step schema
montaj validate project <filename>  # validate a project.json
montaj validate workflow <filename> # validate a workflow .json

Step Chaining

Steps chain via stdout — the output path of one step becomes the --input of the next:

FILE=$(montaj step rm_fillers --input clip.mp4 --model base.en)
FILE=$(montaj step waveform_trim --input "$FILE")
FILE=$(montaj step resize --input "$FILE" --ratio 9:16)

Tier 4 — Project Commands

montaj fetch --url "https://www.tiktok.com/@handle/video/123"
# Download a single video via yt-dlp

montaj fetch --url "https://www.tiktok.com/@handle" --limit 15 --out ./clips/
# Download up to N videos from a profile or playlist

montaj init --prompt "tight cuts, remove filler"
# Create empty project.json in current directory

montaj init --prompt "..." --color-space hdr_hlg
# Force the project's working color space. Default is `auto`, which picks
# the MODAL (most common) color space across clips — outliers are
# converted on the fly. 27 HLG + 1 SDR → hdr_hlg (the SDR clip is stretched).
# Tiebreaks: PQ wins HDR-only ties; SDR wins SDR-vs-HDR ties.
# Choices: auto | sdr_bt709 | hdr_hlg | hdr_pq. Peer of --resolution.

montaj init --prompt "..." --resolution 1080x1920
# Force the project's output resolution. Default is `auto`, which preserves
# the MODAL source resolution. Mixed-aspect inputs (portrait + landscape)
# are scale-fit and center-padded to the chosen canvas at compose time.
# Format: WxH (e.g. 1080x1920, 3840x2160). Peer of --color-space.

montaj init --prompt "..." --project-path my-project
# Pin the project directory's path under the workspace root. Single segment
# for flat layouts (`my-project`), multi-segment slash-separated for nested
# layouts (`teamA/my-project`). Intermediate directories are created on
# demand. When omitted, the directory name is generated as `<date>-<slug>`
# from --name (or `<date>-<HHMMSS>` if --name is also absent). Useful for
# sidecar deploys where the caller already has its own project ID and wants
# to skip the date prefix. Segments must match `[A-Za-z0-9_-]+`; collisions
# on an explicit path are hard errors, not auto-suffixed.

montaj init --workflow carousel --carousel-aspect portrait --prompt "..."
# Create an image-carousel project. --carousel-aspect picks the slide ratio:
# `square` (1:1, 1080x1080), `portrait` (4:5, 1080x1350), or `vertical`
# (9:16, 1080x1920). Locked at creation. Add reference images with --asset
# (repeatable); they're copied into the workspace and surface in
# project.assets[]. The agent reads project.json + project.assets and the
# `montaj/carousel` callable skill to author slides. See projects/carousel
# for the full flow.

montaj init --prompt "..." \
  --remote-clip '{"url":"https://...","destPath":"clip1.mp4","contentType":"video/mp4","sizeBytes":12345}' \
  --remote-asset '{"url":"https://...","destPath":"logo.png","contentType":"image/png","sizeBytes":678}'
# Fetch clips/assets from remote URLs at init time (S3 pre-signed, R2, GCS,
# Azure SAS, plain HTTPS) directly into the project workspace. Repeatable.
# For batch input use --remote-clips-file / --remote-assets-file pointing at
# a JSON array of the same item shape. Fail-closed: requires
# MONTAJ_HTTP_ALLOWED_HOSTS in the environment (comma-separated lowercase
# hostnames). Content-type and byte count are verified against declared
# values; writes are atomic.

montaj upload --project <id-or-path> \
  --src output/render.mp4 --to "https://..." \
  --src output/manifest.json --to "https://..."
# Push project workspace files to caller-supplied URLs. --src/--to is a
# repeatable pair. Returns 200 on full success or 207 Multi-Status on
# partial failure (per-op results in stdout). Use this with cloud
# storage's pre-signed PUT URLs to ship renders without provider-specific
# code in Montaj. Same allowlist gate as remote inputs.

montaj status
# Show current project.json state + step progress

montaj approve
# ai_video projects only — mark the storyboard as approved

montaj doctor
# Check all system dependencies (ffmpeg filters, ffprobe, node, whisper)
# Exit 0 = OK, exit 1 = issues

montaj regen <clip_id>
# Queue a full-scene regeneration for an ai_video clip

montaj regen subcut <clip_id>
# Queue a sub-range regeneration within a clip

montaj profile
# Manage creator style profiles

montaj profile asset list <name>
# List all assets registered in the profile's asset library

montaj profile asset add <name> <path> [--description TEXT] [--tags A,B,C]
# Copy a file into the profile's assets dir and register it in the manifest

montaj profile asset rm <name> <filename>
# Remove an asset from the library (deletes the file and its manifest entry)

montaj profile asset notes <name> --get
# Print the profile-wide creative notes

montaj profile asset notes <name> --set "your notes here"
# Overwrite the profile-wide creative notes

Step Params Quick Reference

All steps accept --out <path>. Run montaj step <name> --help for full details.

StepKey params
probe
snapshot--cols <n>, --rows <n>, --at <t>
trim--start <t>, --end <t>
cut--start <t>, --end <t> or --cuts <json> or --spec
jump_cut--cuts <json> or --keeps <json>
cross_cut--b-roll <file>, --segment-duration <s>
montage--inputs <files>, --beat-duration <s>
resize--ratio <9:16|1:1|16:9>
normalize--target <youtube|podcast|broadcast|custom>, --lufs <n>
extract_audio--format <wav|mp3|aac>
stem_separation--stems <vocals|drums|bass|other>, --out-dir <path>
rm_fillers--model <tiny.en|base.en|medium.en|large>
waveform_trim--threshold <dB>, --min-silence <s>
waveform_image--chunk-duration <s>
rm_nonspeech--model <base|small|medium>, --max-word-gap <s>, --sentence-edge <s>
crop_spec--keep <start:end> (repeatable), --out <path>
virtual_to_original--inverse
transcribe--model <base.en|medium.en>, --language <code>
caption--style <word-by-word|pop|karaoke|subtitle>
lyrics_sync--lyrics <txt>, --model <base.en|medium.en>, --out <path>
lyrics_render--captions <json>, --audio <mp3>, --input <video>, --position, --color, --fontsize
kling_generate--prompt, --out, --first-frame, --last-frame, --ref-image (max 7), --duration, --mode, --model, --aspect-ratio
analyze_media<input>, --prompt, --model, --json-output, --out
generate_image--prompt, --out, --provider <gemini|openai>, --ref-image, --size, --aspect-ratio
generate_music--prompt, --out, --with-vocals, --seed
generate_voiceover--text, --text-file, --voice, --vendor <kling|gemini>, --speed
normalize<file>, --color-space <sdr_bt709|hdr_hlg|hdr_pq>, --out <path>
fetch--url, --limit, --format
doctor(no params)

CLI Flag Conventions

Two flags look similar and must not be conflated:

FlagPurpose
--jsonWrap stdout in a JSON envelope for machine-readable output. Available on every command.
--json-outputAsk the underlying model or API to return structured JSON data. Only on steps that call a model/API (e.g., analyze-media).

Output Convention

All commands follow the same contract:

  • stdout — the result: file path or JSON. Nothing else.
  • stderr — errors only: {"error":"code","message":"detail"}
  • exit 0 on success, exit 1 on failure