Appearance
Config contract
A package that takes configuration declares a config block in matrix.json plus optional config.schema.json / config.defaults.json files. The block tells the runner where to look for values and how to merge them.
The config block
The shape used in production today (paraphrased from packages/chat/matrix.json):
json
{
"config": {
"schema": "./config/config.schema.json",
"defaults": "./config/config.defaults.json",
"envPrefix": "MATRIX_CHAT_",
"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 }
]
}
}| Field | Purpose |
|---|---|
schema | Relative path to a JSON Schema file describing the legal config shape |
defaults | Relative path to a JSON file with the default values |
envPrefix | Convention used by the env provider |
providers[] | Ordered list of resolvers; later providers override earlier ones |
Status: present state, partial. The CLI validator (
manifestValidator.ts) does not currently inspect theconfigblock. The block exists by convention; the chat runtime reads it directly. Schema validation across packages is target state.
Provider kinds in use
kind | Meaning |
|---|---|
env | Read environment variables that start with prefix |
file | Read a file path from env (the env var holds the path) |
service | Look up config under service/namespace via a config-service actor |
Providers compose: a value present in service overrides one from file, which overrides one from env, which overrides the default.
Per-environment runtime config
Separate from the config block, package authors ship per-environment runtime config under .matrix/<env>.environment.json. This is what mx run . --env <env> reads (packages/mx-cli/src/utils/package-environment.ts):
json
{
"name": "dev",
"nats": {
"mode": "embedded", "port": 4330, "wsPort": 4331,
"dataDir": ".matrix/state/dev/nats",
"pidFile": ".matrix/state/dev/nats-server.pid"
},
"runtime": {
"root": "COM.OPEN-MATRIX.LOCAL.DIRECTOR",
"runtimeId": "director-dev"
},
"package": { "publicRoot": "director" },
"http": { "enabled": true, "port": 4332 }
}| Top-level | Purpose |
|---|---|
name | Required identifier (dev, integration, hivecast) |
nats | Embedded or external NATS config (mode, port, wsPort, url, credentialsRef, dataDir, pidFile, binaryPath) |
runtime.root | Required. The wire root used for the bus (e.g. COM.NIMBLETEC.RICHARD-SANTOMAURO) |
runtime.runtimeId | Optional override of the runtime id |
runtime.runtimeMount, runtime.controlMount | Optional overrides |
package.publicRoot | Optional public namespace root for the package |
http | Per-environment HTTP port for the standalone runner |
host | Optional matrixDir pointing at a Host home |
Runtime config resolution order
At runtime startup, when the package's factory is called:
- The runner loads
.matrix/<env>.environment.jsonand uses it for transport and runtime identity. - The factory reads
config.defaults(if declared) as a base. - The factory iterates
config.providers[]in order, merging each provider's values onto the base. - The merged config is validated against
config.schema(if present), then handed to the actor instances viaprops.
Provider 1 → 2 → 3 is the documented order; the chat runtime implements it. Other packages with simpler needs may only declare defaults + envPrefix.
What goes in config vs in .matrix/<env>.environment.json
Belongs in config block | Belongs in .matrix/<env>.environment.json |
|---|---|
| Tunables a deployer might change (timeouts, feature flags, retries) | Transport: NATS URL, WebSocket port, root |
| Provider connection options | HTTP port for the runtime |
| Per-package limits | Per-Host paths (matrixDir, dataDir) |
| Schema-validated user config | Identity (runtimeId, root) |
The split mirrors CLAUDE.md "Four Operational Units": package owns its config schema; environment owns the wire/transport identity.
Credentials never go in either file
CLAUDE.md Rule 4: credentials go through Factotum only. Do not reference API keys, OAuth tokens, or NATS credentials directly in matrix.json:config or .matrix/<env>.environment.json. Reference them through secretRefs in matrix.service.json (see mx-cli/src/utils/service-manifest.ts:IMatrixServiceSecretRef).
See also
- Authoring → Package manifest
- Local Development → Config explain
- Deployment Profiles → Config
- Reference → Config contract schema
Source: The
configblock convention is documented by use inpackages/chat/matrix.json; runtime config layout is enforced bypackages/mx-cli/src/utils/package-environment.ts.