Shared sessions
One conversation, many devices — the gateway keeps the ordered event log; the device with the tools executes; everyone else follows or steers.
A shared session is a server-side conversation. The gateway's store is the source of truth for its ordered event log; every device keeps a local cache and reconciles by seq. The conversation travels; execution stays where the tools are — your laptop runs the shell, your phone watches and answers the agent's questions, a teammate reads along.
This is the protocol behind "continue on phone", the hub's session view and the desktop's live mirror. It is public, versioned (v1, stable) and published with JSON Schemas at github.com/codai-ro/codai-protocol.
The moving parts
┌──────────────── gateway (ai.codai.ro) ────────────────┐
│ session ──▶ events[seq 1..n] controls lease │
└──────▲──────────────┬──────────────▲────────┬────────┘
appends events POST │ │ SSE / WS │ POST │ push (FCM)
claims lease │ ▼ │ ▼
┌────────────────┐ ┌───────────┐ ┌───────────┐ ┌────────────┐
│ EXECUTOR │ │ VIEWER │ │ EDITOR │ │ DISPATCHED │
│ desktop / CLI │ │ hub, web │ │ phone │ │ device │
│ holds the lease│ │ read-only │ │ sends │ │ woken with │
│ runs the tools │ │ follows │ │ controls │ │ a `send` │
└────────────────┘ └───────────┘ └───────────┘ └────────────┘| Object | What it is |
|---|---|
| Session | The container. Has an id (server UUID) and your own session_key, an owner, a title, last_seq, and who holds the lease. |
| Event | One entry in the log, with a dense server-assigned seq, a kind (turn_start, tool_call, ask, assistant, …) and an opaque payload. Only the executor appends. |
| Control | An instruction to the executor — send, answer, approve, deny, cancel, steer, inject. Persisted so a late executor can drain them, echoed into the log so every viewer sees them. |
| Lease | The right to append. Exactly one device holds it, for 30 seconds at a time, renewed by heartbeat every 10 seconds. |
| Device | Any client installation — a UUID you choose, sent as x-codai-device, registered lazily under your account. |
| Share | A grant of viewer, editor or owner on one session to a user, an org, or a link token. |
| Presence | Who is connected right now, and whether they are driving. In memory only. |
| Dispatch | A send targeted at one of your devices, plus a push notification to wake it. |
Roles
| Role | May |
|---|---|
viewer | Read the session, its events and controls; follow the live stream. |
editor | Everything a viewer may, plus submit controls and dispatch. |
owner | Everything, plus rename, archive, delete, manage shares and claim the lease. |
You are owner of sessions you created. On a shared session your role is the highest of the shares that match you — directly, through an org you belong to, or via a link token you present.
A minimal round trip
Every request carries your key and, on writes, your device id:
export DEV=$(uuidgen) # once per installation; reuse it
# 1. create (or reopen) a session by your own key
curl -X POST https://ai.codai.ro/v1/sessions \
-H "Authorization: Bearer $CODAI_API_KEY" \
-H "x-codai-device: $DEV" -H "x-codai-device-platform: cli" \
-H "Content-Type: application/json" \
-d '{ "session_key": "laptop-2026-09-23", "title": "Fix the flaky test" }'
# 2. take the lease — you are the executor now
curl -X POST https://ai.codai.ro/v1/sessions/laptop-2026-09-23/lease \
-H "Authorization: Bearer $CODAI_API_KEY" -H "x-codai-device: $DEV"
# 3. append what happened
curl -X POST https://ai.codai.ro/v1/sessions/laptop-2026-09-23/events \
-H "Authorization: Bearer $CODAI_API_KEY" -H "x-codai-device: $DEV" \
-H "Content-Type: application/json" \
-d '{ "events": [
{ "kind": "turn_start", "turn_id": "t1", "client_event_id": "t1-start", "payload": { "text": "Fix the flaky test" } },
{ "kind": "assistant", "turn_id": "t1", "client_event_id": "t1-a1", "payload": { "text": "Reading test_retry.py…" } }
] }'
# 4. from any other device: follow it
curl -N "https://ai.codai.ro/v1/sessions/laptop-2026-09-23/stream?after=0" \
-H "Authorization: Bearer $CODAI_API_KEY" -H "x-codai-device: $(uuidgen)"The stream replays the two events, then a lease frame naming your laptop as holder, then stays open for whatever comes next.
Where to go from here
Protocol reference
Every object, route, error and limit of v1.
Streaming
SSE and WebSocket frames, resuming with ?after=, idempotent writes.
Sharing and orgs
Invite a person, a team or a link; manage organisations.
Hosts relay
Run a shell command or read a file on your desktop from your phone.
Storing and streaming your own sessions is available on every paid tier. The persistent_memory entitlement gates only server-side memory and search, not this protocol. A session created with e2e: true is encrypted client-side (HIDE — experimental, unaudited) and the gateway stores ciphertext.