Skip to content

Local actor invocation

matrix invoke is the operator's general-purpose tool for talking to any actor mounted on the local Host's bus. It is the same wire protocol the runtimes use to talk to each other — request-reply over NATS.

CLI

matrix invoke <mount> <op> [json-payload]

Examples:

bash
# Ask host.control to list runtimes
matrix invoke host.control runtime.list '{}'

# Ask system.devices for the device inventory
matrix invoke system.devices devices.list '{"includeOffline":true}'

# Ask the supervisor directly
matrix invoke host.supervisor.PID-12345 status '{}'

# A package-specific op
matrix invoke chat conversation.list '{"limit":10}'

The CLI implementation is at projects/matrix-3/packages/host-service/src/cli.ts:254-265 (entry) and cli.ts:856-918 (invokeHostActor).

What it does

  1. Read host.status.json for transport.root, transport.nats.url, and transport.nats.credentialsRef. Refuse if the Host is not running.
  2. Open a short-lived NATS connection.
  3. Build the request subject:
    <root>.<mount>.$inbox
    with <root> from the live status and <mount> as given on the command line.
  4. Build the reply subject:
    <root>.$reply.<correlationId>
  5. Subscribe to the reply subject (max: 1).
  6. Publish the JSON envelope:
    json
    { "op": "<op>", "payload": <json>, "correlationId": "...", "replyTo": "..." }
  7. Wait for the reply, race against the deadline (default 5s, override via --timeout <ms>).
  8. Print the response and close the NATS connection.

If the response has ok: false, the CLI throws and exits 1 with the embedded error message.

What "mount" means

<mount> is the dot-delimited subject the actor is listening on, without the <root>. prefix and without the .$inbox suffix. Examples:

Wire subjectMount you pass to matrix invoke
COM.OPEN-MATRIX.LOCAL.AUTHORITY.host.control.$inboxhost.control
COM.OPEN-MATRIX.LOCAL.AUTHORITY.system.runtimes.$inboxsystem.runtimes
COM.OPEN-MATRIX.LOCAL.AUTHORITY.system.runtimes.RUNTIME-X.control.$inboxsystem.runtimes.RUNTIME-X.control
COM.OPEN-MATRIX.LOCAL.AUTHORITY.host.supervisor.PID-12345.$inboxhost.supervisor.PID-12345

The <root> is taken from the running Host's status, so you do not specify it. This is also why matrix invoke requires the Host to be running — it does not know which root to use otherwise.

When to use it

Use matrix invoke forDon't use it for
Ad-hoc operator queries against any actorStreaming events (use a real NATS subscriber)
Smoke-testing a new runtime's control mountBulk traffic — every call opens and closes a NATS connection
Calling supervisor ops directlyFire-and-forget; this is request-reply only

Programmatic equivalents

The same RPC wrapped as a function:

ts
import { invokeMatrixActor } from '@open-matrix/host-control';

const result = await invokeMatrixActor({
  natsUrl: 'nats://127.0.0.1:4270',
  root: 'COM.OPEN-MATRIX.LOCAL.AUTHORITY',
  targetMount: 'host.control',
  op: 'runtime.list',
  payload: {},
  timeoutMs: 5_000,
});

invokeMatrixActor (host-control/src/matrix-actor-invoke.ts:72-150) is the shared implementation — both matrix invoke and the Host's own supervisor use it.

For host-control specifically, prefer the helper:

ts
import { invokeHostControlFromStatus } from '@open-matrix/host-control';

const status = JSON.parse(fs.readFileSync('<home>/host.status.json', 'utf8'));
const result = await invokeHostControlFromStatus(status, 'runtime.list', {}, 5_000);

Timeouts and errors

  • Default timeout: 5s. Pass --timeout 30000 for slow ops.
  • Connection timeout: 5s. If NATS is not reachable, the CLI errors out before the request is published.
  • ok: false responses are translated into thrown errors with the embedded message.
  • If the actor never replies, you get Timed out invoking <mount>.<op> after <ms>ms.

See also