Skip to content

WebSocket API

Live terminal streaming over WebSocket at /ws/{session_id}.

Connection

const ws = new WebSocket('wss://localhost:8081/ws/coding-0');

WebSocket connections require authentication via session cookie (same-origin).

Message Format

All messages are JSON except for PNG frame data which is sent as binary.

Server → Client Messages

viewer_assigned

Sent immediately after connection with the server-assigned viewer tag.

Fields:

Field Description
viewer_tag Server-assigned viewer identifier for log correlation.

role_assigned

Sent immediately after connection with this viewer's driver/passenger role.

Fields:

Field Description
role Assigned role: driver or passenger.
driver_tag Current driver viewer tag, if any.
driver_info Driver connection metadata when this viewer is a passenger.

status

Sent with PNG-mode frames and as periodic status in xterm mode.

Fields:

Field Description
frame Capture counter for sync.
program Detected program name.
state Current state (Idle, Working, Blocked, Error).
detail State detail string.
scroll Scroll state object.
cols Terminal width from tmux.
rows Terminal height from tmux.
cwd Current working directory reported by the daemon, when known.

terminal

Sent to xterm-mode viewers with terminal text and cursor metadata.

Fields:

Field Description
text Captured terminal text including ANSI sequences.
cursor_x Cursor column, zero-indexed.
cursor_y Cursor row, zero-indexed.
cursor_visible Whether the cursor should be visible.
frame Capture counter for sync.
program Detected program name.
state Current state.
cols Terminal width from tmux.
rows Terminal height from tmux.

terminal_diff

Sent to diff-capable xterm viewers: only the rows that changed since the viewer's last frame (issue #82). Applied without clearing the screen. Full 'terminal' frames are interleaved on connect, resize, large changes, and a periodic re-sync.

Fields:

Field Description
seq Daemon capture counter for this frame (logging/debug).
changes Array of {line, content}: 0-indexed row + its full new content (ANSI preserved).
cursor_x Cursor column, zero-indexed.
cursor_y Cursor row, zero-indexed.
cursor_visible Whether the cursor should be visible.
frame Capture counter for sync.
program Detected program name.
state Current state.
cols Terminal width from tmux.
rows Terminal height from tmux.

scroll_up

Sent to xterm viewers immediately before a frame when tmux reports that lines left the top of the pane. The client writes that many line feeds first, which moves the rows off its screen and into xterm's own scrollback — a real scroll rather than a repaint.

Fields:

Field Description
lines Rows that scrolled off since this viewer's last frame, capped at the screen height.

scrollback_seed

Sent once when a viewer enters xterm mode, carrying the pane history that predates its connection. The client writes it as ordinary output before the first frame arrives, so the session opens with a scrollback instead of an empty one.

Fields:

Field Description
text Captured history including the current screen, ANSI preserved.
total_lines Number of lines captured.
pane_height Visible pane height at capture time.
cols Terminal width from tmux.

scroll_buffer

Metadata returned with a captured scrollback buffer.

Fields:

Field Description
total_lines Number of scrollback lines captured.
pane_height Visible pane height.
history_size Total tmux history size.
cols Terminal width from tmux.
retina Whether the generated scrollback image used retina scaling.

tmux_session_ended

Sent when the underlying tmux session no longer exists.

Fields:

Field Description
reason Why the session ended.

server_restarting

Broadcast before the daemon restarts so clients can reconnect.

Fields:

Field Description
reason Restart reason.

input_rejected

Sent when a passenger attempts driver-only input.

Fields:

Field Description
reason Rejection reason, such as passenger_mode.

control_requested

Sent to the driver when a passenger requests control.

Fields:

Field Description
requester_tag Viewer tag requesting control.
timeout_seconds Seconds before the request auto-resolves.
message Optional requester-supplied message.
requester_info Requester connection metadata, when available.

control_request_sent

Sent to a passenger after its control request is accepted for delivery.

Fields:

Field Description
timeout_seconds Seconds before the request auto-resolves.

control_request_error

Sent when a passenger control request cannot be created.

Fields:

Field Description
error Failure reason.

control_request_result

Sent to a requester when a control request is accepted, denied, or times out.

Fields:

Field Description
granted Whether control was granted.
reason Result reason, such as accepted, denied, or timeout.

