Mobile remote

Each machine connects outward to a relay you deploy in your own Cloudflare account. Nothing listens on the machine. Partyline operates no relay service and needs no Partyline account. This release provides the relay registry and pairing transport. Phone approval, storage and remote sessions follow separately.

Deploy

Install Node.js 22 or newer and npm. Create a Cloudflare API token scoped to your account. Creating the Worker requires the Workers product-level Admin role; later deployments can use Editor on that Worker. For a custom domain, also grant Workers Routes Write for the affected zone. See Cloudflare’s Wrangler permissions. Keep the token out of shell history.

ptln relay deploy

The command prompts for the API token without echoing it, or reads CLOUDFLARE_API_TOKEN from the environment. It uses the token for this run and never saves it. It reports a saved Wrangler login: any program running as you could use that login to redeploy the relay. Review or remove saved Cloudflare credentials separately if that is outside your security policy.

The CLI extracts embedded TypeScript sources and the package lock to a temporary directory, runs npm ci, then npx wrangler deploy. It removes that directory afterward. The default Worker name is ptln-relay, with one SQLite Durable Object. Deploying again updates that Worker and disconnects its sockets; watchers reconnect automatically. The relay occupies that Worker name in the selected account, so do not use it for another application. If your token can access several accounts, select one with CLOUDFLARE_ACCOUNT_ID in Wrangler's environment.

By default, the relay uses your account's workers.dev subdomain. To use a domain in a zone you own:

ptln relay deploy --domain remote.example.com

Both paths record the relay host as the WebAuthn RP ID. Changing the host changes the RP ID; future phone pairings will need to be made for the new origin.

Add another machine

On an already joined machine:

ptln relay invite

This prints an invite containing the relay URL and a random secret. Treat the whole string as a credential. It can be used once and expires after ten minutes. On the other machine:

ptln relay join '<string>'

Joining refuses to overwrite an existing relay configuration. Unregistered machines cannot attach to the relay. Invites and machine tokens are stored as hashes in the relay's SQLite registry.

Status and local files

ptln relay status

Status prints the URL, RP ID and whether this machine has an authenticated socket at the relay. If the relay cannot be reached, connectivity is reported as unknown and the command fails. The watcher connects when Partyline's tmux server is running, and exits when that server stops. Reconnect uses exponential backoff with jitter, capped at five minutes.

~/.partyline/remote/relay.json contains the URL, RP ID and machine id, with mode 0600. The separate relay-token beside it is also 0600. You can show relay.json without exposing the machine token. Back up both files privately; losing the token requires joining again with a fresh registration. The Cloudflare deploy token is never written to either file.

The relay sees machine identifiers and connection metadata. Phone pairing and end-to-end encryption are not part of this release. In the later phone client, a compromised relay could serve modified client code; passkeys alone cannot prevent that. See the repository's mobile remote design for the security model and person-run iPhone checks.

Pairing transport

Run ptln remote pair inside tmux. It opens a private popup with a QR code and the same PTLN-PAIR string. Open the relay app on your phone and scan the QR inside the app, or paste that string while the popup remains open. The string expires after ten minutes. Treat it as a secret; never paste it into a URL. Name the phone and create its passkey. The phone completes IKpsk2 with the watcher and proves possession of the passkey against a fresh machine challenge. Compare the eight groups of the phone fingerprint on both screens, then approve in the machine popup with the code it shows. Refusing, closing, or timing out the popup saves no pairing and issues no device token.

ptln remote phones lists each phone's id, name, fingerprint, pairing time, and last seen. ptln remote revoke <id> removes the phone and revokes its relay device token. The approval popup also lists phones; select one and press a, then confirm to revoke it. Closing live sessions is handled by the subsequent remote-session step.

Approved pairings and their audit log live in ~/.partyline/remote/phones.json and ~/.partyline/remote/events.jsonl, both private to your user. The phone saves its Noise key, credential id, and device token only after the machine confirms approval. The authenticator creates its passkey during enrollment; refusing pairing does not remove that passkey from the authenticator.

The relay receives only a hash of a separate one-use invite, never the Noise pairing secret. The invite admits one socket that can reach only this machine's pairing route. The QR is app data, not a Safari link. Camera scanning in an installed iPhone app still needs a hardware check; the pasted string is the fallback.