needs_human wall, or because a human wanted to check on the work.
Minting a session
POST /v1/devices/{id}/sessions mints a session and returns its connection
details exactly once. There is no route that reads a session token back; a
lost token means a new session.
The request’s mode accepts:
Both
watch and view are accepted for the read-only mode; they name the
same thing. An omitted mode defaults to watch, the less privileged of the
two, so a forgotten field can never accidentally mint control. Minting a
control session without the control scope is 403 insufficient_scope.
ttl_secs is a request, clamped to the server’s allowed band; a client does
not get to decide how long a live-browser capability lives.
The session token rides the WebSocket handshake in Sec-WebSocket-Protocol
(omega.operator.v1, omega.token.<ops_…>), never a query parameter, and the
returned ws_url is only honoured if it matches the API origin over wss:.
See authentication
for why.
Watching and driving are different privileges
In the TypeScript client, the type system holds the line: aWatchConnection
has no method that sends input, and the only route to a ControlConnection is
a successful takeover().
The takeover lease requires presence
Taking over acquires a lease on the device; the socket heartbeats it. If the holder vanishes (a closed laptop, a dropped connection), the device is handed back to the agent about a minute later. Releasing explicitly withPOST /v1/sessions/{id}/release is the polite version of the same thing.
A takeover can carry a reason ("clearing a captcha" above, or a ticket id).
It is recorded on the takeover’s audit event, which is what makes a human
intervention a recorded fact rather than an anecdote.