All docs
Concepts

Architecture

How the Qubox components fit together — from capture backend to GPU presentation.

Last updated July 5, 2026

Architecture overview

Qubox is a five-binary, ten-crate Rust workspace. The data plane runs over QUIC; the control plane is JSON over the same QUIC stream; updates are signed with TUF. This page is a high-level map.

The five binaries

Binary Where it runs What it does
qubox-host-agent The machine being shared Captures displays + audio, synthesises input
qubox (daemon) Same as host agent IPC, identity storage, TUF updates
qubox-client-cli The viewer Connects, decodes, presents frames on the GPU
qubox-client-gui The viewer Tauri/React wrapper around the CLI
qubox-signaling-server Optional relay NAT-traversal + identity pairing across nets

The wire protocol

We use QUIC with a custom multiplexing layer. One QUIC connection carries multiple substreams:

  • Control — bidirectional, JSON-encoded, one per session
  • Media video — unidirectional datagrams, Annex-B H.264 / AV1
  • Media audio — unidirectional datagrams, Opus
  • Input — bidirectional, batched
  • Clipboard — bidirectional, image + text
  • Pen — bidirectional, high-frequency pointer events

QUIC's built-in TLS 1.3 gives us end-to-end encryption without an extra handshake. 0-RTT is supported for repeat connections.

Capture backends

The host agent picks the right capture backend at runtime:

OS Display backend Audio backend
Linux X11, PipeWire (Wayland) PipeWire, PulseAudio
macOS ScreenCaptureKit CoreAudio
Windows DXGI WASAPI

All backends expose the same qubox_display::DisplayCapture trait, so the rest of the codebase is portable.

The transport layer

qubox-transport is a thin wrapper over quinn (Rust QUIC). It adds:

  • Reconnection with exponential backoff
  • Path probing (direct IP → relay → TURN)
  • 0-RTT session resumption
  • Datagram priorities (input > clipboard > video)

Identity and pairing

Each installation generates an Ed25519 keypair at first run. Pairing exchanges the public key plus a shared 6-word phrase derived from BIP-39. The shared phrase is the only authentication needed to add a device — no central authority is involved.

Pairings are stored locally in ~/.config/qubox/pairings.json and never leave your machines.

Updates via TUF

We use The Update Framework for release distribution. The daemon verifies the metadata chain before applying any update:

  1. Pulls root.json (pinned at first install)
  2. Verifies targets.json against root.json
  3. Verifies timestamp.json against snapshot.json
  4. Verifies snapshot.json against root.json
  5. Downloads the binary, verifies its hash against targets.json, verifies its signature against the targets key

If any step fails, the update is rejected and the previous version keeps running. Rollback to any prior version is one command: qubox update --rollback.

Why QUIC, not WebRTC?

Both work. We chose QUIC because:

  • Single stack — same Rust library for client, server, daemon, and CLI
  • 0-RTT — sub-100ms resumption on flaky networks
  • Datagrams — first-class support for unreliable, ordered or unordered data channels without an extra RTP layer
  • No browser requirement — the relay doesn't need to be served over HTTPS; it's a pure binary protocol

The downside is no browser fallback. If you need a browser client, check back in 6 months — we're prototyping a WebTransport gateway.

What we'd do differently

We're honest about the trade-offs. The biggest one is no WebRTC fallback: if your network blocks UDP, you need a TCP-friendly workaround. The TURN fallback exists for that, but it adds latency.

The second is single-tenant relay: the signaling server is one process per deployment. A multi-tenant cloud relay with isolation boundaries is on the Team-tier roadmap.