Skip to content

Configuration Reference

BMO prefers TOML. This reference covers config file locations, merge precedence, and the common shape of BMO configuration. The generated docs/config.reference.toml artifact contains the exhaustive field inventory.

Maturity: Reference surface. Use this page when you need durable configuration behavior, precedence, and editable-vs-config-only boundaries. For first-run setup, start with Authentication and Quickstart.

Start here when you need to change BMO behavior persistently. First identify the config layer you want to affect, then find the matching section and verify the merged result with the relevant CLI command or TUI setting. Use the generated config artifact only when this page does not list the exact field.

  • Global config: ~/.config/bmo/bmo.toml
  • Project-local overrides: bmo.toml or .bmo.toml
  • JSON fallback: bmo.json or .bmo.json if you already have one, but new examples should use TOML

BMO_GLOBAL_CONFIG overrides the config directory. BMO_GLOBAL_DATA overrides the runtime data directory for databases, logs, caches, and generated metadata; BMO does not load bmo.toml from the data directory.

BMO deep-merges config from lowest to highest precedence:

  1. Global config directory (~/.config/bmo/bmo.toml by default)
  2. Project configs discovered from the nearest repository or Go module boundary down to the current working directory, with the closest file winning

Use bmo dirs, bmo dirs config, and bmo dirs data to confirm the active directories on your machine.

Field shapeBehavior
Strings, enums, and other scalar valuesHigher-precedence non-empty values replace lower-precedence values.
Presence-tracked booleans and compatibility aliasesHigher-precedence explicit values win, including explicit false.
MapsKeys are merged; a higher-precedence layer can replace the value for one key without replacing the whole map.
Lists and arraysCombined rather than wholesale replaced unless a specific surface documents different behavior.
Presence-tracked numerics where 0 is meaningfulAn explicit 0 in a higher-precedence file overrides an inherited nonzero value and reverts behavior to that field’s documented default or disabled state.

The generated docs/config.reference.toml comments tell you whether 0 means “use default”, “disable”, or “immediate”. For implementation details on how presence tracking works in load and merge, see config-merge-precedence.md.

Example: resetting an inherited numeric value

Section titled “Example: resetting an inherited numeric value”

If a global config sets a limit and the project wants to go back to default behavior, the project config can set that field to 0 explicitly:

~/.config/bmo/bmo.toml
[options]
agent_max_depth = 2
[options.workspace_strategy_memory]
enabled = true
retention_cap = 40
./bmo.toml
[options]
agent_max_depth = 0
[options.workspace_strategy_memory]
retention_cap = 0

In the merged config, agent_max_depth = 0 means “use the normal default depth” and retention_cap = 0 means “use the normal default retention cap” rather than inheriting 2 and 40.

TUI settings parity (editable vs config-only)

Section titled “TUI settings parity (editable vs config-only)”

Open the settings dialog with /settings (alias /config). It intentionally covers common runtime controls, not the full config surface.

Editable in TUI settings

  • General: permissions.skip_requests, options.sandbox_mode, options.tui.diff_mode, options.tui.compact_mode, options.thinking_display, options.progress, options.tui.run_progress_in_tui, options.tui.slash_opens_commands, options.tui.show_landing_hints, options.tui.transparent
  • Agent: options.agent_backend, options.auto_debug.enabled, options.auto_debug.max_retries, options.reflection.enabled, options.staged_workflow.enabled, options.staged_workflow.require_approval_before_execute, options.pruning.enabled, options.agent_max_depth, options.agent_max_threads
  • Advanced: telemetry_config.enable_metrics, options.enable_auto_summarize, options.auto_lsp, options.adaptive_orchestration.enabled, options.debug, options.debug_lsp, options.tui.completions.max_depth, options.tui.completions.max_items
  • Shown but not editable in dialog: options.token_budget_ux.display, options.data_directory

options.tui.show_landing_hints is default-on; setting it to false hides the initial landing guidance text and numbered quick-start choices, and removes those hidden rows from click and digit-shortcut handling.

