Skip to content

Config

IChatRuntimeConfig (src/runtime/resolve-chat-config.ts:18-91) is the typed configuration shape Chat resolves at startup. This page documents each section.

Top-level shape

ts
interface IChatRuntimeConfig {
  mode:          'standalone-local' | 'standalone-connected' | 'daemon-hosted';
  mount:         string;
  app:           { ... };
  transport:     { ... };
  bootstrap:     { ... };
  serviceRefs:   { conversation, componentLibrary, identity?, preferences?, sessionState, mcp? };
  state:         { ... };
  security:      { ... };
  theme:         { ... };
  timeouts:      { promptMs, chatMessagesMs, streamIdleMs, serviceCallMs };
  features:      { ... };
  telemetry?:    { debug? };
}

app

ts
{
  appName:               'chat',
  publicBase:            './',
  windowTitle:           'Matrix Chat',
  showAddressTags:       false,
  readOnly:              false,
  enablePrintExport?:    true,
  enableMarkdownExport?: true,
  enableJsonExport?:     true,
}

transport

ts
{
  kind:               'in-memory' | 'nats' | 'browser-nats',
  root:               'CHAT-LOCAL',                    // wire root
  addressRoot:        string | null,                   // authority root
  daemonRoot:         string | null,                   // legacy alias
  natsUrl:            string | null,
  wsUrl:              string | null,
  credentialsRef:     string | null,
  connectionSharing:  'runtime',
  debug:              boolean,
}

For standalone-local, kind is 'in-memory' with no URLs. For daemon-hosted, kind is typically 'browser-nats' and wsUrl is /nats-ws.

bootstrap

ts
{
  source?:        'embedded' | 'host-http' | 'host-actor',
  bootstrapUrl?:  string | null,
  authMeUrl?:     string | null,
  natsJwtUrl?:    string | null,
  required?:      boolean,
}

source: 'embedded' is for standalone-local. host-http and host-actor are for hosted modes.

serviceRefs

Each is an IChatServiceRef:

ts
interface IChatServiceRef {
  required:   boolean,
  mode:       'local' | 'remote-actor' | 'http-adapter',
  target:     string,         // mount path or URL
  timeoutMs?: number,
}

Default values (from config.defaults.json):

json
{
  "conversation":     { "required": true,  "mode": "local", "target": "chat.conversation",      "timeoutMs": 10000 },
  "componentLibrary": { "required": true,  "mode": "local", "target": "chat.component-library", "timeoutMs": 10000 },
  "identity":         { "required": false, "mode": "local", "target": "chat.identity",          "timeoutMs": 3000 },
  "preferences":      { "required": false, "mode": "local", "target": "chat.preferences",       "timeoutMs": 3000 },
  "sessionState":     { "required": true,  "mode": "local", "target": "chat.session-state",     "timeoutMs": 10000 },
  "mcp":              { "required": false, "mode": "local", "target": "chat.mcp",               "timeoutMs": 5000 }
}

In standalone-connected and daemon-hosted, the per-profile overrides switch mode from 'local' to 'remote-actor', so the binding picks the RemoteActor* adapter instead of the in-memory Local* service.

state

ts
{
  provider:      'memory' | 'indexeddb' | 'local-record-store' | 'remote-session-service',
  pageManifestKey:    'page_manifest',
  canvasKey:          'canvas',
  transcriptKey:      'transcript',
  persistMessages:        boolean,
  persistInlineComponents: boolean,
}

provider selects the state backend. In remote-actor modes, this is overridden to 'remote-session-service'.

security

ts
{
  enableLocalCapabilityRealm: true,
  enableTopicClaims:          true,
  spawnPolicy:                'sandboxed-ui-only',
  defaultCapabilityTtlMs:     1_800_000,           // 30 minutes
}

Inline component spawning is gated by the local capability realm. spawnPolicy: 'sandboxed-ui-only' means components can render but cannot reach beyond their declared mount.

theme

ts
{
  defaultPreset:      'dark',
  persistScope:       'user',                     // 'user' | 'session' | 'local'
  fallbackToLocalState: true,
}

timeouts

ts
{
  promptMs:        300_000,    // 5 minutes — max time waiting for $activity frames
  chatMessagesMs:   60_000,    // request-reply timeout for chat.messages ops
  streamIdleMs:    360_000,    // max time between $activity frames
  serviceCallMs:    10_000,    // generic service call timeout
}

features

ts
{
  mcpStatus?:        true,
  inlineComponents?: true,
  retargeting?:      true,
  exports?:          ['md', 'json', 'pdf'],
}

Per-mode profile overrides

Three profile files in chat/config/profiles/:

  • standalone.local.json — sets mode, in-memory transport, all serviceRefs to mode: 'local'.
  • standalone.connected.json — sets mode, browser-nats transport (default), serviceRefs to mode: 'remote-actor'.
  • daemon-hosted.json — sets mode, browser-nats transport with bootstrap from host-http, serviceRefs to mode: 'remote-actor'.

resolveChatConfig(overrides) deep-merges in this order: defaults → profile → overrides.

Resolution providers

matrix.json declares three config providers:

json
"providers": [
  { "kind": "env",     "prefix": "MATRIX_CHAT_" },
  { "kind": "file",    "env": "MATRIX_CHAT_CONFIG_FILE", "optional": true },
  { "kind": "service", "service": "system.config", "namespace": "@open-matrix/chat",
    "env": "MATRIX_CHAT_CONFIG_SERVICE", "optional": true }
]

resolveConfiguredChatConfig (in resolve-chat-config.ts:126) reads each provider in declared order and merges. So MATRIX_CHAT_* env vars override the file, which overrides the system.config service, which overrides the defaults.

Schema

config/config.schema.json documents the JSON Schema for the merged result. Used for validation when reading the file/service providers.

See also

Source: projects/matrix-3/packages/chat/src/runtime/resolve-chat-config.ts:1-140, chat/config/config.defaults.json, chat/config/profiles/, chat/matrix.json config block.