> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omegas.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Operator: live view and takeover

> Watch sessions, control sessions, the takeover lease, and why read-only is genuinely read-only.

A live-view session lets a person see a device's browser as it works, and,
under a separately scoped permission, take over its controls: for a
`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:

| `mode`                  | What it grants                                | Scope required                                                |
| ----------------------- | --------------------------------------------- | ------------------------------------------------------------- |
| `watch` (alias: `view`) | Frames only. No input, ever.                  | `operator:sessions:write`                                     |
| `control`               | Frames, plus the right to request a takeover. | `operator:sessions:write` **and** `operator:sessions:control` |

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](/operator/authentication#a-credential-must-not-reach-a-url)
for why.

## Watching and driving are different privileges

In the TypeScript client, the type system holds the line: a `WatchConnection`
has no method that sends input, and the only route to a `ControlConnection` is
a successful `takeover()`.

```ts theme={null}
const connection = await omega.devices.watch(device.id, { mode: "control", ttl_secs: 900 });

for await (const frame of connection.frames()) render(frame.data); // base64 JPEG

const control = await connection.takeover("clearing a captcha");
control.sendInput({ t: "mouse", type: "mousePressed", x: 412, y: 233 });
await control.release(); // back to the agent; the returned view cannot send input
```

The gateway is authoritative either way: it re-checks the mode and the
takeover lease on every message and drops what it will not relay. It drops
silently, so the client mirrors the check and throws on a send without a held
lease, instead of producing a click the browser appears to ignore. If you
build your own client, mirror it too.

## 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 with
`POST /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.
