codai docs
Shared sessions

Hosts relay

Run a shell command or read a file on your desktop from your phone, a browser or a script — no SSH, no inbound port, same account only.

The hosts relay lets any client of yours execute a small, fixed vocabulary of operations on one of your desktops that has the codai desktop app open. The desktop keeps an outbound SSE connection to the gateway and announces itself as a host; a requester POSTs an exec and the gateway relays it, then relays the answer back. Nothing is persisted, nothing listens on the desktop, and in v1 host and requester must belong to the same user.

   phone / browser / script                 gateway                       desktop (host)
   ──────────────────────                 ─────────                      ───────────────
   POST /v1/hosts/:dev/exec  ───────▶  rendezvous by device id  ─────▶  event: exec  (over its SSE)
        { op, args }                                                      runs the op locally
   200 { ok, result }        ◀───────  rendezvous by req_id     ◀─────  POST /v1/hosts/exec/:reqId/result

This surface is served by https://ai.codai.ro and is not part of the published Shared Sessions v1 spec; treat it as remote sessions v1.

Which desktops are online

curl https://ai.codai.ro/v1/hosts -H "Authorization: Bearer $CODAI_API_KEY"
{
  "hosts": [
    {
      "device_id": "1c2f…-uuid",
      "name": "Work laptop",
      "platform": "desktop",
      "os": "windows",
      "hostname": "DRAGOS-PC",
      "roots": ["E:\\gh\\codai", "C:\\Users\\dragos\\Documents"],
      "since": 1790160000000,
      "last_seen": 1790160045000
    }
  ]
}

Only your own devices appear, most recently seen first. since and last_seen are epoch milliseconds; a host drops off the list 45 seconds after its last heartbeat. roots are the directories the desktop will let file operations touch.

Run something on a host

POST /v1/hosts/:deviceId/exec — needs your key and an x-codai-device header identifying the requester.

Prop

Type

curl https://ai.codai.ro/v1/hosts/1c2f…/exec \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "x-codai-device: $(uuidgen)" -H "x-codai-device-platform: cli" \
  -H "Content-Type: application/json" \
  -d '{ "op": "shell", "args": { "cmd": "git status --short", "cwd": "E:\\gh\\codai" }, "timeout_ms": 30000, "label": "docs check" }'

Response — the host's answer, verbatim:

{
  "req_id": "c0de…-uuid",
  "ok": true,
  "result": { "code": 0, "stdout": " M apps/docs/content/docs/en/sessions/hosts.mdx\n", "stderr": "", "truncated": false, "timed_out": false, "duration_ms": 412 },
  "error": null
}

A host-side failure — a path outside roots, a bad argument, a command that could not start — is still HTTP 200 with ok: false and error set. Only relay problems are HTTP errors:

StatuscodeWhen
400bad_requestMissing x-codai-device, unknown op, timeout_ms out of range.
404not_founddeviceId is not one of your devices (the gateway never reveals other users' device ids).
409host_offlineIt is your device but it is not connected as a host right now — open codai desktop.
504host_timeoutThe host did not answer within timeout_ms — host did not answer within 30000 ms.

Operations

The desktop implements each op with its own permission-checked commands; file paths must fall under the host's roots.

opargsresult
shell{ cmd: string, cwd?: string, timeout_ms?: number } — PowerShell on Windows, the login shell elsewhere; timeout_ms is clamped to the request's.{ code, stdout, stderr, truncated, timed_out, duration_ms }
fs_read{ path: string, max_bytes?: integer } — default 64 KB, max 512 KB.{ path, content, size, truncated }
fs_write{ path: string, content: string }{ path, bytes, created }
fs_list{ path: string }{ path, entries: [{ name, kind, size }], truncated }
fs_roots{}{ roots: string[] }
info{}{ os: 'windows' | 'linux' | 'macos', hostname, roots, platform: 'desktop' }

shell runs with the desktop user's privileges. The relay adds no sandbox of its own — the desktop app's autonomy setting and rules gate what it will execute, and every request shows up in its UI with your label. Keep API keys that can reach /v1/hosts as tightly scoped as any SSH key.

Building a host

You only need this section if you are writing your own host (the codai desktop app already is one).

Announce yourself

Open GET /v1/hosts/stream with your key and the host's own x-codai-device. Describe the machine in the query string (a GET has no body): ?os=windows&hostname=DRAGOS-PC&roots=E:\gh\codai,C:\Users\dragos\Documents — os ≤ 40 chars, hostname ≤ 120, up to 32 roots.

The first frame is hello, then a ping every 15 s; each ping refreshes your presence (TTL 45 s). The server closes the stream after 6 hours — reconnect with backoff (the desktop uses 1 s → 30 s).

event: hello
data: {"device_id":"1c2f…","heartbeat_ms":15000}

event: ping
data: {"t":1790160045000}

event: exec
data: {"req_id":"c0de…","op":"shell","args":{"cmd":"git status --short","cwd":"E:\\gh\\codai"},"timeout_ms":30000,"label":"docs check","from_device_id":"9a0b…","ts":1790160050000}

Execute and reply

For every exec frame, run the op and POST /v1/hosts/exec/:reqId/result with { "ok": boolean, "result"?: any, "error"?: string ≤ 4000 }. The body must stay under 2 MB, and reqId must be the 36-character UUID you received. A missing or late reply simply lets the requester's timeout_ms expire.

curl -X POST https://ai.codai.ro/v1/hosts/exec/c0de…/result \
  -H "Authorization: Bearer $CODAI_API_KEY" -H "x-codai-device: 1c2f…" \
  -H "Content-Type: application/json" \
  -d '{ "ok": true, "result": { "code": 0, "stdout": "…", "stderr": "", "truncated": false, "timed_out": false, "duration_ms": 412 } }'

The req_id is an unguessable capability handed only to you; the gateway matches the reply to the waiting requester by it and answers { "ok": true }.

Enforce your own roots

The gateway relays; you decide what runs. Refuse paths outside your advertised roots, clamp shell timeouts to the request's timeout_ms, cap output sizes (set truncated: true), and surface every request in your UI with its label and from_device_id.

On this page