Config-only (not editable in Settings)

  • options.tui.runtime_activity_rowDefault on (nil-guard in config); when true, shows the Activity strip above the chat for coarse in-flight work (tools, agents, PTY, scheduler, etc.). Distinct from the phase timeline in gloss / get_session_phases; see TUI — phases vs activity. Set to false to hide the strip. Legacy: [ui] runtime_activity_row in bmo.toml is still accepted; it applies only when options.tui.runtime_activity_row is unset in the merged config. If the canonical option is explicitly false, the strip stays off (legacy cannot override).
  • options.tui.query_focus_eventsDefault on (nil-guard); when true, the TUI startup capability probe asks the terminal for focus-in/out reporting support. Set to false to skip the probe.
  • options.tui.chat_max_content_width — caps user messages and most tool output to this many columns (minimum with the chat pane width). When omitted or set to 0, uses the full chat pane width. Set a positive value (for example 120) for a fixed column cap. Negative values fall back to 120.
  • options.tui.theme — TUI color palette. Known themes: codex-graphite (default), bmo (BMO flagship styling), monokai, claude-aubergine, copilot-midnight, vscode-panel-dark, goose-light-contrast, ops-high-contrast-dark, gemini-material, trajectory-mono, gold-kawaii, and SoM. Unknown values fall back to codex-graphite with a load warning. Legacy [ui] theme is accepted when options.tui.theme is unset.
  • options.workspace_observerDefault on (nil-guard); when enabled, registers workspace_snapshot and shows a short Observer: hint in the TUI status bar (see workspace-observer.md). Set enabled = false to disable.
  • options.compaction.reaction_gate — required when any options.automation.rules enqueue_job action sets compaction_idle_gate. This is the gate for one automation-engine trigger path into compaction: the coordinator runs idle + dedupe preflight (internal/compaction/compose) before RunNow. Recent evaluations appear in the TUI /compaction inspector, a short Compaction: line on the status bar when the latest check denied enqueue, and the Agent Debugger prompt trace segment compaction_reactions. Overview: Compaction (idle-gated). See 004-compaction-orchestration-seam.md (repository decision).
  • Provider/model/auth definitions (providers.*, models.*)
  • Adaptive orchestration internals beyond on/off: options.adaptive_orchestration.default.*, options.adaptive_orchestration.classifier.*, options.adaptive_orchestration.monitor.*
  • Integration and tooling surfaces such as mcp.*, lsp.*, and broader per-agent/tool policy tables not listed above
  • Staged workflow plan-phase copy: options.staged_workflow.plan_phase_prompt, plan_phase_prompt_path, optional project file .bmo/templates/staged_workflow_plan_phase.md, then the embedded default (see the contributor references in the implementation reference profile for the implementation-level precedence notes)

Each setting row shows one of these apply notes:

  • Applies immediately: takes effect right away in the current app process
  • Restarts agent runtime when idle: reloads the coordinator; if an agent is busy, BMO asks you to retry when idle
  • Applies on next app launch: value is saved now and used after restart

options.adaptive_orchestration.enabled is available in Settings → Advanced as Adaptive orchestration and applies immediately for new runs.

BMO config uses keyed tables for named things. Use [providers.<id>], [mcp.<id>], [lsp.<id>], and [agents.<id>]; reserve [[...]] arrays for repeating children such as a provider’s model list.

Use this shape when a repository only needs a local data directory and one model provider:

./bmo.toml
[options]
data_directory = ".bmo"
disable_provider_auto_update = false
[providers.anthropic]
type = "anthropic"
api_key = "${ANTHROPIC_API_KEY}"
[[providers.anthropic.models]]
id = "claude-sonnet-4-20250514"
name = "Claude Sonnet 4"

Use keyed integration tables for remote tools and local language servers:

[mcp.github]
type = "http"
url = "https://api.githubcopilot.com/mcp/"
auth = "github_cli"
[lsp.go]
command = "gopls"

