Skip to content

Start runtime

matrix up <target> (or its hivecast up alias when the wrapper delegates) starts a supervised runtime. This page covers what the Host actually does between "operator presses Enter" and "runtime is in status: running."

CLI surface

matrix up <package-or-path>
matrix up <package-or-path> --id <runtime-id> --mount <actor-mount>
matrix up <package-or-path> --serve [--port <p>]
matrix up <package-or-path> --startup auto --restart always
matrix up <package-or-path> --runtime-id <id> --env <env-name>
matrix up <package-or-path> -- <command> [args...]

Source: projects/matrix-3/packages/host-service/src/cli.ts:145-235. Selected flags:

FlagDefaultEffect
--id, --runtime-idderived from target nameruntime identity used for the on-disk record
--mountderived from package's matrix.jsonlogical mount the actor will own
--env"host"environment name written into the env file
--startup automanualincluded in next Host start's auto-start sweep
--restart alwaysnevercrashed runtime is respawned 1s later
--restart on-failureneverrespawn only on non-zero exit and not SIGTERM
--serveoffalso serve the package's webapp; allocates an HTTP port
--port <p>OS-allocatedpin the served port
--auto-start-priority <n>20smaller numbers go first during auto-start
--timeout <ms>30 000readiness deadline for runtime.ready and system.runtimes $ping
--control supervisorhost-controlroute start RPC through host.supervisor directly instead of the host.control actor

What the supervisor does

MatrixHostService.startRuntimeProcess (matrix-host-service.ts:344-492) is the one true codepath. In order:

  1. Sanitize and resolve. runtimeId must match ^[A-Za-z0-9_-]+$; packageDir must be an existing directory; cwd must be an existing directory.
  2. Mount conflict check (_findRuntimeStartConflict, matrix-host-service.ts:543-576). For every other live runtime record:
    • If both runtimes claim the same logical mount (private system.runtimes.<id> mounts excluded), refuse.
    • If both runtimes claim the same web routePrefix (e.g. /apps/chat/), refuse. The error message names the conflicting other runtime so an operator can identify it without reading the JSON.
  3. Log streams. Open two append-mode WriteStreams pointed at <home>/logs/runtimes/<runtimeId>/{stdout,stderr}.log.
  4. Spawn.
    ts
    spawn(spec.command, spec.args, {
      cwd,
      env: { ...process.env, ...spec.env, MATRIX_HOST_HOME, MATRIX_RUNTIME_ID, MATRIX_ENV },
      stdio: ['ignore', 'pipe', 'pipe'],
      windowsHide: true,   // crucial: stops console-window storm on restart loops
    });
  5. Pipe stdout/stderr into the log streams.
  6. Persist record. Write runtime.json with status: "running" and the spawned pid. The record is durable before readiness; if the readiness probe times out, the record is updated to failed with a failedReason.
  7. Wait for control readiness (_waitForRuntimeControlReady, matrix-host-service.ts:691-737). The runtime declares a controlMount; the Host invokes runtime.ready over NATS until it gets a healthy response — verifying runtimeId and pid match the spawn (invalidRuntimeControlResponseReason, matrix-host-service.ts:1062-1085).
  8. If the runtime owns system.runtimes, also wait for that mount to respond to $ping (_waitForRuntimeRegistryReadyIfOwned, matrix-host-service.ts:739-777).
  9. Hook child.exit to record final status and trigger restart per restart policy.

If any step from 4–8 fails, the Host:

  • Stops the child.
  • Closes the log streams.
  • Re-writes the record with status: "failed", stoppedAt, and failedReason derived from the actual error plus a tail of the runtime's stderr (appendRuntimeLogTail, matrix-host-service.ts:1322-1334).

Default run command

When the operator does not pass --, the Host builds the default command (buildDefaultRunCommand, cli.ts:599-617):

text
node <bundled-mx-cli> run <packageDir> [--serve] --env <env> --env-file <env-file> [--mount <m>]

This is how the same supervisor code path runs system, gateway, web, edge, chat, director, etc. The mx-cli run invocation reads the environment file, instantiates a MatrixRuntime, and mounts the package's actors.

Auto-start sequencing

_autoStartPersistedRuntimes (matrix-host-service.ts:494-541) runs at Host start:

  1. Filter records to startup: "auto".
  2. Sort by metadata.autoStartPriority (default 20), then by runtimeId.
  3. Walk the list in order. For each, refresh liveness (kill stale pid identity), then _startRuntimeFromRecord from the persisted command line.

If a record points at a live unmanaged process, the Host refuses to double-spawn and records the conflict.

Examples

bash
# Start one package, manual lifetime, manual restart.
matrix up @open-matrix/chat

# Start as a supervised webapp on a known port; survives Host restart.
matrix up @open-matrix/matrix-web --serve --port 5001 \
  --runtime-id WEB --startup auto --restart always

# Start with a custom command (no Matrix runner).
matrix up /path/to/my-package -- node ./dist/serve.js --port 8080

# Inspect.
matrix runtimes | jq '.runtimes[].runtimeId'

See also