premiere-bridge
Skill2 starsChanged 5 days agoMITView on GitHub
Driving Adobe Premiere Pro from Claude without an MCP server, through a file-based ExtendScript bridge (a self-signed CEP panel that runs .jsx files dropped into an inbox folder and writes JSON results). Covers installing and signing the panel, sending scripts safely, inspecting projects/sequences/clips/bins, exporting preview frames, relinking media (e.g. to transcoded .mp4) with before/after verification, transcoding settings that keep Premiere's picture identical, and verified traps. Use whenever a task touches Premiere Pro / .prproj projects.
In this repository26 other files it gives its agents.
- aftereffects-bridgeSkill
- aftereffects-scriptingSkill
- cinema4d-alembicSkill
- cinema4d-mcpSkill
- cinema4d-motion-trackerSkill
- cinema4d-particlesSkill
- cinema4d-redshiftSkill
- cinema4d-render-previewSkill
- cinema4d-riggingSkill
- cinema4d-takesSkill
- houdini-flipbookSkill
- houdini-mcpSkill
- houdini-network-layoutSkill
- houdini-pop-particlesSkill
- houdini-pyro-smokeSkill
- houdini-to-cinema4dSkill
- houdini-vdb-surfacingSkill
- project-notesSkill
- unreal-content-managementSkill
- unreal-editor-toolsSkill
- unreal-led-volume-rigSkill
- unreal-materials-pythonSkill
- unreal-mcpSkill
- unreal-sequencer-pythonSkill
- unreal-ultra-dynamic-skySkill
- vo-timingSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 1 is distinctive, and 9 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
9
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 34
Every edit to a panel file breaks the signature: re-run install.ps1.
- Very specific: line 40
Never write straight into inbox/: scripts/send.sh NAME [timeout] stages $STAGE/NAME.jsx under a non-.jsx name, renames it, waits for the …
- Very specific: line 53
After only read-only scripts (plus enableQE, exportFramePNG, openSequence, setPlayerPosition) the title bar showed the project as modified …
- Very specific: line 94
escape-processes its path: After a backslash, a digit starts an octal escape (\009_cti cut the path, so …\frames\009_cti wrote …\frames.png.
- Very specific: line 100
Look at frames with Pillow (uv run --with pillow python -I …): before|after side by side plus a 1:1 centre crop shows both framing and fine …
- Very specific: line 115
Check alpha before choosing MP4: getFootageInterpretation() gives frameRate, alphaUsage, ignoreAlpha, and Pillow shows whether alpha really …
- Very specific: line 119
Prove nothing moved: before and after, snapshot every clip in the affected sequences (seq, track, index, name, start/end/in/out ticks) and …
- Very specific: line 132
Before relinking, check every output against its source with ffprobe: nb_frames, rate, size, timecode, audio streams.
- Very specific: line 140
Leave alpha sources alone (ProRes 4444 yuva…, QuickTime RLE argb): MP4 drops the alpha.
- Distinctive: line 144
After a session that used the bridge, add only what was tested in a real project (mark the rest *(unverified)*), correct wrong entries …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Premiere Pro via the file bridge (verified Premiere 2026 / 26.5.2, Windows, CEP 12.0.1)
There is no Premiere MCP server here. panel/ is a CEP extension ("Claude Bridge"): while it is
open, index.html calls ClaudeBridge.tick() in host.jsx about once a second. Each tick takes
every *.jsx in <ROOT>/inbox, moves it to done/ first, runs it inside (function(){ ... })()
(so a top-level return works) and writes <ROOT>/outbox/<name>.json = {file, ok, result |
error+line, ms}. <ROOT>/status.json is rewritten every ~5 s: {state: listening|paused|running,
time, file (while running), premiere, project, runs}. Default ROOT is D:/WORK/Claude/premiere-bridge
(the ROOT line in host.jsx). $.global.ClaudeBridge exposes ROOT, stringify, readText,
writeText, log (shown in the panel) and exportFrame (below).
Premiere has no scriptable undo groups: a bridge script is not one Ctrl+Z. Before anything
destructive, work on a copy (app.project.saveAs, see Relinking) or have the user save first.
Installing (verified)
scripts/install.ps1setsHKCU\Software\Adobe\CSXS.12\PlayerDebugMode = "1"(string), self-signs the panel whenD:\WORK\Claude\premiere-bridge-signing\ZXPSignCmd.exeexists, and copies it to%APPDATA%\Adobe\CEP\extensions\com.claude.premierebridge. Then Window › Extensions › Claude Bridge (with a project open; whether the Home screen offers it is unverified). Keep it docked so it stays open; whether it reopens by itself after a restart is unverified.- CEP 12.0.1 ignores PlayerDebugMode. An unsigned panel just doesn't open: no window, no
CEPHtmlEngine process.
%TEMP%\CEP12-PPRO.log(needsLogLevel≥ 1 under the same key) saysSignature verification failed for extension com.claude.premierebridge.panel. Self-signing fixes it:ZXPSignCmd.exe4.1.3 x64 from Adobe-CEP/CEP-Resources (ZXPSignCMD/4.1.3/x64, git blobf5df2ed8…; it has no Authenticode signature, so check the hash). The certificate and its password are created in the signing folder on first install. Never commit them. - Premiere discovers new extensions only at start-up. After signing a panel Premiere had already discovered (and refused), clicking the menu item again loaded it without a restart.
- Every edit to a panel file breaks the signature: re-run
install.ps1. A newhost.jsxthen loads via the panel's Reload host, or from a bridge script:$.evalFile(Folder.userData.fsName + "/Adobe/CEP/extensions/com.claude.premierebridge/host.jsx")(keeps the run count). A changedindex.htmlneeds the panel closed and reopened.
Sending scripts
- Never write straight into
inbox/:scripts/send.sh NAME [timeout]stages$STAGE/NAME.jsxunder a non-.jsxname, renames it, waits for the JSON (envBRIDGE= ROOT). Number scripts (023_snapshot.jsx) sodone/reads as a history. - On a timeout
send.shreadsstatus.json:running X (started N s ago)= Premiere is stuck in that script; a stale heartbeat = panel closed. A call that never returns (seen with QEexportFramePNG, below) leaves Premiere idle at 0 % CPU with a responsive UI, but the bridge is blocked until Premiere restarts. Scripts are claimed before they run, so the restart won't rerun it. err.lineis the line in the script file.JSONexists in Premiere 26.5's ExtendScript.- DOM objects stringify as
"<Project>","<Sequence>": copy the fields you need into plain objects. - The regex literal
/\\/gis a SyntaxError in ExtendScript; uses.split("\\").join(...)ornew RegExp("\\\\", "g"). ExtendScript is ES3: a reserved word as an object key ({ in: … }) is a SyntaxError too ("Illegal use of reserved word"). Backslash paths written through sed/heredocs get mangled easily ("y:\bbc"is a backspace): build them withString.fromCharCode(92)orFile.fsName. - After only read-only scripts (plus
enableQE,exportFramePNG,openSequence,setPlayerPosition) the title bar showed the project as modified (*); which call does it is unverified. Tell the user rather than letting them wonder about unsaved edits.
Inspecting (verified)
- Time: 254016000000 ticks per second.
seq.timebase= ticks per frame (string);seq.end,seq.zeroPoint= tick strings. Clipstart/end/inPoint/outPointare Time objects (.seconds,.ticksstring).seq.getInPoint()/getOutPoint()return seconds as strings,"-400000"= not set.seq.getSettings().videoFrameRate.seconds= frame duration;audioSampleRateis a Time (1/48000 s).seq.getPlayerPosition()→ Time;seq.setPlayerPosition(ticksString). - Tracks:
seq.videoTracks[i].clips[j](numTracks,numItems);clip.projectItem,clip.nodeId,clip.mediaType,track.isMuted(). Higher track index = on top. ProjectItemType: CLIP 1, BIN 2, ROOT 3, FILE 4. Sequences are CLIP items withisSequence(); map them viaapp.project.sequences[i].projectItem.nodeId. Walk bins viarootItem.children;item.treePath,item.getMediaPath(),item.isOffline().- "Used in these timelines, including nested ones": recurse through
clip.projectItem.nodeId→ sequence. Subclips (X.mp4.Subclip01) are separate items sharing the master's media path, so count a media path as used when any used item has it.getInPoint()/getOutPoint()on a subclip project item returned the whole file (0 to full length), not the subclip's range: take used source ranges from the track items'inPoint/outPoint(master-media time, timecode-based). clip.getSpeed()(1, 2, 0.75…) andclip.isSpeedReversed()(0/1) work on track items.seq.getWorkAreaInPoint()/getWorkAreaOutPoint()return seconds as strings, likegetInPoint.- Timelines often park material after the edit. One 1-minute edit ran to 94 minutes, with two full 30-minute B-roll files laid end to end after its out point. Before calling anything "used", compare clip positions with the sequence's out point and look for a big gap, and ask which counts. In that project the master items and their subclips were both used, several of them at far-apart points. An item links to one file only, so cutting a source into separate pieces cannot serve such an item. (Unverified idea: re-encode at full length with unused stretches blacked out, which keeps timing and every link intact.)
- ProjectItem in 26.5 has no delete for clips (
deleteBinonly), plusmoveBin,changeMediaPath,canChangeMediaPath,findItemsMatchingMediaPath,isMergedClip,isMulticamClip,setOffline,createSubClip,saveProjectSnapshot(list fromitem.reflect.methods). app.project.openSequence(sequenceID)activates a sequence (returns true);qe.project .getActiveSequence()follows it within the same script.
Exporting frames (verified)
ClaudeBridge.exportFrame(timecode, name)→<ROOT>/frames/<name>.pngat full sequence size, synchronously (4K ≈ 0.3–1 s), from the active sequence. Timecode as QE gives it ("00:00:26:11"). For an exact moment:openSequence(id),setPlayerPosition(ticks), thenqe.project.getActiveSequence().CTI.timecode. The time argument is honoured.- Why the helper exists: QE
exportFramePNG(timecode, pathWithoutExtension)appends.pngand escape-processes its path. After a backslash, a digit starts an octal escape (\009_cticut the path, so…\frames\009_ctiwrote…\frames.png;\123becameS). Lowercase a–e lose the backslash (…\frames\d2\abc_defwrote…\framesd2abc_def.png).\Fhung Premiere for good. Forward slashes, a.pngending or doubled backslashes throw "Unknown error exception". Lowercase f–z and uppercase A–E survive. The helper allows names[f-z][a-z0-9_-]*only and refuses folders with an unsafe segment. - Look at frames with Pillow (
uv run --with pillow python -I …): before|after side by side plus a 1:1 centre crop shows both framing and fine detail.
Relinking media (verified on a 249-item, 17-sequence project)
- Work on a copy:
app.project.saveAs(fsPath)saves the open state to the new file and switches the open project to it. The original file keeps its old save (mtime unchanged). item.changeMediaPath(newPath, false)relinked ProRes/MJPEG.mov→ HEVC.mp4and NAS → local paths for 225 items without the override flag.canChangeMediaPath()is false for Motion Graphics Template items (.aegraphic): they can't be relinked by script.- Premiere keeps linked media open. To replace an
.mp4in place, relink the item elsewhere (e.g. back to the.mov), overwrite the file, then relink again. - An image-sequence item (
X.0001.png) relinks to a movie withchangeMediaPathtoo. A 172-frame RGBA PNG sequence became a lossless PNG-in-MOV (ffmpeg -framerate 25 -start_number 1 -i X.%04d.png -c:v png -pix_fmt rgba -f mov, the same 102 MB as the frames). It kept its 25 fps interpretation, length and alpha settings, and the composite check frames were pixel-identical. Check alpha before choosing MP4:getFootageInterpretation()givesframeRate,alphaUsage,ignoreAlpha, and Pillow shows whether alpha really drops below 255. changeMediaPathalso works on items that went offline (files removed outside Premiere).item.isOffline()finds them. CheckisOfflineafter any file moves the user may make too.- Prove nothing moved: before and after, snapshot every clip in the affected sequences (seq, track, index, name, start/end/in/out ticks) and export a check frame mid-clip for each changed medium. Ticks must be identical. Compare frames with numpy: PSNR plus mean level shift. Healthy HEVC re-encodes gave 35–48 dB with a shift of about −0.3. An edge-glow effect on a clip amplified the same compression to about 26 dB (identical framing). A levels problem shows as a steady shift (+9).
Transcoding for a relink (verified, ffmpeg 7.1.1, RTX 4090)
- HEVC 10-bit on NVENC:
-map 0:v:0 -map 0:a? -map_metadata 0 -c:v hevc_nvenc -preset p7 -tune hq -rc vbr -multipass fullres -b:v 40M -maxrate 60M -bufsize 120M(HD: 20M/30M)-profile:v main10 -pix_fmt p010le -tag:v hvc1 -c:a aac -b:a 320k -movflags +faststart, plus-timecode <source tc>when the source has one. Write.partand rename on success. 17.7 GB of 4K ProRes LT (Topaz upscales) became 1.1 GB in about 2.5 min. Premiere read the timecode: in/out stayed identical, including sources starting at 01:40:00:00 and 21:55:31:16. - Before relinking, check every output against its source with ffprobe:
nb_frames, rate, size, timecode, audio streams. - MJPEG sources (
yuvj422p: full range, BT.601 matrix). A plain-pix_fmt p010lewrites video-range pixels but keeps thepcflag, and Premiere showed lifted blacks. Use-vf scale=in_range=pc:out_range=tv:in_color_matrix=bt601:out_color_matrix=bt709,format=p010le,setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=tv. The-color_trc/-color_primariesoutput options do not override tags carried by the frames;setparamsdoes. A leftover sRGB transfer tag (iec61966-2-1) on the HEVC made Premiere 26 render it brighter than the MJPEG with the same tag; forcing bt709 matched. - Leave alpha sources alone (ProRes 4444
yuva…, QuickTime RLEargb): MP4 drops the alpha. Re-encoding small or already-H.264.movfiles saves little and costs a generation.
Keeping this skill current
After a session that used the bridge, add only what was tested in a real project (mark the rest
(unverified)), correct wrong entries instead of appending, keep this file under ~300 lines, and
commit and push the skills repo. Project-specific facts (sequence names, paths, clients) go to that
production's notes (see project-notes), never here.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