auth = "github_cli" resolves gh auth token and attaches it as an Authorization bearer header for GitHub’s hosted MCP endpoint. Run gh auth login first, or set BMO_MCP_BEARER_TOKEN_GITHUB to inject the token without invoking gh.

Remote MCP servers that support OAuth can use BMO’s hosted Client ID Metadata Document by default:

[mcp.github]
type = "http"
url = "https://api.githubcopilot.com/mcp/"
auth = "oauth"

Build the binary with mcp_go_client_oauth for OAuth flows, for example task build:mcp:oauth. The default client metadata URL is https://instagrim-dev.github.io/bmo/oauth/bmo-mcp-client.json, with callback URL http://127.0.0.1:46895/callback.

If a server does not advertise Client ID Metadata Document support or dynamic client registration, configure a preregistered host-app client instead:

[mcp.github]
type = "http"
url = "https://api.githubcopilot.com/mcp/"
auth = "oauth"
auth_client_id = "$BMO_GITHUB_MCP_CLIENT_ID"
auth_client_secret = "$BMO_GITHUB_MCP_CLIENT_SECRET"

auth_client_metadata_url can override the hosted metadata URL. auth_client_secret uses normal config value resolution: $VAR, ${VAR}, and $(command) are expanded. Keep secrets out of checked-in config.

Agent-specific tools live under the agent table. Global tool policy lives under permissions or options.disabled_tools.

[agents.coder]
name = "Coder"
model = "large"
[agents.coder.tools]
allowed = ["view", "grep", "glob", "bash"]
[agents.task.delegation]
worktree_isolation = true
worktree_auto_remove = false

These options are useful to operators and safe to read before the generated field inventory.

Config surfaceDefault postureUse it whenDisable or constrain with
options.adaptive_orchestrationOn after runtime initializationYou want BMO to classify and tune run behavior from session signals.enabled = false; advanced fields live under default, classifier, and monitor.
options.prompt_enhancerOnYou want prompt context enrichment before model calls.enabled = false.
options.codebase_contextOnYou want metadata-only workspace snapshots for stale-aware prompt gating and bounded system appendages.enabled = false; set inject_in_prompt = false to keep capture without appendage; see Codebase Context Snapshots.
options.pruningOnYou want context trimming to protect long sessions.enabled = false.
options.auto_debugOnYou want bounded retry/debug loops after failures.enabled = false or lower retry counts.
options.session_mode_autoselectOnYou want BMO to pick a fitting session mode automatically.enabled = false.
options.workspace_observerOnYou want workspace_snapshot, checkpoint hints, bounded git/path summaries, prompt workspace hints, and TUI observer status.enabled = false; set include_in_prompt = false / include_resume_workspace_advisory_in_prompt = false for a slimmer prompt.
options.workspace_trailOnYou want bounded cross-session trail rows and workspace_trail.changed session events for shared-workspace friction.enabled = false; set partition_id for a stable shared scope, or omit it in local MCP mode to use BMO’s derived user/workspace partition.
options.workspace_strategy_memoryOnYou want BMO to reuse deterministic cross-session orchestration strategy signals in the same workspace.enabled = false for strategy-cold sessions.
options.health_followonsOnYou want bounded follow-on signals when token pressure is detected.enabled = false; enable spawn_agent only with explicit caps and allowlists.
options.history.redact_secretsOnYou want message content scanned and one-way redacted before SQLite persistence.Set redact_secrets = false only for controlled local debugging where raw history is acceptable.
options.privacyOff until configuredYou need to suppress requester identity or redact selected requester fields from prompts/persistence.Use suppress_requester_identity = true or redact_requester_fields = ["email"].
options.session_budgetUnlimitedYou want per-session cumulative input/output token ceilings and warning telemetry.Leave ceilings at 0 for unlimited, or set warn_at_percent lower for earlier warnings.

Advanced automation and collaboration options

Section titled “Advanced automation and collaboration options”

