Concepts

The control lease

How agent and human share one browser without racing each other.

A session broker holds the only connection to the browser. The agent and every viewer are clients of the broker, never of Chrome. Control is a lease:

{
  sessionId: string,
  owner:     'agent' | 'human' | 'none' | 'transferring',
  epoch:     number,          // increments on every transfer
  holderId:  string | null,   // the user when owner is 'human'
  expiresAt: number           // renewed by the viewer's heartbeat
}

Every input command carries the epoch it was planned under. The broker rejects any command whose epoch is not current with a typed STALE_EPOCH error, and the caller must re-observe. This makes the agent-versus-human race impossible rather than unlikely.

Transfer sequence

  1. Owner becomes transferring; agent input is refused from this point.
  2. In-flight agent commands are awaited, bounded.
  3. Quiescence: no pending navigation, no in-flight main-frame requests.
  4. Hardware-level input ignore is switched on as a backstop.
  5. The page is snapshotted: latest frame, full accessibility tree, frame tree, cookies.
  6. Epoch increments; owner becomes human; input ignore is switched off.

Hand-back reverses the sequence and always re-snapshots.

Where the lease lives

In the broker's store, keyed by session, never in the streaming connection. A dropped WebSocket does not lose your control; reconnecting resumes it. Lease changes reach the run's workflow as a signal, and while a run is parked the workflow re-reads the lease periodically so a lost signal cannot strand it.

Expiry

The viewer heartbeats the lease. If the heartbeat stops, the policy is per environment: destructive environments park the run for a human, others return control to the agent.

The control lease · Handoff