Skip to content

Inference dependency

Chat does not run inference. It depends on three things that must be configured on the runtime side:

  1. system.agents — handles $prompt, owns sessions and memory.
  2. system.inference — provider routing and the actual model call.
  3. system.factotum — reads provider credentials from the local home.

If any are missing or misconfigured, Chat's prompts fail with the dependency-probe error described in Overview: Chat and inference.

Required state

For a healthy Chat:

bash
matrix invoke system.agents $introspect '{}'
# Expect: ok=true, accepts includes $prompt, $sessionList, session_state.read
bash
matrix invoke system.inference status.get '{}'
# Expect: ok=true, effective: { provider: <name>, model: <name>, ... }
bash
matrix invoke system.factotum factotum.list '{}'
# Expect: list of credential records, including the provider Chat needs.

If effective.provider is empty, no inference will happen. If the provider is set but system.factotum has no matching credentials, the provider driver will fail at call time and system.agents will surface the error to Chat as an $activity error frame.

Configuring inference

There are two configuration surfaces (operator picks one):

Inference Settings webapp

/apps/inference-settings/ — UI for editing the inference config. Writes to a runtime-managed config file. After saving, the change takes effect on the next system.inference reload.

Direct edit

The inference config file lives at <host-home>/credentials/inference-config.json (or wherever system.inference is configured to read it). Format:

json
{
  "providers": {
    "anthropic": { "model": "claude-3-5-sonnet-20240620" },
    "openai":    { "model": "gpt-4-turbo" }
  },
  "effective": {
    "provider": "anthropic",
    "model":    "claude-3-5-sonnet-20240620"
  }
}

The exact schema lives in @open-matrix/inference. After editing, restart the inference runtime so it re-reads.

OAuth providers

Per the auto-memory note "OAuth tokens are NOT API keys" (2026-04-02): Codex, ChatGPT, and Claude consumer plans use OAuth JWT, not static API keys. The user must complete an OAuth flow locally; system.factotum reads ~/.codex/auth.json or the equivalent.

To pair Codex:

  1. Run codex auth (or the equivalent in the codex CLI) on the local machine.
  2. ~/.codex/auth.json is written.
  3. system.factotum picks it up; system.inference can route to the Codex provider.

@open-matrix/factotum is the single actor that touches credentials. Chat sees only the effective.provider from system.inference status.get.

What Chat does when inference is missing

  1. User sends prompt.
  2. system.agents receives $prompt, opens a session.
  3. system.agents calls system.inference for tokens.
  4. system.inference status.get shows effective.provider === ''.
  5. system.agents (or the inference path) fails.
  6. After PROMPT_DEPENDENCY_PROBE_DELAY_MS (~2s), Chat probes system.inference status.get itself and sees the empty effective provider.
  7. Chat appends "Dependency Unavailable" to the transcript with provider-config guidance.

Pre-flight check

Before letting users in, validate:

bash
matrix invoke system.runtimes runtimes.registered '{}' \
  | jq '.runtimes[] | .app' | sort -u
# Expect: agents, chat, host-control, inference, system, etc.

If agents or inference is missing, bring them up before exposing Chat to users.

See also

Source: projects/matrix-3/packages/chat/src/ChatApp.ts:3296, 3336-3384, projects/matrix-3/packages/inference/, projects/matrix-3/packages/factotum/.