Skip to content

nimblebrain.json

NimbleBrain splits configuration into two files:

  • nimblebrain.json — instance-level settings (models, HTTP, logging, limits, feature flags). One file per deployment. This page.
  • workspace.json — per-workspace settings (bundles, skill directories, named agent profiles, optional model + identity overrides). See workspace.json.

Top-level bundles, skillDirs, agents, home, and preferences entries in nimblebrain.json are silently stripped at load — they belong in workspace.json now. See Workspace Isolation for the rationale.

NimbleBrain looks for the config file in this order, stopping at the first match:

  1. --config <path> — Explicit path passed as a CLI flag
  2. .nimblebrain/nimblebrain.json — Project-local config directory in the current working directory
  3. --workdir <dir>/nimblebrain.json — Inside the working directory (flag or NB_WORK_DIR env var)
  4. ./nimblebrain.json — Current working directory (bare file)

If no config file exists at the resolved path, NimbleBrain auto-creates a minimal default file as long as the parent directory exists.

NB_WORK_DIR takes precedence over both workDir in the file and --workdir.

{
"$schema": "https://schemas.nimblebrain.ai/v1/nimblebrain-config.schema.json",
"version": "1",
"models": {
"default": "anthropic:claude-sonnet-4-6",
"fast": "anthropic:claude-haiku-4-5-20251001",
"reasoning": "anthropic:claude-opus-4-6"
},
"providers": {
"anthropic": { "apiKey": "sk-ant-..." },
"openai": { "apiKey": "sk-..." }
},
"maxIterations": 25,
"maxInputTokens": 500000,
"maxOutputTokens": 16384,
"maxHistoryMessages": 40,
"maxToolResultSize": 1000000,
"store": { "type": "jsonl", "dir": "~/.nimblebrain/conversations" },
"logging": { "dir": "~/.nimblebrain/logs", "disabled": false, "level": "normal", "retentionDays": 30 },
"http": { "port": 27247, "host": "127.0.0.1" },
"features": {
"bundleManagement": true,
"skillManagement": true,
"delegation": true,
"toolDiscovery": true,
"bundleDiscovery": true,
"mcpServer": true,
"fileContext": true,
"userManagement": true,
"workspaceManagement": true
},
"files": {
"maxFileSize": 26214400,
"maxTotalSize": 104857600,
"maxFilesPerMessage": 10,
"maxExtractedTextSize": 204800
},
"allowInsecureRemotes": false,
"telemetry": { "enabled": true },
"workDir": "~/.nimblebrain"
}
FieldTypeDefaultDescription
$schemastringJSON Schema URI. Set to "https://schemas.nimblebrain.ai/v1/nimblebrain-config.schema.json" for editor autocompletion.
versionstringConfig file version. Must be "1".
modelsobjectRole-based model slots. See models.
providersobjectPer-provider API keys. See providers.
modelobject{ "provider": "anthropic" }Legacy single-provider config. Use providers instead.
defaultModelstringDeprecated. Use models.default instead.
maxIterationsinteger25Max agentic iterations per request. Range: 1—50.
maxInputTokensinteger500000Max input tokens per request. Engine stops when this budget is exceeded.
maxOutputTokensinteger16384Max output tokens per LLM call.
maxHistoryMessagesinteger40Max conversation message groups in context. Tool call/result pairs count as one group.
maxToolResultSizeinteger1000000Max characters for a single tool result. 0 disables the cap.
storeobject{ "type": "memory" }Conversation storage backend. See store.
sessionStoreobject{ "type": "memory", "ttlSeconds": 28800 }MCP session metadata store for /mcp. See sessionStore.
loggingobjectStructured logging config. See logging.
httpobject{ "port": 27247, "host": "127.0.0.1" }HTTP server config. Omit for programmatic-only use.
featuresobjectall trueFeature flags. See Feature Flags.
filesobjectFile upload limits. See files.
allowInsecureRemotesbooleanfalseAllow HTTP (non-TLS) remote bundle connections. Dev only.
telemetryobject{ "enabled": true }Anonymous usage telemetry. See telemetry.
workDirstring"~/.nimblebrain"Working directory for runtime state (conversations, logs, workspaces).

