Skip to content

Host config

<host-home>/host.json is the Host's only top-level configuration file. The schema is IMatrixHostConfig (projects/matrix-3/packages/host-service/src/types.ts:51-61):

ts
interface IMatrixHostConfig {
  readonly kind: 'MatrixHostConfig';
  readonly version: 1;
  readonly home: string;
  readonly externalUrl?: string;
  readonly http: { readonly host: string; readonly port: number | null };
  readonly transport: IHostTransportConfig;
  readonly auth: IHostAuthConfig;
  readonly runtimeStorage: { readonly recordsDir: string; readonly logsDir: string };
  readonly packageStorage: { readonly globalDir: string; readonly systemDir: string };
}

Loading and writing

HostStateStore.loadOrCreateConfig (host-state-store.ts:31-44) is the single entry point. On read it:

  1. If <home>/host.json does not exist, generates the default (defaultHostConfig, host-paths.ts:16-48) and writes it.
  2. If it exists, parses and runs normalizeMatrixHostConfig (host-state-store.ts:251-318) to fill in defaults, normalize paths, and reject unknown shapes.
  3. If the in-memory normalized form differs from what was on disk, writes the normalized form back. This is intentional: editing host.json and restarting will canonicalize it.

All writes go through atomicWriteJson (projects/matrix-3/packages/host-service/src/util/atomic-write.ts:17-20): write to a .tmp.<pid>.<ts> file, fsync, then rename. Reading a half-written file is impossible.

Default host.json

json
{
  "kind": "MatrixHostConfig",
  "version": 1,
  "home": "/home/me/.matrix",
  "http": {
    "host": "127.0.0.1",
    "port": null
  },
  "transport": {
    "root": "COM.OPEN-MATRIX.LOCAL.AUTHORITY",
    "authorityRoot": "COM.OPEN-MATRIX.LOCAL.AUTHORITY",
    "nats": {
      "mode": "embedded",
      "port": 4270,
      "wsPort": 4271,
      "dataDir": "nats/host-default",
      "pidFile": "nats/host-default/nats-server.pid"
    }
  },
  "auth": {
    "mode": "local-client"
  },
  "runtimeStorage": {
    "recordsDir": "runtimes",
    "logsDir": "logs/runtimes"
  },
  "packageStorage": {
    "globalDir": "packages/global",
    "systemDir": "packages/system"
  }
}

port: null means "let the OS pick." transport.nats.port: 4270 is the wrapper-default NATS port; the .deb postinst overrides this to 4222 for production-style installs.

Field reference

http

ts
interface IHostHttpConfig {
  readonly host: string;        // e.g. "127.0.0.1", "0.0.0.0"
  readonly port: number | null; // null = OS-allocated
}

The Host itself does not run an HTTP server. This config is consumed by the gateway runtime (@open-matrix/system-gateway-http) when the Host writes that runtime's environment file. Pinning a known port here is how operators get stable URLs.

transport

ts
interface IHostTransportConfig {
  readonly authorityRoot?: string;
  readonly addressRoot?: string;
  readonly spaceId?: string;
  readonly routeKey?: string;
  readonly publicNamespace?: string;
  readonly root: string;        // legacy; equals authorityRoot for new configs
  readonly nats: IHostNatsTransportConfig;
}

root is the dot-delimited NATS subject prefix used for every wire message. authorityRoot is the same value, kept for the v1 transition (see repo CLAUDE.md § "Public Space identity"). addressRoot is what public bootstrap clients see; it equals authorityRoot unless overridden.

spaceId, routeKey, publicNamespace are populated by system-auth on device-link approval. Do not edit them by hand.

auth

ts
interface IHostAuthConfig {
  readonly mode: 'local-client' | 'public-session';
  readonly sessionSecret?: string;
  readonly actorTimeoutMs?: number;
  readonly providers?: { readonly google?: { ... } };
}
  • mode: "local-client" — Host acts as a local client; runtimes use the bus directly without browser-session machinery. Right for headless and per-user laptop installs.
  • mode: "public-session" — required for browser-served packages (matrix-web, matrix-edge) on a multi-tab dev box. The auth runtime issues per-tab session tokens. See repo AGENTS.md § "Worker Bootstrap Gotchas" — this trips up worker bootstrap when missed.

runtimeStorage, packageStorage

Relative paths under <home>. Defaults:

FieldDefaultResolved path
runtimeStorage.recordsDirruntimes<home>/runtimes
runtimeStorage.logsDirlogs/runtimes<home>/logs/runtimes
packageStorage.globalDirpackages/global<home>/packages/global
packageStorage.systemDirpackages/system<home>/packages/system

Paths are joined by hostPaths at host-paths.ts:50-62. These are the only knobs the Host respects for filesystem layout; do not symlink things under <home> and expect them to be honored — runtime spawn assumes direct paths.

Editing the config

bash
# Show the current config (the Host normalizes on read).
cat <host-home>/host.json | jq .

# Edit and let the next start canonicalize.
$EDITOR <host-home>/host.json
hivecast stop  --home <home>
hivecast start --home <home>

# Or signal a config reload to a running Host (host-control RPC).
matrix invoke host.control config.reload '{}'

config.reload triggers MatrixHostService.applyUpdatedHostConfig (matrix-host-service.ts:169-198): stops every runtime, restarts NATS (if embedded), rewrites host.status.json, refreshes every per-runtime environment file, then auto-restarts persisted runtimes. It is a real restart, not a no-op.

See also