control_request_cancelled

Sent when a pending control request is cancelled.

Fields:

Field Description
requester_tag Viewer tag whose request was cancelled, when known.

control_cancel_error

Sent when cancelling a control request fails.

Fields:

Field Description
error Failure reason.

control_response_error

Sent when a driver response to a control request cannot be applied.

Fields:

Field Description
error Failure reason.

role_changed

Sent when a viewer's driver/passenger role changes.

Fields:

Field Description
role New role: driver or passenger.
driver_tag Current driver viewer tag.
driver_info Driver connection metadata, when available.
reason Reason for the role change, when available.

relinquish_failed

Sent when the driver cannot relinquish control.

Fields:

Field Description
reason Failure reason.

inbox_new

Sent when a new inbox item is shared to the session.

Fields:

Field Description
item Inbox item payload.

ack

Acknowledgment of a queued client input message.

Fields:

Field Description
msgId Client message id being acknowledged.

error

Sent when a WebSocket input or stream error occurs.

Fields:

Field Description
message Error description.

version_mismatch

Sent when the client version does not match the server-required asset version.

Fields:

Field Description
client_version Client's reported version.
server_version Server's required version.

Binary Frames

PNG image data is sent as binary WebSocket frames after each status message.

Client → Server Messages

ping

Client keepalive used to keep upstream WebSocket traffic active.

Fields:

Field Description
t Client timestamp in milliseconds.

quality

Update viewer quality and streaming-mode settings.

Fields:

Field Description
fps Frame rate. PNG mode is clamped to 0.1-10; xterm mode to 0.1-30.
retina Enable 2x PNG rendering.
palette Enable 8-bit color quantization for PNG frames.
mode Streaming mode: png or xterm.
diff xterm line-diff capability: when true, the server may send terminal_diff frames.
client_version Client asset version for sync checking.

frame_ack

Acknowledge first frame receipt so the server can enable deduplication.

visibility

Page Visibility signal (issue #82). Hidden tabs stop counting toward the session capture rate (drops to ~1 Hz); foregrounding resumes high fps and forces a full frame before diffs resume.

Fields:

Field Description
visible Whether the viewer's tab is foregrounded.

resize

Request a tmux pane resize; driver role required.

Fields:

Field Description
cols Requested terminal columns.
rows Requested terminal rows.

request_control

Passenger request to become the driver.

Fields:

Field Description
message Optional message shown to the current driver.

relinquish_control

Driver request to give control to the next passenger.

control_response

Driver response to a pending control request.

Fields:

Field Description
grant true to grant control, false to deny.

cancel_control_request

Passenger request to cancel its pending control request.

keys

Send literal text to the terminal; driver role required.

Fields:

Field Description
text Text to send.

enter

Send Enter; driver role required.

ctrl

Send a Ctrl+key combination; driver role required.

Fields:

Field Description
key Single character, such as c for Ctrl+C.

special

Send a named special key; driver role required.

Fields:

Field Description
key Named key such as Escape, Tab, Backspace, Up, Down, Left, or Right.

scroll

Control tmux copy-mode scrolling; driver role required.

Fields:

Field Description
direction up, down, or exit.

batch

Send multiple input actions in sequence; driver role required.

Fields:

Field Description
actions Array of keys, enter, ctrl, special, and scroll actions.

Example Session

const ws = new WebSocket('wss://localhost:8081/ws/coding-0');

ws.onopen = () => {
  // Set quality preferences
  ws.send(JSON.stringify({
    type: 'quality',
    fps: 2.0,
    retina: true,
    client_version: window.CLIENT_VERSION
  }));
};

ws.onmessage = (event) => {
  if (typeof event.data === 'string') {
    const msg = JSON.parse(event.data);
    if (msg.type === 'status') {
      console.log(`State: ${msg.state}`);
    }
  } else {
    // Binary PNG frame
    const blob = new Blob([event.data], { type: 'image/png' });
    img.src = URL.createObjectURL(blob);
  }
};

// Send keystrokes
ws.send(JSON.stringify({ type: 'keys', text: 'hello' }));
ws.send(JSON.stringify({ type: 'enter' }));
ws.send(JSON.stringify({ type: 'ctrl', key: 'c' }));