# Shared sessions (/docs/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](https://github.com/codai-ro/codai-protocol).

## The moving parts [#the-moving-parts]

```text
                     ┌──────────────── 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 [#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 [#a-minimal-round-trip]

Every request carries your key and, on writes, your device id:

```bash
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 [#where-to-go-from-here]

<Cards>
  <Card title="Protocol reference" href="./protocol.mdx" description="Every object, route, error and limit of v1." />
  <Card title="Streaming" href="./streaming.mdx" description="SSE and WebSocket frames, resuming with ?after=, idempotent writes." />
  <Card title="Sharing and orgs" href="./sharing-and-orgs.mdx" description="Invite a person, a team or a link; manage organisations." />
  <Card title="Hosts relay" href="./hosts.mdx" description="Run a shell command or read a file on your desktop from your phone." />
</Cards>

<Callout type="info">
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.
</Callout>
