Skip to main content

System components

High-level flow

Session lifecycle

  1. wrapper share or wrapper run starts wrapper shell-host (wrapper install is optional).
  2. Host creates a PTY, binds loopback WebSocket + token, and registers locally.
  3. Unshared hosts send nothing to Convex.
  4. Local viewers attach with the registry token. No Convex row is required.
  5. Share opens a Convex session, issues a hashed share code plus host relay ticket, and starts heartbeats.
  6. Viewers request viewer tickets, connect to the relay, and optionally open P2P.
  7. Unshare or host exit revokes tickets, closes the Convex row, and closes remote viewers.
The backend expires stale sessions that miss heartbeats.

Relay auth and routing

Backend-issued relay tickets are short-lived and single-use. Each session has one host and can have multiple viewers. The relay routes terminal frames and WebRTC signaling only within that session. Host disconnect closes every viewer. Peer ids are assigned by the relay.

Protocol

Wire messages are JSON validated with Zod in @repo/protocol. Common types:
  • session.opened / session.closed
  • input / output / resize
  • attach / detach
  • error
  • signal (WebRTC SDP and ICE)
  • viewer.caps (whether that viewer may type)
The relay stamps from on input and drops guest typing unless canInput is true. The host enforces the same rule on P2P input. Frames have explicit size caps (wire and terminal payload limits) before parse and fan-out.

Session access

  • A session that is not shared is owner only.
  • The owner joins a shared session without a share code.
  • A non-owner needs the session id, share code, and a valid ticket.
  • Access failures use a uniform denial shape.
  • People you invite see output. They cannot type unless the host allows it.
See Security and privacy, Transports, and Pricing.
Last modified on September 14, 2026