Appearance
Host vs runtime
A common confusion: "the daemon," "the host," "the runtime," "the supervisor" sound like the same thing. They are not. The four operational units rule (see repo CLAUDE.md § "Architecture: The Four Operational Units") names four distinct things: Environment, Package, Runner/Runtime, and Host.
This page is just about the last two.
Definitions
Host — one process. Loads host.json, supervises NATS (or connects to an external one), spawns child processes, persists their runtime.json records, auto-starts the ones whose startup is auto. Implementation: MatrixHostService in projects/matrix-3/packages/host-service/src/matrix-host-service.ts.
Runtime — one supervised child process. Reads its <host-home>/runtime-env/<id>.environment.json, connects to the same NATS the Host configured, instantiates a MatrixRuntime and the actors of one or more deployed packages, mounts them on declared subjects, then runs forever. Examples in the default install: RUNTIME-HOST-...-SYSTEM, RUNTIME-HOST-...-HOST-CONTROL, RUNTIME-HOST-...-GATEWAY, RUNTIME-HOST-...-WEB, etc.
Status: today vs target. The codebase today implements one package per runtime; the runtime ID encodes the package (
-CHAT,-DIRECTOR, etc.). The substrate target shape is multi-package runtimes: a single runtime hosts everyshared-isolation package in a substrate role, namedRUNTIME-HOST-...-CONTROL-PLANE/-USER-APPS/-WEB-SHELL/-EDGE. See P1.40. Read every "runtime hosts <package>" claim with that correction in mind.
Lifetimes
| Host | Runtime | |
|---|---|---|
| Process count per machine | one (per Host home) | many |
| Owns NATS? | yes (or connects to external) | no, connects only |
| Owns disk state? | yes — the home directory | no, only its log dir |
| Restarts other processes? | yes (per restart policy) | no |
| Survives a Host crash? | n/a | only via auto-start on next Host start |
| Holds long-lived browser sockets? | no | yes (gateway runtime) |
Records
A runtime is represented to the Host by a JSON record on disk:
json
// <host-home>/runtimes/RUNTIME-HOST-LOCAL-ABC123-CHAT/runtime.json
{
"runtimeId": "RUNTIME-HOST-LOCAL-ABC123-CHAT",
"packageRef": "@open-matrix/chat",
"packageDir": "/home/user/.matrix/packages/global/node_modules/@open-matrix/chat",
"environment": "host",
"pid": 41522,
"status": "running",
"startup": "auto",
"restart": "always",
"startedAt": "2026-05-04T18:21:01.103Z",
"updatedAt": "2026-05-04T18:21:02.991Z",
"runtimeMount": "system.runtimes.RUNTIME-HOST-LOCAL-ABC123-CHAT",
"controlMount": "system.runtimes.RUNTIME-HOST-LOCAL-ABC123-CHAT.control",
"runtimeWireRoot": "COM.OPEN-MATRIX.LOCAL.AUTHORITY",
"localMounts": [
"chat",
"system.runtimes.RUNTIME-HOST-LOCAL-ABC123-CHAT",
"system.runtimes.RUNTIME-HOST-LOCAL-ABC123-CHAT.control"
],
"metadata": { "command": "...", "args": ["..."], "cwd": "...", "logDir": "..." }
}Status: target state —
deployedPackages: []field, P1.40-a. Today the schema has a singlepackageRef. P1.40-a adds an additivedeployedPackages: [{ packageRef, instanceName, mountRoot }]array so a multi-package runtime can list every package it hosts; the legacypackageReffield stays for backward compatibility.
The full schema lives in IHostRuntimeRecord (projects/matrix-3/packages/host-service/src/types.ts:79-96) and is documented in Runtime record schema.
Why separate processes
The retired matrixd daemon mounted every package's actors inside its own single process. One leaky actor took the whole daemon down; every package shared a heap and an event loop. The host-service split fixes that: every runtime has its own pid, its own crash signal, and its own restart policy.
The substrate target shape (P1.40) layers per-package isolation declarations on top of that split. A package that declares runtime.isolation: process keeps its own pid; packages that declare shared co-tenant in one runtime to save resources but still cannot crash the supervisor. The crash domain is the runtime, not the package, and the runtime is replaceable.
See projects/matrix-3/packages/docs/content/architecture/daemon-migration.md for the post-mortem.
How a Host starts a runtime
Source: MatrixHostService.startRuntimeProcess at projects/matrix-3/packages/host-service/src/matrix-host-service.ts:344-492.
- Sanitize
runtimeId. Resolve the package directory. - Detect mount conflicts: if another live runtime already owns a logical mount or web route claimed by this start, refuse with a clear error (
matrix-host-service.ts:543-576). - Create the per-runtime log directory; open append-mode log streams.
- Spawn the child with
spawn(spec.command, spec.args, { cwd, env, ... }),windowsHide: true(so failing-runtime +restart: alwaysdoes not pop console windows on Windows), stdout/stderr piped into the log files. - Write the
runtime.jsonrecord before waiting for readiness, so a crashed readiness probe still leaves a durable record. - Wait for
runtime.readyon thecontrolMount(withruntimeIdandpididentity-checked against the spawn) and, if the runtime ownssystem.runtimes, additionally$pingthat mount. - Hook the child's
exitevent: write a final record, restart perrestartpolicy.