The models object declares three role-based slots. Each value is a provider:model-id string (e.g. "anthropic:claude-sonnet-4-6").

{
"models": {
"default": "anthropic:claude-sonnet-4-6",
"fast": "anthropic:claude-haiku-4-5-20251001",
"reasoning": "anthropic:claude-opus-4-6"
}
}
SlotUsed for
defaultChat, general requests, most tool-using turns
fastTitle generation, briefing, skill matching — cheap/fast workloads
reasoningComplex analysis, planning, long-horizon tasks

A workspace can override individual slots via workspace.json → models. When a nb__delegate call or agent profile specifies a slot name (e.g. "model": "fast"), it’s resolved against these slots.

Per-provider API keys. Takes precedence over the legacy model object when both are present.

{
"providers": {
"anthropic": { "apiKey": "sk-ant-..." },
"openai": { "apiKey": "sk-..." },
"google": { "apiKey": "AIza..." }
}
}

Each provider key is optional. If a provider’s apiKey is omitted, the SDK falls back to the provider’s standard env var (ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY).

Choose where conversations are persisted.

{
"store": {
"type": "jsonl",
"dir": "~/.nimblebrain/conversations"
}
}

The CLI defaults to JSONL storage with conversations in {workDir}/conversations/.

FieldTypeRequiredDescription
type"jsonl" | "memory"YesStorage backend.
dirstringJSONL onlyDirectory for conversation JSONL files.

Pluggable metadata store for MCP HTTP sessions. Tracks each Mcp-Session-Id and its idle TTL across the cluster.

{
"sessionStore": {
"type": "memory",
"ttlSeconds": 28800
}
}

Process-local Map with periodic TTL sweep. No external dependencies. Default; fine for any single-replica deploy.

