Skip to content

Pair

Pairing connects this Device to a HiveCast account. After pairing, the Device:

  • Appears on the user's HiveCast Devices page.
  • Is reachable via https://hivecast.ai/<spacePath>/edge/.
  • Sends heartbeats to the cloud.
  • Has a per-Device NATS user JWT signed by the principal account.

Pairing is optional. Local-only use does not require it (per CONSTRAINTS.md C1-C2).

When to pair

Pair when you want:

  • Cross-Device access to your stuff via hivecast.ai.
  • A public route for your apps (e.g., https://hivecast.ai/<spacePath>/director/).
  • Federation with other paired users.

Do not pair if:

  • You only ever use Matrix on this one machine.
  • You don't have a HiveCast account.
  • The Device is short-lived (CI runner, scratch container) — paring leaves a Host Link record on the platform you'd then need to revoke.

Two pair flows

Flow A: from Edge ("Connect to HiveCast" button)

  1. Open Edge: http://127.0.0.1:3100/apps/edge/.
  2. Click "Connect to HiveCast" in the action panel.
  3. Edge starts a pair request via auth.pair.start — receives pairRequestId.
  4. Browser is redirected to https://hivecast.ai/auth/pair?pairRequestId=<id>....
  5. Sign in to HiveCast (if not already).
  6. Click "Approve."
  7. HiveCast calls auth.pair.approve and returns an approvalCode.
  8. Browser is redirected back to http://127.0.0.1:3100/auth/link?...&approvalCode=<code>.
  9. The local Host calls auth.pair.exchange with the approval code.
  10. Exchange returns the Host Link, credentials, and route metadata.
  11. The local Host persists <host-home>/credentials/hivecast-link.json.
  12. Refresh Edge — the link card now shows linked.

Flow B: from CLI (hivecast login --device)

For headless installs:

bash
hivecast login --device --cloud https://hivecast.ai \
  --route-key <your-spacePath> \
  --device-name "<friendly-name>" \
  --home <host-home>

CLI:

  1. Calls auth.device.start.
  2. Prints a user code: WDJB-MJHT.
  3. Opens (or asks the user to open) https://hivecast.ai/apps/web/#activate.
  4. User enters the user code, clicks Approve.
  5. CLI polls auth.device.poll until approved.
  6. CLI calls auth.device.exchange, gets credentials, persists.

The --route-key flag selects which Space the Device pairs to. If omitted, the user's default Space is used.

--device-name sets the hostName (mutable label). Per terminology rules, the CLI exposes --device-name as user-facing language, but writes hostName internally.

What you need to pair

  • A HiveCast account (sign up at hivecast.ai first).
  • A Space owned by your account with a public-namespace claim (created automatically on first sign-in).
  • The Device's local Host running and reachable via 127.0.0.1.
  • Network access from the Device to hivecast.ai.

What pairing returns

The exchange step returns:

ts
{
  ok: true,
  hostLink: { id, hostId, hostName, deviceSlug, principalId, spaceId, ... },
  credentials: { jwt, seed, ... },        // 24h NATS user JWT
  routeKey, publicNamespace, spaceId,
  authorityRoot, principal: { id, displayName },
}

The Host stores all of this under <host-home>/credentials/.

Verifying the pair

After pairing:

bash
# 1. Check link state
matrix invoke system.auth auth.hostLink.list \
  '{"principalId":"<your-id>"}' --home <host-home>

# 2. Refresh Edge — the link card should now show:
#    route key, namespace, Space, authority root with green "linked" pill.

# 3. Visit the public URL:
# https://hivecast.ai/<spacePath>/edge/
# This should serve THIS Device's Edge, routed by HiveCast.

What pairing changes locally

  • A new file: <host-home>/credentials/hivecast-link.json.
  • A new file: NATS creds file (varies by setup) under <host-home>/credentials/.
  • The local Host's bootstrap response now includes routeKey, publicNamespace, spaceId, authorityRoot.

What does NOT change:

  • Local apps still work via 127.0.0.1.
  • Inference credentials stay local (Factotum-only).
  • Local owner mode still bypasses auth on loopback.

Cancellation

If you start a pair flow and want to abort:

bash
matrix invoke system.auth auth.pair.cancel '{"pairRequestId":"<id>"}'
# or for device-flow:
matrix invoke system.auth auth.device.cancel '{"userCode":"<code>"}'

Or simply do nothing — the request expires (10 min for pair-flow, 30 min for device-flow).

See also

Source: Edge UI: projects/matrix-3/packages/matrix-edge/src/main.ts:357-387. Backend ops: projects/matrix-3/packages/system-auth/src/index.ts:1055-1196 (pair-flow), 882-1054 (device-flow).