Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/jasonkneen/openclicky/llms.txt

Use this file to discover all available pages before exploring further.

Every bridge command is a plain HTTP request to http://127.0.0.1:32123. All POST bodies are JSON. All responses are JSON except for the SSE stream at /events. Most endpoints require the bridge token supplied via x-openclicky-token or Authorization: Bearer <token>; the /health endpoint is public.
Coordinates use macOS/AppKit global screen space: origin at the bottom-left of the combined display rectangle, Y increasing upward. Capture a screenshot first if you need to translate visual positions to AppKit coordinates.

GET /health

Returns the bridge status, port, transport type, configured tool names, and whether the bridge token is configured. Does not require authentication.
curl -s http://127.0.0.1:32123/health
Response (200)
{
  "ok": true,
  "name": "OpenClicky External Control Bridge",
  "port": 32123,
  "transport": "local-http+sse",
  "bridgeTokenRequired": true,
  "bridgeTokenConfigured": true,
  "tools": [
    "openclicky_point",
    "openclicky_point_many",
    "show_cursor",
    "show_cursors",
    "show_caption",
    "screenshot",
    "clear",
    "speak",
    "notify"
  ],
  "multiToolEndpoints": ["/mcp/calls", "/tools/calls"]
}
When inferenceProxyEnabled is true, the response also includes proxyEndpoints: ["/v1/messages", "/v1/responses", "/v1/chat/completions"].

GET /events

Opens a server-sent event stream. The connection stays open until the client disconnects. Requires a valid bridge token.
curl -N http://127.0.0.1:32123/events \
  -H 'x-openclicky-token: YOUR_TOKEN'
SSE event types
EventWhen emittedData fields
readyImmediately on connectok, port
commandAfter every bridge command completesok, path, count (batch only)
Example stream
event: ready
data: {"ok":true,"port":32123}

event: command
data: {"ok":true,"path":"/cursor"}

event: command
data: {"ok":true,"path":"/mcp/calls","count":3}

POST /cursor

Points at a single screen coordinate. By default, uses OpenClicky’s native primary cursor choreography: the triangular cursor animates to the target, shows the caption, then returns — without warping the real macOS pointer. Pass mode: "secondary" to place an extra temporary colored marker instead.
curl -s -X POST http://127.0.0.1:32123/cursor \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"x":640,"y":520,"caption":"Click this menu","durationMs":4500}'
Request body
x
number
required
AppKit screen X coordinate (origin at bottom-left of the global display rectangle).
y
number
required
AppKit screen Y coordinate.
caption
string
Short text label shown beside the cursor. Aim for 3–8 words.
durationMs
number
default:"~4000"
How long the caption stays visible, in milliseconds. Clamped to 200–60000 ms.
travelMs
number
Accepted for compatibility with older callers. Primary cursor motion always uses OpenClicky’s own smooth pointing choreography; this field does not override the animation timing.
accentHex
string
Caption accent color as a CSS hex string, e.g. #60A5FA.
mode
string
default:"primary"
"primary" (default) uses the native pointing choreography. "secondary" creates an additional temporary colored marker at the coordinate instead.
Secondary cursor example
curl -s -X POST http://127.0.0.1:32123/cursor \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"x":640,"y":520,"caption":"Look here","mode":"secondary","accentHex":"#34D399","durationMs":4500}'
Response (200)
{"ok": true}

POST /cursors

Places multiple temporary secondary markers at once. All cursors in the batch become visible simultaneously and disappear after durationMs. Use this for orientation overviews, side-by-side comparisons, or multi-step screen tours where you want the user to see several labeled points at the same time.
curl -s -X POST http://127.0.0.1:32123/cursors \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{
    "durationMs": 4500,
    "cursors": [
      {"x":640,"y":520,"caption":"Editor","accentHex":"#60A5FA"},
      {"x":900,"y":520,"caption":"Logs","accentHex":"#F59E0B"}
    ]
  }'
