# Octomind Config

> Field-by-field reference for octomind's config.toml: root settings, performance and spending limits, [capabilities] and [taps] overrides, [[roles]] and [roles.mcp], [mcp] servers (builtin/http/stdio), [[hooks]], [[layers]], [[commands]], [[agents]], [[prompts]], [skills], [compression], [registry], multi-file merge, and template variables. Activate when a user asks how to configure, tune, validate, or upgrade octomind, add a role or MCP server, set limits or spending caps, or debug a config parse error.

- Skill: `muvon/octomind-config` (Agent Skill)
- Install (CLI): `npx skillmds@latest add muvon/octomind-config`
- Raw SKILL.md: https://api.skillmd.com/api/skills/muvon/octomind-config/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: Apache-2.0
- Author: Muvon (https://skillmd.com/u/muvon)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/muvon/octomind-config

---


## Overview

Octomind's configuration lives at `~/.local/share/octomind/config/config.toml` (`%LOCALAPPDATA%\octomind\config\config.toml` on Windows), overridable with `OCTOMIND_CONFIG_PATH`. This skill documents every section and field, so config answers cite real field names and defaults rather than plausible-sounding ones.

Supervisor tuning has its own skill (`octomind-supervisor`); this one covers everything else in the file.

## Mental model

The file has three kinds of section, and they fail differently:

- Scalars with defaults — omit them and you get the default.
- Strict sections — `[supervisor]` and its required keys are a hard parse error when missing. Octomind owns that schema and fails loudly instead of degrading silently.
- Required-field tables — `[[layers]]` and `[[commands]]` require `input_mode`, `output_mode`, and `output_role`; omitting any fails config loading.

So a config error is usually a missing required key, not a wrong value. Validate after every edit: `octomind config --validate`. Never modify `version` — it drives `--upgrade`.

## Rules

### Root-level settings

| Field | Type | Default | Meaning |
|-------|------|---------|---------|
| `version` | u32 | template ships `8` | Schema version. Do not modify. |
| `log_level` | string | `"info"` | `none`, `info`, `debug` |
| `model` | string | `"octohub:auto"` | Default model, `provider:model` |
| `default` | string | `"assistant:concierge"` | Default TAG for `run`/`acp`/`server` |
| `max_tokens` | u32 | `32768` | Global max tokens |
| `sandbox` | bool | `false` | Restrict writes to CWD; Linux Landlock 5.13+, macOS Seatbelt |
| `telemetry` | bool | `true` | Anonymous usage counts; never code, prompts, or paths |
| `auto_capabilities` | bool | `true` | Automatic capability activation on user messages |
| `system` | string | none | Legacy global system-prompt fallback; prefer per-role `system` |

`default = "assistant:concierge"` is a tap agent from the built-in tap, not a role in this file — searching for a `concierge` role finds nothing. A bare tag without a colon resolves against `[[roles]]`; `category:variant` resolves against taps.

### Performance and limits

| Field | Default | Meaning |
|-------|---------|---------|
| `mcp_response_tokens_threshold` | `20000` | Hard truncation ceiling for MCP responses; `0` = unlimited |
| `max_session_tokens_threshold` | `200000` | Session ceiling, also the hard compression ceiling; validation fails above 2,000,000 |
| `max_retries` | `1` | API retry attempts |
| `retry_timeout` | `30` | Exponential-backoff base, seconds |
| `request_timeout_seconds` | `300` | Per-request HTTP timeout; `0` = none |
| `reasoning_effort` | `"medium"` | `low`/`medium`/`high`/`xhigh`/`max`; ignored by non-thinking models |
| `cache_keepalive_enabled` | `false` | Idle cache pings; provider-aware, currently Anthropic only |
| `cache_keepalive_max_idle_seconds` | `1800` | Stop pinging after this idle time; validation fails above 86400 |

### User interface and spending

`enable_markdown_rendering` (`true`), `markdown_theme` (`default`, `dark`, `light`, `ocean`, `solarized`, `monokai`), `max_session_spending_threshold` and `max_request_spending_threshold` (USD, `0.0` = no limit). Session threshold prompts before continuing; request threshold stops execution.

### `[capabilities]` and `[taps]`

```toml
[capabilities]
codesearch = "octocode"        # picks capabilities/codesearch/octocode.toml

[taps]
"developer:general" = "ollama:glm-5"
```

`[capabilities]` routes a capability name to a non-default provider. `[taps]` sets a model per tap agent, acting at the `config.model` tier — it applies only when neither `--model` nor the agent's own role model is set, and only to tags containing a colon.

### `[[roles]]`

Fields: `name` (required), `model`, `system`, `welcome`, `temperature` (0.0–2.0), `top_p` (0.0–1.0), `top_k` (1–1000). Roles in config override tap-provided agents of the same name.

```toml
[[roles]]
name = "assistant"
temperature = 0.3
system = "You are a helpful assistant. Working directory: {{CWD}}"

[roles.mcp]
server_refs = ["core", "runtime", "filesystem", "agent"]
allowed_tools = ["core:*", "runtime:*"]
```

`[roles.mcp].server_refs` lists servers to enable; `allowed_tools` filters them, empty meaning all, wildcards supported.

### `[mcp]` and `[[mcp.servers]]`

`[mcp].allowed_tools` is a global fallback used when a role does not specify its own.

Builtin servers need no process: `core` (`recall`), `orchestration` (`tap`, `schedule`, `monitor`), `runtime` (`mcp`, `agent`, `skill`, `capability`), `agent` (one `agent_<name>` tool per `[[agents]]` entry). The `filesystem` server that default roles reference is not a builtin — it is an external stdio server backed by `octofs`, supplied by the built-in tap, exposing `view`, `text_editor`, `batch_edit`, `extract_lines`, `shell`, `workdir`.

Common server fields: `name`, `type` (`builtin`|`http`|`stdio`), `timeout_seconds` (required; per-operation, reset by tool-call progress), `tools` (filter, wildcards ok), `auto_bind` (role names to auto-include for). HTTP adds `url` (required) and `headers` (values support `{{ENV:KEY}}`). Stdio adds `command` (required) and `args`.

Authentication: a static `Authorization` header carries a bearer token and disables OAuth discovery. Without one, Octomind uses MCP Authorization Discovery (RFC 9728), registers via CIMD/DCR, and authenticates with PKCE.

### `[[hooks]]`

Webhook listeners: `name`, `bind` (e.g. `"0.0.0.0:9876"`), `script`, `timeout` (default 30, range 1–3600). Activate with `octomind run --daemon --hook <name>`.

### `[[layers]]`, `[[commands]]`, `[[agents]]`, `[[prompts]]`

`[[layers]]` and `[[commands]]` share one schema: `name`, `description`, `command` (`"octomind acp <role>"`), `input_mode` (`last`|`all`|`summary`), `output_mode` (`none`|`append`|`replace`|`last`|`restart`), `output_role` (`assistant`|`user`), and optional `workdir`. The three modes have no defaults — omitting any fails loading. Model and prompt live in the referenced `[[roles]]` entry, never in the layer. Layers are ACP orchestration units; commands are typed as `/run <name>`.

Multi-step AI pipelines are not config — they are `octomind workflow <file.toml>`.

`[[agents]]`: `name`, `description`, `command`, optional `workdir`. Each becomes an MCP tool `agent_<name>`.

`[[prompts]]`: `name`, `description`, `prompt`. Injected verbatim via `/prompt <name>`; no variable substitution.

### `[skills]`

`auto_activation` (`true`) evaluates declarative rules on every user message. `auto_validation` (`false`) runs skill `validate` scripts at end of turn — it gates only SKILL.md validators, not guardrail `[[validator]]` entries, which always run. Also `activation_timeout` (reserved), `validation_timeout` (`60`, `0` = unlimited), `max_retries` (`3`).

### `[compression]`

`knowledge_retention` (`25`), `analysis_findings_max_tokens` (`6000`, `0` disables), `threshold` (`70000` absolute tokens, `0` disables). Depth is computed, not configured: once past `threshold`, the ratio derives per cycle from measured growth and the context ceiling, always landing in [2.0, 16.0].

`[compression.decision]` picks the model doing the work: `model` (`openai:gpt-5-mini`), `max_tokens` (`16000`), `temperature` (`0.3`), `top_p`, `top_k`, `max_retries`, `retry_timeout`. Cheap and fast is the right choice.

### `[registry]`

`cache_ttl_hours` (`24`) governs tap manifest caching. Within the TTL the cache is served; once stale, the cached copy is still served while a background refresh runs.

### Multi-file configuration

All `*.toml` in the config directory merge: `config.toml` first, then others alphabetically, with arrays of tables concatenated, same-name entries deduplicated (last wins), and scalars overridden by later files. Files matching `mcp-*.toml` load last regardless of alphabetical order, so they reliably override servers defined in `mcp.toml`. The `mcp persist` command relies on this, writing `<config_dir>/mcp-<name>.toml` with `auto_bind`.

### Template variables

Substituted in role `system` and `welcome` at prompt-expansion time: `{{CWD}}`, `{{ROLE}}`, `{{DATE}}`, `{{SHELL}}`, `{{OS}}`, `{{BINARIES}}`, `{{GIT_STATUS}}`, `{{GIT_TREE}}`, `{{README}}`, plus `{{CONTEXT}}` and `{{SYSTEM}}` for layers. `{{HOME}}` is not substituted in prompts — it only appears in the `octomind vars` listing, so it stays literal in a role prompt. Use an absolute path or `{{CWD}}`.

## Examples

### Example 1: layer missing required modes

❌ Bad:
```toml
[[layers]]
name = "task_refiner"
description = "Refines requests"
command = "octomind acp task_refiner"
```

✅ Good:
```toml
[[layers]]
name = "task_refiner"
description = "Refines requests"
command = "octomind acp task_refiner"
input_mode = "last"
output_mode = "none"
output_role = "assistant"
```

What changed: the three mode fields have no defaults — the first version fails config loading outright.

### Example 2: model and prompt in the wrong place

❌ Bad:
```toml
[[layers]]
name = "reduce"
model = "openai:gpt-5-mini"
system = "Compress the transcript."
```

✅ Good:
```toml
[[roles]]
name = "reduce"
model = "openai:gpt-5-mini"
system = "Compress the transcript."

[[commands]]
name = "reduce"
description = "Compress session history"
command = "octomind acp reduce"
input_mode = "all"
output_mode = "replace"
output_role = "assistant"
```

What changed: layers delegate over ACP; model, prompt, and MCP config belong to the role the command references.

### Example 3: overriding a server from a separate file

Put the override in `mcp-github.toml`, not `zz-github.toml`. Only the `mcp-*.toml` prefix guarantees loading after `mcp.toml`; any other name risks being overwritten by alphabetical order.

## Checklist

- [ ] `octomind config --validate` run after the edit and passing?
- [ ] `version` left untouched?
- [ ] Every `[[layers]]`/`[[commands]]` entry has `input_mode`, `output_mode`, `output_role`?
- [ ] Every `[[mcp.servers]]` has `timeout_seconds`, plus `url` for http or `command` for stdio?
- [ ] `server_refs` names resolve to a builtin, a tap-provided server, or a declared `[[mcp.servers]]`?
- [ ] No API key written into the file — environment or `.env` instead?
- [ ] Override files that must win named `mcp-*.toml`?
- [ ] Model, system prompt, and MCP config placed in `[[roles]]`, not in a layer or command?

## Composition / References

- Pairs with `octomind-cli` for the `octomind config` flags that mutate this file.
- Pairs with `octomind-supervisor` for `[supervisor]`, which is strict and documented separately.
- Pairs with `octomind-runtime` for how capabilities and taps resolve into a role's tool surface.
- Octomind docs: `doc/reference/03-config-reference.md`, `config-templates/default.toml`, `doc/usage/03-configuration.md`, `doc/usage/06-roles.md`, `doc/usage/10-commands-and-layers.md`