Keep these in config when you intentionally run background work, mesh calls, or stricter tool policy.

Config surfacePurposeNotes
options.meshEnables the Agent mesh and capability-based invoke_a2a routing.Configure enabled, registry_url, and allowed_capabilities.
options.automationCanonical structured automation engine.Use jobs for cron-backed work and rules for event-driven typed actions.
options.hooks.outcomes.*Shell callback hooks.This stays outside the structured automation engine.
options.disabled_toolsHides built-in tools globally.Prefer this for global policy; use agent-local allow/deny lists for role-specific policy.
options.mcp_client.tls.ca_bundle_pathAdds a PEM CA bundle for HTTP/SSE MCP clients.Use for corporate TLS interception or private internal CAs; it is global to MCP client transports.
options.change_contract_enabledRuns change-contract preflight after the first file mutation in a run.Defaults on; set false to disable. BMO_CHANGE_CONTRACT_ENABLED can override the environment.
permissions.allowed_toolsPre-approves permission prompts for named tools.Keep the allowlist narrow.
agents.<id>.tools.allowed / agents.<id>.tools.disabledShapes one agent’s tool set.Use this when a role should be stricter than the global policy.

Use options.automation.jobs for cron-backed recipes and options.automation.rules for event-driven typed actions. Removed public surfaces such as options.reactions, options.activations, and feature-specific managed schedule wrappers now fail config loading with actionable migration errors instead of silently translating into automation.

The user path above is intentionally short. Implementation details live in the maintainer references:

ReferenceWhen to read it
Workspace observerWorkspace snapshot JSON, prompt appendages, path probing, persistence status, and environment fields.
Automation reactionsInternal event dispatch semantics and the merge checklist for new automation events.
Activation graphInternal activation routing and nested workflow behavior.
SchedulerCron-backed automation jobs and scheduler execution.
Health spawn monitor boundariesToken-pressure follow-ons and guarded spawn-agent behavior.

BMO still normalizes several sectioned aliases into the canonical runtime fields. The main ones are:

  • [context]
  • [workflow]
  • [memory]
  • [ui]
  • [integrations]
  • [debug_config]
  • [telemetry_config]
  • [experimental]
  • [backends]
  • [teams_config]
  • [tools_config]
  • [permissions_config]

These remain supported for compatibility, but new configs and examples should prefer canonical fields such as [options], [providers.<id>], [mcp.<id>], [lsp.<id>], [agents.<id>], [permissions], and [options.automation].

For sectioned compatibility aliases that normalize list/map values into canonical fields, an explicit empty value means clear the inherited effective value. For example, [context] paths = [] clears inherited/default options.context_paths; [context] skills_paths = [], [tools_config] disabled_tools = [], [workflow] build_budget_presets = [], and empty [permissions_config] collections follow the same presence-aware rule. Omitting the field preserves inherited values.

For prompt context features specifically, prefer [options.prompt_enhancer] and [options.context_retriever]. The matching [context.*] tables still normalize correctly, but they are compatibility aliases rather than the preferred public surface.

For automation specifically, a top-level [automation] table is also accepted as a compatibility alias and normalizes to [options.automation].

Use provider IDs as map keys under [providers.<id>]:

[providers.local-openai]
type = "openai-compat"
base_url = "http://localhost:11434/v1"
api_key = "dummy"

Ollama is first-class as a local Anthropic-compatible coding-agent provider. Install models with ollama pull ... before selecting them in BMO. For Codex/Claude Code-style local coding use, prefer models with at least a 64k context window. Discover installed Ollama models with:

Terminal window
bmo models discover ollama

Discovery reads Ollama’s /v1/models endpoint and enriches rows with best-effort /api/show metadata such as native context length when the daemon exposes it.

[providers.ollama]
type = "anthropic"
base_url = "http://localhost:11434"
[[providers.ollama.models]]
id = "qwen2.5-coder:1.5b"
name = "Qwen2.5 Coder 1.5B via Ollama"
context_window = 32768
[models.large]
provider = "ollama"
model = "qwen2.5-coder:1.5b"

