Appearance
Devices
A Device is a linked compute participant: a laptop, workstation, server, VM, container, phone, or appliance running HiveCast/Matrix and paired to an account. Devices are the unit of compute on the platform — the Host that runs the user's actors.
User-facing language
Per WORKSTREAMS/product-launch/HIVECAST-DEVICE-ENROLLMENT-SPEC.md and CONSTRAINTS.md C13, the product term is "Device." Internal terms (hostId, host.json, installId, Host Service, Host Link, leaf, bundle, account seed) stay out of UI surfaces and end-user docs. This page is operator-facing, so internal terms are referenced for cross-checking against the code, but the platform shell and Edge UI must say "Device."
Device identity, three fields
Per HIVECAST-DEVICE-ENROLLMENT-SPEC.md "Device Identity Fields" and CLAUDE.md:
| Field | Source | What it identifies | Scope |
|---|---|---|---|
installId | <host-home>/credentials/hivecast-install.json | The local install (laptop install, container install, server install) | Always present, durable per install |
hostId | <host-home>/credentials/hivecast-link.json | The pairing bond between an install and a HiveCast account | Per-link, only after pairing |
hostName | <host-home>/credentials/hivecast-link.json | Mutable human label ("Richard's Laptop") | Mutable |
deviceSlug | Allocated once by system-auth from hostName, collision-resolved | Stable, address-safe management projection key | Per-link, durable across renames |
installId is durable per install — it survives rsync between machines and idempotent reinstalls. hostId only exists after pairing. hostName is the mutable label users can change. deviceSlug is the stable management key under system.devices.<deviceSlug>; it does not change when hostName changes.
displayName is principal/user identity only. It is forbidden as a Device label. deviceName is forbidden in new contracts (the CLI keeps a user-facing --device-name flag, but it writes hostName internally).
Where a Device lives in code
The platform stores a Device as an IHostLinkRecord (system-auth/src/host-auth.ts:94-114):
ts
export interface IHostLinkRecord {
readonly id: string;
readonly hostId: string;
readonly hostName?: string;
readonly deviceSlug: string;
readonly natsUserPublicKeys?: readonly string[];
heartbeatTokenHash?: string;
heartbeatTokenIssuedAt?: string;
readonly principalId: string;
readonly spaceId: string;
readonly routeKey?: string;
readonly publicNamespace?: string;
readonly authorityRoot: string;
readonly scopes: readonly string[];
status: 'active' | 'revoked';
readonly createdAt: string;
updatedAt: string;
lastRefreshedAt?: string;
revokedAt?: string;
}A Host Link is the durable proof that this install (hostId) is bonded to this principal (principalId) inside this Space (spaceId, authorityRoot). It carries the per-Device NATS user public keys (so revocation can target exactly that Device's credentials), the heartbeat token hash, and any granted scopes.
The platform-account-facing facade
system.devices is the product/account-facing linked-Device facade. Per CLAUDE.md and HIVECAST-DEVICE-ENROLLMENT-SPEC.md:
system.devicesis an inventory/control facade. It may exposedevices.list,devices.get,devices.heartbeat,devices.runtimes.list/register. It must not become the public actor namespace. Actors still mount logically throughsystem.registryaschat,system.inference.openai,director, etc. Logical address != management path.
The Devices page on the platform shell (/apps/web/#dashboard) and Edge both read system.devices.devices.list directly through the bus to render linked Devices. Per P1.43, system.devices is the authority for Device inventory. Any HTTP /api/devices endpoint that may exist is a read-only projection for non-bus-aware external clients (CI smoke tests, third-party uptime monitors); internal substrate consumers always invoke the bus actor.
The Devices facade unifies:
- Durable Host Links (the records above) — these define "linked Devices."
- Live runtime presence via
host.controlheartbeats — these define "online/offline." - Runtime inventory —
devices.runtimes.listlists runtimes under one Device.
An offline linked Device is still a linked Device. Runtime presence alone does not create a durable linked Device — that requires the pairing approval ceremony.
Pairing model
There are three entry points for pairing, but one backend protocol (per the device enrollment spec). Each entry point starts the same auth.device.* or auth.pair.* flow in system-auth:
- Browser-initiated (
auth.pair.*). User opens Edge on their Device, clicks "Connect to HiveCast." Edge starts an interactive pair request, opens the browser tohivecast.ai, the user authenticates, approves, and the Device redeems an approval code for credentials. - CLI-initiated headless (
auth.device.*). User runshivecast login --device --cloud https://hivecast.ai. CLI prints a user code; user approves on any signed-in browser; CLI polls and exchanges for credentials. - HiveCast-initiated (
auth.device.*). User signed into HiveCast clicks "Connect another device" or "Open on this machine"; HiveCast creates an enrollment, the target Device redeems it.
All three end with the same outcome: a Host Link record on the platform Host, a credential file on the Device, and a heartbeat token the Device uses to phone home.
What pairing returns
The exchange ops (auth.device.exchange, auth.pair.exchange) return:
ts
{
ok: true,
status: 'exchanged',
hostLink: { id, hostId, deviceSlug, principalId, spaceId, authorityRoot, ... },
credentials: { jwt, seed, ... }, // device-scoped NATS user JWT (24h TTL)
principalId,
routeKey, // v1 alias for spacePath
publicNamespace,
spaceId,
authorityRoot,
}The Device persists hostLink, credentials, and a heartbeat token. The Device's host.control then sends authenticated heartbeats — auth.hostLink.verifyHeartbeat validates the token and updates lastRefreshedAt.
Credentials are per-Device, not shared
Per CONSTRAINTS.md C7-C8 and Rule 4 (Factotum-only):
- One principal → one principal-scoped NATS account.
- Each Device gets its own NATS user JWT, signed by the principal account.
- The principal account seed stays server-side (
system.factotum/system-auth). - Revoking one Device revokes only that Device's user JWT, not other Devices.
- There is no shared broker password.
The credential rotation path is auth.hostLink.credentials.refresh. The Device-side CLI is mx refresh-credentials --home <matrix-home>.
Health: what counts as online
A Device is "online" if its most recent heartbeat is within the heartbeat TTL. Heartbeats arrive at system-gateway-http's /_auth/host-link/heartbeat route, which calls auth.hostLink.verifyHeartbeat. system.devices aggregates that into the Device row's status.
A Device that has no fresh heartbeat is rendered as "offline" but still exists as a linked Device — it does not disappear from the list. Disappearance only happens on explicit revoke.
Target state
- Renaming a Device —
auth.hostLink.createacceptshostName, but no UI today exposes a rename flow. CLI flag--device-nameis the only path. - Per-Device scopes —
IHostLinkRecord.scopesexists; the scope authorization model is target state. - Physical-device grouping — multiple installs (e.g., laptop + container on the same laptop) belong to one physical machine but show as separate Devices today.
- Driver/resource summaries on the Device card — Devices expose drivers and resources via
system.drivers/system.resources, but the Device card does not summarize them yet.
See also
- Devices / Pairing — full pairing flows.
- Devices / Device grants — scopes and authorization.
- Devices / Device inventory —
system.devicesops. - Devices / Disconnect / unlink — revoke flow.
- Devices / Device health — heartbeat protocol.
- Edge / Device Management / Pair — Edge-side pair UX.
Source:
WORKSTREAMS/product-launch/HIVECAST-DEVICE-ENROLLMENT-SPEC.mdis the SSOT for the Device model.projects/matrix-3/packages/system-auth/src/host-auth.ts:92-157for the schemas.projects/matrix-3/packages/system-auth/src/index.ts:719-1188for the ops.