FieldTypeDefaultDescription
type"memory" | "redis""memory"Provider. redis requires redis.url.
ttlSecondsinteger (s)28800 (8 h)Idle TTL. Each request resets the clock — actively-used sessions never expire.
redis.urlstringRedis connection URL (redis:// or rediss://). Required when type is "redis". Supports ${VAR} env expansion.
redis.keyPrefixstring"nb:mcp:session:"Hash key prefix for session entries.

The MCP /mcp endpoint is stateful. Each session has two parts:

  • MetadatasessionId, identityId, workspaceId, timestamps. Just data; lives in the session store.
  • Live transport — open HTTP response stream, SDK Server instance, registered request handlers, in-flight JSON-RPC state. Process-bound — holds open file descriptors and JS object references that cannot be serialized or moved.

Metadata is shareable across processes; the live transport is not. Routing requests to the process that owns a session’s transport is the load balancer’s job (cookie stickiness, header-hash on Mcp-Session-Id), not the session store’s. The session store is deliberately deployment-vocabulary-free — no notion of “which pod owns this” — so the same interface fits any deployment topology.

When a request arrives at a process that doesn’t have the live transport for the requested session, the 404 carries error.data.reason:

ReasonMeaning
not_foundSession store has no record. Idle-TTL eviction, or session never existed.
unavailableSession exists in the store, but the live transport isn’t on this process. Possible causes: process restart, sticky-routing miss, transport closed locally.

Spec-compliant clients re-initialize on either reason. Operators distinguish unavailable causes via deploy timing, process uptime, and “session-store size vs local transport count” signals.

ReplicasStoreUse case
1memoryDefault. Dev, programmatic use, simple production. Sessions die on process restart; clients re-initialize.
1redisSingle-process with cluster-shared metadata for ops visibility, audit trails, or future scale-out.
NredisHorizontal scale. Pair with sticky load-balancing (e.g. ALB lb_cookie) — without it, every cross-process request returns unavailable and clients re-initialize constantly.
NmemoryNot supported. Sessions partition across processes.

When type: "redis" is set without a redis.url, NimbleBrain refuses to fall back to in-memory and fails the boot — silently degrading would mask a misconfiguration.

platform.replicas > 1 requires all of:

  1. Storage that supports concurrent multi-process mounts. The default chart’s PVC is ReadWriteOnce and blocks RollingUpdate rollouts. Move workspace data out of the PVC (Postgres/S3) or relocate to ReadWriteMany (EFS).
  2. Routing strategy keyed on Mcp-Session-Id. ALB lb_cookie stickiness is the simplest path on AWS; alternatives are NGINX/Envoy with header-hash routing, or application-level cross-process proxying.
  3. Cluster-shared session store. sessionStore.type: "redis".
  4. Deploy strategy that doesn’t drop all replicas at once. platform.strategy.type: RollingUpdate (with the storage from (1) in place).

Drop any one of these and multi-replica is broken in a different way: PVC deadlock, re-init storms, partitioned session view, or deploy-time outages.

The 8 h default is tuned for a connector left open during a working day. Tighten it (e.g. 1800 for 30 minutes) if you want sessions to evict faster on idle; loosen it if your typical usage pattern leaves connectors open across days.

MCP_SESSION_TTL_SECONDS env var overrides this when set.

{
"logging": {
"dir": "~/.nimblebrain/logs",
"disabled": false,
"level": "normal",
"retentionDays": 30
}
}
FieldTypeDefaultDescription
dirstring{workDir}/logsLog directory.
disabledbooleanfalseDisable structured logging entirely.
level"normal" | "debug""normal""debug" persists additional verbose fields.
retentionDaysintegerAuto-delete log files older than N days on startup. Omit for no cleanup.

File upload limits applied when features.fileContext is enabled.

{
"files": {
"maxFileSize": 26214400,
"maxTotalSize": 104857600,
"maxFilesPerMessage": 10,
"maxExtractedTextSize": 204800
}
}
FieldTypeDefaultDescription
maxFileSizeinteger (bytes)26 MBMaximum size of a single uploaded file.
maxTotalSizeinteger (bytes)100 MBMaximum total size of all files per message.
maxFilesPerMessageinteger10Maximum number of files per chat message.
maxExtractedTextSizeinteger (bytes)200 KBMaximum extracted text size per file.

NimbleBrain collects anonymized, aggregate usage data with no PII — no bundle names, tool names, error messages, or file paths are sent.

{ "telemetry": { "enabled": false } }

Disable with NB_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1 env vars, or run nb telemetry off.

The older single-provider model shape is still accepted for backward compatibility but deprecated. Prefer providers for mixing API keys and models for model selection.

{
"model": { "provider": "anthropic", "apiKey": "sk-ant-..." },
"defaultModel": "claude-sonnet-4-6"
}
FieldTypeDescription
provider"anthropic" | "openai" | "google"Default provider when providers isn’t set.
apiKeystringFalls back to the provider’s env var when omitted.

NimbleBrain validates nimblebrain.json at startup against the JSON Schema (draft-07) using AJV.

  • Unknown keys produce a warning on stderr and are ignored.
  • Structural errors (wrong types, missing required fields) throw an error and prevent startup.
  • Workspace-owned keys (bundles, skillDirs, agents, home, preferences, noDefaultBundles) are silently stripped — no warning.
  • Deprecated keys (identity, contextFile) produce a warning pointing at context skills.
[config] Warning: unknown key "foo" in /home/user/.nimblebrain/nimblebrain.json (ignored)
Error: Invalid config in /home/user/.nimblebrain/nimblebrain.json:
- /maxIterations: must be <= 50

CLI flags take precedence over values in the config file:

FlagOverrides
--config <path>Config file location
--workdir <dir>Default location of the config file and workDir fallback
--model <id>defaultModel field (legacy)
--port <n>http.port field
--debugEnables verbose debug event logging

The smallest valid config file:

{
"$schema": "https://schemas.nimblebrain.ai/v1/nimblebrain-config.schema.json",
"version": "1"
}

This uses all defaults: Anthropic provider (key from ANTHROPIC_API_KEY), default model, no MCP bundles installed (platform capabilities are built in), in-memory conversation storage, and structured logging enabled.