| name | premiere-cli |
| description | Use when Claude needs to query or drive Premiere Pro itself (not just log a message) via the Premiere Bridge CEP panel — e.g. reading the active project's sequences — or drive the native Premiere Pro UI directly via macOS Accessibility/synthetic input (screenshot, key press, text entry, mouse move/click, a persistent on-screen notification). Growing list of commands; check here first before assuming a capability doesn't exist. |
/premiere-cli
Sends a command to the Premiere Bridge CEP panel and prints its JSON
response. This is the general mechanism for Claude to read and act on
live state inside Premiere Pro — distinct from premiere-log, which only
displays text in the panel and never touches the project.
Setup (once per machine)
premiere-cli comes from the premiere-cli Python package
(https://github.com/stefanwebb/premiere-cli):
pipx install premiere-cli # or: uv tool install premiere-cli
premiere-cli install-panel # installs the CEP panel + enables PlayerDebugMode
# restart Premiere Pro, open Window > Extensions > Premiere Bridge
premiere-cli doctor # verifies the whole chain
If premiere-cli is not on PATH or doctor reports failures, fix that
before attempting any other command. API behavior notes are calibrated
against Premiere Pro 26.3.0 (see the repo's docs/BUILD_FINDINGS.md) —
re-verify build-sensitive commands after a Premiere upgrade.
Running a command
premiere-cli <command>
The full response is a JSON object printed to stdout:
{"ok": true, "result": ...} on success, {"ok": false, "error": "..."}
on any failure (including the panel being closed). Exit code is 0 for
ok: true, 1 otherwise — but the JSON on stdout is always well-formed
either way, so parse it directly rather than branching only on exit code.
Time precision: ticks, samples, and frame snapping
Every command takes time as a decimal --*-seconds value, but Premiere
stores time internally as ticks, at a fixed
254,016,000,000 ticks per second. That number is chosen to divide
evenly by every common frame rate and sample rate, which has two
practical consequences (both live-verified 2026-07-24 on a 25fps
sequence with 48kHz audio):
1. Sample-exact positions are addressable. At 48kHz,
254016000000 / 48000 = 5,292,000 ticks per sample — an exact integer,
so every sample boundary is representable with no rounding. To place
something at sample N, pass N / 48000 as the seconds value:
# sample 289522 = 6s + 1522 samples
premiere-cli trim-clip --track-type audio --track-index 0 \
--clip-index 0 --in-point-seconds 6.03170833333333
Read-back confirmed exactly 289,522.0 samples. The tick grid is finer
than a sample (5.29M ticks per sample), so nothing rounds to sample
boundaries on your behalf — a computed offset like 6.031709952881989
lands 0.078 of a sample past a boundary and stays there. Round to a whole
sample yourself when you want a clean audio position.
2. Placement commands snap to the VIDEO frame grid; trim-clip does
not. add-to-timeline and move-clip-to-track quantize a clip's
in-point to a frame boundary — at 25fps that is 40ms, or ~1,920 samples
at 48kHz — silently discarding sub-frame precision even on an audio-only
clip. Observed: an in-point set to 6.0317 became 6 after
add-to-timeline, then 6.04 after a later move-clip-to-track.
Only trim-clip --in-point-seconds writes the exact value (it sends a
ticks string and verifies the read-back). So for anything needing
sub-frame accuracy — audio sync above all — apply trim-clip last,
after the clip is on its final track, and re-apply it after any
subsequent placement command. Confirm inPointSeconds in the response
before treating the position as correct; changes.inPoint.verified
reports whether the read-back matched.
3. trim-clip --out-point-seconds does NOT shorten a clip on the
timeline (live-tested 2026-07-24). It writes the source out-point and
reads it back successfully — verified: true — but the track item keeps
its original endSeconds, and get-timeline-summary still shows the old
coveragePercent and sequence duration. verified here means "the
out-point property took the value", not "the clip got shorter", so it is
not evidence the edit did what you wanted.
To actually shorten a clip from the tail, razor and delete:
premiere-cli split-clip --track-type video --track-index 0 --seconds 1230.72
premiere-cli remove-from-timeline --track-type video --track-index 0 \
--clip-index 1 --ripple false
Then confirm against get-timeline-summary — durationSeconds and the
track's coveragePercent are what actually move. The in-point path has
no such problem: trimming the head with --in-point-seconds does take
effect.
Available commands
2026-07-17 correction — undo: several entries below say "undo is
non-functional on this build". That is now known to be only PARTLY
true (see BUILD_FINDINGS.md): qe.project.undo()/redo() DO work for
operations that enter the undo stack (timeline edits, speed changes,
placements), verified via qe.project.undoStackIndex(). Marker adds
and track renames never enter the stack, so they remain un-undoable —
and calling undo after one of those pops the NEXT stack entry
(possibly a user edit). The previousValue read-backs those entries
recommend remain the safest restoration path.
create-sequence
Creates a new sequence in the currently open project.
premiere-cli create-sequence --name "My Sequence" --bin "B-Roll/Interviews"
premiere-cli create-sequence --name "Vertical Cut" --bin "Shorts" --fps 30 --width 1080 --height 1920
--name and --bin are required; --fps/--width/--height default to
25/3840/2160 (4K, 25fps). --bin is a /-separated path; missing
bin segments are created automatically. Fails (does not create anything)
if a sequence with that exact name already exists in that bin.
Runs fully autonomously — no dialog pops up. The sequence is created from
a bundled preset (4K/25fps/Rec.709) rather than Premiere's interactive
"New Sequence" dialog. Only the default fps/width/height (25/3840/2160)
are reliable right now — confirmed working, no dialog, correct settings.
Requesting non-default values goes through a getSettings()/setSettings()
override step (host/index.jsx) that is confirmed buggy as of 2026-07-12
(live-tested: the sequence is created, but the requested fps/resolution do
not reliably end up applied) — this is a known, open issue to revisit, not
a documented working feature yet. Until it's fixed, prefer the defaults or
verify the result's actual sequence settings in Premiere Pro after any
non-default create-sequence call.
Result shape:
{
"name": "My Sequence",
"bin": "B-Roll/Interviews",
"sequenceID": "<guid>",
"settingsApplied": ["fps", "resolution"],
"settingsFailed": {},
"colorSpace": "rec709 (from bundled sequence preset)"
}
settingsFailed (a {field: error message} object) being non-empty means
the sequence WAS created but one or more of bin placement / frame rate /
resolution could not be applied as requested — check it even when
ok: true, don't assume every field in the request took effect.
extract-audio-track
Extracts part or all of one audio track to a local audio file.
premiere-cli extract-audio-track --output /tmp/vo.wav --audio-track-index 0
premiere-cli extract-audio-track --output /tmp/clip.mp3 --audio-track-index 1 \
--start-seconds 12.0 --end-seconds 45.5 --sequence-name "Sequence 02" --format mp3
--output and --audio-track-index (0-based, e.g. 0 = Audio 1) are
required. --sequence-name defaults to the currently active sequence.
--start-seconds/--end-seconds must be given together or not at all —
omit both to extract the entire sequence duration. --format is
wav (default) / mp3 / aac, each resolved to a preset bundled inside
the installed Premiere Pro app itself — no Adobe Media Encoder or external
preset file needed. --preset-path overrides --format with any other
.epr file (e.g. a specific bitrate/format not covered above).
Implementation: temporarily mutes every video track and every audio track
except the target one, sets the sequence's in/out points if a range was
given, calls the standard DOM's seq.exportAsMediaDirect() (synchronous,
no Adobe Media Encoder dependency), then restores all original mute
state and in/out points — this happens even if the export throws.
Result shape:
{
"sequenceName": "Sequence 02",
"audioTrackIndex": 1,
"outputPath": "/tmp/clip.mp3",
"format": "mp3",
"presetPath": "/Applications/Adobe Premiere Pro 2026/.../MP3 256kbps High Quality.epr",
"range": { "startSeconds": 12.0, "endSeconds": 45.5 },
"fileSizeBytes": 1234567
}
All three formats (wav, mp3, aac) are live-tested and confirmed
working, including the ranged --start-seconds/--end-seconds path.
remove-track-intervals
Ripple-deletes a list of time intervals from an audio track — and,
optionally, the same intervals from one or more linked video tracks, so
they stay in sync. Destructive: verify on a duplicate/throwaway sequence
before running against real footage.
premiere-cli remove-track-intervals --audio-track-index 0 \
--intervals-file /tmp/main-mic.cuts.txt
premiere-cli remove-track-intervals --sequence-name "Sequence 01" \
--audio-track-index 0 --video-track-index 0 \
--intervals-file /tmp/main-mic.cuts.txt
--audio-track-index and --intervals-file are required. --sequence-name
defaults to the currently active sequence (switched to automatically if a
named sequence isn't already the active tab — the QE DOM this command
uses only ever operates on whichever sequence is frontmost). --video-track-index
is repeatable — pass one per video track that should get the same cuts
(e.g. the camera track linked to this audio track); omit entirely if
there's no linked video. --intervals-file is a remove-pauses-style
cuts file: one "MM:SS:FF - MM:SS:FF" line per interval (blank lines
ignored) — exactly what remove-pauses <file> -o cuts.txt writes.
Result shape:
{
"sequenceName": "Sequence 01",
"audioTrackIndex": 0,
"videoTrackIndices": [0],
"intervalsApplied": 2,
"totalSegmentsRemoved": 4,
"warnings": []
}
warnings lists any interval where a segment couldn't be removed on a
given track (rare — surfaced rather than silently dropped) but doesn't
fail the whole command; the intervals that did succeed still get applied.
export-frame
Exports a single PNG frame from a sequence at a given timecode.
premiere-cli export-frame --output /tmp/frame.png --timecode 00:12:05
premiere-cli export-frame --output /tmp/frame.png --timecode 00:12:05 --sequence-name "Sequence 02"
--output and --timecode (as "MM:SS:FF", same format as
remove-track-intervals's interval boundaries) are required.
--sequence-name defaults to the currently active sequence (switched to
automatically if a named sequence isn't already the active tab — the QE
DOM this command uses only ever operates on whichever sequence is
frontmost).
Result shape:
{
"sequenceName": "Sequence 02",
"timecode": "00:12:05",
"timeSeconds": 12.2,
"outputPath": "/tmp/frame.png",
"width": 3840,
"height": 2160,
"method": "qe",
"attempts": [{"args": ["/tmp/frame.png"], "success": false, "error": "..."},
{"args": ["/tmp/frame.png", "/tmp/frame.png"], "success": true}],
"succeededWithArgs": ["/tmp/frame.png", "/tmp/frame.png"],
"fileSizeBytes": 6408423
}
Two export mechanisms are tried in order, reported via method:
"qe" — the QE DOM's exportFramePNG. Its argument order is
version-dependent across Premiere builds and its return value is
outright unreliable (live-tested returning false on calls that DID
write a file), so the command tries a short list of plausible
signatures and judges success only by checking the filesystem.
attempts records every signature tried; succeededWithArgs is the
one that worked. Live-tested 2026-07-17 on Premiere Pro 2026: the
variant that works on this build is exportFramePNG(outputPath, outputPath) — the output path passed twice, an undocumented quirk
(sensible-looking width/height string args ran without error but wrote
nothing).
"ame" — if every QE guess fails, a blocking one-frame Media
Encoder export via seq.exportAsMediaDirect() with the bundled
PNG Sequence (Match Source) preset (path reported as presetPath
in the result; succeededWithArgs is absent for this method). The
sequence's in/out points are narrowed to exactly one frame and
restored afterward. Also live-tested working 2026-07-17.
Premiere writes the file under a variant of the requested name — QE
appends .png even to an already-.png path (frame.png →
frame.png.png) and AME appends a frame number (frame.png →
frame0.png). The command detects these variants by checking their exact
paths directly and renames the file to the path you asked for, so callers
never have to care. (Direct path checks, not directory listing: macOS
returns an empty listing to the panel for some directories, e.g. /tmp,
even though the files themselves are readable — the same TCC/sandboxing
quirk previously hit with /Applications during preset discovery.)
If both mechanisms fail, the result is {"ok": false, "error": "...", "attempts": [...]} — not a crash. The error string states whether the
AME fallback was skipped (no bundled preset found) or ran and produced
no file.
A frame exported from a time range with no video clips is a "success"
that yields a blank image (QE: fully transparent; AME: fully black) —
if you get a suspiciously small fileSizeBytes, check that the sequence
actually has visible content at that timecode.
Playhead-move failure: before attempting export, the command must move the
playhead to the target timecode using seq.setPlayerPosition(...), trying two
argument forms: a ticks string and a Time object. If neither form succeeds, the
command returns {"ok": false, "error": "could not move the playhead to the requested timecode with any known argument form (ticks string, Time object)", "attempts": [...]}. Note that this failure's attempts items have a different
shape than the exportFramePNG-failure case — they are {form, success, error}
(where form is a string like "ticksString" or "TimeObject") rather than
{args, success, error}, so the two failure modes can be distinguished by
inspecting the attempts array structure.
Restores the sequence's original playhead position afterward, regardless
of success or failure.
get-project-info
Snapshot of the currently active project — app.project only.
premiere-cli get-project-info
Result shape:
{
"name": "project0002",
"path": "/Volumes/MediaDrive/.../project0002.prproj",
"numSequences": 1,
"sequences": [
{
"name": "Sequence 01",
"sequenceID": "<guid>",
"frameRate": 25.0,
"durationSeconds": 143.2
}
],
"numRootItems": 4
}
numRootItems is app.project.rootItem.children.numItems — the count of
top-level bins/items in the Project panel, not a recursive total.
frameRate/durationSeconds can be null per-sequence if that field
couldn't be read. Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
list-project-items
Recursively lists every item in the active project's bin tree.
premiere-cli list-project-items
Result shape:
{
"items": [
{
"name": "B-Roll",
"treePath": "/B-Roll",
"nodeId": "<guid>",
"type": "BIN",
"isSequence": false,
"mediaPath": null
},
{
"name": "interview-01.mp4",
"treePath": "/B-Roll/interview-01.mp4",
"nodeId": "<guid>",
"type": "CLIP",
"isSequence": false,
"mediaPath": "/Volumes/MediaDrive/.../interview-01.mp4"
}
],
"count": 2
}
Depth-first walk of app.project.rootItem.children, descending into bins
(capped at depth 32 as a defensive limit against pathological structures).
type is "BIN"/"CLIP"/"FILE"/"ROOT" where the ProjectItemType
constant is resolvable, else the raw numeric type as a string. isSequence
and mediaPath are null if their underlying calls (item.isSequence()/
item.getMediaPath()) throw — bins in particular have no media path. This
Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
get-full-project-overview
Comprehensive snapshot of the active project: a nested bin tree, every
sequence, and a classification of every non-bin item by media type.
premiere-cli get-full-project-overview
Result shape:
{
"project": { "name": "project0002", "path": "/tmp/project0002.prproj" },
"binTree": {
"name": "project0002",
"bins": [
{
"name": "B-Roll",
"bins": [],
"items": [
{ "name": "interview-01.mp4", "type": "CLIP", "mediaPath": "/tmp/interview-01.mp4" }
]
}
],
"items": []
},
"sequences": [
{ "name": "Sequence 01", "sequenceID": "<guid>", "frameRate": 25.0, "durationSeconds": 143.2 }
],
"mediaTypeCounts": { "video": 3, "audio": 1, "image": 0, "sequence": 1, "other": 0, "offline": 0 }
}
binTree starts at the root bin and nests recursively (capped at depth
32). mediaTypeCounts classifies every non-bin item by its mediaPath
extension: video (mp4/mov/mxf/avi/m4v/mts), audio
(wav/mp3/aac/m4a/aiff), image (png/jpg/jpeg/tif/tiff/psd/svg/gif), and
other for anything else. A sequence item always counts as "sequence"
regardless of any extension on its media path. An item where
item.isOffline() is true additionally increments "offline", on top of
its type bucket — the two counts aren't mutually exclusive. This command
Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
search-project-items
Searches the project's item tree by name substring, extension, offline
status, and/or color label — at least one filter is required.
premiere-cli search-project-items --name-contains "interview"
premiere-cli search-project-items --extension mov --offline-only
premiere-cli search-project-items --color-label 3
Result shape:
{
"items": [
{
"name": "vo-01.wav",
"treePath": "/Audio/vo-01.wav",
"nodeId": "<guid>",
"mediaPath": "/tmp/vo-01.wav",
"isOffline": false,
"colorLabel": 3
}
],
"count": 1
}
--name-contains is a case-insensitive substring match against item
names. --extension is compared case-insensitively against the media
path's extension, with or without a leading dot. --offline-only matches
items where item.isOffline() is true. --color-label (an int 0-15)
matches items where item.getColorLabel() equals it. A matching item must
satisfy ALL filters given (AND, not OR). Walks the whole project tree the
same way list-project-items does, skipping bins themselves for matching
purposes but always recursing through them.
Fails client-side (exit 2) if no filter is given at all. If
--color-label is given but getColorLabel() isn't available on this
Premiere build, the whole command fails:
{"ok": false, "error": "getColorLabel is not available on this Premiere build"}.
Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
get-active-sequence
Reads the ACTIVE sequence's full track/clip structure — no arguments, no
sequence-name override (use get-full-sequence-info for that). Standard-DOM
read only, no QE DOM involved, no need to switch tabs. This command Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
premiere-cli get-active-sequence
Result shape:
{
"name": "Sequence 01",
"sequenceID": "<guid>",
"frameRate": 25.0,
"durationSeconds": 143.2,
"width": 3840,
"height": 2160,
"videoTracks": [
{
"index": 0,
"name": "V1",
"isMuted": false,
"isLocked": false,
"clipCount": 2,
"clips": [
{
"name": "clip.mp4",
"trackIndex": 0,
"clipIndex": 0,
"nodeId": "<id>",
"startSeconds": 0.0,
"endSeconds": 10.0,
"inPointSeconds": 0.0,
"outPointSeconds": 10.0,
"durationSeconds": 10.0,
"mediaPath": "/Volumes/.../clip.mp4",
"disabled": false
}
]
}
],
"audioTracks": [ /* same shape as videoTracks */ ]
}
Fails with {"ok": false, "error": "no active sequence"} if nothing is
active. Every clip field is read individually — an unreadable field is
null, not a command failure.
get-full-sequence-info
Everything get-active-sequence has, plus per-clip effect components and
the sequence's markers. Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
premiere-cli get-full-sequence-info
premiere-cli get-full-sequence-info --sequence-name "Sequence 02"
--sequence-name defaults to the currently active sequence. Result shape
adds, per clip:
"components": [
{"displayName": "Motion", "matchName": "AE.ADBE Motion", "enabled": true, "numProperties": 8}
]
and, at the sequence level:
"markers": [
{"name": "Chapter 1", "comments": "...", "type": "Comment", "startSeconds": 5.0, "endSeconds": 5.0, "guid": "<guid>"}
],
"markerCount": 1
Markers are iterated via getFirstMarker()/getNextMarker() (no reliable
indexing on this API), capped at 10000 iterations as a safety guard. Output
can be large for big sequences — there is no pagination.
get-full-clip-info
Full detail on one specific clip, including every property of every
applied effect. Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
premiere-cli get-full-clip-info --track-type video --track-index 0 --clip-index 2
premiere-cli get-full-clip-info --sequence-name "Sequence 01" --track-type audio --track-index 1 --clip-index 0
--track-type (video/audio), --track-index, and --clip-index are
required; --sequence-name defaults to the active sequence. Out-of-range
indices fail with a message naming the actual track/clip counts, e.g.
"trackIndex 3 is out of range — sequence has 2 video track(s)".
Result shape (everything get-active-sequence's clips have, plus):
{
"name": "clip.mp4",
"trackIndex": 0,
"clipIndex": 2,
"nodeId": "<id>",
"startSeconds": 20.0,
"endSeconds": 30.0,
"inPointSeconds": 0.0,
"outPointSeconds": 10.0,
"durationSeconds": 10.0,
"mediaPath": "/Volumes/.../clip.mp4",
"disabled": false,
"type": "Clip",
"speed": 100.0,
"isSpeedReversed": false,
"linkedItemsCount": 1,
"projectItem": {"name": "clip.mp4", "treePath": "/Bin/clip.mp4", "nodeId": "<id>"},
"components": [
{
"displayName": "Motion",
"matchName": "AE.ADBE Motion",
"enabled": true,
"properties": [
{"displayName": "Position", "value": "[1920,1080]", "isTimeVarying": false, "keyCount": null}
]
}
]
}
value is always a stringified, 200-char-truncated representation of
prop.getValue() (which can throw or return a non-primitive) — treat it as
diagnostic text, not a typed value. keyCount is only populated when
isTimeVarying is true. Components are capped at 50 per clip and
properties at 100 per component; a truncated: true field appears on the
clip and/or component if either cap was hit.
get-timeline-summary
A compact, human-oriented overview of a sequence — per-track clip counts
and coverage, not per-clip detail. Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
premiere-cli get-timeline-summary
premiere-cli get-timeline-summary --sequence-name "Sequence 02"
--sequence-name defaults to the currently active sequence. Result shape:
{
"sequenceName": "Sequence 01",
"frameRate": 25.0,
"durationSeconds": 143.2,
"videoTracks": [
{"index": 0, "name": "V1", "clipCount": 5, "coveragePercent": 82.4}
],
"audioTracks": [
{"index": 0, "name": "A1", "clipCount": 3, "coveragePercent": 60.0}
],
"totalClips": 8,
"clipsWithEffects": 2,
"markerCount": 1
}
coveragePercent is that track's total clip duration divided by the
sequence duration, as a percentage rounded to 1 decimal (0 if the
sequence duration is unreadable or zero). clipsWithEffects counts clips
whose components collection exceeds the built-in baseline (Motion +
Opacity for video clips, one baseline component for audio clips) —
unreadable clips are skipped rather than counted.
get-premiere-state
Full point-in-time snapshot of whatever Premiere Pro state currently
exists — app version, open project, active sequence, playhead position,
and current selection. Live smoke-tested 2026-07-17 against a real project
(returned correct app version, active sequence, playhead position, and a
real timeline selection); individual fields have not been exhaustively
validated.
premiere-cli get-premiere-state
No flags. Unlike most other commands, having no project open (or no active
sequence, or nothing selected) is not an error here — the whole point
of this command is a truthful snapshot of whatever exists right now, so
ok: true with every nested field null is a normal, valid response.
Result shape:
{
"appVersion": "25.0.0",
"project": { "name": "project0002", "path": "/Volumes/.../project0002.prproj" },
"activeSequence": {
"name": "Sequence 01",
"sequenceID": "<guid>",
"frameRate": 25.0,
"durationSeconds": 143.2,
"width": 3840,
"height": 2160
},
"playheadSeconds": 12.2,
"selection": [
{
"name": "clip1.mp4",
"mediaType": "Video",
"startSeconds": 10.0,
"endSeconds": 15.0,
"nodeId": "<node-id>"
}
]
}
project, activeSequence, playheadSeconds, and selection are each
null when there's no project open, no active sequence, the playhead
couldn't be read, or getSelection() itself is unavailable, respectively.
An empty array (not null) for selection means a sequence is active but
nothing is currently selected in it. Individual fields inside
activeSequence/each selection entry can also independently be null if
that one Premiere API call failed — this doesn't fail the whole command.
inspect-dom-object
Interactive DOM explorer for API discovery: evaluates a property-path
expression against the live Premiere Pro DOM and reflects on whatever it
finds — properties, method names, and enumerable keys. This is a
discovery/debug tool, not a stable feature, and Live smoke-tested 2026-07-17 against a real project (returned plausible, correct-looking data); individual fields have not been exhaustively validated.
premiere-cli inspect-dom-object --expression "app.project.activeSequence"
premiere-cli inspect-dom-object --expression "qe.project"
--expression is required and must be a bare property path rooted at
app, qe, or $.global — dots and bracket-indexing are allowed
(app.project.rootItem.children[0]), but parentheses are not: a call like
app.project.save() is rejected outright, since this command is strictly
read-only and a method call could mutate the open project. If the
expression starts with qe, app.enableQE() is called first.
Result shape:
{
"expression": "app.project.activeSequence",
"typeofValue": "object",
"stringValue": "[object Sequence]",
"isNull": false,
"isUndefined": false,
"reflectMethods": ["getSettings", "getPlayerPosition", "..."],
"reflectProperties": ["name", "sequenceID", "..."],
"forInKeys": ["name", "videoTracks", "..."],
"commonProperties": { "name": "Sequence 01", "sequenceID": "<guid>" }
}
reflectMethods/reflectProperties come from ExtendScript's own
.reflect mechanism when the object exposes it (authoritative when
present, null otherwise). forInKeys is a plain for-in enumeration,
capped at 200 entries. commonProperties is a fixed candidate list
(name, numItems, numTracks, numSequences, length, path, type,
mediaType, seconds, ticks, sequenceID, nodeId, treePath,
guid) probed defensively — only properties that exist, aren't functions,
and don't throw on read are included, each stringified. stringValue is
String(value) truncated to 500 characters. A malformed or non-property-path
expression, or an evaluation error (e.g. a typo'd path), returns
{"ok": false, "error": "..."} rather than throwing.
Related to, but more general than, debug-qe-inspect: that command is
hardcoded to one specific QE sequence/track/clip investigation, while this
one accepts an arbitrary path into either the standard or QE DOM.
get-open-projects
Lightweight list of every currently open project in Premiere Pro — this
replaces the multi-project-listing role of get-project-metadata, which
has been removed. Live smoke-tested 2026-07-17 (correct single-project listing with isActive).
premiere-cli get-open-projects
No flags. Result shape:
{
"projects": [
{
"name": "project0002",
"path": "/Volumes/MediaDrive/.../project0002.prproj",
"isActive": true
}
],
"count": 1
}
isActive is true for whichever open project's path matches
app.project.path, false for the others, or null if either path
couldn't be read. Having no project open is not an error here —
{"ok": true, "result": {"projects": [], "count": 0}} is the normal,
truthful response. Deliberately shallow: no per-project sequence detail is
included — use get-project-info (or get-full-project-overview) for
that on whichever project is currently active.
set-active-project
Switches which currently-open project is active.
premiere-cli set-active-project --name "project0002"
premiere-cli set-active-project --path "/Volumes/MediaDrive/.../project0002.prproj"
Partially live-verified 2026-07-17 (target resolution, the
alreadyActive short-circuit, and the unknown-project error path are
confirmed working; the actual activation path still needs a second open
project to test). Unlike the rest of this file's commands, this
one has not been confirmed working against a real multi-project-open
Premiere session. The activation API is uncertain on this Premiere build,
so the ExtendScript implementation tries three candidate methods in order
and verifies success after each by checking that app.project.path
actually changed to the target (never by trusting a method's own return
value):
targetProject.activate(), if this build exposes it.
app.openDocument(path) — documented as an "open project" call, but a
fallback guess here: its behavior when the target is already open
is unconfirmed on this build, and it may simply foreground the
project, pop a dialog, or (worst case) re-open a duplicate. Treat this
command as mutating and verify manually before scripting it into an
unattended workflow.
- A bare
app.project = target assignment — no supporting reference in
any of the three MCP repos studied for PREMIERE_API_NOTES.md, kept as
a last-resort guess.
At least one of --name/--path is required (client-side exit 2 if
neither is given); if both are given they must resolve to the same open
project, or the command fails. Already-active target short-circuits
without trying any activation method.
Result shape on success:
{
"activated": { "name": "project0002", "path": "/Volumes/.../project0002.prproj" },
"attempts": [
{"method": "activate", "success": false, "error": "..."},
{"method": "openDocument", "success": true}
]
}
or, if already active:
{
"activated": { "name": "project0002", "path": "/Volumes/.../project0002.prproj" },
"alreadyActive": true
}
Failure shapes: {"ok": false, "error": "at least one of name or path is required"} (client-side), {"ok": false, "error": "no open project matched ...", "availableProjects": [...]} if neither --name nor
--path matches an open project, {"ok": false, "error": "name and path did not resolve to the same open project", "availableProjects": [...]}
if both are given and disagree, and {"ok": false, "error": "could not activate project \"...\" with any known method", "attempts": [...]} if
every method fails.
move-playhead
Moves a sequence's playhead to a target time — either a "MM:SS:FF"
timecode or a raw seconds value (exactly one of the two is required).
premiere-cli move-playhead --timecode 00:12:05
premiere-cli move-playhead --seconds 12.5 --sequence-name "Sequence 02"
--timecode and --seconds are mutually exclusive — passing both, or
neither, fails client-side (exit 2) before the panel is even contacted.
--sequence-name defaults to the currently active sequence; if the
resolved sequence isn't already the active one, it's made active first
(moving the playhead implies the user wants to see it, same as
remove-track-intervals's tab-switch behavior) — no QE DOM needed.
Result shape:
{
"sequenceName": "Sequence 02",
"timecode": "00:12:05",
"requestedSeconds": 12.2,
"playheadSeconds": 12.2,
"attempts": [{"form": "ticksString", "success": true}]
}
timecode is only present in the result when you supplied one (omitted
for the --seconds form). playheadSeconds is a read-back of the actual
position via seq.getPlayerPosition() — it can differ slightly from
requestedSeconds due to frame quantization.
Implementation reuses the exact seq.setPlayerPosition() pattern
export-frame uses to move the playhead: try a ticks string first, fall
back to a Time object, recording each attempt as {form, success, error?}. Live-tested 2026-07-17: both the seconds and timecode
forms moved the playhead to the exact requested position, with the
read-back playheadSeconds matching.
Unlike export-frame, there is no restore step afterward: moving the
playhead is the entire point of this command.
If neither argument form succeeds in moving the playhead:
{"ok": false, "error": "could not move the playhead to the requested
time with any known argument form (ticks string, Time object)",
"attempts": [...]}
Additional commands (compact reference)
Work area / in-out points
premiere-cli get-work-area [--sequence-name NAME] — read the work area bar bounds. Returns {sequenceName, inSeconds, outSeconds}. live smoke-tested 2026-07-17.
premiere-cli set-work-area --start-seconds N --end-seconds N [--sequence-name NAME] — set the work area bar. Returns {sequenceName, startSeconds, endSeconds}. live smoke-tested 2026-07-17.
premiere-cli get-sequence-in-out [--sequence-name NAME] — read sequence in/out points. Returns {sequenceName, inSeconds, outSeconds}. live smoke-tested 2026-07-17.
premiere-cli set-sequence-in-out --in-seconds N --out-seconds N [--sequence-name NAME] — set sequence in/out points (export range etc.), via the shared multi-form range helper. Returns {sequenceName, inSeconds, outSeconds, attempts}. live smoke-tested 2026-07-17.
premiere-cli is-work-area-enabled [--sequence-name NAME] — check if the work area bar is enabled. Returns {sequenceName, workAreaEnabled}. live-tested 2026-07-17: no work-area-enabled API exists on this Premiere 2026 build — returns the honest probe-failure error.
premiere-cli get-export-file-extension --preset-path PATH [--sequence-name NAME] — get the file extension a given .epr preset would export. Returns {sequenceName, presetPath, extension}. live smoke-tested 2026-07-17.
Workspace
premiere-cli get-workspaces — list available workspace layouts. Returns {workspaces, count}. live smoke-tested 2026-07-17.
premiere-cli set-workspace --name NAME — switch workspace (e.g. Editing, Color, Audio). Returns {set: true, workspace}. live smoke-tested 2026-07-17.
Playback
premiere-cli play-timeline — start QE playback of the frontmost sequence tab (active-sequence-only, no --sequence-name). Returns {playing: true}. live smoke-tested 2026-07-17.
premiere-cli stop-playback — stop QE playback (same active-sequence-only scope). Returns {stopped: true}. live smoke-tested 2026-07-17.
premiere-cli play-source-monitor [--speed N] — play the clip open in the Source Monitor; speed defaults to 1.0. Returns {playing: true, speed}. live smoke-tested 2026-07-17.
premiere-cli get-source-monitor-position — read the Source Monitor's time indicator. Returns {seconds}; fails if no clip is open. live smoke-tested 2026-07-17.
Version info
premiere-cli get-version-info — Premiere Pro version/build info. Returns {version, buildNumber, isDocumentOpen, path}, each field individually best-effort. live smoke-tested 2026-07-17.
Project & media reports
get-bin-contents --bin-path "B-Roll/Interviews" — recursively lists a bin's
contents by /-separated path (same convention as create-sequence's
--bin, never auto-created here). Key fields: items[].{name,treePath, nodeId,type,mediaPath,isOffline,colorLabel}, count. live smoke-tested 2026-07-17.
get-project-item-info --node-id <id> (or --tree-path <path>) — full
detail on one project item: media path, footage interpretation, in/out
points, proxy status, project/XMP metadata, markers, isSequence/
isMulticamClip/isMergedClip. Merges the reference project's
get_project_item_info and get_item_info tools into one command — they
were near-duplicates, so a separate get-media-item-info was skipped
entirely (see premiere-pro/plugin/README.md for the full field list).
live smoke-tested 2026-07-17.
get-timeline-gaps [--sequence-name NAME] [--track-type video|audio|both] [--min-gap-seconds N] — finds empty spaces between clips on a sequence's
tracks. Key fields: gapCount, gaps[].{trackType,trackIndex, gapStartSeconds,gapEndSeconds,gapDurationSeconds,beforeClip,afterClip}.
live smoke-tested 2026-07-17.
get-offline-media — project-wide scan for offline/missing media. Key
fields: offlineCount, items[].{nodeId,name,treePath,mediaPath}. Not yet
live-tested.
get-used-media-report [--sequence-name NAME] — every distinct source file
a sequence references, with a use count. Key fields: uniqueMediaCount,
media[].{name,mediaPath,offline,useCount,tracks}. live smoke-tested 2026-07-17.
get-all-project-paths — every unique media file path in the project. Key
fields: pathCount, paths[].{path,name,nodeId,offline}. Not yet
live-tested.
get-unused-media — project items never referenced by a clip in any
sequence. Key fields: unusedCount, items[].{nodeId,name,treePath, mediaPath}. live smoke-tested 2026-07-17.
get-duplicate-media — project items that share the same source media
file. Key fields: duplicateGroupCount, duplicates[].{mediaPath,count, items}. live smoke-tested 2026-07-17.
get-clip-links --track-type video --track-index 0 --clip-index 2 [--sequence-name NAME] — clips linked to the addressed clip (same
addressing as get-full-clip-info), matched heuristically by shared source
media and identical start time — there's no direct "get linked items" API.
Key fields: linkedCount, linkedClips[].{nodeId,name,trackType, trackIndex,startSeconds,endSeconds}. live smoke-tested 2026-07-17.
get-insertion-bin — the bin currently focused in the Project panel (where
a new import would land). Key fields: name, nodeId, treePath. Not yet
live-tested.
get-project-panel-metadata — the Project panel's column/metadata
configuration as an XML string. Key field: metadata. Not yet
live-tested.
Catalogs, markers & metadata reads
list-available-effects — premiere-cli list-available-effects. Lists
every video effect this Premiere install exposes via QE
(qe.project.getVideoEffectList()), e.g. for looking up an exact name
before scripting an effect-apply command. Result: {"effects": [{"name", "index"}], "count"}. live smoke-tested 2026-07-17.
list-available-audio-effects — premiere-cli list-available-audio-effects.
Same as above for qe.project.getAudioEffectList(). Result:
{"effects": [{"name", "index"}], "count"}. live smoke-tested 2026-07-17.
list-available-transitions — premiere-cli list-available-transitions.
Lists video transitions via qe.project.getVideoTransitionList(); per
PREMIERE_API_NOTES.md, PPro 2026 is known to return this list EMPTY
even though by-name lookup still works, so an empty list falls back to
probing a fixed set of common transition names via
getVideoTransitionByName (entries carry source: "list" or
"byName"). Result: {"transitions", "count", "listError", "probedByName"}.
live smoke-tested 2026-07-17.
list-available-audio-transitions — premiere-cli list-available-audio-transitions.
Lists audio transitions via qe.project.getAudioTransitionList(), no
fallback probing. Result: {"transitions": [{"name", "index"}], "count"}.
live smoke-tested 2026-07-17.
list-markers — premiere-cli list-markers [--sequence-name NAME].
Lists every marker on a sequence (defaults to the active one), same
getFirstMarker/getNextMarker iteration as get-full-sequence-info.
Result: {"sequenceName", "markers": [{"name", "comments", "type", "startSeconds", "endSeconds", "guid"}], "markerCount"}. live smoke-tested 2026-07-17.
get-clip-markers — premiere-cli get-clip-markers --track-type video --track-index 0 --clip-index 2 [--sequence-name NAME]. Lists markers on
one TIMELINE clip (addressed the same way as get-full-clip-info —
sequenceName?/trackType/trackIndex/clipIndex — not a project-item
item_id as the reference tool used, since clip-scoped commands in this
panel address the timeline consistently). Result: {"sequenceName", "trackType", "trackIndex", "clipIndex", "clipName", "markers", "markerCount"}.
live smoke-tested 2026-07-17.
get-sequence-markers-by-type — premiere-cli get-sequence-markers-by-type --type Chapter [--sequence-name NAME]. Lists sequence markers whose
type matches exactly one of Comment/Chapter/Segmentation/
WebLink/FlashCuePoint. Result: {"sequenceName", "type", "markers", "count"}.
live smoke-tested 2026-07-17.
get-item-metadata — premiere-cli get-item-metadata --node-id ID or
--name NAME. Reads a project item's Premiere project metadata
(item.getProjectMetadata()) — at least one of --node-id/--name is
required (client-side exit 2 otherwise); --node-id is matched
exactly, --name matches the first item found with that exact name in
a depth-first bin walk. Result: {"name", "nodeId", "mediaPath", "projectMetadata"}. live smoke-tested 2026-07-17.
get-color-label — premiere-cli get-color-label --node-id ID. Reads
item.getColorLabel() for a project item (same nodeId/name addressing
as get-item-metadata). Result: {"name", "nodeId", "colorLabel"} —
colorLabel is null (not a command failure) if unreadable on this
Premiere build. live smoke-tested 2026-07-17.
get-footage-interpretation — premiere-cli get-footage-interpretation --node-id ID. Reads item.getFootageInterpretation() (alpha usage,
field type, frame rate, alpha flags, pixel aspect ratio). Fails with
{"ok": false, "error": "no footage interpretation available for this item"} if the item has none (e.g. a bin or sequence item) — that's a
command-level failure, not a per-field null. Result: {"name", "nodeId", "alphaUsage", "fieldType", "frameRate", "ignoreAlpha", "invertAlpha", "pixelAspectRatio"}. live smoke-tested 2026-07-17.
get-xmp-metadata — premiere-cli get-xmp-metadata --node-id ID. Reads
the raw XMP XML via item.getXMPMetadata(); truncated to 100KB
(102400 chars) with truncated: true if it was cut. Result: {"name", "nodeId", "xmpMetadata", "truncated"}. live smoke-tested 2026-07-17.
get-color-space — premiere-cli get-color-space --node-id ID. Reads
item.getColorSpace()/getOriginalColorSpace()/getEmbeddedLUTID()/
getInputLUTID(), each independently best-effort. Result: {"name", "nodeId", "colorSpace", "originalColorSpace", "embeddedLUT", "inputLUT"}.
live smoke-tested 2026-07-17.
get-render-queue-status — premiere-cli get-render-queue-status. Per
PREMIERE_API_NOTES.md, Adobe Media Encoder exposes no real
queue-introspection API from ExtendScript, so this reports only
app.encoder.isRunning() (if that method exists on this build) rather
than inventing job/progress detail; fails if app.encoder itself is
unavailable. Result: {"isRunning", "info"}. live smoke-tested 2026-07-17.
Ported from leancoderkavy's premiere-pro-mcp reference project. All are
read-only, standard-DOM only unless noted, and none are live-tested yet.
Item metadata writes
Write-side counterparts of the metadata reads above. Every setter returns
{previousValue, requestedValue, newValue, verified} (field names vary
slightly per command) — undo is NON-FUNCTIONAL on this build, so
previousValue is the only restoration path if a caller needs to revert.
live smoke-tested 2026-07-17.
set-item-metadata --node-id ID --field-path "Column.Intrinsic.Description" --value "..." —
sets one project metadata field via item.setProjectMetadata(value, [fieldPath]). No single-field getter exists, so previousValue/newValue
are the full metadata blob before/after; verified is a substring check.
set-color-label --node-id ID --color-label 0-15 — item.setColorLabel();
degrades honestly (getter and setter both) if unavailable on this build,
mirroring get-color-label.
set-footage-interpretation --node-id ID [--frame-rate N] [--pixel-aspect-ratio N] [--field-type N] [--alpha-usage N] —
at least one field required. getFootageInterpretation() → mutate given
fields → setFootageInterpretation(i) → re-get to verify; returns full
before/after interpretation objects.
set-xmp-metadata --node-id ID (--xmp XML | --xmp-file PATH) —
REPLACES THE ITEM'S ENTIRE XMP BLOCK, not a merge — run
get-xmp-metadata first and modify. XMP is too large for a command
line, so --xmp-file reads a local file in the Python CLI (never on
the ExtendScript side) and sends its contents. Read-back truncated to
100KB like the getter.
Clip, track & edit-point reads
premiere-cli get-clip-at-position --seconds 12.5 [--track-type video --track-index 0] [--sequence-name "Seq 01"] — finds every clip covering a given time; --track-index requires --track-type, and omitting both scans every video/audio track. Result: {"sequenceName", "seconds", "clipCount", "clips": [...]}. Test status: request-body test only.
premiere-cli get-clip-at-playhead [--track-type video|audio|both] [--sequence-name ...] — clips covering the current playhead across one or both track types (default both). Result: {"playheadSeconds", "clipCount", "clips": [...]}. Test status: request-body test only.
premiere-cli get-next-edit-point [--direction next|previous] [--track-type ...] [--sequence-name ...] — nearest clip start/end boundary before/after the playhead. Result: {"found", "direction", "editPointSeconds"?, "playheadSeconds"}. Test status: request-body test only.
premiere-cli get-sequence-count — number of sequences in the active project. Result: {"count"}. Test status: request-body test only.
premiere-cli get-total-clip-count [--sequence-name ...] — clip counts across all tracks of a sequence. Result: {"videoClips", "audioClips", "total"}. Test status: request-body test only.
premiere-cli get-target-tracks [--sequence-name ...] — which tracks are currently targeted for editing. Result: {"video": [{"index","name"}], "audio": [...]}. Test status: request-body test only.
premiere-cli get-track-info --track-type video --track-index 1 [--sequence-name ...] — one track's full clip/transition list plus mute/lock/target state. Result: {"name", "clipCount", "isMuted", "isLocked", "isTargeted", "clips": [...], "transitions": [...]}. Test status: request-body test only.
premiere-cli get-encoder-presets [--format "H.264"] — probes app.encoder.getExporters()/.getPresets(), an API flagged unconfirmed in PREMIERE_API_NOTES.md; an unsupported build returns {"available": false, "error": "..."} rather than failing. Result: {"available", "presets": [{"exporterName","name","path"}], "count"}. Test status: request-body test only.
premiere-cli get-qe-clip-info --track-type video --track-index 0 --clip-index 2 [--sequence-name ...] — QE-DOM clip detail beyond what the standard DOM exposes; activates the resolved sequence first (QE only reads the active sequence). Time fields are suffixed Seconds since QE uses .secs, not .seconds. Test status: request-body test only.
premiere-cli get-source-monitor-info — info about the clip open in the Source Monitor; no clip loaded is a valid {"loaded": false}, not an error. Test status: request-body test only.
premiere-cli get-clip-adjustment-layer --track-type video --track-index 0 --clip-index 1 [--sequence-name ...] — whether the addressed clip is an adjustment layer. Result: {"clipName", "isAdjustmentLayer"}. Test status: request-body test only.
Markers & history
premiere-cli add-marker --seconds 5.0 [--name "Chapter 1"] [--comments ...] [--type Chapter] [--duration-seconds 2.0] [--color-index 3] [--sequence-name ...] — adds a marker to a sequence via markers.createMarker(). Verified by re-finding the new marker by guid after creation (never trusting createMarker()'s own returned object). Result: {"sequenceName", "marker": {"name","comments","type","startSeconds","endSeconds","guid"}}. live smoke-tested 2026-07-17.
premiere-cli update-marker --guid GUID [--name ...] [--comments ...] [--type ...] [--color-index N] [--duration-seconds N | --end-seconds N] [--sequence-name ...] — updates a marker identified by guid (not by time-matching, unlike the reference tool). marker.start is not mutable here. Verified by re-reading the marker fresh after mutating. Result adds applied (per-field success map). live smoke-tested 2026-07-17.
premiere-cli delete-marker --guid GUID [--sequence-name ...] — deletes a marker identified by guid via markers.deleteMarker(). Verified by confirming the marker count dropped by exactly one and the guid is gone from a fresh walk. Result: {"deleted": true, "markerCountBefore", "markerCountAfter"}. live smoke-tested 2026-07-17.
premiere-cli add-marker-to-project-item (--node-id ID | --name NAME) --seconds 3.0 [--marker-name ...] [--comments ...] [--type ...] [--duration-seconds N] [--color-index N] — adds a SOURCE marker to a project item via item.getMarkers(); the marker's label is --marker-name (not --name, which addresses the item, same convention as get-item-metadata). Verified the same way as add-marker. live smoke-tested 2026-07-17.
premiere-cli redo — REWRITTEN 2026-07-17: qe.project.redo() WORKS on this build (the earlier "non-functional" finding was wrong — see the correction note at the top of this section). Verified via qe.project.undoStackIndex() incrementing. Result: {"redone", "verified", "method", "undoStackIndexBefore", "undoStackIndexAfter", "note"}. Underlying API live-verified 2026-07-17; the rewritten command itself takes effect on the next panel reload.
premiere-cli undo [--count N] — REWRITTEN 2026-07-17: qe.project.undo() WORKS for operations that entered the undo stack (see the correction note at the top of this section); each iteration is verified via qe.project.undoStackIndex() decrementing, and the loop stops as soon as the index stops moving. CAUTION: marker adds and track renames never enter the stack — undoing right after one of those pops the next stack entry instead (possibly a user edit). Result: {"undoneCount", "stackExhausted", "undoStackIndexBefore", "undoStackIndexAfter", ...}. Underlying API live-verified 2026-07-17; the rewritten command itself takes effect on the next panel reload.
premiere-cli move-playhead-to-edit [--direction next|previous] [--sequence-name ...] — finds the nearest clip boundary before/after the playhead (same search as get-next-edit-point) and seeks there using move-playhead's ticks-string/Time-object pattern, verified via a getPlayerPosition() read-back. Result: {"editPointSeconds", "playheadSeconds", "attempts"}. live smoke-tested 2026-07-17.
premiere-cli set-poster-frame (--node-id ID | --name NAME) --seconds N — API uncertain: no poster-frame method is documented anywhere in PREMIERE_API_NOTES.md. Probes several plausible setter names and, if one doesn't throw, probes plausible getters to attempt a read-back; verified: false means unconfirmed, not a real success. live smoke-tested 2026-07-17.
LIVE FINDING 2026-07-17: no poster-frame API on this build — returns the probe-failure error.
premiere-cli select-project-item (--node-id ID | --name NAME) — calls item.select() on a Project-panel item (renamed from the reference's select_item). No confirmed selection read-back API exists — the result honestly reports only that the call didn't throw. live smoke-tested 2026-07-17.
Timeline selection
Ported from leancoderkavy's premiere-pro-mcp selection.ts/advanced.ts. All
are MUTATING (they change Premiere's clip selection) and standard-DOM only
(clip.setSelected()/isSelected()). Every command verifies the outcome via
a fresh seq.getSelection() read-back afterward — never the setter's own
return value — and returns {"selectedCount", "selectedClips": [...up to 20], "truncated"?} alongside command-specific fields. live smoke-tested 2026-07-17.
premiere-cli select-clips-by-name --name-contains STR [--add-to-selection] [--sequence-name ...] — selects every clip (video+audio) whose name contains STR (case-insensitive); replaces the existing selection unless --add-to-selection is given.
premiere-cli select-all-clips [--track-type video|audio|both] [--sequence-name ...] — selects every clip on the given track type (default both).
premiere-cli deselect-all-clips [--sequence-name ...] — deselects every clip across all video/audio tracks.
premiere-cli select-clips-in-range --start-seconds N --end-seconds N [--sequence-name ...] — replaces the selection with every clip that OVERLAPS [start, end) (partial overlap qualifies, not just full containment).
premiere-cli select-clips-by-color --color-label N [--sequence-name ...] — replaces the selection with clips whose source projectItem.getColorLabel() equals N (0-15); fails honestly with "getColorLabel is not available on this Premiere build" if that getter is absent, same degrade pattern as search-project-items.
premiere-cli invert-selection [--sequence-name ...] — flips every clip's selection state; a clip whose isSelected() throws is skipped (left untouched), tracked in skippedUnreadable.
premiere-cli select-disabled-clips [--sequence-name ...] — replaces the selection with clips where clip.disabled === true; unreadable clips are skipped (skippedUnreadable).
premiere-cli set-clip-selection --track-type video|audio --track-index N --clip-index N (--select|--deselect) [--sequence-name ...] — selects/deselects one clip, addressed the same way as get-full-clip-info; result also includes actualSelected (a direct clip.isSelected() read-back on the addressed clip, independent of the sequence-wide selectedClips list).
Track management
Mutation ports of leancoderkavy's premiere-pro-mcp track tools. Every one
verifies its own mutation by reading the affected state back afterward —
that read-back is the result's proof, not the mutation call's return
value. live smoke-tested 2026-07-17.
premiere-cli add-track --track-type video|audio [--index N] [--count N] [--sequence-name ...] — adds track(s) one at a time (never a bulk call — see PREMIERE_API_NOTES.md's CEP-bridge-wedging warning), --count capped at 8. Merges the reference's add_track and add_tracks tools. Tries standard-DOM insert, then addTrack, then two QE addTracks signatures. Verified by numTracks increasing. Result: {"added", "totalTracks", "attempts"}.
premiere-cli lock-track --track-type video|audio --track-index N --locked true|false [--sequence-name ...] — locks/unlocks a track (setLocked, falling back to setLock). Verified via isLocked().
premiere-cli set-track-visibility --track-index N --visible true|false [--sequence-name ...] — video-only; renamed from the reference's toggle to an explicit set. Caveat: no distinct visibility flag exists — this is track.setMute() on a video track with the sense inverted. Verified via isMuted().
premiere-cli set-track-mute --track-type video|audio --track-index N --muted true|false [--sequence-name ...] — mutes/unmutes a track; renamed from the reference's toggle to an explicit set, generalized to both track types. Verified via isMuted().
premiere-cli rename-track --track-type video|audio --track-index N --name "..." [--sequence-name ...] — renames a track via track.name assignment. Verified by reading track.name back.
premiere-cli set-target-track --track-type video|audio --track-index N --targeted true|false [--sequence-name ...] — targets/untargets a track for insert/overwrite edits. Verified via isTargeted().
premiere-cli set-all-tracks-targeted --targeted true|false [--track-type video|audio|both] [--sequence-name ...] — targets/untargets every track of the given type(s). Verified with a per-track isTargeted() read-back summary. Result includes tracksAffected and per-track video/audio arrays.
Clip transform & opacity
Mutation ports of leancoderkavy's premiere-pro-mcp track-targeting.ts/
clipboard.ts property setters (wave 3), addressed the same way as
get-full-clip-info (--track-type/--track-index/--clip-index, not
node_id). All build on shared host/index.jsx helpers (findClipComponent,
setComponentProperty) that identify components by matchName (never index
alone) and properties by displayName (exact, then normalized-lowercase —
locale-dependent). Every setter reads the property before AND after
setValue(), returning {"previousValue", "requestedValue", "newValue", "verified"} — undo is non-functional on this build, so previousValue
is the only restoration path if a mutation turns out unwanted. Design-only —
live smoke-tested 2026-07-17.
premiere-cli set-clip-position --track-type video|audio --track-index N --clip-index N --x N --y N [--sequence-name ...] — sets Motion/Position (pixels).
premiere-cli set-clip-scale --track-type video|audio --track-index N --clip-index N --scale N [--sequence-name ...] — sets Motion/Scale (100 = original size).
premiere-cli set-clip-rotation --track-type video|audio --track-index N --clip-index N --degrees N [--sequence-name ...] — sets Motion/Rotation (degrees; can exceed 360 for multiple rotations).
premiere-cli set-clip-anchor-point --track-type video|audio --track-index N --clip-index N --x N --y N [--sequence-name ...] — sets Motion/Anchor Point (pixels).
premiere-cli set-clip-opacity --track-type video|audio --track-index N --clip-index N --opacity N [--sequence-name ...] — sets Opacity/Opacity (0-100).
premiere-cli set-uniform-scale --track-type video|audio --track-index N --clip-index N --uniform true|false [--sequence-name ...] — sets Motion/Uniform Scale, which links (true) or unlinks (false) Scale Width/Scale Height.
premiere-cli set-scale-width-height --track-type video|audio --track-index N --clip-index N [--scale-width N] [--scale-height N] [--sequence-name ...] — sets Scale Width and/or Scale Height independently; unlike the reference tool (which silently force-disables Uniform Scale first), this reads Uniform Scale and fails with an informative error if it's on rather than flipping it for the caller — call set-uniform-scale --uniform false first.
premiere-cli set-anti-alias-quality --track-type video|audio --track-index N --clip-index N --enabled true|false [--sequence-name ...] — API uncertain: no anti-alias property is documented for the Motion component; probes a short list of plausible displayNames and returns an honest "not found on this build" error (naming every name tried) if none exist.
premiere-cli set-blend-mode --track-type video|audio --track-index N --clip-index N --blend-mode N [--sequence-name ...] — sets Opacity/Blend Mode to a raw int. API uncertain: the int↔name enum mapping is version-dependent across Premiere builds (reference repos disagree on map size/order), so this command takes/returns the raw int only — no name-mapping table of our own.
Clip audio & flags
Mutation ports of leancoderkavy's premiere-pro-mcp audio/timeline/advanced
tools (wave 3). Clip addressing matches get-full-clip-info
(--track-type video|audio --track-index N --clip-index N [--sequence-name ...]). live smoke-tested 2026-07-17 — undo is non-functional on this build, so
previousValue in each result is the only restoration path.
premiere-cli set-clip-volume --track-type ... --track-index N --clip-index N --db N [--sequence-name ...] — sets the Volume/Level property. dB calibration is UNVERIFIED: Level is linear amplitude, not dB; converted via hetpatel's linear = 10^((db-15)/20), which disagrees with the other two reference repos. Result includes raw linear previousValue/requestedValue/newValue plus previousDbEstimate so a caller can recalibrate.
premiere-cli set-clip-pan --track-type ... --track-index N --clip-index N --pan N [--sequence-name ...] — sets the Panner Balance/Pan property, -100 (full left) to 100 (full right). No dB conversion involved.
premiere-cli adjust-audio-levels --track-type ... --track-index N --clip-index N --db N [--sequence-name ...] — --db is a DELTA relative to the clip's current level, not an absolute value: reads current linear Level, estimates its dB via the same calibration as set-clip-volume, adds the delta, writes back. Same calibration uncertainty, compounded.
premiere-cli add-audio-keyframes --track-type ... --track-index N --clip-index N --keyframes '[{"seconds":0,"db":-60},{"seconds":1,"db":0}]' [--sequence-name ...] — adds Level keyframes; seconds is clip-relative, offset internally by clip.start to sequence time. Calls setTimeVarying(true) first. Uses a DIFFERENT, uncalibrated dB->linear formula (10^(db/20)) from set-clip-volume — the two commands' dB values are not interchangeable. Reports per-keyframe {addKeySuccess, setValueSuccess}.
premiere-cli rename-clip --track-type ... --track-index N --clip-index N --name "..." [--sequence-name ...] — renames a timeline clip; tries standard-DOM clip.name = x first, falls back to QE setName(). Verified via read-back.
premiere-cli batch-rename-clips --track-type ... --track-index N --new-name-template "Scene_{n}" [--name-contains ...] [--start-number N] [--sequence-name ...] — renames clips on one track via QE setName(); template supports {n} (counter) and {name} (existing name). Capped at 200 renames per call.
premiere-cli set-clip-enabled --track-type ... --track-index N --clip-index N --enabled true|false [--sequence-name ...] — enables/disables a clip (renamed from the reference's enable_disable_clip); probes clip.disabled = !enabled then clip.setDisabled(!enabled). Verified via read-back.
premiere-cli batch-set-clips-enabled --enabled true|false [--name-contains ...] [--track-type video|audio|both] [--sequence-name ...] — enables/disables every matching clip; capped at 200. No target: "selected" equivalent — combine with select-clips-by-name/--name-contains instead.
premiere-cli set-frame-blend --track-type ... --track-index N --clip-index N --enabled true|false [--sequence-name ...] — QE qeClip.setFrameBlend(bool). Activates the sequence first; maps the standard-DOM clip index to the Nth non-"Empty" QE item (QE track item lists interleave gap items).
premiere-cli set-time-interpolation --track-type ... --track-index N --clip-index N --type 0|1|2 [--sequence-name ...] — QE qeClip.setTimeInterpolationType() (0=sampling, 1=blending, 2=optical flow); same Empty-item-skipping QE addressing as set-frame-blend.
premiere-cli set-clip-properties --track-type ... --track-index N --clip-index N [--opacity N] [--speed N] [--scale N] [--position-x N] [--position-y N] [--rotation N] [--sequence-name ...] — bulk setter over Motion/Opacity properties; at least one property flag required. Position sets X/Y together, preserving whichever axis wasn't specified.
Effects
Mutation ports of leancoderkavy's premiere-pro-mcp effects.ts/clipboard.ts (wave 4). Clip addressing matches get-full-clip-info (--track-type --track-index N --clip-index N [--sequence-name ...]); every mutation reads clip.components before/after and reports counts AND names, never trusting a QE call's own return value. Undo is non-functional on this build, so remove-effect/remove-effect-by-name are the primary cleanup path — Motion/Opacity are always refused. live smoke-tested 2026-07-17.
premiere-cli apply-effect --track-type video --track-index N --clip-index N --effect-name "Gaussian Blur" [--sequence-name ...] — applies a video effect via the standard QE dance (getVideoEffectByName + addVideoEffect); verified by components.numItems increasing by 1. See list-available-effects for exact names.
premiere-cli apply-audio-effect --track-type audio --track-index N --clip-index N --effect-name "..." [--sequence-name ...] — audio counterpart via getAudioEffectByName/addAudioEffect.
premiere-cli remove-effect --track-type ... --track-index N --clip-index N --component-index N [--sequence-name ...] — removes one component by index. component.remove() is DISPUTED across reference repos (works vs. impossible) — judged only by components.numItems dropping, not by whether the call throws. Refuses Motion/Opacity.
premiere-cli remove-effect-by-name --track-type ... --track-index N --clip-index N --effect-name "..." [--sequence-name ...] — removes every component matching a displayName/matchName (backwards iteration); Motion/Opacity still refused even by name.
premiere-cli remove-all-effects --track-type ... --track-index N --clip-index N [--sequence-name ...] — QE qeClip.removeEffects(); strips all applied effects in one call, built-ins survive per QE semantics.
premiere-cli color-correct --track-type video --track-index N --clip-index N [--exposure N] [--contrast N] [--saturation N] [--temperature N] [--tint N] [--sequence-name ...] — applies Lumetri Color if missing, then sets each given control by displayName; Lumetri repeats displayNames across sub-sections, so each control tries every matching property until one write succeeds ("first writable match wins"). 0 is a legitimate value, never falsy-checked.
premiere-cli apply-lut --track-type video --track-index N --clip-index N --lut-path /path/to/look.cube [--sequence-name ...] — CORRECTED 2026-07-23: ensures Lumetri Color is applied, but the --lut-path step itself always fails on this build — "Input LUT" is a registry-backed dropdown INDEX, not a settable path string (see BUILD_FINDINGS.md). Only useful now for the Lumetri-Color-ensure side effect. To switch to a LUT already loaded in Premiere's dropdown, use set-effect-property --component-name "Lumetri Color" --property-name "Input LUT" --value N --value-type number instead. To load a brand-new .cube file Premiere hasn't seen before: driving the native UI directly is the only way to do this on this build — there's no dedicated command for it, but the correct-color skill's step 6 documents the full process, composed from these generic desktop-* primitives (desktop-take-screenshot, desktop-press-key, desktop-enter-text-with-validate, desktop-move-mouse, desktop-click-mouse) plus AI vision-language screen understanding to locate Premiere's custom-drawn Lumetri controls, since they expose no AX geometry to hit-test against.
premiere-cli stabilize-clip --track-type video --track-index N --clip-index N [--smoothness N] [--method "Subspace Warp"|"Position"|"Position, Scale, Rotation"] [--sequence-name ...] — applies Warp Stabilizer; analysis itself runs asynchronously in Premiere afterward.
premiere-cli copy-effects-between-clips --source-track-type ... --source-track-index N --source-clip-index N --target-track-type ... --target-track-index N --target-clip-index N [--effect-name "..."] [--source-sequence-name ...] [--target-sequence-name ...] — re-applies each non-intrinsic effect (or just --effect-name) from source to target via QE, then copies property values across. Source/target may be on different sequences.
premiere-cli copy-effect-values --source-track-type ... --source-track-index N --source-clip-index N --target-track-type ... --target-track-index N --target-clip-index N --effect-name "..." [--source-sequence-name ...] [--target-sequence-name ...] — copies one effect's property VALUES only; the effect must already exist on BOTH clips.
premiere-cli batch-apply-effect --effect-name "..." [--name-contains ...] [--track-type video|audio|both] [--track-index N] [--sequence-name ...] — applies an effect to every matching clip, capped at 100; no target: "selected" equivalent — combine with select-clips-by-name instead.
Keyframes & effect properties
Wave-4 ports of leancoderkavy's premiere-pro-mcp keyframes.ts/advanced.ts
(set_color_value). Addressed by --track-type/--track-index/--clip-index
(same as get-full-clip-info) plus --component-name/--property-name —
--component-name is matched generically against BOTH matchName and
displayName (any component, not just Motion/Opacity). --seconds/
--start-seconds/--end-seconds are clip-relative, offset internally by
clip.start to sequence time. Key-time argument form is disputed across
Premiere builds — mutating commands try a ticksString, then a Time object,
then a raw seconds number, recording every attempt. live smoke-tested 2026-07-17;
undo is non-functional on this build, so read-back previousValues are the
only restoration path.
premiere-cli get-effect-properties --track-type ... --track-index N --clip-index N --component-name "Motion" [--sequence-name ...] — lists ALL properties of one named component (value, isTimeVarying, keyCount), uncapped.
premiere-cli set-effect-property --track-type ... --track-index N --clip-index N --component-name "Motion" --property-name "Scale" --value 150 --value-type number [--sequence-name ...] — sets one property; --value-type (number/string/boolean) disambiguates how --value is coerced before sending.
premiere-cli get-keyframes --track-type ... --track-index N --clip-index N --component-name "Motion" --property-name "Position" [--sequence-name ...] — lists every keyframe as {sequenceSeconds, clipRelativeSeconds, value}. Key-time representation is disputed across builds — normalized via an unverified heuristic.
premiere-cli add-keyframe --track-type ... --track-index N --clip-index N --component-name "Motion" --property-name "Scale" --seconds 1.5 --value 120 [--sequence-name ...] — adds a keyframe, calling setTimeVarying(true) first if needed. verified is a keyframe-COUNT check only, not an exact-time match.
premiere-cli remove-keyframe --track-type ... --track-index N --clip-index N --component-name "Motion" --property-name "Scale" --seconds 1.5 [--sequence-name ...] — removes a keyframe within ±half a frame; the cleanup path for add-keyframe mistakes.
premiere-cli remove-keyframe-range --track-type ... --track-index N --clip-index N --component-name "Motion" --property-name "Scale" --start-seconds 0 --end-seconds 2 [--sequence-name ...] — removes all keyframes in a clip-relative range via removeKeyRange().
premiere-cli set-keyframe-interpolation --track-type ... --track-index N --clip-index N --component-name "Motion" --property-name "Scale" --seconds 1.5 --interpolation-type 5 [--sequence-name ...] — sets interpolation to a raw int whose enum meaning is version-dependent (0=Linear/4=Hold/5=Bezier vs. a 0/1/2 map, per two disagreeing reference repos) — no translation applied.
premiere-cli get-value-at-time --track-type ... --track-index N --clip-index N --component-name "Motion" --property-name "Scale" --seconds 1.5 [--sequence-name ...] — reads a property's interpolated value at a clip-relative time.
premiere-cli set-color-value --track-type ... --track-index N --clip-index N --component-name "Lumetri Color" --property-name "Tint" --alpha 255 --red 128 --green 64 --blue 32 [--sequence-name ...] — sets a color-typed property (e.g. Lumetri tint, title fill), each channel 0-255.
Transitions
Mutation ports of leancoderkavy's premiere-pro-mcp transitions.ts (wave 4).
add-transition merges the reference's add_transition/add_transition_to_clip
into one command, addressed like get-full-clip-info (--track-index --clip-index, not node_id/cut-point-seconds). Apply is QE-only
(qe.project.getVideoTransitionByName() then a disputed addTransition()
signature — arity 3-7, duration as seconds-string/ticks-string/number,
tried on both qeClip and qeTrack); every attempt is verified via a
track.transitions.numItems delta, never the call's return value. Not yet
live-tested.
premiere-cli add-transition --track-type video --track-index N --clip-index N --at-end true|false [--transition-name "Cross Dissolve"] [--duration-seconds N] [--sequence-name ...] — adds a transition at one clip's start (--at-end false) or end (--at-end true); omit --transition-name for the default transition. Video only.
premiere-cli batch-add-transitions [--track-index N] [--at-end true|false] [--transition-name "..."] [--duration-seconds N] [--sequence-name ...] — applies the same transition to every cut point on one video track (default track 0, --at-end default true); capped at 100 clips per call.
premiere-cli remove-transition --track-type video|audio --track-index N --transition-index N [--sequence-name ...] — new, not a reference port: cleanup for the two commands above since undo is non-functional on this build. Standard-DOM track.transitions[i].remove(...), arity probed via an attempts array, verified via a numItems drop of exactly one. An out-of-range --transition-index gets a transitions listing back (index + name) to help find the right one.
Timeline editing
Mutation ports of leancoderkavy's premiere-pro-mcp timeline.ts/advanced.ts
(wave 5) — the highest-risk tier: these directly add, remove, move, trim,
split, duplicate, replace, and re-speed clips. Undo is NON-FUNCTIONAL on this
build, so every command re-reads the timeline afterward (clip counts,
start/end times) rather than trusting a call's own return value. Not yet
live-tested.
premiere-cli add-to-timeline --node-id ID|--name NAME --track-type video|audio --track-index N --start-seconds N --mode insert|overwrite [--sequence-name ...] — UPDATED 2026-07-17: places a project item via the TRACK object's own track.insertClip(item, TimeObject)/overwriteClip(item, TimeObject), which HONORS the track index (probe-verified — the sequence-level seq.insertClip()/overwriteClip() ignore their video-track index on this build and are kept only as a fallback; check placedVia/trackHonored in the result). For video placements, auto-scans every audio track afterward for the source's own linked-audio clip landing near the requested time and removes it (the auto-linked-audio trap in PREMIERE_API_NOTES.md) — reports linkedAudioCleanup. The updated placement path takes effect on the next panel reload.
premiere-cli remove-from-timeline --track-type ... --track-index N --clip-index N --ripple true|false [--sequence-name ...] — Destructive: permanently removes a clip via clip.remove(ripple, false); verified via a numItems drop of exactly one.
premiere-cli move-clip --track-type ... --track-index N --clip-index N --start-seconds N [--sequence-name ...] — moves a clip to a new absolute start time on the SAME track via clip.start assignment (does not change track, per the documented API limitation); verified via a read-back.
premiere-cli trim-clip --track-type ... --track-index N --clip-index N [--in-point-seconds N] [--out-point-seconds N] [--sequence-name ...] — trims in and/or out point (source-media-relative seconds); each field verified independently. The only command that writes a tick-exact, sub-frame in-point — see Time precision.
premiere-cli split-clip --track-type ... --track-index N --seconds N [--sequence-name ...] — razors whichever clip covers a sequence-time position via QE qeTrack.razor(); verified via the track's clip count increasing by exactly one.
premiere-cli duplicate-clip --track-type ... --track-index N --clip-index N [--target-start-seconds N] [--sequence-name ...] — inserts a new instance of the clip's own project item onto the SAME track (ripple insert, so never destructive), defaulting the target start to right after the original's own end.
premiere-cli replace-clip --track-type ... --track-index N --clip-index N --replacement-node-id ID|--replacement-name NAME [--sequence-name ...] — Destructive: removes a clip and reinserts a different project item at the same start time; verified by re-finding a clip there whose media path matches the replacement.
premiere-cli set-clip-speed --track-type ... --track-index N --clip-index N --speed-percent N [--sequence-name ...] — REWRITTEN + LIVE-VERIFIED 2026-07-17: sets playback speed via the calibrated 5-arg qeClip.setSpeed(multiplier, durationTicksString, reverse, false, false) (the only working form on this build — speeds are MULTIPLIERS internally, 1 = 100%). Negative --speed-percent = reversed. Speed-up shortens the clip (frame-rounded, so the applied speed can differ slightly); slow-motion does NOT extend the timeline item. Verified via clip.getSpeed()/isSpeedReversed() read-backs; result includes newSpeedPercent and verified. (--ripple/--maintain-audio are still accepted for compatibility but IGNORED — the working signature has no such knobs.)
premiere-cli get-clip-speed --track-type ... --track-index N --clip-index N [--sequence-name ...] — read-only: clip.getSpeed()/isSpeedReversed().
Advanced timeline edits