> ## Documentation Index
> Fetch the complete documentation index at: https://continuum-three-olive.vercel.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Pairing

> Sign in with the same account on every device and they find each other — no QR code, no tokens to copy.

Pairing connects a **remote** — your iPhone, Android phone, Apple Watch, or a
browser tab — to a **host** that runs your sessions. Signing in *is* pairing:
devices on the same account discover each other, and the host approves each new
one once.

Connecting a machine that *runs* sessions — a second Mac, a Linux box, a VPS —
is a different flow, covered in [remote devices](/docs/features/remote-devices).

<Note>
  If you remember scanning a QR code from the Mac: that flow is gone. Tailscale
  QR/URL pairing was removed in **0.60.0**, and the Mac's Pair-iPhone QR card in
  **0.62.10**. Email sign-in replaced both. The tailnet transport for execution
  hosts is unaffected.
</Note>

## How to connect

<Steps>
  <Step title="Sign in on the host">
    Open **Settings → Account** on the Mac (or the Windows/Linux desktop app)
    and sign in with your email. The app shows a short code and sends you to
    your browser to finish; come back and it reads **Signed in as \<your
    email>**.

    Mac onboarding offers this on first launch, and it's skippable — you can do
    it later without losing anything.
  </Step>

  <Step title="Leave the device mesh on">
    Signing in switches the **device mesh** on for you. It syncs your devices
    over the cloud so enrolled machines appear in **Settings → Devices** and can
    reach each other over the relay, with no Tailscale required. The toggle
    lives in **Settings → Account → Device mesh**, separate from the
    organisation usage upload.
  </Step>

  <Step title="Sign in on the remote">
    Sign in with the same email in the iPhone or Android app, or at
    [continuumcode.ai/app](https://continuumcode.ai/app). Your hosts appear
    automatically — on iPhone under **Devices**, grouped into **This device**,
    **Available** (online hosts you can open), and **Other** (offline machines
    and your other phones).
  </Step>

  <Step title="Approve the device once, from the host">
    The first time a phone or tablet connects, the host holds it at
    **WAITING FOR APPROVAL**. Open **Settings → Devices** on the host and click
    **Approve** (or **Reject**). Approval is per device and survives restarts.
  </Step>

  <Step title="Open a host">
    Tap an online host in the phone's device list and its sessions, gauges, and
    approvals load. Everything from there travels end-to-end encrypted.
  </Step>
</Steps>

## Managing devices

**Settings → Devices** is the same surface on every client: the Mac, the iOS
Devices sheet, and the web dashboard all list every device on your account with
a kind icon (Mac, Windows, Linux, iPhone, iPad, server), live online/offline
health, and a session count on hosts that are running work.

* **Rename** — give a device a name you'll recognize; 1 to 64 characters.
* **Remove** — revokes it. The device loses access to your account immediately
  and its live credentials are dropped on the spot.
* **Device limit** — accounts hold a limited number of devices (10 by default).
  Past that, remove one before adding another.
* **New-device email** — adding a device sends you a heads-up email with a
  one-tap path to revoke it if it wasn't you.

Adding a Linux box or a server uses the same surface: **Settings → Devices →
Add a device** generates a one-time enroll command you run on that machine. It
enrolls over the relay — no Tailscale needed — and the code is short-lived. See
[remote devices](/docs/features/remote-devices).

## Transport

Remotes reach hosts through **Continuum Cloud**, an end-to-end encrypted relay
at `relay.continuumcode.ai`. It works across any network — no shared LAN, no
tailnet, no port forwarding.

* Every frame is **XChaCha20-Poly1305** sealed end to end. The relay forwards
  opaque bytes and never sees body content.
* The relay observes only protocol version, sender role, envelope type, byte
  count, and your IP.
* Each pairing derives its own symmetric key from fresh ephemeral **X25519**
  keypairs on both sides, via HKDF. Private keys live in process memory and are
  zeroized when the session ends.
* The relay never holds the derived key. An operator with full storage access
  cannot decrypt captured traffic.
* The relay session is valid for **30 days**; re-pairing rotates the keypair and
  both bearer tokens. A bounded lifetime caps the blast radius of a leaked
  bundle.

See [Security](/docs/security) for the full cryptographic specification.

### The local daemon

Whether or not anything is connected remotely, a host runs a local HTTP and
WebSocket daemon:

* The HTTP listener takes the first free port in **`21731–21741`** (default
  `21731`). The WebSocket listener binds the HTTP port **+ 1**, normally
  `21732`, with its own fallback.
* Non-loopback connections are accepted only from Tailscale's CGNAT range
  (`100.64.0.0/10`) and its IPv6 prefix (`fd7a:115c:a1e0::/48`), plus loopback
  (`127.0.0.0/8`, `::1`). Everything else is rejected at accept time.
* Every request — loopback included — must present a `Bearer` token. Non-loopback
  peers are additionally verified through Tailscale Whois, which is
  **fail-closed**: if the lookup is unavailable, the connection is refused.

## Apple Watch

The Watch pairs through the iPhone and never connects to a host directly. The
phone pushes the current token and the latest usage snapshot to the Watch, and
replays it when the Watch reconnects. Pair the phone and the Watch follows.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The host doesn't appear on my phone">
    Check three things: both devices are signed in to the **same** email;
    **Settings → Account → Device mesh** is on; and the host is awake and
    online. A signed-in phone with no hosts yet shows a "Discovering your Macs"
    state rather than an error — that's the app still looking.
  </Accordion>

  <Accordion title="The device is stuck at WAITING FOR APPROVAL">
    That's the security gate, not a bug. Open **Settings → Devices** on the
    host and click **Approve**. Until you do, the phone can see the device
    exists but can't connect to it.
  </Accordion>

  <Accordion title="ACCESS REVOKED, RE-PAIR">
    Someone removed that device from the account — possibly you, possibly via
    the revoke link in a new-device email. Sign in again on the device to
    re-enroll, then approve it from the host.
  </Accordion>

  <Accordion title="'Update Continuum on … to connect without a QR code'">
    The host is running a build old enough that it predates account-mesh
    connections and can't complete the key exchange without a scanned bundle.
    Update the host app — see [Installation](/docs/installation).
  </Accordion>

  <Accordion title="'Device limit reached'">
    You've hit the per-account device cap. Remove a device you no longer use
    from **Settings → Devices**, then retry.
  </Accordion>

  <Accordion title="iPhone shows an 'Update Continuum on the Mac' banner">
    The phone checks the host daemon's wire version. When the host is older,
    features that need a newer wire version are hidden and the banner appears.
    Update the host app. The connection itself degrades gracefully — only the
    version-gated features go quiet.
  </Accordion>

  <Accordion title="Ports already in use">
    The daemon tries `21731` through `21741` in order; if all eleven are
    occupied it fails to start and the app says so. Find the conflict with
    `lsof -i :21731`.
  </Accordion>

  <Accordion title="Starting over on the phone">
    **Forget connection** in iOS Settings erases the stored host, port, and
    token from the phone. The host is untouched. Sign in with the same email on
    both devices to reconnect over Continuum Cloud.
  </Accordion>
</AccordionGroup>
