Skip to content

API

The Jimothy UI talks to the engine through one typed API (FactoryApi). In the desktop app it’s exposed to the renderer as window.factory over Electron IPC (one channel per method, factory:<method>). With Remote access on, the same methods are available over HTTP.

This isn’t a versioned public API; it can change between releases. It’s documented here so you can script Jimothy from your tailnet and understand what the remote UI can do.

Method Description
snapshot(): Snapshot Everything the UI needs: settings, projects, pipelines, accounts, triggers and their state, harnesses and detection status, channels, the latest 300 runs (without outputs), the latest 100 inbox items, data folder, version, webhook URL and remote status
listRuns(filter?: { status?, pipelineId?, search?, limit? }): Run[] Runs, newest first (default limit 500), without step outputs and prompts
getRun(id): Run | undefined One run with everything, including outputs, rendered prompts and the pipeline snapshot
startRun({ pipelineId, issue?, variables? }): Run Start a run. issue needs at least title; key, description, url, labels, priority, source are optional. variables override pipeline variables.
cancelRun(id) Cancel a queued or running run
retryRun(id, fromStepId?): Run Re-queue a finished run, optionally from a step
deleteRun(id) Delete a finished run and its logs
approveStep(runId, stepId, approved: boolean, comment?, selected?: string[]) Approve or reject a waiting approval step. For a step with choices, approving needs selected: the option ids (numbers as strings) to pick, exactly one for single mode. Unknown ids are ignored.
readStepLog(runId, stepId, attempt?): LogLine[] A step attempt’s log (default: the latest attempt)
readRunLog(runId): LogLine[] The run’s setup log
Method Description
saveProject(project): Project Create (empty id) or update a project
deleteProject(id) Fails while the project still has pipelines
savePipeline(pipeline): Pipeline Create or update; validates the pipeline first
createPipelineFromTemplate(templateId, projectId?): Pipeline Templates: demo, feature, bugfix, blank
duplicatePipeline(id): Pipeline Copy named … (copy)
deletePipeline(id) Fails while a trigger uses it
exportPipeline(id): string JSON with "jimothyPipeline": 1
importPipeline(json): Pipeline Import an export
generatePipeline({ description, harnessId, model? }): Pipeline Have an agent design a pipeline (Build with AI)
cancelPipelineGeneration() Stop it
Method Description
saveConnection(connection): Connection Sign in / update an account (verified first)
deleteConnection(id) Fails while triggers use it
testConnection(connection): { ok, error?, account? } Verify credentials without saving
saveTrigger(trigger): TriggerConfig Create or update a trigger
deleteTrigger(id) Delete a trigger and its dedup state
testTrigger(trigger): { ok, error?, issues } Preview matching issues / Validate
pollTrigger(id): TriggerState Check now
resetTrigger(id) Forget processed issues
Method Description
saveHarness(harness): HarnessDefinition Create or update (built-ins are stored as overrides)
deleteHarness(id) Delete a custom harness, or reset a built-in
setHarnessEnabled(id, enabled) Enable / disable
detectHarnesses(): Record<string, HarnessStatus> Re-detect
listModels(harness): string[] Fetch models for an (unsaved) harness definition
refreshModels(id): HarnessDefinition Fetch and save a harness’s models
generateText({ target, instructions, harnessId, model?, current?, pipeline?, stepId?, requestId? }) Generate with AI for a prompt, system prompt or command
cancelGenerate(requestId) Cancel it
Method Description
saveChannel(channel) / deleteChannel(id) Manage channels
testChannel(channel): { ok, error? } Send test
markInboxRead(ids?) Mark items (or all) read
clearInbox() Clear the inbox
Method Description
saveSettings(settings): Settings Save settings (restarts the webhook server / remote access if needed)
pickDirectory() Native folder picker — desktop only
openExternal(url) Open an http(s) URL — desktop only (the remote UI opens links locally)
openPath(path) Reveal a folder — desktop only
openInEditor(path) Open in code, then cursor, else the file manager — desktop only
remotePairing(): { url, token, qrSvg } Sign-in link and QR code — desktop only
resetRemoteToken() Sign out all devices — desktop only

platform is 'darwin', 'linux', or 'web' in the remote UI.

on(event, callback) subscribes to pushes from the engine and returns an unsubscribe function.

Event Payload
run A run that changed (coalesced, about every 60 ms)
run-deleted The id of a deleted run
logs A batch of { runId, stepId, attempt, line } log events (about every 80 ms)
inbox A new inbox item
snapshot A fresh snapshot after configuration or trigger state changed
navigate A path to show (tray menu, notification clicks) — desktop only

With remote access on, every method except the desktop-only ones can be called over HTTP at the remote address.

Authentication: the session cookie from pairing, or Authorization: Bearer <token> (the token from the sign-in link, …/pair?t=<token>).

Calls: POST /api/call/<method> with Content-Type: application/json and a JSON array of arguments. Use null for omitted optional arguments.

Status Body
200 {"result": …}
400 {"error": "…"} — the method threw, or the body wasn’t an array
401 {"error": "Not signed in"}
403 {"error": "<method> is only available on the desktop"}
415 {"error": "Expected JSON"}

Events: GET /api/events is a server-sent events stream with the events above (except navigate), each as event: <name> + data: <json>, plus a : ping comment every 20 seconds.

Examples from a machine on your tailnet:

Terminal window
BASE=https://my-mac.tail1234.ts.net:7443
TOKEN=… # from the sign-in link
# Start a run
curl -s "$BASE/api/call/startRun" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '[{"pipelineId":"pl_0mfz…","issue":{"title":"Bump dependencies","key":"OPS-12"}}]'
# Approve a waiting step
curl -s "$BASE/api/call/approveStep" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '["run_0mfz…","approve",true,"LGTM"]'
# Approve a step with choices, picking options 1 and 3
curl -s "$BASE/api/call/approveStep" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '["run_0mfz…","pick",true,"Keep them short",["1","3"]]'
# Follow live events
curl -N "$BASE/api/events" -H "Authorization: Bearer $TOKEN"

For anything reachable from outside your tailnet, use a webhook trigger instead.