Skip to main content
Version: 0.4.1

Scripting Solar Sailer

Use the local HTTP API to read the running editor and send edit batches from any language. You don't need a repo checkout or build step. For a module with its own Process menu entry and settings, use the Plugin Development Guide instead.

Connect to the editor​

  1. Keep Solar Sailer open.
  2. Open Edit > Preferences... > Scripting.
  3. Copy the Server address and API token.
  4. Send the token as a bearer token on every /timeline/* request and on the token-protected project and media routes shown below.
Authorization: Bearer <token>

The server listens only on 127.0.0.1. It chooses a new port and token each time Solar Sailer starts, so copy both values again after a restart.

Scripts launched in the embedded agent terminal can read the same values from PROKO_EDITOR_PORT and PROKO_EDITOR_TOKEN.

Start with the live command reference​

Call GET /agent/instructions first. Solar Sailer generates this reference from the running command registry, including every command's current parameters, descriptions, and notes. This route does not require the bearer token, but it returns 503 until the editor has connected to the local server.

The main routes are:

MethodPathToken requiredPurpose
GET/agent/instructionsNoCurrent command reference.
GET/timeline/summaryYesTrack IDs, clip IDs, positions, and media names. Start here for most scripts.
GET/timeline/stateYesFull clip, track, marker, selection, in/out, and transform data. Pass both start_frame and end_frame to limit clips to a frame range.
GET/timeline/mediaYesMedia bin items with IDs, paths, types, dimensions, frame rates, and durations.
POST/timeline/commandsYesValidate and run an edit batch.
GET/project/currentYesCurrent project as {path, dataDir, name}. All three values are null when no project is open.
POST/project/openYesOpen a .sailer project through the normal save and switch flow.

Use POST /project/open with an absolute project path:

{
"path": "C:/Projects/example.sailer"
}

Solar Sailer saves the current project first if it has unsaved changes and a known path. Add "discardChanges": true only when you mean to abandon those changes. A dirty project with no saved path returns 409 unless you opt to discard it.

After any project switch, read /timeline/summary again. IDs and earlier results may belong to the previous project.

Send an edit batch​

Each command object uses type for the command name and params for its arguments. undoLabel is required and becomes the label for the batch in undo history.

{
"undoLabel": "Script: split at 2s",
"idempotencyKey": "split-at-2s-001",
"commands": [
{
"type": "splitAllAtFrame",
"params": { "frame": 60 }
}
]
}

The editor validates the whole batch before applying it. If any command is invalid, the route returns 400 and applies nothing. A successful batch that changes the timeline creates one undo entry, so the user can reverse it with Ctrl+Z. A valid no-op creates no undo entry.

Every time value is an integer frame, not seconds. Convert with frames = round(seconds * frameRate). Read frameRate from /timeline/summary or /timeline/state.

Most commands that edit clips on locked tracks return an error naming the track. A command may define a different policy. For example, splitAllAtFrame skips locked tracks and reports warnings. Check the notes in /agent/instructions before relying on a command's lock or link behavior.

Each entry in the response's results array can include createdIds, deletedIds, and warnings. Created IDs are the real store IDs, so you can use them in a later request. Warnings report a non-fatal compromise, such as a best-effort split that skipped locked content.

The range commands deleteRanges and disableRanges require a non-empty trackIds array on every range. Read those IDs from /timeline/summary.

Retry without applying an edit twice​

A 503 or 504 response from /timeline/commands is ambiguous. The editor may have applied the batch before the response was lost.

Include an idempotencyKey in the original request if you may retry it. The key can be any unique string from 1 to 128 characters. Reuse the same key only for a retry of that logical edit. Solar Sailer remembers keys for about two minutes and returns the original result instead of applying the batch again.

A 409 means a project switch interrupted the request and the command did not run. Read /timeline/summary again, decide whether the edit still applies, and use a new key if you send it.

A replay always returns the original execution result. If the project changed between attempts, that result still describes the edit on the project that was open during the first attempt.

Example​

This example reads the summary, then splits every eligible clip at frame 60. On a 30 fps timeline, that is two seconds. splitAllAtFrame succeeds as a no-op when no clip spans the frame.

TOKEN="<paste from Preferences > Scripting>"
BASE="http://127.0.0.1:<port>"

curl -s -H "Authorization: Bearer $TOKEN" "$BASE/timeline/summary"

curl -s -X POST "$BASE/timeline/commands" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{
"undoLabel": "Script: split at 2s",
"idempotencyKey": "split-at-2s-001",
"commands": [{ "type": "splitAllAtFrame", "params": { "frame": 60 } }]
}'

The same request in Python:

import requests

BASE = "http://127.0.0.1:<port>"
HEADERS = {"Authorization": "Bearer <token>"}

summary = requests.get(f"{BASE}/timeline/summary", headers=HEADERS).json()

result = requests.post(
f"{BASE}/timeline/commands",
headers=HEADERS,
json={
"undoLabel": "Script: split at 2s",
"idempotencyKey": "split-at-2s-001",
"commands": [{"type": "splitAllAtFrame", "params": {"frame": 60}}],
},
)
print(result.json())

Read analysis data​

These read routes do not require the bearer token:

  • GET /transcripts returns the project's readable transcripts keyed by media ID. It returns {} when none are available.
  • GET /transcripts/{media_id} returns one word-level transcript and its saved annotations. It returns 404 when the project or transcript is missing.
  • GET /face-tracking/sidecar/{media_id}, GET /motion/sidecar/{media_id}, and GET /umm/sidecar/{media_id} return {mtime, sidecar}. They return 404 when that module has no completed sidecar for the media and 409 when no saved project is open.
  • GET /characters returns {characters, last_run_started_at, settings}. The characters array is empty when the project library has none.

Import media​

Import files into the current media bin with the token-protected POST /media/import route:

{
"paths": [
"C:/Media/interview.mp4",
"C:/Media/room-tone.wav"
]
}

The response always has media for newly imported items. When applicable, skipped lists the file names of duplicates and failed contains {path, reason} entries for files Solar Sailer could not import. Use /timeline/media to get IDs for media already in the bin, then use the appropriate command from /agent/instructions to place it on the timeline.

Limits and security​

The command API can insert, move, trim, split, slip, delete, and disable clips. It also covers gaps, copy and paste, markers, tracks, link groups, selection, in/out points, transforms, undo, and redo. It cannot add rendering effects or transitions because Solar Sailer does not support those yet. It also cannot drive the embedded chat agent.

Do not edit .sailer files directly. The running editor owns current state, and the file format is not a scripting interface. Going through the API keeps validation, track locks, linked edits, and undo intact.

The token permits full edit control of the running editor. Treat it like a password. Do not commit it or send it to another service. The server accepts connections only from the local machine, but unauthenticated read routes can still expose project analysis data to other local processes.