OpenAI-compatible provider profiles can also target hosted gateways. Examples below are config-only support: model rows, provider routing headers, and deployment readiness remain operator-owned until provider-specific regression coverage proves first-class behavior.

[providers.nanogpt]
type = "openai-compat"
base_url = "https://nano-gpt.com/api/v1"
api_key = "${NANOGPT_API_KEY}"
[providers.nanogpt.extra_headers]
X-Provider = "novita"
[[providers.nanogpt.models]]
id = "openai/gpt-5.2"
name = "GPT-5.2 via NanoGPT"
[providers.nim]
type = "openai-compat"
base_url = "https://integrate.api.nvidia.com/v1"
api_key = "${NVIDIA_API_KEY}"
[[providers.nim.models]]
id = "nvidia/llama-3.3-nemotron-super-49b-v1"
name = "Llama 3.3 Nemotron Super 49B"

For self-hosted NIM, point base_url at the deployment’s /v1 endpoint and list the models loaded by that deployment. Loopback or private deployments can omit api_key when the endpoint does not require auth; use api_key = "dummy" when a local OpenAI-compatible server expects a non-empty bearer value.

To inspect loaded NIM models and the readiness endpoint, run:

Terminal window
bmo models discover openai-compat --profile nim
bmo models discover openai-compat --profile nim --base-url http://localhost:8000/v1 --api-key ""

CLI and passthrough providers are also configured under [providers.<id>]. They run an external agent process, so BMO’s normal approval and sandbox rules do not apply inside that child process.

bmo serve-mcp reads options.mcp_server from config:

[options.mcp_server]
enabled = true
transport = "stdio"
allowed_roots = ["."]
[options.mcp_server.http]
identity_header = "X-Authenticated-User"
trusted_proxies = ["127.0.0.1"]

Use transport = "http" only behind a trusted reverse proxy. In that mode, identity_header and trusted_proxies are required.

options.codebase_context gates metadata-only workspace snapshots for prompt integrity. The feature is default-on; explicit enabled = false disables snapshot walks during prompt preparation.

[options.codebase_context]
enabled = true
inject_in_prompt = true
stale_policy = "suppress_risky"
min_refresh_interval_seconds = 30
strict_on_child_spawn = false
OptionDefaultDescription
enabledtrueBuild and diff snapshots during prompt preparation
inject_in_prompttrueInclude bounded codebase_context system appendage when capture exists
stale_policysuppress_riskywarn_only or suppress_risky stale handling for risky user-message injections
min_refresh_interval_seconds30Throttle auxiliary walks (describe_context refresh); prompt prep still walks each user turn
strict_on_child_spawnfalseFail spawn_agent when snapshot is stale

See Codebase Context Snapshots for Activity-row messages, describe_context refresh, and cost notes.

learning.shadow enables opt-in capture and replay of eligible real runs:

[learning.shadow]
enabled = true
capture_top_level_runs = true
sample_rate = 1.0
retention_days = 30
max_capture_bytes = 1048576
[[learning.shadow.variants]]
name = "candidate-sonnet"
model = "anthropic/claude-sonnet-4-20250514"
prompt_prefix = "Prefer concise code-review style output."
agent = "coder"
OptionDefaultDescription
enabledfalseTurn on the shadow capture and replay worker
capture_top_level_runstrueCapture eligible top-level app runs for replay
sample_rate1.0Fraction of eligible runs to capture
retention_days30Retention window for artifacts, runs, and scorecards; worker purges older artifacts automatically
max_capture_bytes1048576Maximum captured snapshot bytes per artifact
allow_repos(empty)If set, only capture when working dir path matches one of these prefixes
deny_repos(empty)If set, do not capture when working dir path matches any of these prefixes
allow_sessions(empty)If set, only capture when session ID matches one of these (exact or prefix)
deny_sessions(empty)If set, do not capture when session ID matches any of these
allow_task_classes(empty)If set, only capture when task class is in this list (e.g. coding, review)
deny_task_classes(empty)If set, do not capture when task class is in this list
[[learning.shadow.variants]]noneOne replay candidate per table entry

