Runtime Config
Status: Running today. The runtime config contract (
K-CFG-001..K-CFG-011) governs canonical config path, source priority, schema versioning, secret policy, and reload boundaries.
The runtime reads configuration from a single canonical path with explicit source priority. Config validation fails closed; reload boundaries are explicit. There is no implicit hot-reload.
Canonical Config Path
| Rule | Value |
|---|---|
| Canonical path | ~/.nimi/config.json |
| Legacy paths | NOT read |
The runtime does not consult older config locations. Migrating machines must move their config to the canonical path.
Source Priority
Sources resolve in fixed priority order:
environment variables > config file > built-in defaultsEnvironment variables override config file values. Config file values override built-in defaults.
Schema Version
| Rule | Value |
|---|---|
| Required field | schemaVersion |
| Current version | 1 |
| Unknown fields | Forward-compatible ignore |
A config without schemaVersion does not load. The forward-compat posture lets older runtimes ignore newer fields without crashing.
Provider Name Canonicalization
Provider names in config must use the canonical values from provider-catalog.yaml. Aliases and legacy names are rejected. This prevents the situation where two configs spell the same provider two different ways and silently route to different paths.
Secret Policy
| Rule | Value |
|---|---|
| Per provider, choose one | apiKey or apiKeyEnv |
| Both set | Rejected |
| Recommended | Environment variable or system secure store |
apiKey inline | Allowed only as canonical config file fallback |
User-facing tooling should prefer environment variables or secure storage. Inline apiKey survives in the canonical config file as a fallback because some onboarding flows require the value persist across daemon restart, but the recommendation pushes toward apiKeyEnv and secure storage.
Atomic Write
Config writes use temp-file + rename atomic write. A crashed write does not leave a half-written config; either the new config landed atomically or the old one is still in place.
Runtime Command Surface
config init / validate / get / set behavior must match this contract. Errors emit unified reason codes; partial-success returns are not admitted.
Validation Fail-Close
| Rule | Value |
|---|---|
| Validation failure | Fail-close — runtime does NOT start core paths |
| Partial success | NOT admitted |
A config with one invalid field does not partially work with the valid fields. The runtime refuses to start core execution paths until config validates clean.
Provider Env Binding
The mapping from provider to its baseUrl / apiKey environment variable names lives in provider-probe-targets.yaml. The config contract does not inline this mapping.
Hot Reload Boundaries (K-CFG-010)
The most important rule on this page:
Config changes that take effect at runtime versus only on restart must be explicitly declared. Implicit hot-reload is not admitted.
A config field is either documented as hot-reloadable or it is not. Behavior that depends on whether something hot-reloaded "works sometimes" is the error mode this rule prevents.
Credential Plane Boundary (K-CFG-011)
The config layer admits credential references and admits an inline secret fallback in the canonical config file. Higher-level install and configuration entry points must prefer env / secure-store paths.
For public CLI first-run, if interactive credential capture happens, the user-pasted provider key must immediately write to the canonical machine config. The same onboarding run cannot succeed using only a "this-call-only inline memory credential." The path must:
- Warn about inline secret risk
- Continue to recommend
apiKeyEnv/ secure-store - Fail closed if write fails — no continuation with cloud generation
The current invocation may continue with inline metadata to the already-running daemon (avoiding the assumption that the daemon hot-reloaded), but the persisted truth is the canonical config.
Reader Scenario: Initial Config
- User runs
config init. Runtime writes a fresh~/.nimi/config.jsonwithschemaVersion: 1and built-in defaults. - User sets a provider.
config setwrites provider entry with canonical name fromprovider-catalog.yaml. - User adds API key. Tooling prompts for
apiKeyEnvfirst; if the user insists on inline, the value is stored underapiKeywith a recommendation to switch to env. - User starts daemon. Validation runs; passes; daemon enters service.
Reader Scenario: A Validation Failure At Boot
- Daemon starts. Reads
~/.nimi/config.json. - Validation fails. Provider name is a legacy alias.
- Fail-close. Daemon refuses to enter service. Reason code pinpoints the problem.
- User fixes. Updates provider name to canonical; re-runs
config validate; restarts daemon.
The daemon does not "partially start with the bad provider disabled."
Reader Scenario: A Hot-Reload Question
A user changes a config field and asks: does this take effect now?
- Check the field's documented reload boundary. If it is documented hot-reloadable, the runtime applies it; subscribed subsystems re-read.
- If documented restart-only, the user must restart the daemon for the change to take effect.
- If not explicitly declared, the field is not assumed hot-reloadable — the contract requires explicit declaration.
This rule is what makes config behavior predictable across upgrades.
What Runtime Config Does Not Do
- It does not read legacy config paths.
- It does not accept provider aliases or legacy names.
- It does not permit both
apiKeyandapiKeyEnvfor a single provider. - It does not partially start when validation fails.
- It does not implicitly hot-reload arbitrary fields.