> ## 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.

# Remote Devices

> Sign into one account and your machines find each other: add a Linux box, a second Mac, a Windows desktop or Continuum Cloud as an execution host.

A session's process has to run somewhere. That somewhere is an **execution host**: a machine — or a managed cloud sandbox — that owns the agent process, the git worktree, and the terminal. Your Mac is a host. So is a Linux server you rent, a spare desktop in the corner, or a Continuum-managed cloud runner with no machine of yours involved at all.

**Settings → Devices** is where you add and manage them. Once a host is connected, it shows up in the **Run on** picker everywhere you start a session, and you can drive it from any of your clients — including the ones that can't host anything themselves.

## Why register a device

* Run heavy or long-running agents on a beefier box while your Mac stays free and quiet.
* Keep a session alive on a machine that doesn't sleep, then drive it from your phone.
* Spread parallel work across a fleet — each session's process lives on exactly one host.
* Start a session with no machine at all, from a browser, on Continuum Cloud.

## Hosts and remotes

Every client can *drive* a session. Only some can *run* one.

| Client              | Hosts sessions | Notes                                                                    |
| ------------------- | -------------- | ------------------------------------------------------------------------ |
| macOS app           | Yes            | The reference host. Also the hub that proxies to your other hosts.       |
| Windows desktop     | Yes            | Electron app with a bundled Go agent. Enrolls itself, with your consent. |
| Linux desktop       | Yes            | Same app, same bundled agent.                                            |
| Linux server / VPS  | Yes            | Headless agent, installed with a one-line enroll command.                |
| Continuum Cloud     | Yes            | Managed sandbox. No machine of yours, no install.                        |
| iPhone, Apple Watch | No             | Drive sessions running elsewhere.                                        |
| Android             | No             | Drive sessions running elsewhere.                                        |
| Web app             | No             | Drive sessions running elsewhere, including on Continuum Cloud.          |

<Note>
  Your Mac's own row is always present in Devices and can't be removed. Every other host is something you added, and can remove.
</Note>

## Signing in is how a fleet forms

**Sign into the same account on two devices and they find each other.** That's the whole mechanism. Each device enrolls itself with Continuum's cloud backend and reaches the others through the relay — no QR code to scan, no Tailscale, no pasted token. Your Mac, your iPhone, a Linux box and the web app all converge on one device list you can see from any of them.

This applies to your phone too. Sign into the iPhone app with the same email and it's paired; there is no QR-scanning step any more.

<Note>
  Devices are part of the free app — you don't need a subscription to run your own fleet. A subscription buys [hosted inference](/docs/features/hosted-inference) and Continuum Cloud, not the ability to connect machines you already own.
</Note>

A few properties worth knowing:

* **An account holds up to 10 devices.** Enrolling past the limit is refused rather than silently evicting one.
* **Adding a device emails you**, so an enrollment you didn't perform is visible rather than quiet.
* **New devices don't get access automatically.** A device that enrolls lands in a **Pending approval** list until you **Approve** it — and a device can never approve itself.
* **Enrollment self-heals.** If a device's enrollment record goes missing, gets corrupted, or belongs to an account you've since switched away from, it re-enrolls itself under the right owner instead of quietly dropping off your fleet.
* **Signing out fences a device immediately.**

