Skip to content

Device model

A Device is a linked compute participant: a laptop, workstation, server, VM, container, phone, or appliance running HiveCast. "Linked" means the local install has completed the pairing ceremony with a HiveCast account/Space and the cloud has issued a hostLinkId for it.

User-facing product copy says "Device" everywhere. Internal storage names — hostId, hostLinkId, host.json, installId — are intentionally kept out of UI text (per WORKSTREAMS/product-launch/CONSTRAINTS.md C27); they appear on this page only because we are documenting the data model.

The substrate addresses Devices through the bus actor system.devices, which is the authority for Device inventory per P1.43. Substrate consumers (the platform shell, Edge, CLI, federation peers) read system.devices directly through matrix invoke system.devices devices.list etc. HTTP /api/devices/* endpoints are read-only projections for non-bus-aware external clients.

What a Device is not

Not a DeviceWhy
A driver packageDrivers are software that adapts a Device to expose Resources. They are not the Device itself.
An external service account (OpenAI, Google)These are Resources reachable through Drivers, not Devices.
A bus subjectBus subjects address actors. system.devices.<deviceSlug> is a management projection, not the public actor namespace.
A NATS leaf nodeA NATS leaf is a transport detail. Multiple leaves may belong to one Device; one leaf may serve multiple runtimes.
A user/principalA principal is a person/account. One principal owns many Devices.

The relationship the Devices contract describes is:

text
Principal -> [owns] -> Device(s)
Device -> [hosts] -> Runtime(s)
Runtime -> [mounts] -> Actor(s)
Device -> [exposes via Driver] -> Resource(s)
Actor address (logical)  != Device management path

Logical actor address (chat, system.inference.openai, garage.gps) is distinct from the Device's management path (system.devices.<deviceSlug>). Code in SystemDevicesActor.ts enforces that distinction by exposing system.devices as a facade only.

The three identity fields

A Device record carries three distinct identifiers. Confusing them is the single largest source of UI copy bugs in this product. They are:

FieldPurposeMutabilityWhere it comes from
deviceIdProduct-facing stable id for the linked install. Same value as the internal Host Link hostId.Stable for the lifetime of a link.Generated by generateHostId() in system-auth/src/host-auth.ts:1683 on first pairing.
hostNameMutable human label. Rendered in UI as "Device name".Mutable; the user can rename.Provided at pairing time via --device-name (CLI) or the local-Host setup form, or imported from a legacy displayName field.
deviceSlugStable, address-safe management projection key. Used to build system.devices.<deviceSlug>.Stable for the lifetime of a link, even when hostName changes.Allocated by system-auth at pairing time via allocateDeviceSlug() in host-auth.ts, collision-resolved per principal+Space.

Three additional names also appear and must NOT be conflated with these three:

  • installId — durable per-install id stored in <host-home>/credentials/hivecast-install.json by ensureHiveCastInstallIdentity() in mx-cli/src/utils/hivecast-link-store.ts:159. Generated on first hivecast install, before pairing. It survives unlink/relink ceremonies and is reused to recognize the same install across pairings.
  • hostLinkId — id of the Host Link record itself (hostlink_<24 hex> per generateHostLinkId() in host-auth.ts:1687). One installId may have multiple Host Link records over its lifetime (each link/unlink/relink mints a new one); only one is active at a time per hostId.
  • displayName — principal/user identity only. Forbidden as a Device label in any device record, heartbeat payload, or system.devices view. Old displayName values written before this rule are migrated into hostName on read by readLegacyHiveCastInstallDisplayNameAsHostName() and readLegacyHiveCastLinkDisplayNameAsHostName() in mx-cli/src/utils/hivecast-link-store.ts.

deviceName is also forbidden in new contracts because it is ambiguous between label and slug. The CLI keeps a user-facing --device-name flag, but internally that flag writes hostName.

Where Devices live in the actor graph

system.devices is a singleton management actor. Its op surface (declared in SystemDevicesActor.accepts) is intentionally narrow:

ts
// projects/matrix-3/packages/system/src/SystemDevicesActor.ts:67-76
static override accepts: Record<string, unknown> = {
  'devices.status':            { description: 'Report linked-device facade status' },
  'devices.register':          { description: 'Register a linked HiveCast compute participant in this namespace' },
  'devices.heartbeat':         { description: 'Refresh linked-device presence heartbeat' },
  'devices.deregister':        { description: 'Mark a linked device offline' },
  'devices.list':              { description: 'List linked devices for one principal/Space' },
  'devices.get':               { description: 'Get one linked device within the requested principal/Space scope' },
  'devices.runtimes.register': { description: 'Register a runtime under a linked device in the same principal scope' },
  'devices.runtimes.list':     { description: 'List runtimes for one linked device' },
};

This is the entire public op surface of the linked-device facade. Anything not in that table belongs somewhere else (system.runtimes for raw runtime inventory, system.registry for logical mount claims, system.auth for durable Host Link records).

Device sources

A Device record can come from one of three sources, tracked as the source field on the view:

sourceMeaning
presenceLive in-memory record from devices.register/devices.heartbeat. The Device is currently posting heartbeats.
host-linkDurable record reconstructed from system.auth's hostLinks store via auth.hostLink.list. The Device may be offline but is still linked.
mergedBoth sources agree (same hostLinkId, principalId, spaceId, authorityRoot). The view fuses presence and durable data.

devices.list calls into system.auth (auth.hostLink.list) when the caller provides a principalId, then merges live presence with durable links. The merge logic lives in SystemDevicesActor._listHostLinksForPrincipal() and hostLinkDeviceView().

Status values

A Device view has one of four status values:

statusMeaning
onlineLive presence record, last heartbeat younger than heartbeatTtlMs (default 45 s).
offlineLive presence record but heartbeat exceeded TTL — set by _pruneStaleDevices() (runs every 15 s).
linkedDurable Host Link record exists but no presence — Device is paired but not currently running, or its NATS connection is down.
revokedThe Host Link record's status is revoked. The Device is unlinked at the platform level even if it still has local credentials.

See also

Source: projects/matrix-3/packages/system/src/SystemDevicesActor.ts (accepts declaration at line 67; identity fields and source/status enums at lines 27-53). Identity-field rules from WORKSTREAMS/product-launch/HIVECAST-DEVICE-ENROLLMENT-SPEC.md § "Device Identity Fields".