Request body
cursors
array
required
Array of cursor objects. Each object supports x, y, caption, accentHex, and its own durationMs. If a cursor object does not include durationMs, the top-level durationMs is used.
durationMs
number
default:"~4000"
Default display duration for all cursors that do not specify their own, in milliseconds.
Cursor object fields
FieldTypeDescription
xnumberAppKit X coordinate (required)
ynumberAppKit Y coordinate (required)
captionstringShort label
accentHexstringCSS hex accent color
durationMsnumberPer-cursor override duration
Response (200)
{"ok": true}

POST /caption

Shows a floating text caption near a screen coordinate. If x and y are omitted, the caption appears near the current mouse location.
curl -s -X POST http://127.0.0.1:32123/caption \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"x":900,"y":700,"text":"This is the setting you want","durationMs":5000}'
Request body
text
string
required
The caption text to display.
x
number
AppKit X coordinate near which the caption appears. Omit to use the current mouse position.
y
number
AppKit Y coordinate. Omit to use the current mouse position.
durationMs
number
default:"~4000"
How long the caption stays visible, in milliseconds.
Response (200)
{"ok": true}

POST /screenshot

Captures screenshots of all connected displays (or just the focused window when focused is true). Returns local JPEG file paths and display frame metadata in AppKit coordinate space — the same coordinate space used by /cursor and /cursors. Use this when you need to find a UI element before pointing at it.
curl -s -X POST http://127.0.0.1:32123/screenshot \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"focused": false}'
Request body
focused
boolean
default:"false"
When true, captures only the focused window rather than all displays.
Response (200)
{
  "ok": true,
  "count": 2,
  "screens": [
    {
      "path": "/var/folders/.../openclicky-screen-0.jpg",
      "frame": {"x": 0, "y": 0, "width": 2560, "height": 1440}
    },
    {
      "path": "/var/folders/.../openclicky-screen-1.jpg",
      "frame": {"x": 2560, "y": 0, "width": 1920, "height": 1080}
    }
  ]
}
The frame values are in AppKit global screen coordinates. Use them to translate pixel positions in the JPEG into the x/y values you pass to /cursor. Screenshot-to-pointer workflow
# Step 1 — capture
curl -s -X POST http://127.0.0.1:32123/screenshot \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"focused":false}'

# Step 2 — point at the identified target
curl -s -X POST http://127.0.0.1:32123/cursor \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"x":1180,"y":760,"caption":"Use this button"}'

POST /speak

Speaks a short instruction through OpenClicky’s TTS without entering dictation mode or triggering voice-response state. If OpenClicky is already speaking, the request is rejected with HTTP 409 unless interrupt: true is passed.
curl -s -X POST http://127.0.0.1:32123/speak \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"text":"Click the button in the top right."}'
Request body
text
string
required
The text to speak aloud through OpenClicky’s TTS engine.
interrupt
boolean
default:"false"
When true, stops any in-progress speech and begins speaking text immediately. Prefer false unless the user explicitly wants the new instruction spoken now.
Responses
StatusMeaning
200Speech queued or started successfully.
409OpenClicky is already speaking. Pass interrupt: true to override.
Interrupt example
curl -s -X POST http://127.0.0.1:32123/speak \
  -H 'Content-Type: application/json' \
  -H 'x-openclicky-token: YOUR_TOKEN' \
  -d '{"text":"Stop — look at this instead.","interrupt":true}'

POST /clear

Clears all bridge-created overlay elements — cursors and captions placed by /cursor, /cursors, and /caption. Has no effect on overlays managed by OpenClicky’s own conversation or voice flows. Takes no request body.
curl -s -X POST http://127.0.0.1:32123/clear \
  -H 'x-openclicky-token: YOUR_TOKEN'
Response (200)
{"ok": true}
Call /clear between scenes in a screen tour to prevent stale markers from accumulating and cluttering the recording.

Error responses

All error responses follow a consistent shape:
{"ok": false, "error": "Descriptive error message"}
StatusCause
400Malformed JSON or missing required fields.
401Bridge token missing or invalid.
404Unknown endpoint path.
405Wrong HTTP method (use POST for control commands).
409Conflict — e.g. TTS already speaking and interrupt not set.

Build docs developers (and LLMs) love