Appearance
Runtime health
A runtime is "healthy" when it responds correctly to runtime.health on its controlMount with a matching runtimeId and pid. That is the only check the Host treats as authoritative.
The contract
Every runtime declares a controlMount (defaulting to system.runtimes.<runtimeId>.control). The runtime is expected to implement at least these three ops on that mount:
| Op | Purpose |
|---|---|
runtime.ready | "Are you done initializing? Return { ready: true }." Used at startup readiness gate. |
runtime.health | "Are you healthy right now? Return { healthy: true | false, state? }." Used at observation time. |
runtime.shutdown | "Please exit cleanly." Used at stop. |
The Host invokes these via invokeRuntimeControl (projects/matrix-3/packages/host-control/src/matrix-actor-invoke.ts). Every response must include runtimeId and pid matching the supervised process; mismatches are flagged via invalidRuntimeControlResponseReason (matrix-host-service.ts:1062-1085).
Health probe at observation time
MatrixHostService._refreshRuntimeRecordControlLiveness (matrix-host-service.ts:269-309) runs whenever listRuntimeRecordsWithControlLiveness is called — which the supervisor's status and runtime.list ops do (matrix-host-service.ts:802-807). For each runtime in a live state:
- If
pidis missing, nocontrolMount, or pid is not alive: skip. - Otherwise, invoke
runtime.healthwith a 1.5s deadline. - If the response is missing/invalid, mark the record degraded with a
controlHealthReason. - If the response says
healthy: false, mark the record degraded withruntime.health returned unhealthy state=.... - If the response is fine, leave the record alone.
Degraded marking does not change status — a degraded runtime is still running. It adds three metadata fields:
json
"metadata": {
"controlHealthCheckedAt": "2026-05-04T18:30:01.512Z",
"controlHealthStatus": "degraded",
"controlHealthReason": "runtime.health did not respond: timeout"
}These fields are stable across reads — every refresh that gets a clean response can clear them by writing a fresh record without those keys (though the current code only writes them on degrade — a "healthy" recheck does not erase past degrade markers; rely on controlHealthCheckedAt timestamp for currency).
Why HTTP 200 is not proof
A runtime serving a webapp can answer GET / with 200 OK while its NATS handshake is broken. The browser sees the HTML, then fails its WebSocket connect to /nats-ws, and the user sees a blank page with console errors. This is the failure mode called out repeatedly in the repo AGENTS.md § "Worker Bootstrap Gotchas" — "HTTP 200 is not proof."
runtime.health covers what HTTP 200 cannot:
- The runtime's
MatrixRuntimeis connected to NATS. - Its actors are mounted.
- Its
runtimeIdandpidmatch the supervised process.
If you rely only on curl /healthz, you can miss a runtime whose actor mount silently never came up.
Readiness probe at start time
_waitForRuntimeControlReady (matrix-host-service.ts:691-737) is the parallel codepath used during startRuntimeProcess. It polls runtime.ready every 100ms until the runtime returns a healthy response or the deadline elapses. Default deadline is 30s (matrix-host-service.ts:442), overridable via --timeout or spec.readyTimeoutMs.
If readiness times out, the Host:
- Stops the child.
- Reads up to 4 KiB of stderr + 2 KiB of stdout from the runtime's log files (
appendRuntimeLogTail,matrix-host-service.ts:1322-1334). - Persists the record as
failedwithfailedReasoncontaining both the timeout message and the log tail.
This means a startup error is visible without leaving the supervisor prompt; you do not have to go reading log files separately.
Querying health from outside
bash
# Per-runtime health, via control mount directly.
matrix invoke system.runtimes.RUNTIME-HOST-LOCAL-ABC-CHAT.control runtime.health '{}'
# Aggregate via host-control.
matrix invoke host.control runtime.list '{}' | jq \
'.runtimes[] | { runtimeId, status, ch: .metadata.controlHealthStatus, why: .metadata.controlHealthReason }'
# Aggregate via host-supervisor (skips host-control).
hivecast status --control supervisor 2>/dev/null \
|| matrix status --control supervisorThe --control supervisor flag (cli.ts:338-344) bypasses the host-control actor and talks straight to host.supervisor over NATS. Useful when host-control is itself the runtime in trouble.
What runtimes should do
Package authors implementing runtime.health should make it cheap and honest:
- Return
{ healthy: true, state: "running", runtimeId, pid }quickly. - Return
{ healthy: false, state: "degraded", reason: "..." }if any invariant is broken (NATS disconnected, JetStream stream missing, required service unreachable). - Do not block on user-facing work or external network calls.
- Always include
runtimeIdandpid; the Host's validator will mark the record degraded if either is missing.