Skip to main content
rakumux-api exposes the session operations of the running Rakumux server over HTTP/1.1 and JSON, plus WebSocket streams for a live terminal and for session events. It’s a thin adapter: the server still decides folder confinement, permissions and the audit log. The MCP server is its main client, and scripts can use it directly. The endpoint pages in this section are generated from its OpenAPI 3.1 document.
The API answers only on 127.0.0.1, and refuses browsers, so these pages show requests to copy rather than a live playground.

Running

  • One API runs per Rakumux home. --detach with a healthy API already running just prints its URL.
  • The API starts the Rakumux server on the first request when none runs. It never stops the server, so stopping the API leaves every session running.
  • SIGINT and SIGTERM stop it cleanly. A detached API logs to ~/.rakumux/logs/api.log.

Finding it: api.json

While it runs, the API writes ~/.rakumux/api.json (mode 0600):
The token is new on every start. A file whose pid is gone is stale.

Authentication

  • Bearer token. Every route except GET /v1/health needs Authorization: Bearer <token>, with the token from api.json.
  • Loopback only. Host must be 127.0.0.1, localhost or [::1] (any port), which defeats DNS rebinding.
  • No browsers. A request with an Origin or Sec-Fetch-Site header gets 403, and the API never sends CORS headers.
  • Bodies must be Content-Type: application/json, at most 64 KiB. Unknown fields and query parameters are rejected.
The token keeps other local users and web pages out. Like the server’s own tokens, it doesn’t stop a hostile process running as your user, which can read api.json.

Identity

Without identity headers the API acts as you. With both of these, the variables Rakumux sets in every session, it acts as that session, confined to its own folder:
Session callers may create sessions in their folder within limits (4 running per creating session, nesting 2 deep, 8 running agent-created sessions per folder, 10 creates a minute); beyond that the answer is 429 limit_exceeded. For agents whose tool calls arrive without the session’s environment (OpenCode 2.x), X-Rakumux-Agent: opencode and X-Rakumux-Agent-Conversation: <id> act as the session that bound that conversation.

Folders and sessions

A session’s folder is the directory it was started in. Wherever a folder is accepted it may be an absolute directory (~/ expanded) or the name of a known folder. Sessions come back as {"session": {...}} or {"sessions": [...]}, with folder, status (live, exited, dead), lifecycle (working, blocked, done, idle, unknown, none), command, git, terminal and RFC 3339 times. Earlier builds said project; those names still work and are marked deprecated.

Errors

Errors are {"error": {"code", "message", "details"?}}. The API’s own: method_not_allowed 405, payload_too_large 413, unsupported_media_type 415, and upgrade_required 426 (a WebSocket route without the upgrade).

Streams

GET /v1/events and GET /v1/sessions/{id}/attach are WebSockets on the same port, with the same checks. The server pings every 30 seconds.
  • /v1/events sends {"type":"subscribed"}, then {"type":"event","folder":"/path","session_id":"01J…","at":<unix ms>,"event":{…}}, where event is created, updated, removed, exited, lifecycle, reported or activity.
  • /v1/sessions/{id}/attach?role=observer|controller&cols=&rows= first sends attached, with a base64 checkpoint to feed a fresh terminal of cols×rows, then terminal output as binary frames. Send input as binary frames (as controller), and resize, promote, demote or fit as text. Closing the socket detaches.

Remote access

With phone access on, the API adds a remote listener on the machine’s Tailscale addresses, at remote.json’s port (7337 by default), or on remote.json’s listen addresses or --remote-listen ADDR:PORT instead.
  • Its bearer is the remote token from remote.json, not the api.json token.
  • It doesn’t check Host and allows Origin (the phone app’s WebSocket sends one).
  • The caller is always you: identity headers are refused (403).
  • It serves the same routes.

Example

(jq is used only by this example; Rakumux doesn’t need it.)