The relay is the universal transport. If a host also lives on your [Tailscale](https://tailscale.com) tailnet *and* the client asking is on the same tailnet, Continuum prefers the direct tailnet route; otherwise it falls back to the relay. Either way there is no inbound port to open and nothing exposed to the public internet.

Tailscale and SSH are still supported, but they've moved to **Advanced** in Settings → Devices — they're for adding *execution hosts*, not for connecting your phone.

## Adding a device

<Tabs>
  <Tab title="Linux box">
    The primary path, and the one that needs no Tailscale.

    <Steps>
      <Step title="Generate an enroll command">
        **Settings → Devices → Add a Linux device**. Continuum mints a one-time code and shows a copyable command:

        ```bash theme={"dark"}
        curl -fsSL https://continuumcode.ai/install.sh | sudo bash -s -- --enroll XXXX-XXXX
        ```

        The code is single-use, account-scoped, and expires in **10 minutes**. The alphabet skips `0`, `O`, `1`, `I` and `L` so it survives being read aloud.
      </Step>

      <Step title="Run it on the box">
        SSH in and paste. The installer downloads the agent for the box's OS and architecture, **verifies both the binary and the runtime against a published `SHA256SUMS` and aborts on any mismatch**, installs to `/usr/local/bin`, and registers a systemd service running as a dedicated **non-root** service user. It refuses to run the daemon as root, and it refuses a non-HTTPS account URL.
      </Step>

      <Step title="Approve it">
        The box redeems the code, checks in, and appears under **Pending approval**. Approve it and it turns green.
      </Step>
    </Steps>

    On the web and desktop apps the same sheet offers **Linux**, **macOS**, and **Windows** command variants; the Mac app shows the Linux one.
  </Tab>

  <Tab title="Second Mac">
    Install Continuum on the other Mac and sign in with the same email. It enrolls itself into the account mesh and appears in your device list — no pairing code, no Tailscale.

    If you'd rather push the install from the Mac you're already sitting at, use the **Add Tailscale device** path instead: it launches Continuum on the target Mac in headless-agent mode under a per-user LaunchAgent, with no `sudo`. That requires Continuum to already be installed there; if it isn't, the sheet stops and tells you to install it first.
  </Tab>

  <Tab title="Windows / Linux desktop">
    The Windows and Linux desktop apps ship a bundled Go agent and can host their own sessions.

    Hosting is **opt-in and off by default**. At sign-in there's an unchecked box — *"Allow my other signed-in devices to run sessions on this computer"* — and signing in without it enables your account but not remote access. You can turn it on later from **Devices → Add a Linux device → Enroll this computer**.

    Enrollment still lands in **Pending approval**, and signing out fences it immediately.
  </Tab>

  <Tab title="Tailscale">
    Under **Settings → Devices → Advanced → Add Tailscale device**. Continuum scans your tailnet and lists what it finds; phones, tablets and TVs appear tagged *"can't host"*.

    <Steps>
      <Step title="Pick the device">
        Select a Linux or macOS peer, or type its MagicDNS hostname (e.g. `thinkpad.tail87a721.ts.net`).
      </Step>

      <Step title="Enter the login username">
        The device's own login account, which Continuum will SSH into over **Tailscale SSH**. This is the one field that can't be auto-filled, and it's the usual reason **Install & connect** is greyed out — an inline hint names the missing field.
      </Step>

      <Step title="Install & connect">
        Continuum SSHes in, detects OS and CPU architecture, installs and starts the agent, learns its bearer token, registers the host, and health-probes it. A determinate progress sheet walks six steps: connect, install agent, set up runtime, install coding CLIs, sync credentials, verify connection.
      </Step>
    </Steps>

    The **Also enable relay access** toggle (on by default, recommended) lets the device reach you when you're off the tailnet.

    The agent listens on port **21731**. On Linux the install sets `CLAWDMETER_BIND_ALL=1` so it binds the tailnet interface — it binds `127.0.0.1` otherwise — and best-effort installs Node, `tmux`, and the coding CLIs it can find.

    **Add manually** (a disclosure inside the same sheet) registers a device without installing anything — optionally with a pairing token. It shows *unreachable* until an agent actually runs there. **Test connection** probes the device's health endpoint over the tailnet first, so you can confirm reachability before committing.
  </Tab>

  <Tab title="SSH / Termius">
    **Settings → Devices → Advanced → Add via SSH / Termius** finds hosts you already have configured and installs the agent over plain SSH, then connects the box through the relay.

    It reads `~/.ssh/config` and Termius imports, and you can paste `ssh …` commands or a CSV. Discovery stays passive: if the selected entry could execute local SSH config commands when resolved (a `ProxyCommand`, say), Continuum names the risk and makes you tick **I trust this SSH config for setup** before it will invoke SSH.
  </Tab>

  <Tab title="Continuum Cloud">
    No device, no install. Sessions run in an isolated Continuum-managed cloud sandbox.

    On the Mac it's an entry in the composer's device menu; on the web it's a card on the **Connect compute** screen with a repo field, an agent picker, and a minutes meter. Because the sandbox has no copy of your working tree, a cloud session starts from a **repository** rather than a local folder — it clones the repo itself, and it can't take local file attachments.

    For private repositories that means connecting the GitHub App. The sandbox is then handed a **short-lived installation token scoped to the one repository you authorized**, re-checked on every wake; if the authorization doesn't resolve, the sandbox gets no repository token at all rather than a broader one.

    Continuum Cloud is included with hosted-inference plans, not with the free app. Without one, the row reads *"Upgrade"* and links to your account settings.

    Defaults worth knowing: **1,200 active minutes per seat** per period and **2 concurrent cloud sessions**, with sessions stopping after **15 minutes idle**. Organizations can set their own active-minute and concurrency caps on top of those. Idle leases show as **Sleeping** and are woken automatically when you next act on the session.

    There is also an optional **Cloud Burst** path on the web that runs leases in *your* Cloudflare account against an API token you paste.
  </Tab>
</Tabs>

<Note>
  **Advanced → Add AWS cloud** launches an EC2 runner in your own AWS account using the `aws` CLI already configured on your Mac. It is incomplete — its machine images are placeholders and a launched instance does not finish connecting — so treat it as unfinished rather than a supported way to add a host.
</Note>

## Credentials follow the box

A host is **compute, not a credential custodian**. It holds only what Continuum deliberately pushes to it, and each file lands mode `0600` under the service user's home:

| Provider                   | What lands on the device                                                                                   |
| -------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Claude                     | Your OAuth token, in a private credentials file the spawn environment reads.                               |
| Codex                      | `~/.codex/auth.json`.                                                                                      |
| Antigravity (Gemini)       | `~/.gemini/oauth_creds.json`.                                                                              |
| OpenCode, OpenRouter, Z.ai | One OpenCode `auth.json` blob plus its provider config — these API-key providers share a single transport. |
| GitHub                     | Your `gh` token, wired up as git's credential helper, so the device can clone private repos and open PRs.  |

A Mac-side watcher re-pushes **Codex, Antigravity and OpenCode** credentials whenever the local file rotates, so a device doesn't silently go stale. **Claude is deliberately out of scope for that watcher** — its source is a Keychain item, not a file with a stable mtime — so a Claude token rotation needs you to re-run device setup.

<Warning>
  The push is **fail-closed on the other side**: a session spawned on a device for a provider with no usable credential is *refused*, never run against some ambient fallback. Wrong-account billing is the failure mode being defended against.
</Warning>

**Cursor and Grok have no push of their own.** The setup sheet marks them **"Log in on device"** — sign in there directly.

Pushes are best-effort and never fail an install: if one doesn't land, the host still comes up green and you can re-run setup or sign that provider in on the device. Every push is recorded to the hash-only audit log — provider and byte count, never the secret.

## Running a session on a host

Once a host is green it appears in the **Run on** picker wherever you start a session — the Mac empty-state composer, the iPhone new-session sheet, the web Code screen — alongside **This Mac**, each with a live status suffix. Every eligible device in your fleet is selectable, not just the one you're sitting at. Pick one and the session's process spawns there.

On the web, if you have no connected host at all, the picker offers Continuum Cloud instead of dead-ending — you can start in the cloud and connect a machine later.

Every session records which host owns its process. That provenance is the spine of the model: **the running host is the authority**, and no surface invents ownership — it reads it off the session. Session rows carry a small OS mark showing *where* each one actually ran, so a fleet list stays readable when the same repo has sessions on three different machines. Opening a session that lives on another host attaches you to it live — transcript and composer included — rather than showing a read-only copy.

### From the Mac

When you act on a session whose process lives elsewhere, your Mac acts as a **hub** and proxies the request to the owning host, preserving the remote's HTTP status and body verbatim — so a structured `403`, `422` or `429` reaches you intact rather than being flattened into a generic failure. For chat, the hub pulls only the new transcript bytes, projects them through the same chat builder local sessions use, and mirrors the result to disk, so the transcript still renders if a later fetch comes back empty or the host blips.

### From the iPhone

iOS can reach a remote host two ways. **Through the Mac hub** always works. **Directly** — when the phone can reach the host itself and holds its bearer — control survives your Mac going to sleep. The direct path is a pure optimization: whenever a direct client isn't ready, every call falls back to the hub, so it can never make things worse.

The phone fetches a host's connection details from a bearer-gated per-host endpoint on the hub, persists the token to a host-scoped Keychain entry, and never logs it. That token is deliberately **not** carried in the public host list.

## Handing a session off

Right-click a session in the sidebar and pick **Continue on…** to migrate it to a different host. The source host pushes its branch, the target spawns a fresh session on it, and the new session picks up where the old one left off.

## Health and status

Each host row shows a colored dot plus a text label — state never rides on hue alone:

| Label        | Meaning                                                                        |
| ------------ | ------------------------------------------------------------------------------ |
| Connected    | Reachable and serving.                                                         |
| Provisioning | Coming up — a cloud runner mid-boot, or an install finishing.                  |
| Sleeping     | A cloud lease that scaled down. It's woken before anything is forwarded to it. |
| Degraded     | Reachable but unhealthy.                                                       |
| Unreachable  | Can't be reached right now.                                                    |
| —            | Not yet probed.                                                                |

Hosts are probed concurrently, so adding boxes doesn't make the refresh serial. A probe that comes back reachable also re-reads the host's self-reported capabilities and available agents. On the web and desktop apps each row has a **Check** button to re-probe on demand; rows also offer **Rename** and **Remove**.

Registered hosts persist to `~/Library/Application Support/Clawdmeter/execution-hosts.json` on the Mac.

<Info>
  Hosts advertise what they can serve, and Continuum degrades visibly rather than silently. A device paired with an agent too old for interactive control still shows up, but returns **426 Upgrade Required** with "Update this device's agent" instead of proxying to an endpoint that doesn't exist. Keeping every device on a current build is the short answer.
</Info>

## Security posture

Remote execution is gated at every hop:

* **Nothing is exposed publicly.** Devices talk over the relay, or directly over your tailnet when both ends are on it. There is no inbound port to open.
* **Every request is bearer-authed.** The remote daemon is a full daemon and applies the *same* gates as your local one — the loopback / Tailscale-CGNAT peer filter, the per-peer bearer check, and a fail-closed Tailscale identity check on every non-loopback request.
* **New devices need approval.** Enrollment alone grants nothing; a device sits in **Pending approval** until you approve it, and can't approve itself.
* **Confused-deputy guard.** Before forwarding, the hub verifies that a session's provenance actually matches the target host. A bearer-holding peer can't drive a session on a host that doesn't own it by guessing a session id — the proxy rejects it with `403`.
* **Secrets never land world-readable.** Credential files are staged into a `0700` directory and written `0600`, and credential targets are checked to be inside the service user's home with no symlink components.
* **Removal is immediate.** Removing a device drops its cloud access and its live credentials right away.

See [Security](/docs/security#remote-execution-host-trust) for the full trust model and [Pairing](/docs/pairing) for how your iPhone and Watch join your account.

## Related

* [Sessions](/docs/features/sessions) — the unit of work that runs on a host.
* [Pairing](/docs/pairing) — signing your iPhone and Watch into your account.
* [Security](/docs/security) — trust boundaries, per-peer auth, and the remote-host trust model.
* [Code](/docs/surfaces/code) — the workbench where you drive sessions.
* [Hosted inference](/docs/features/hosted-inference) — the plans that include Continuum Cloud.
