Configuration Schema
System configuration reference for Nous-OSS
Configuration Schema
Nous uses JSON5 for configuration. The config file is validated at load time with Zod schemas.
Location: {dataDir}/config.json5 (or path from NOUS_CONFIG_PATH)
Top-Level Sections
| Section | Description |
|---|---|
profile | Deployment profile (local_strict, hybrid_controlled, remote_primary; legacy: local-only, remote-only, hybrid) |
pfcTier | Cortex tier 0–5 (see Cortex Mode Capability Matrix) |
pfcTierPresets | Capability definitions per tier |
modelRoleAssignments | Which provider fulfills which model role |
providers | Provider configurations (Ollama, Chat Completions-compatible remote providers, etc.) |
agent | Agent identity, personality, welcome-message tracking, and user profile (optional; absent in default config — populated by the first-run wizard or by hand-editing) |
defaults | Default project settings |
storage | Storage backends and options |
security | Trace sensitivity, optional settings |
Profile
{
"profile": {
"name": "hybrid_controlled", // see Profile names below
"description": "Local preferred with explicit remote fallback",
"defaultProviderType": "local",
"allowLocalProviders": true,
"allowRemoteProviders": true,
"allowSilentLocalToRemoteFailover": false
}
}Profile names (Phase 2.3):
| Canonical | Legacy (deprecated) | Semantics |
|---|---|---|
local_strict | local-only | Local providers only; no silent local→remote failover |
remote_primary | remote-only | Remote providers primary; local only when explicitly configured |
hybrid_controlled | hybrid | Local preferred with explicit remote fallback under policy |
Legacy names are normalized at runtime. allowSilentLocalToRemoteFailover — when false (default), remote is allowed only as explicit fallback in hybrid_controlled.
When Anthropic or OpenAI credentials are restored at startup and the active profile is local-only or local_strict, Nous promotes the runtime into a hybrid-compatible profile so remote providers can actually be routed. Removing the last cloud provider returns the runtime to local-only posture.
Cortex Tier
pfcTier is a number 0–5. Higher tiers enable more capabilities (reflection, memory gating, tool authorization, planning, escalation detection). See Cortex Mode Capability Matrix.
Model Role Assignments
{
"modelRoleAssignments": [
{
"role": "cortex-chat",
"providerId": "550e8400-e29b-41d4-a716-446655440002",
"fallbackProviderId": "550e8400-e29b-41d4-a716-446655440001"
}
]
}providerId and optional fallbackProviderId must be valid UUIDs matching provider id values in the providers array. Built-in provider ids are deterministically derived from certified provider-definition vendorKey values at runtime and surfaced through provider config identity; custom/user provider instances use persisted generated ids. Model assignment writers validate role compatibility before saving so command-bound CLI providers cannot be assigned to Cortex persistent-chat roles. Roles: cortex-chat, cortex-system, orchestrators, workers.
Saved Principal and System model selections are restored into this structure at startup. When both saved selections are available, Nous uses the primary selection as providerId and the secondary selection as fallbackProviderId for the active cortex-chat assignment.
Providers
{
"providers": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"name": "Ollama",
"type": "text",
"modelId": "llama3.2:3b",
"isLocal": true,
"capabilities": ["chat", "streaming"],
"providerClass": "local_text",
"vendor": "ollama",
"meetsProfiles": ["review-standard", "prompt-generation"]
},
{
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "openai",
"type": "text",
"endpoint": "https://api.openai.com",
"modelId": "gpt-4o",
"isLocal": false,
"capabilities": ["chat", "streaming"],
"providerClass": "remote_text",
"vendor": "openai",
"meetsProfiles": ["review-standard", "review-implementation"]
}
]
}- providerClass (optional):
local_text|remote_text— used for credential segregation and profile boundary. - vendor (optional): Certified provider vendor key for adapter selection. Known vendor values include
anthropic,openai, andollama; see Provider Adapters for how vendor keys map to provider leaves. Unknown values fall back through the adapter resolver rather than becoming certified vendors. - adapterKey (derived internally): Adapter implementation key resolved from the provider definition, such as
anthropic,chat-completions, orollama.textis the fallback adapter key, not a certified provider vendor. - meetsProfiles (optional): Array of capability profiles (e.g.
review-standard,review-implementation). Router enforces that the selected provider meets the required profile unless Principal override evidence is present. - endpoint (optional): Use the provider base URL (for example
https://api.openai.comorhttps://api.anthropic.com), not the full/v1/chat/completionspath.
Provider types: text, image, video, vision, embedding, external-api.
Codex CLI Provider
The certified codex-cli provider is a local text provider that shells out to the installed Codex CLI. It does not use an API key in nous-config.json5; it uses the local Codex CLI login session instead. Install and authenticate Codex outside Nous before assigning this provider to a model role.
For transient and batch work, Codex CLI still runs through the one-shot codex exec command path. The Codex provider declares session_bound_command, which means it is command/session-bound and does not expose a strict long-lived process protocol.
Cortex Chat and Cortex System require persistent_process semantics for agent-cli providers. Settings disables/rejects Codex CLI for those Cortex roles instead of letting the chat path fail later. Codex CLI can still be used in compatible command-bound agent roles.
When a compatible CLI provider is used in a chat-bound context, the runtime session key is derived from the provider id, chat fixture role, and chat session id. Project-scoped chat also includes projectId; system-wide chat omits it. Conversation history remains in Cortex STM, not in provider session state.
Agent
The agent block stores agent identity and personality settings authored by the first-run wizard's Identity step or by direct hand-edit of the JSON5 file. This agent section is independent of the top-level profile (deployment profile) section above — they share no fields.
{
"agent": {
"name": "Nia",
"personality": {
"preset": "balanced",
"overrides": { "thoroughness": "strict" }
},
"welcomeMessageSent": true,
"profile": {
"displayName": "Andrew",
"role": "Software engineer",
"primaryUseCase": "Architecture exploration",
"expertise": "advanced"
}
}
}name(string, optional) — Display name for the agent. When absent, readers return the typed default"Nous".personality(object, optional) — Personality preset plus optional per-axis overrides.presetis one ofbalanced,professional,efficient,thorough.overridesis a partial map ofTraitAxes(thoroughness,initiative,candor,communicationStyle,codeStyle). When absent, readers return the typed default{ preset: "balanced" }and the production prompt path is byte-identical to the pre-personality baseline (regression-parity invariant).welcomeMessageSent(boolean, optional) — Tracks whether the welcome message has been delivered (consumed by the welcome-message wiring in SP 1.6). When absent, readers return the typed defaultfalse.profile(object, optional) — Typed user-profile sub-fields, all optional:displayName,role,primaryUseCase,expertise('beginner' | 'intermediate' | 'advanced'). When absent, readers return the typed default{}. The schema is additive over time — new fields may be added in future sub-phases without breaking existing configs; renames or removals are migrations.
Read-time defaults — never persisted on read. The entire agent block is absent from the default system config. Readers (getAgentName, getPersonalityConfig, getUserProfile, getWelcomeMessageSent) synthesize their typed defaults at read time without writing to disk. The agent key first appears in nous-config.json5 only after the user completes the first-run Identity step or hand-edits the file.
Reset semantics. The firstRun.resetWizard tRPC mutation clears the entire agent block while leaving providers and modelRoleAssignments untouched. After reset, all four readers return their typed defaults again.
JSON5 comment caveat. Writes to nous-config.json5 (e.g. when the wizard's firstRun.writeIdentity procedure runs) emit JSON, not JSON5 — any comments you add to the file by hand are lost on the next write. This is a pre-existing Phase 1 tradeoff documented in the ConfigManager source. Hand-editors who rely on comments should be aware that wizard-driven writes will strip them.
Storage
{
"storage": {
"dataDir": "/path/to/data",
"documentBackend": "sqlite",
"vectorBackend": "stub",
"graphBackend": "stub",
"storageEncryption": false
}
}storageEncryption— When true, user is responsible for filesystem-level encryption (LUKS, BitLocker, FileVault). Phase 1: option validated; runbook in Security Baseline.
Security
{
"security": {
"traceSensitiveData": false
}
}traceSensitiveData— When false (default), user input, model output, and memory candidate content are redacted from traces. Structure (traceId, projectId, Cortex decisions) is preserved.
Defaults
{
"defaults": {
"projectType": "hybrid",
"governance": "should",
"memoryAccessPolicy": {
"canReadFrom": "all",
"canBeReadBy": "all",
"inheritsGlobal": true
},
"retrievalBudgetTokens": 500,
"stmCompactionPolicy": {
"maxContextTokens": 1024,
"targetContextTokens": 640,
"minEntriesBeforeCompaction": 8,
"retainedRecentEntries": 4
},
"escalationChannels": ["in-app"]
}
}These apply to newly created projects.
retrievalBudgetTokens— Default token budget for retrieval result assembly in new projects.stmCompactionPolicy— Default short-term-memory pressure policy for new projects.maxContextTokens— Threshold where STM should compact.targetContextTokens— Post-compaction token budget.minEntriesBeforeCompaction— Minimum recent turns required before compaction is allowed.retainedRecentEntries— Number of newest turns kept verbatim when older context is summarized.
targetContextTokens must be lower than maxContextTokens, and retainedRecentEntries must be lower than minEntriesBeforeCompaction.
Environment Variables
| Variable | Purpose |
|---|---|
NOUS_DATA_DIR | Overrides storage.dataDir |
NOUS_CONFIG_PATH | Overrides the config file path |
NOUS_BASIC_AUTH | Enables basic auth for tRPC (format: user:password) |
OPENAI_API_KEY | Enables the built-in OpenAI remote provider at startup |
ANTHROPIC_API_KEY | Enables the built-in Anthropic remote provider at startup |
NOUS_PUBLIC_BASE_URL | Base URL used in OAuth discovery documents for the public MCP edge (default: http://localhost:3000). Set this when deploying behind a non-localhost public endpoint. |
NOUS_PUBLIC_MCP_HOSTED_BINDINGS_JSON | Seeded hosted public-MCP binding records used to map a public host or user handle onto a hosted tenant runtime. Accepts a JSON object or JSON array of binding records. |
NOUS_PUBLIC_MCP_TUNNEL_SESSIONS_JSON | Seeded public-MCP tunnel session records used to map a public host or user handle onto a local tunnel runtime. Accepts a JSON object or JSON array of session records. |
When OPENAI_API_KEY or ANTHROPIC_API_KEY is present at startup, Nous registers the matching remote provider, updates available cloud models, restores saved model selections against stable provider IDs, and enables hybrid-compatible routing. These variables can be supplied directly or populated from stored vault credentials during bootstrap.
Phase 13.5 config audit result: public MCP deployment routing adds two operator-facing seed
variables for hosted and local-tunnel routing. NOUS_PUBLIC_BASE_URL remains the public MCP edge
override for OAuth metadata and discovery URLs.
NOUS_PUBLIC_MCP_HOSTED_BINDINGS_JSON
Use this variable to seed hosted tenant routing records during web bootstrap. Each record must match the hosted-binding schema used by the public gateway:
[
{
"bindingId": "binding-1",
"tenantId": "tenant-1",
"userHandle": "andre",
"host": "andre.nous.run",
"storePrefix": "tenant-andre",
"serverName": "Andre Hosted Nous",
"phase": "phase-13.5",
"status": "active",
"createdAt": "2026-03-14T00:00:00.000Z",
"updatedAt": "2026-03-14T00:00:00.000Z"
}
]bindingId— stable binding record identifiertenantId— tenant-scoped runtime identityuserHandle— public handle used for hosted routinghost— public host that resolves to the hosted tenant runtimestorePrefix— tenant-local storage prefix used for document/vector/task/audit isolationserverName— public-safeortho.system.v1.infoserver name overridephase— public-safe phase label surfaced inortho.system.v1.infostatus— current binding state (activeordisabled)
NOUS_PUBLIC_MCP_TUNNEL_SESSIONS_JSON
Use this variable to seed local-tunnel routing records during web bootstrap. Each record must match the tunnel-session schema used by the public gateway:
[
{
"sessionId": "session-1",
"userHandle": "casey",
"host": "casey.tunnel.nous.run",
"sharedSecret": "0123456789abcdef0123456789abcdef",
"status": "active",
"createdAt": "2026-03-14T00:00:00.000Z",
"updatedAt": "2026-03-14T00:00:00.000Z"
}
]sessionId— stable tunnel session identifieruserHandle— public handle associated with the tunnel sessionhost— public host that resolves to the tunnel backendsharedSecret— shared secret used to validate edge-issued tunnel envelopesstatus— current session state (activeordisabled)
These variables affect deployment routing only. They do not change the public MCP tool catalog, OAuth posture, or JSON-RPC request and response shapes seen by external clients.