Skip to content

Device inventory

system.devices is the platform-account-facing facade for paired Devices. It unifies durable Host Link records with live runtime presence and exposes the union as ops the dashboard, Edge, and CLI consume.

Ontology contract

Per HIVECAST-DEVICE-ENROLLMENT-SPEC.md:

system.devices = product/account-facing linked-device facade. It must not become the public actor namespace. Actors still mount logically through system.registry as chat, system.inference.openai, director, etc. Logical address != management path.

Three things system.devices is:

  • A read facade over Host Links (system-auth) and runtime registrations (system.runtimes, host.control).
  • An inventory that survives offline Devices.
  • A control surface for management ops: revoke, refresh credentials, list runtimes per Device.

Three things system.devices is not:

  • The public actor namespace. Apps mount as chat, director, etc., not system.devices.<deviceSlug>.chat.
  • A source of truth for runtime state — that is system.runtimes and host.control.
  • A source of truth for pairing — that is system-auth.

Op surface

The current ops:

OpPurpose
devices.listList linked Devices for the principal (or for the platform admin scope).
devices.getFetch one Device row by deviceId / deviceSlug.
devices.heartbeatAccept a Device heartbeat. Internal: called by _auth/host-link/heartbeat.
devices.runtimes.listList runtimes registered under one Device.
devices.runtimes.registerRegister a runtime against a Device. Internal: called by host.control.

These are a superset of system-auth's auth.hostLink.list / get because they merge link + runtime + heartbeat data into one row.

What devices.list returns

bash
matrix invoke system.devices devices.list \
  '{"includeOffline":true}'

Returns one row per linked Device:

ts
{
  deviceId: 'install_<short>',
  deviceSlug: 'richard-laptop',
  hostName: "Richard's Laptop",
  status: 'online' | 'offline' | 'revoked',
  lastSeenAt: '2026-05-05T14:23:00Z',
  routeKey: 'alt.stories.ghost-stories.funny',
  publicNamespace: 'space.alt.stories.ghost-stories.funny',
  spaceId: 'spc_xxx',
  authorityRoot: 'SPACE.SPC_XXX',
  runtimeHostCount: 1,
  runtimeCount: 8,
  webappCount: 4,
  source: 'merged' | 'durable-only' | 'live-only',
  // ...full Host Link fields under 'hostLink' for full-detail views
}

source: 'merged' means both a Host Link record and live heartbeat presence agreed. 'durable-only' means the Device has not heartbeated recently. 'live-only' is anomalous (heartbeat without a durable record) and indicates a bug or a stale credential.

Filtering by principal

For platform-operator views, pass principalId:

bash
matrix invoke system.devices devices.list \
  '{"principalId":"p_xxx","includeOffline":true}'

The current implementation scopes to the calling identity by default (a signed-in user only sees their own Devices). Cross-principal listing is only available to local-client (loopback) callers and operators.

Live proof of the model

Per P1.22 progress notes:

Live authenticated Playwright proof shows https://hivecast.ai/apps/web/#dashboard rendering the linked Device as Online with 8 runtime hosts and links to /richard-santomauro-gmail/edge/, /richard-santomauro-gmail/director/, and /richard-santomauro-gmail/chat/.

devices.list is what the dashboard's Device cards consume. Each row's runtime count drives the "8 runtimes" pill; webappCount drives the "4 web apps" pill.

Identity merge

Per HIVECAST-DEVICE-ENROLLMENT-SPEC.md, three fields identify a Device:

  • installId — durable per local install.
  • hostId — durable per pairing.
  • deviceSlug — durable address-safe management key.

devices.list projects deviceId (currently equal to installId for locally-paired flows, equal to the Host Link's hostId for HiveCast-initiated flows) and deviceSlug for URL-safe routing. The two are kept in sync at pairing time; they differ in the schema specifically because one physical machine could have multiple installs (today it doesn't, but the schema allows it).

What is NOT yet in the op surface

Not implemented today, but design space:

  • devices.rename — change hostName. Workaround: re-pair with --device-name <new>.
  • devices.scopes.update — see Device grants.
  • devices.transfer — move a Device to a different Space (without revoking).
  • devices.bulkRevoke — revoke many Devices at once.
  • Cross-Space federation views (devices.list-federated).

These are target state.

How runtime registration ties in

Each Device's runtimes register with system.devices.devices.runtimes.register (called by host.control periodically). The runtime row carries runtimeId, appName, webapp metadata, route info, last heartbeat. devices.runtimes.list exposes them grouped by Device.

The dashboard reads devices.runtimes.list per Device to render the per-app cards under each Device. Discrepancies between devices.runtimes.list and system.runtimes.list are debugging signal — a runtime that registered with system.runtimes but not with system.devices.runtimes indicates the Device's host.control did not propagate the registration. See Reference: Operational runbooks.

See also

Source: WORKSTREAMS/product-launch/HIVECAST-DEVICE-ENROLLMENT-SPEC.md for the contract. The system.devices actor implementation is in projects/matrix-3/packages/system/src/ (the system package merges Host Links and runtime registration data into the facade rows).