# @mono-agent/config

Typed, adapter-neutral configuration for mono-agent hosts. Most users author
`mono-agent.config.json` and let `@mono-agent/agent-app` load it; install this
package directly when building a custom host, config editor, or validator.

## Category

<!-- package-metadata:start -->
<!-- Generated by scripts/generate-package-docs.mjs. Do not edit by hand. -->

Category: `core`
Tier: `core`
Catalog responsibility: Loads adapter-neutral runtime, context, memory, tool, and artifact settings.

<!-- package-metadata:end -->

## Responsibility

Load, validate, source-annotate, and redact the core runtime, context, memory,
tool/MCP, artifact, traceability, observability, provider, and sandbox settings.
Channel packages remain responsible for their own configuration.

## Install / Usage

```bash
npm install @mono-agent/config
```

```ts
import {
  buildMonoAgentConfigView,
  loadMonoAgentConfigWithSources,
} from "@mono-agent/config";

const config = await loadMonoAgentConfigWithSources({
  env: process.env,
  cwd: process.cwd(),
  jsonPath: "./mono-agent.config.json",
});

console.log(config.runtime.model);
```

A non-empty environment value overrides its mapped JSON field. Blank values are
normally ignored; the legacy `MONO_AGENT_FALLBACK_MODELS=""` clear operation is
the deliberate exception. Not every nested JSON field has an environment
counterpart, so use the [environment variable
map](https://mono-agent-docs.vercel.app/config/env-vars/) rather than assuming a
blanket override. A missing or empty JSON file contributes an empty layer.

### Agent identity and runtime routes

`agent.name` is public display metadata. It can seed human-facing trace and A2A
labels, but it never changes paths, service ids, session keys, or provider
identity. `MONO_AGENT_NAME` overrides the JSON value.

Use `runtime.fallbacks` for new fallback chains. It is an ordered, uncapped array
of `{ model, effort? }` entries; omitted route effort means the provider default.
`runtime.fallbackModels` and `MONO_AGENT_FALLBACK_MODELS` remain compatibility
surfaces and retain their historical inheritance from `runtime.effort`.

```json
{
  "agent": { "name": "Research Companion" },
  "runtime": {
    "model": "pi:openai-codex:gpt-5.6-terra",
    "effort": "high",
    "fallbacks": [
      { "model": "claude:claude-sonnet-5", "effort": "xhigh" },
      { "model": "pi:ollama:gemma4:31b" }
    ],
    "routeSafety": "per-route-native"
  }
}
```

`routeSafety` defaults to `uniform`; `per-route-native` is the explicit opt-in
for isolated provider-native contracts in a mixed chain. Effort values are
`none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, and `ultra`, subject
to the selected model's supported subset.

`ultra` is route-specific. Reasoning-capable `pi:*` maps `ultra` to LOW; Pi
without reasoning uses OFF. Direct `codex:*` forwards `ultra` unchanged.
Mono-agent rejects `ultra` on its Claude SDK route because the pinned SDK public
contract ends at `max` (the SDK JavaScript itself forwards the value). The
Claude CLI route passes `--effort ultra`, but both tested Claude Code binaries
(SDK-bundled 2.1.206 and local 2.1.210) warn that it is unknown, ignore it, and
use default effort. Direct OpenCode rejects explicit effort. `effortRank`
places `ultra` above `max` only so keyword escalation cannot downgrade an
explicitly configured value.

### Pi credentials

Built-in Pi OAuth and API-key providers read credentials through the configured
Pi auth file. The default path is
`~/.pi/agent/auth.json`; override it with JSON or env:

```json
{
  "providers": {
    "piAuthPath": ".worklab/auth.json"
  }
}
```

```bash
MONO_AGENT_PI_AUTH_PATH=/Users/example/.pi/agent/auth.json
```

Only the path is stored in config. Token contents stay in the auth JSON file and
are never included in `redactMonoAgentConfig()`.

Pi-native transport selection is optional and defaults to `auto`. Configure
`providers.piNative.transport` or `MONO_AGENT_PI_TRANSPORT` with `auto`, `sse`,
`websocket`, or `websocket-cached`; unsupported providers ignore the choice.

### Local providers

Core config can also define local Pi providers under `providers.local`. The primary supported path is Ollama:

```json
{
  "runtime": {
    "model": "pi:ollama:qwen3:8b",
    "executionMode": "sdk",
    "workspace": "."
  },
  "providers": {
    "local": [
      {
        "id": "ollama",
        "type": "ollama",
        "baseUrl": "http://localhost:11434",
        "enabled": true,
        "models": [
          { "name": "qwen3:8b", "capabilities": { "context_window": 32768 } }
        ]
      }
    ]
  }
}
```

`runtime.maxTurns` is optional. Omit it or set `0` for unlimited runs; set `1`-`100` to keep a hard cap.

Environment overrides for the common one-provider case:

```bash
MONO_AGENT_LOCAL_PROVIDER_ID=ollama
MONO_AGENT_LOCAL_PROVIDER_TYPE=ollama
MONO_AGENT_LOCAL_PROVIDER_BASE_URL=http://localhost:11434
MONO_AGENT_LOCAL_PROVIDER_ENABLED=true
MONO_AGENT_LOCAL_PROVIDER_TRUST_PUBLIC_URL=false
```

`MONO_AGENT_LOCAL_PROVIDERS_JSON` can hold the full local-provider array. Env values win over JSON; empty env values are ignored. `MONO_AGENT_LOCAL_PROVIDER_API_KEY` and provider `apiKeyEnv` are passed only to the runtime path and are redacted from `redactMonoAgentConfig()`.

### Local-first web tools

The resolved `tools.web` block configures the managed Pi `WebSearch` and
`WebFetch` tools:

```json
{
  "tools": {
    "web": {
      "search": {
        "backend": "auto",
        "endpoint": "http://127.0.0.1:8088",
        "codex": { "model": "gpt-5.6-luna" }
      },
      "fetch": {
        "render": "never",
        "browserCommand": "agent-browser"
      }
    }
  }
}
```

Search backend values are `auto`, strict `searxng`, strict `codex`, and
`keyless`. Auto tries local SearXNG, ChatGPT-subscription Codex search, then the
keyless chain. SearXNG endpoints are deliberately limited to unauthenticated
loopback HTTP URLs.
Fetch rendering is `never` by default (browser capability disabled) or `auto`
for static-first isolated `agent-browser` fallback.

Environment overrides are
`MONO_AGENT_WEB_SEARCH_BACKEND`,
`MONO_AGENT_WEB_SEARCH_ENDPOINT`,
`MONO_AGENT_WEB_SEARCH_CODEX_MODEL`,
`MONO_AGENT_WEB_FETCH_RENDER`, and
`MONO_AGENT_WEB_BROWSER_COMMAND`.

### Managed memory embeddings

Journal and BuJo accept `ollama`, `lmstudio`, or `openai` in
`memory.embeddings.provider`. Keep the provider, service root, exact model, and
actual dimension explicit because they form the managed index identity:

```json
{
  "memory": {
    "mode": "journal",
    "path": "./.mono-agent/memory",
    "embeddings": {
      "provider": "lmstudio",
      "endpoint": "http://localhost:1234",
      "model": "text-embedding-nomic-embed-text-v1.5",
      "dim": 768,
      "apiKeyEnv": "LM_STUDIO_API_KEY"
    }
  }
}
```

Omit `apiKeyEnv` for keyless LM Studio. When the field is present, the loader
preserves the variable name and resolves its value only from the environment;
the app reports a missing/empty declared variable as `waiting` and never silently
retries keyless. OpenAI still requires a resolved key. Provider selection is
exclusive and does not define fallback behavior. Changing provider, model, or
dimension on an existing Journal/BuJo root requires the config-aware stopped
`mono-agent memory rebuild` workflow.

### Provider sessions and conversation history

Continuous provider sessions are configured under `runtime.session` (JSON: `{ "runtime": { "session": { "mode": "continuous", "idleTimeoutMs": 1800000 } } }`):

```bash
MONO_AGENT_SESSION_MODE=continuous           # or per-message (fresh turn with history replay)
MONO_AGENT_SESSION_IDLE_TIMEOUT_MS=1800000   # 30 min default; min 1s, max 24h
MONO_AGENT_SESSION_ROLLOVER=daily            # none (default) or daily
MONO_AGENT_SESSION_ROLLOVER_TIMEZONE=UTC     # optional IANA timezone for daily rollover
MONO_AGENT_SESSION_ROLLOVER_NOTICE=true      # opt in to adapter-visible new-bucket notices
```

In `continuous` mode (the default), consecutive messages in a conversation can
reuse one provider session (a Codex app-server thread, Claude resume token, or
Pi session transcript). Only a confirmed warm resume omits prior messages from
the next provider input; the default app host still appends every successful
turn to canonical durable conversation history. Expiry, invalidation, a
non-resumable runtime, or any configured fallback route uses the cold
history-replay path. `per-message` always starts a fresh provider turn and
relies on that canonical history for context.

### Sandbox policy

Sandbox config is optional. When any `MONO_AGENT_SANDBOX_*` variable is present, config builds a fail-closed `@mono-agent/runtime-adapter` policy rooted at `runtime.workspace`:

```bash
MONO_AGENT_SANDBOX_MODE=native
MONO_AGENT_SANDBOX_NETWORK=none
MONO_AGENT_SANDBOX_FALLBACK=fail-closed
```

Enforced network modes are `none`, `localhost`, and `allowlist`. `allowlist` reads comma-separated domains from `MONO_AGENT_SANDBOX_NETWORK_ALLOWLIST`. `all`, bare `*`, and IPv6 literals are rejected because pinned SRT 0.0.64 cannot enforce them exactly. Migrate an existing native `network.mode: "all"` config to `none`, `localhost`, or an explicit allowlist; if unrestricted shell networking is intentional, set `sandbox.mode: "off"` and remove the network policy. Unsafe host-process fallback requires both `MONO_AGENT_SANDBOX_FALLBACK=unsafe-host-process` and `MONO_AGENT_SANDBOX_UNSAFE_ALLOW_HOST_PROCESS=true`.

## Architecture

### Data flow

Configuration follows one deterministic pipeline:

1. `readMonoAgentConfigJson()` reads the optional file and treats a missing or
   empty file as an empty object.
2. `loadMonoAgentConfigWithSources()` validates JSON-only structures, then
   `layerJsonOntoEnv()` maps supported JSON leaves onto the loader's env-shaped
   input without replacing non-empty environment values.
3. `loadMonoAgentConfig()` applies defaults, coercion, range checks, model
   parsing, execution-mode compatibility, and fail-closed sandbox policy.
4. Consumers use `buildMonoAgentConfigView()` for source-aware display and
   `redactMonoAgentConfig()` before logging or exposing the resolved result.

### Package structure

| Module | Purpose |
| --- | --- |
| `json-source.ts` | Typed JSON file shape plus safe read/write operations. |
| `layered-loader.ts` | JSON-to-env mapping, precedence, and JSON-source diagnostics. |
| `config.ts` | Authoritative parsing, defaults, validation, and redaction. |
| `types.ts`, `enums.ts` | Resolved config contracts and closed value sets. |
| `config-view.ts` | Source-annotated, secret-safe settings UI model. |
| `effort-keywords.ts` | Shared effort escalation vocabulary and ordering. |

## Public API

### Start here

| Need | Primary API |
| --- | --- |
| Load JSON plus environment settings | `loadMonoAgentConfigWithSources` |
| Load an already prepared environment map | `loadMonoAgentConfig` |
| Read or write the JSON source | `readMonoAgentConfigJson`, `writeMonoAgentConfigJson` |
| Display config provenance safely | `buildMonoAgentConfigView` |
| Remove secret values before output | `redactMonoAgentConfig` |
| Validate or present closed choices | `EFFORT_LEVELS`, `MEMORY_MODES`, `PERMISSION_MODES`, `ROUTE_SAFETY_MODES` |
| Apply effort-keyword escalation | `detectEffortKeyword`, `maxEffortLevel`, `effortRank` |

<!-- public-api-inventory:start -->
<!-- Generated by scripts/generate-public-api-docs.mjs. Do not edit by hand. -->

Every symbol exported by each public code entrypoint is listed below.

**`@mono-agent/config`**

```text
ALLOW_ALL_TOOLS
ArtifactRetentionConfig
BuildMonoAgentConfigViewInput
CONFIG_ENV_KEYS
ConfigViewField
ConfigViewFieldId
ConfigViewFieldSource
ConfigViewSection
ConfigViewSectionStatus
EFFORT_KEYWORD_TRIGGERS
EFFORT_LEVELS
EffortKeywordMatch
EffortKeywordTrigger
EffortLevel
LoadMonoAgentConfigInput
LoadMonoAgentConfigWithSourcesInput
MAX_AGENT_NAME_LENGTH
MEMORY_BACKENDS
MEMORY_EMBEDDINGS_PROVIDERS
MEMORY_LLM_PROVIDERS
MEMORY_MODES
MEMORY_WRITE_MODES
MemoryAgentHostLlmConfig
MemoryBackend
MemoryConsolidationConfig
MemoryEmbeddingsCircuitBreakerConfig
MemoryEmbeddingsConfig
MemoryEmbeddingsProvider
MemoryLlmConfig
MemoryLlmProvider
MemoryMode
MemoryOllamaLlmConfig
MemorySupermemoryConfig
MemoryWriteMode
MonoAgentArtifactRetentionJson
MonoAgentConfig
MonoAgentConfigError
MonoAgentConfigErrorCode
MonoAgentConfigErrorDetails
MonoAgentConfigJson
MonoAgentLocalProviderJson
MonoAgentLocalProviderModelJson
MonoAgentMemoryConsolidationJson
MonoAgentMemoryEmbeddingsCircuitBreakerJson
MonoAgentMemoryEmbeddingsJson
MonoAgentMemoryLlmJson
MonoAgentObservabilityExporterJson
MonoAgentProvidersJson
MonoAgentRuntimeFallbackJson
ObservabilityExporterConfig
PERMISSION_MODES
PermissionMode
PhoenixExporterConfig
PiNativeProviderConfig
ROUTE_SAFETY_MODES
ReadMonoAgentConfigJsonResult
RedactedLocalProviderDefinition
RedactedMemoryConfig
RedactedMemoryEmbeddingsConfig
RedactedMemorySupermemoryConfig
RedactedMonoAgentConfig
RedactedObservabilityConfig
RedactedObservabilityExporterConfig
RedactedPhoenixExporterConfig
RemovedConfigWarningsInput
RouteSafetyMode
RuntimeFallbackConfig
SessionMode
buildMonoAgentConfigView
detectEffortKeyword
effortRank
findJsonSecretConfigWarnings
findRemovedConfigWarnings
loadMonoAgentConfig
loadMonoAgentConfigWithSources
maxEffortLevel
readMonoAgentConfigJson
redactMonoAgentConfig
resolveSupermemoryContainer
writeMonoAgentConfigJson
```

<!-- public-api-inventory:end -->

## Dependency Boundary

`@mono-agent/config` may depend on `@mono-agent/agent-contracts` and `@mono-agent/runtime-adapter`. It must not depend on communication adapters, agent harness, or UI packages.

## What This Package Does Not Own

It does not load Telegram, WhatsApp, Slack, or other adapter-specific credentials or allowlists. Adapter packages own those settings and their safety rules.

## Related Documentation

- [Configuration overview](https://mono-agent-docs.vercel.app/config/)
- [Complete configuration blueprint](https://mono-agent-docs.vercel.app/config/blueprint/)
- [Environment variable map](https://mono-agent-docs.vercel.app/config/env-vars/)
- [Generated field reference](https://mono-agent-docs.vercel.app/config/reference/)
- [Local-first web research](https://mono-agent-docs.vercel.app/tools/web-research/)
- [Runtime and provider configuration](https://mono-agent-docs.vercel.app/runtime/)
- [Package source and generated API inventory](https://github.com/robertsreberski/mono-agent/tree/main/packages/config)

## Verification

```bash
pnpm --filter @mono-agent/config run build
pnpm --filter @mono-agent/config run typecheck
pnpm --filter @mono-agent/config run test
```
