Skip to content

Product model

HiveCast is built on four operational units. They look similar from a distance and get conflated in casual conversation, but every architectural decision in the codebase respects their separation. Knowing the difference is the difference between a working setup and a confused operator.

The four units, summarized by the repo-root CLAUDE.md:

UnitOwnsDoes NOT own
EnvironmentNATS URL/ports, WebSocket port, JetStream storage, PID files, HTTP port, credentials, logssource code, mount declarations
Packagematrix.json, source, dist/, component declarations, mount defaultsports, storage paths, transport roots
Runnerone execution: reads one package + one environment, creates MatrixRuntime + transport, mounts actorssupervision (a runner ends when its process ends)
Hostsupervision: starts/stops/restarts runners, may start shared local NATS, persists runtime recordssource code; a Host is not a package

Concretely, in a HiveCast install

hivecast install creates an Environment (<MATRIX_HOME>), seeds a Host (hivecast-host process or systemd unit), seeds a set of Packages into the Host's package store, and registers each as a Runner.

Environment = <MATRIX_HOME>

A Host home directory. Default ~/.matrix on Linux/macOS, configurable with --home or the MATRIX_HOME environment variable. Layout (from projects/matrix-3/packages/host-service/src/host-paths.ts):

<MATRIX_HOME>/
├── host.json                       ← config (HTTP port, NATS mode/URL, auth mode, root)
├── host.status.json                ← live status (set when Host is running)
├── host.pid                        ← Host pidfile
├── runtimes/<runtime-id>/runtime.json  ← per-runtime records
├── runtime-env/                    ← per-runtime environment files
├── logs/host.stdout.log, host.stderr.log
├── logs/runtimes/<runtime-id>.{stdout,stderr}.log
├── packages/system/node_modules/   ← Host-internal package store
├── packages/global/node_modules/   ← user-facing package store
├── credentials/hivecast-install.json   ← installId (per local install)
├── credentials/hivecast-link.json      ← hostId / link record (only after login)
├── nats/host-default/nats-server.{conf,pid}, jetstream/  ← bundled NATS data
└── bin/nats-server[.exe]           ← bundled NATS binary

The seedHostProductHome function in hivecast.mjs:348-394 lays this out idempotently. See Reference → Filesystem layout for every path.

Package = a directory with a matrix.json

A package owns code and declares actors. It does NOT own ports or transport roots — those come from the Environment at runtime. Packages live either in the Host's bundled store (after hivecast install) or as folder-backed source you point at with matrix run <path>.

Examples shipped by HiveCast:

PackageMount(s)What it does
systemsystem.runtimes, system.registry, system.devices, system.factotumthe system actor set every Host needs
@open-matrix/host-controlhost.controlruntime lifecycle control plane
@open-matrix/system-gateway-httpsystem.gateway.httpHTTP gateway and nats-ws proxy
@open-matrix/system-authsystem.authauth/session/namespace/device approval
@open-matrix/matrix-webwebthe platform/account shell (served at /apps/web/)
@open-matrix/matrix-edgeedgethe local-Device shell (served at /apps/edge/)
@open-matrix/directordirector.httpthe dashboard webapp
@open-matrix/chat, @open-matrix/flowpad, @open-matrix/smithers, @open-matrix/inference-settingsvariousbundled user-facing apps

Runner = one running process

A Runner is the execution unit. One process. Reads one package + one Environment, creates a MatrixRuntime + transport, mounts actors. The browser is also a runner — every tab connects to NATS via /nats-ws and mounts its own per-tab actors.

Each headless Runner on a Host has a record under <MATRIX_HOME>/runtimes/<runtime-id>/runtime.json. The schema (from projects/matrix-3/packages/host-service/src/types.ts:79-96):

ts
interface IHostRuntimeRecord {
  readonly runtimeId: string;
  readonly packageRef?: string;
  readonly packageDir?: string;
  readonly environment?: string;
  readonly pid?: number;
  readonly status: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed';
  readonly startup?: 'manual' | 'auto';
  readonly restart?: 'never' | 'always' | 'on-failure';
  readonly startedAt?: string;
  readonly stoppedAt?: string;
  readonly updatedAt: string;
  readonly runtimeMount?: string;
  readonly controlMount?: string;
  readonly runtimeWireRoot?: string;
  readonly localMounts: readonly string[];
  readonly metadata: Record<string, unknown>;
}

See Local Device → Runtime records for what each field means and how to read them.

Host = the supervisor

The Host (Host Service) reads runtime records and reconciles desired state to running processes. It never executes package code itself — it spawns Runner processes. It writes host.status.json while alive and clears it on stop.

The product Host implementation is projects/matrix-3/packages/host-service/. The retired daemon package is no longer a product path; per CLAUDE.md Rule 1: "the retired daemon is not the product path."

How hivecast install instantiates each unit

  1. EnvironmentseedHostProductHome (hivecast.mjs:348) writes host.json, makes runtimes/, runtime-env/, logs/runtimes/, packages/{global,system}/node_modules/, bin/, copies the bundled NATS binary.
  2. PackagesseedBundledHostPackages (hivecast.mjs:205) mirrors dist/node_modules/<package> into both package stores.
  3. RunnersbootstrapDefaultHostRuntimes (hivecast.mjs:1414) iterates hostDefaultRuntimeTargets and runs host-service-cli up <target> --runtime-id <id> --env hivecast --startup auto --restart always for each.
  4. HoststartHostProduct (hivecast.mjs:1464) starts the NATS sibling, then spawns the host-service supervisor, then waits for host.status.json to land before returning.

See also

Source: repo-root CLAUDE.md "The Four Operational Units"; projects/matrix-3/packages/host-service/src/host-paths.ts (filesystem layout); projects/matrix-3/packages/host-service/src/types.ts (record schemas); projects/matrix-3/packages/hivecast/bin/hivecast.mjs lines 281-394 (Environment seeding) and 1414-1456 (default runtime bootstrap).