Capture scope: when an allow list is non-empty, the run must match it; when a deny list is non-empty, the run must not match. All applicable lists must pass. Artifacts and runs can be deleted manually via bmo eval shadow delete or the HTTP DELETE endpoints; bmo eval shadow purge --retention-days N triggers a one-off TTL purge.

Variant fields:

FieldDescription
nameStable variant name used in listings and exports
modelModel override for the replay run
prompt_prefixAdditional system prompt prefix for that variant
agentOptional agent override such as coder or task

Shadow capture is fail-closed. If BMO cannot capture a replayable artifact with prompt trace, safe file snapshots, and an in-scope working directory, it stores the artifact as non-replayable and does not queue replay runs.

See Shadow Evals for behavior, CLI usage, API surfaces, and proposals and promoted assets (review, decide, promote, rollback).

Suggested edits ([options.suggested_edits])

Section titled “Suggested edits ([options.suggested_edits])”

options.suggested_edits controls how the ripple-backed analyze_ripple_impact flow (and the embedded suggested-edits path inside edit / multiedit) handles the case where ripple analysis is unavailable — for example because no LSP client is configured for the source file’s language.

[options.suggested_edits]
mode = "advisory" # or "required"
OptionTypeDefaultValuesEffect
modestring"advisory"advisory | requiredWhen advisory, ripple-unavailable paths log ripple.action action="unavailable_advisory" at info and the agent still proceeds. When required, the same paths log unavailable_required at warn and the embedded suggested-edits flow surfaces a warning rather than silently dropping suggestions.

The structure is intentionally narrow today — the only field is mode. Caps (max_symbols_per_file, max_affected_files, max_rename_map_entries) and the analyzer timeout are compile-time constants in internal/ripple/; their effective values are surfaced via bmo config show-ripple and /ripple so operators can verify the runtime posture without reading source.

See Ripple Edits for the four triggers, the ripple.fired / ripple.action event schema, and the operator surfaces.

File primitives (view, edit, write, multiedit) emit file_tool.fired / file_tool.action into a process-scoped ring; operators inspect them via bmo config show-file-tools, /files, and list_recent_file_tool_events. See File Tools Telemetry.

Arena compares several models on the same prompt. Optional auto-select can accept a winner when a standalone round completes (disabled for active multi-step arena workflows).

[options.arena]
enabled = true
# auto_select_policy = "off" # off | first_passing | lowest_cost | lowest_latency | eval_shadow
# auto_select_min_passing = 1
OptionDefaultDescription
auto_select_policyofffirst_passing, lowest_cost, and lowest_latency use on-round metrics. eval_shadow ranks eligible candidates using shadow eval scorecards tied to the same session and arena user message (see Shadow Evals).
auto_select_min_passing1Minimum acceptable candidates; for eval_shadow, at least this many must also have matching scorecards.

Full arena behavior (verified mode, TUI keys, HTTP/MCP) lives in arena-verified.md.

  • docs/config.reference.toml in the repo is the exhaustive generated TOML reference
  • schema.json is generated from the runtime config structs
  • bmo config list shows curated config keys at runtime

For examples of specific subsystems, see:

Config precedence stack
Lowest
Built-in defaultsDefault-on and default-off behavior from code.
Global
Global config directoryUser-wide defaults such as providers, model choices, and preferred options.
Data
Runtime data directoryDatabases, logs, caches, generated model metadata, and local runtime state.
Project
Project-local configRepo-specific policy, tools, MCPs, schedules, and workflow posture.
Runtime
Environment and explicit runtime controlsCredentials, CI overrides, and temporary shell-specific values.
When behavior surprises you, inspect the highest layer that could have supplied the value before changing lower layers.