mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
e45a9460ce
* docs: repair spellcheck and anchor drift * docs: satisfy markdown anchor lint
1497 lines
81 KiB
Markdown
1497 lines
81 KiB
Markdown
---
|
|
summary: "Agent defaults, multi-agent routing, session, messages, and talk config"
|
|
read_when:
|
|
- Tuning agent defaults (models, thinking, workspace, heartbeat, media, skills)
|
|
- Configuring multi-agent routing and bindings
|
|
- Adjusting session, message delivery, and talk-mode behavior
|
|
title: "Configuration — agents"
|
|
---
|
|
|
|
Agent-scoped configuration keys under `agents.*`, `multiAgent.*`, `session.*`,
|
|
`messages.*`, and `talk.*`. For channels, tools, gateway runtime, and other
|
|
top-level keys, see [Configuration reference](/gateway/configuration-reference).
|
|
|
|
OpenClaw stamps `agents.ownership: "explicit"` when creating a multi-agent fleet. Such fleets have no default: channels and ambient services need bindings or surface-specific `agentId` targets. Doctor materializes legacy owners during upgrade; sole-agent configs need no marker.
|
|
|
|
## Agent defaults
|
|
|
|
### `agents.defaults.workspace`
|
|
|
|
Default: `OPENCLAW_WORKSPACE_DIR` when set, otherwise `~/.openclaw/workspace` (or `~/.openclaw/workspace-<profile>` when `OPENCLAW_PROFILE` is set to a non-default profile).
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { workspace: "~/.openclaw/workspace" } },
|
|
}
|
|
```
|
|
|
|
An explicit `agents.defaults.workspace` value takes precedence over `OPENCLAW_WORKSPACE_DIR`. A sole agent uses this path directly. In a multi-agent fleet, agents without their own `workspace` use an agent-id subdirectory so no implicit owner claims the shared root.
|
|
|
|
### `agents.defaults.repoRoot`
|
|
|
|
Optional repository root shown in the system prompt's Runtime line. If unset, OpenClaw auto-detects by walking upward from the workspace.
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { repoRoot: "~/Projects/openclaw" } },
|
|
}
|
|
```
|
|
|
|
### `agents.defaults.skills`
|
|
|
|
Optional default skill allowlist for agents that do not set
|
|
`agents.entries.*.skills`.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
ownership: "explicit",
|
|
defaults: { skills: ["github", "weather"] },
|
|
entries: {
|
|
writer: {}, // inherits github, weather
|
|
docs: { skills: ["docs-search"] }, // replaces defaults
|
|
"locked-down": { skills: [] }, // no skills
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- Omit `agents.defaults.skills` for unrestricted skills by default.
|
|
- Omit `agents.entries.*.skills` to inherit the defaults.
|
|
- Set `agents.entries.*.skills: []` for no skills.
|
|
- A non-empty `agents.entries.*.skills` list is the final set for that agent; it
|
|
does not merge with defaults.
|
|
|
|
### `agents.defaults.skipBootstrap`
|
|
|
|
Disables automatic creation of workspace bootstrap files (`AGENTS.md`, `SOUL.md`, `IDENTITY.md`, `USER.md`, `BOOTSTRAP.md`).
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { skipBootstrap: true } },
|
|
}
|
|
```
|
|
|
|
### `agents.defaults.skipOptionalBootstrapFiles`
|
|
|
|
Skips creation of selected optional workspace files while still writing required bootstrap files (`AGENTS.md`, `BOOTSTRAP.md`). Valid values: `SOUL.md`, `USER.md`, and `IDENTITY.md` (`HEARTBEAT.md` is accepted but a no-op since heartbeat context moved to cron monitor scratch).
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
skipOptionalBootstrapFiles: ["SOUL.md", "USER.md"],
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
### `agents.defaults.contextInjection`
|
|
|
|
Controls when workspace bootstrap files are injected into the system prompt. Default: `"always"`.
|
|
|
|
- `"continuation-skip"`: safe continuation turns (after a completed assistant response) skip workspace bootstrap re-injection, reducing prompt size. Heartbeat runs and post-compaction retries still rebuild context.
|
|
- `"never"`: disable workspace bootstrap and context-file injection on every turn. Use this only for agents that fully own their prompt lifecycle (custom context engines, native runtimes that build their own context, or specialized bootstrap-free workflows). Heartbeat and compaction-recovery turns also skip injection.
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { contextInjection: "continuation-skip" } },
|
|
}
|
|
```
|
|
|
|
Per-agent override: `agents.entries.*.contextInjection`. Omitted values inherit
|
|
`agents.defaults.contextInjection`.
|
|
|
|
### `agents.defaults.bootstrapMaxChars`
|
|
|
|
Max characters per workspace bootstrap file before truncation. Default: `20000`.
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { bootstrapMaxChars: 20000 } },
|
|
}
|
|
```
|
|
|
|
Per-agent override: `agents.entries.*.bootstrapMaxChars`. Omitted values inherit
|
|
`agents.defaults.bootstrapMaxChars`.
|
|
|
|
### `agents.defaults.bootstrapTotalMaxChars`
|
|
|
|
Max total characters injected across all workspace bootstrap files. Default: `60000`.
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { bootstrapTotalMaxChars: 60000 } },
|
|
}
|
|
```
|
|
|
|
Per-agent override: `agents.entries.*.bootstrapTotalMaxChars`. Omitted values
|
|
inherit `agents.defaults.bootstrapTotalMaxChars`.
|
|
|
|
### Per-agent bootstrap profile overrides
|
|
|
|
Use per-agent bootstrap profile overrides when one agent needs different prompt
|
|
injection behavior from the shared defaults. Omitted fields inherit from
|
|
`agents.defaults`.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
contextInjection: "continuation-skip",
|
|
bootstrapMaxChars: 20000,
|
|
bootstrapTotalMaxChars: 60000,
|
|
},
|
|
entries: {
|
|
"strict-worker": {
|
|
contextInjection: "always",
|
|
bootstrapMaxChars: 50000,
|
|
bootstrapTotalMaxChars: 300000,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
### Bootstrap truncation notice
|
|
|
|
When bootstrap context is truncated, OpenClaw always injects a concise
|
|
agent-visible notice into the system prompt saying some bootstrap files were
|
|
truncated and to read the affected files directly. This notice is built in
|
|
and not configurable, and it deliberately omits per-file diagnostics: file
|
|
names, raw vs injected counts, and limit causes stay in diagnostics such as
|
|
context/status reports and logs.
|
|
|
|
### Context budget ownership map
|
|
|
|
OpenClaw has multiple high-volume prompt/context budgets, and they are
|
|
intentionally split by subsystem instead of all flowing through one generic
|
|
knob.
|
|
|
|
| Budget | Covers |
|
|
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `agents.defaults.bootstrapMaxChars` / `bootstrapTotalMaxChars` | Normal workspace bootstrap injection |
|
|
| `agents.defaults.startupContext.*` | One-shot reset/startup model-run prelude, including recent daily `memory/*.md` files. Bare chat `/new` and `/reset` are acknowledged without invoking the model |
|
|
| `skills.limits.*` | The compact skills list injected into the system prompt |
|
|
| `agents.defaults.contextLimits.*` | Bounded runtime excerpts and injected runtime-owned blocks |
|
|
|
|
Matching per-agent overrides:
|
|
|
|
- `agents.entries.*.skillsLimits.maxSkillsPromptChars`
|
|
- `agents.entries.*.contextInjection`
|
|
- `agents.entries.*.bootstrapMaxChars`
|
|
- `agents.entries.*.bootstrapTotalMaxChars`
|
|
- `agents.entries.*.contextLimits.*`
|
|
|
|
#### `agents.defaults.startupContext`
|
|
|
|
Controls the first-turn startup prelude injected on reset/startup model runs.
|
|
Bare chat `/new` and `/reset` commands acknowledge the reset without invoking
|
|
the model, so they do not load this prelude.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
startupContext: {
|
|
enabled: true,
|
|
applyOn: ["new", "reset"],
|
|
dailyMemoryDays: 2,
|
|
maxFileBytes: 16384,
|
|
maxFileChars: 1200,
|
|
maxTotalChars: 2800,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
#### `agents.defaults.contextLimits`
|
|
|
|
Shared defaults for bounded runtime context surfaces.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
contextLimits: {
|
|
memoryGetMaxChars: 12000,
|
|
postCompactionMaxChars: 1800,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- `memoryGetMaxChars`: default `memory_get` excerpt cap before truncation
|
|
metadata and continuation notice are added.
|
|
- When `memory_get` omits `lines`, OpenClaw uses a built-in 120-line window and
|
|
then applies `memoryGetMaxChars`.
|
|
- Live tool results use a model-context auto cap: `16000` chars below 100K
|
|
tokens, `32000` chars at 100K+ tokens, and `64000` chars at 200K+ tokens.
|
|
- `postCompactionMaxChars`: AGENTS.md excerpt cap used during post-compaction
|
|
refresh injection.
|
|
|
|
#### `agents.entries.*.contextLimits`
|
|
|
|
Per-agent override for the shared `contextLimits` knobs. Omitted fields inherit
|
|
from `agents.defaults.contextLimits`.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
contextLimits: { memoryGetMaxChars: 12000 },
|
|
},
|
|
entries: {
|
|
"tiny-local": {
|
|
contextLimits: {
|
|
memoryGetMaxChars: 6000,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
#### `skills.limits.maxSkillsPromptChars`
|
|
|
|
Global cap for the compact skills list injected into the system prompt. This
|
|
does not affect reading `SKILL.md` files on demand.
|
|
|
|
```json5
|
|
{
|
|
skills: { limits: { maxSkillsPromptChars: 18000 } },
|
|
}
|
|
```
|
|
|
|
#### `agents.entries.*.skillsLimits.maxSkillsPromptChars`
|
|
|
|
Per-agent override for the skills prompt budget.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
entries: {
|
|
"tiny-local": { skillsLimits: { maxSkillsPromptChars: 6000 } },
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
### `agents.defaults.imageMaxDimensionPx`
|
|
|
|
Max pixel size for the longest image side in transcript/tool image blocks before provider calls.
|
|
Default: `1200`.
|
|
|
|
Lower values usually reduce vision-token usage and request payload size for screenshot-heavy runs.
|
|
Higher values preserve more visual detail.
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { imageMaxDimensionPx: 1200 } },
|
|
}
|
|
```
|
|
|
|
### `agents.defaults.imageQuality`
|
|
|
|
Image-tool compression/detail preference for images loaded from file paths, URLs, and media references.
|
|
Default: `auto`.
|
|
|
|
OpenClaw adapts the resize ladder to the selected image model. For example, Claude Opus 4.8, OpenAI GPT-5.6 Sol, Qwen VL, and hosted Llama 4 vision models can use larger images than older/default high-detail vision paths, while multi-image turns are compressed more aggressively in `auto` mode to control token and latency cost.
|
|
|
|
Values:
|
|
|
|
- `auto`: adapt to model limits and image count.
|
|
- `efficient`: prefer smaller images for lower token and byte usage.
|
|
- `balanced`: use the standard middle-ground ladder.
|
|
- `high`: preserve more detail for screenshots, diagrams, and document images.
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { imageQuality: "auto" } },
|
|
}
|
|
```
|
|
|
|
### `agents.defaults.userTimezone`
|
|
|
|
Timezone for message envelopes, queued system events, and the system prompt's local
|
|
date context. Falls back to the host timezone.
|
|
|
|
```json5
|
|
{
|
|
agents: { defaults: { userTimezone: "America/Chicago" } },
|
|
}
|
|
```
|
|
|
|
### `agents.defaults.model`
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
models: {
|
|
"anthropic/claude-opus-4-6": { alias: "opus" },
|
|
"minimax/MiniMax-M2.7": { alias: "minimax" },
|
|
},
|
|
model: {
|
|
primary: "anthropic/claude-opus-4-6",
|
|
fallbacks: ["minimax/MiniMax-M2.7"],
|
|
},
|
|
utilityModel: "openai/gpt-5.4-mini",
|
|
imageModel: {
|
|
primary: "openrouter/qwen/qwen-2.5-vl-72b-instruct:free",
|
|
fallbacks: ["openrouter/google/gemini-2.0-flash-vision:free"],
|
|
},
|
|
mediaModels: {
|
|
image: {
|
|
primary: "openai/gpt-image-2",
|
|
fallbacks: ["google/gemini-3.1-flash-image"],
|
|
},
|
|
video: {
|
|
primary: "qwen/wan2.6-t2v",
|
|
fallbacks: ["qwen/wan2.6-i2v"],
|
|
},
|
|
},
|
|
pdfModel: {
|
|
primary: "anthropic/claude-opus-4-6",
|
|
fallbacks: ["openai/gpt-5.4-mini"],
|
|
},
|
|
params: { cacheRetention: "long" }, // global default provider params
|
|
pdfMaxMb: 10,
|
|
pdfMaxPages: 20,
|
|
thinkingDefault: "low",
|
|
fastModeDefault: false,
|
|
verboseDefault: "off",
|
|
toolProgressDetail: "explain",
|
|
reasoningDefault: "off",
|
|
elevatedDefault: "on",
|
|
timeoutSeconds: 600,
|
|
mediaMaxMb: 5,
|
|
contextTokens: 200000,
|
|
maxConcurrent: 4,
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- `model`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
|
- String form sets only the primary model.
|
|
- Object form sets primary plus ordered failover models.
|
|
- `utilityModel`: optional `provider/model` ref or alias for short internal tasks. It currently powers generated Control UI session titles, Telegram DM topic titles, Discord auto-thread titles, and [progress-draft narration](/concepts/progress-drafts#status-headline). When unset, OpenClaw derives the primary provider's declared small-model default when one exists (OpenAI → `gpt-5.6-luna`, Anthropic → `claude-haiku-4-5`); title tasks otherwise use the agent's primary model, and narration stays off. If a distinct utility model cannot prepare or complete a generated title, OpenClaw retries that title once with the primary model. For dashboard titles, automatic utility derivation and the regular fallback use the effective session provider and auth profile; an explicit utility model keeps its configured provider/auth. Set `utilityModel: ""` to skip the alternate utility route; dashboard title generation still proceeds directly to the regular session model. `agents.entries.*.utilityModel` overrides the default, and an operation-specific model override wins over both. Utility tasks make separate model calls and send task-specific content to the selected model provider. Dashboard title generation sends at most the first 1,000 characters of the first non-command message; narration sends the inbound request plus compact redacted tool summaries. Choose a provider that matches your cost and data-handling requirements.
|
|
- `imageModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
|
- Used by the `image` tool path as its vision-model config when the active model cannot accept images. Native-vision models receive loaded image bytes directly instead.
|
|
- Also used as fallback routing when the selected/default model cannot accept image input.
|
|
- Prefer explicit `provider/model` refs. Bare IDs are accepted for compatibility; if a bare ID uniquely matches a configured image-capable entry in `models.providers.*.models`, OpenClaw qualifies it to that provider. Ambiguous configured matches require an explicit provider prefix.
|
|
- `mediaModels.image`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
|
- Used by the shared image-generation capability and any future tool/plugin surface that generates images.
|
|
- Typical values: `google/gemini-3.1-flash-image` for native Gemini image generation, `fal/fal-ai/flux/dev` for fal, `openai/gpt-image-2` for OpenAI Images, or `openai/gpt-image-1.5` for transparent-background OpenAI PNG/WebP output.
|
|
- If you select a provider/model directly, configure matching provider auth too (for example `GEMINI_API_KEY` or `GOOGLE_API_KEY` for `google/*`, `OPENAI_API_KEY` or OpenAI Codex OAuth for `openai/gpt-image-2` / `openai/gpt-image-1.5`, `FAL_KEY` for `fal/*`).
|
|
- If omitted, `image_generate` can still infer an auth-backed provider default. It tries the current default provider first, then the remaining registered image-generation providers in provider-id order.
|
|
- `mediaModels.music`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
|
- Used by the shared music-generation capability and the built-in `music_generate` tool.
|
|
- Typical values: `google/lyria-3-clip-preview`, `google/lyria-3-pro-preview`, or `minimax/music-2.6`.
|
|
- If omitted, `music_generate` can still infer an auth-backed provider default. It tries the current default provider first, then the remaining registered music-generation providers in provider-id order.
|
|
- If you select a provider/model directly, configure the matching provider auth/API key too.
|
|
- `mediaModels.video`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
|
- Used by the shared video-generation capability and the built-in `video_generate` tool.
|
|
- Typical values: `qwen/wan2.6-t2v`, `qwen/wan2.6-i2v`, `qwen/wan2.6-r2v`, `qwen/wan2.6-r2v-flash`, or `qwen/wan2.7-r2v`.
|
|
- If omitted, `video_generate` can still infer an auth-backed provider default. It tries the current default provider first, then the remaining registered video-generation providers in provider-id order.
|
|
- If you select a provider/model directly, configure the matching provider auth/API key too.
|
|
- The official Qwen video-generation plugin supports up to 1 output video, 1 input image, 4 input videos, 10 seconds duration, and provider-level `size`, `aspectRatio`, `resolution`, `audio`, and `watermark` options.
|
|
- `pdfModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
|
|
- Used by the `pdf` tool for model routing.
|
|
- If omitted, the PDF tool falls back to `imageModel`, then to the resolved session/default model.
|
|
- `pdfMaxMb`: default PDF size limit for the `pdf` tool when `maxBytesMb` is not passed at call time.
|
|
- `pdfMaxPages`: default maximum pages considered by extraction fallback mode in the `pdf` tool.
|
|
- `fastModeDefault`: default fast mode for agents. Values: `"auto"`, `true`, `false`. Per-agent `agents.entries.*.fastModeDefault` overrides it when no per-message or session fast-mode override is set.
|
|
- `verboseDefault`: default verbose level for agents. Values: `"off"`, `"on"`, `"full"`. Default: `"off"`.
|
|
- `toolProgressDetail`: detail mode for `/verbose` tool summaries and progress-draft tool lines. Values: `"explain"` (default, compact human labels) or `"raw"` (append raw command/detail when available). Per-agent `agents.entries.*.toolProgressDetail` overrides this default.
|
|
- `reasoningDefault`: default reasoning visibility for agents. Values: `"off"`, `"on"`, `"stream"`. Per-agent `agents.entries.*.reasoningDefault` overrides this default. Configured reasoning defaults are only applied for owners, authorized senders, or operator-admin gateway contexts when no per-message or session reasoning override is set.
|
|
- `elevatedDefault`: default elevated-output level for agents. Values: `"off"`, `"on"`, `"ask"`, `"full"`. Default: `"on"`.
|
|
- `model.primary`: format `provider/model` (e.g. `openai/gpt-5.6-sol` for Codex OAuth access). If you omit the provider, OpenClaw tries an alias first, then a unique configured-provider match for that exact model id, and only then falls back to the configured default provider (deprecated compatibility behavior, so prefer explicit `provider/model`). If that provider no longer exposes the configured default model, OpenClaw falls back to the first configured provider/model instead of surfacing a stale removed-provider default.
|
|
- `contextTokens`: optional agent-wide cap. It can lower the effective budget of a larger model but cannot raise a model above its configured or discovered `contextTokens`. To opt one direct OpenAI model into its larger native window, set `models.providers.openai.models[].contextWindow` and `contextTokens` for that model; see [OpenAI context window defaults](/providers/openai#context-window-defaults-and-long-context-opt-in).
|
|
- `models`: configured aliases and per-model settings. Each entry can include `alias` (shortcut) and `params` (provider-specific, for example `temperature`, `maxTokens`, `cacheRetention`, `context1m`, `responsesServerCompaction`, `responsesCompactThreshold`, OpenRouter `provider` routing, `chat_template_kwargs`, `extra_body`/`extraBody`). Adding entries does not restrict model overrides.
|
|
- Use `provider/*` entries such as `"openai/*": {}` or `"vllm/*": {}` to show all discovered models for selected providers without manually listing every model id.
|
|
- Add `agentRuntime` to a `provider/*` entry when every dynamically discovered model for that provider should use the same runtime. Exact `provider/model` runtime policy still wins over the wildcard.
|
|
- Safe metadata edits: use `openclaw config set agents.defaults.models '<json>' --strict-json --merge` to add entries. `config set` refuses replacements that would remove existing entries unless you pass `--replace`.
|
|
- `modelPolicy.allow`: explicit override allowlist. Accepts aliases, exact `provider/model` refs, and trailing prefix wildcards such as `openai/*` or `clawrouter/anthropic/*`. Omit it or use `[]` to allow any model. `agents.entries.*.modelPolicy.allow` replaces the default policy for that agent; an explicit empty list opts that agent into allow-any.
|
|
- Provider-scoped configure/onboarding flows merge selected provider models into this map and preserve unrelated providers already configured.
|
|
- For direct OpenAI Responses models, server-side compaction is enabled automatically. Use `params.responsesServerCompaction: false` to stop injecting `context_management`, or `params.responsesCompactThreshold` to override the threshold. See [OpenAI server-side compaction](/providers/openai#advanced-configuration).
|
|
- `params`: global default provider parameters applied to all models. Set at `agents.defaults.params` (e.g. `{ cacheRetention: "long" }`).
|
|
- `params` merge precedence (config): `agents.defaults.params` (global base) is overridden by `agents.defaults.models["provider/model"].params` (per-model), then `agents.entries.*.params` (matching agent id) overrides by key. See [Prompt Caching](/reference/prompt-caching) for details.
|
|
- `models.providers.openrouter.params.provider`: OpenRouter-wide default provider-routing policy. OpenClaw forwards this to OpenRouter's request `provider` object; per-model `agents.defaults.models["openrouter/<model>"].params.provider` and agent params override by key. See [OpenRouter provider routing](/providers/openrouter#advanced-configuration).
|
|
- `params.extra_body`/`params.extraBody`: advanced pass-through JSON merged into `api: "openai-completions"` request bodies for OpenAI-compatible proxies. If it collides with generated request keys, the extra body wins; non-native completions routes still strip OpenAI-only `store` afterward.
|
|
- `params.chat_template_kwargs`: vLLM/OpenAI-compatible chat-template arguments merged into top-level `api: "openai-completions"` request bodies. For `vllm/nemotron-3-*` with thinking off, the bundled vLLM plugin automatically sends `enable_thinking: false` and `force_nonempty_content: true`; explicit `chat_template_kwargs` override generated defaults, and `extra_body.chat_template_kwargs` still has final precedence. Configured vLLM Qwen and Nemotron thinking models expose binary `/think` choices (`off`, `on`) instead of the multi-level effort ladder.
|
|
- `compat.thinkingFormat`: OpenAI-compatible thinking payload style. Use `"together"` for Together-style `reasoning.enabled`, `"qwen"` for Qwen-style top-level `enable_thinking`, or `"qwen-chat-template"` for `chat_template_kwargs.enable_thinking` on Qwen-family backends that support request-level chat-template kwargs, such as vLLM. OpenClaw maps disabled thinking to `false` and enabled thinking to `true`, and configured vLLM Qwen models expose binary `/think` choices for these formats.
|
|
- `compat.supportedReasoningEfforts`: per-model OpenAI-compatible reasoning effort list. Include `"xhigh"` for custom endpoints that truly accept it; OpenClaw then exposes `/think xhigh` in command menus, Gateway session rows, session patch validation, agent CLI validation, and `llm-task` validation for that configured provider/model. Use `compat.reasoningEffortMap` when the backend wants a provider-specific value for a canonical level.
|
|
- `params.preserveThinking`: Z.AI-only opt-in for preserved thinking. When enabled and thinking is on, OpenClaw sends `thinking.clear_thinking: false` and replays prior `reasoning_content`; see [Z.AI thinking and preserved thinking](/providers/zai#advanced-configuration).
|
|
- `localService`: optional provider-level process manager for local/self-hosted model servers. When the selected model belongs to that provider, OpenClaw probes `healthUrl` (or `baseUrl + "/models"`), starts `command` with `args` if the endpoint is down, waits up to `readyTimeoutMs`, then sends the model request. `command` must be an absolute path. `idleStopMs: 0` keeps the process alive until OpenClaw exits; a positive value stops the OpenClaw-spawned process after that many idle milliseconds. See [Local model services](/gateway/local-model-services).
|
|
- Runtime policy belongs on providers or models, not on `agents.defaults`. Use `models.providers.<provider>.agentRuntime` for provider-wide rules or `agents.defaults.models["provider/model"].agentRuntime` / `agents.entries.*.models["provider/model"].agentRuntime` for model-specific rules. A provider/model prefix alone never selects a harness. With runtime unset or `auto`, OpenAI may select Codex implicitly only for an exact official HTTPS Platform Responses or ChatGPT Responses route with no authored request override. See [OpenAI implicit agent runtime](/providers/openai#implicit-agent-runtime).
|
|
- Config writers that mutate these fields (for example `/models set`, `/models set-image`, and fallback add/remove commands) save canonical object form and preserve existing fallback lists when possible.
|
|
- `maxConcurrent`: max parallel agent runs across sessions (each session still serialized). By default, OpenClaw uses `min(16, max(8, available CPU parallelism))`, based on `os.availableParallelism()` with `os.cpus().length` as a fallback.
|
|
|
|
### Runtime policy
|
|
|
|
```json5
|
|
{
|
|
models: {
|
|
providers: {
|
|
openai: {
|
|
agentRuntime: { id: "codex" },
|
|
},
|
|
},
|
|
},
|
|
agents: {
|
|
defaults: {
|
|
model: "openai/gpt-5.6-sol",
|
|
models: {
|
|
"anthropic/claude-opus-5": {
|
|
agentRuntime: { id: "claude-cli" },
|
|
},
|
|
"vllm/*": {
|
|
agentRuntime: { id: "openclaw" },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- `id`: `"auto"`, `"openclaw"`, a registered plugin harness id, or a supported CLI backend alias. The bundled Codex plugin registers `codex`; the bundled Anthropic plugin provides the `claude-cli` CLI backend.
|
|
- `id: "auto"` lets registered plugin harnesses claim effective routes that declare or otherwise satisfy their support contract, and uses OpenClaw when no harness matches. An explicit plugin runtime such as `id: "codex"` requires that harness and a compatible effective route; it fails closed if either is unavailable or if execution fails.
|
|
- `id: "pi"` is accepted only as a deprecated alias for `openclaw` to preserve shipped configs from v2026.5.22 and earlier. New config should use `openclaw`.
|
|
- Runtime precedence is exact model policy first (`agents.entries.*.models["provider/model"]`, `agents.defaults.models["provider/model"]`, or `models.providers.<provider>.models[]`), then `agents.entries.*` / `agents.defaults.models["provider/*"]`, then provider-wide policy at `models.providers.<provider>.agentRuntime`.
|
|
- Whole-agent runtime keys are legacy. `agents.defaults.agentRuntime`, `agents.entries.*.agentRuntime`, session runtime pins, and `OPENCLAW_AGENT_RUNTIME` are ignored by runtime selection. Run `openclaw doctor --fix` to remove stale values.
|
|
- Eligible exact official HTTPS OpenAI Responses/ChatGPT routes with no authored request override may use the Codex harness implicitly. Provider/model `agentRuntime.id: "codex"` makes Codex a fail-closed requirement but does not make an incompatible route compatible.
|
|
- For Claude CLI deployments, prefer `model: "anthropic/claude-opus-5"` plus model-scoped `agentRuntime.id: "claude-cli"`. Legacy `claude-cli/<model>` refs still work for compatibility, but new config should keep provider/model selection canonical and put the execution backend in provider/model runtime policy.
|
|
- This only controls text agent-turn execution. Media generation, vision, PDF, music, video, and TTS still use their provider/model settings.
|
|
|
|
**Built-in alias shorthands** (only apply when the model is in `agents.defaults.models`):
|
|
|
|
| Alias | Model |
|
|
| ------------------- | ------------------------------- |
|
|
| `opus` | `anthropic/claude-opus-5` |
|
|
| `sonnet` | `anthropic/claude-sonnet-5` |
|
|
| `gpt` | `openai/gpt-5.4` |
|
|
| `gpt-mini` | `openai/gpt-5.4-mini` |
|
|
| `gpt-nano` | `openai/gpt-5.4-nano` |
|
|
| `gemini` | `google/gemini-3.1-pro-preview` |
|
|
| `gemini-flash` | `google/gemini-3-flash-preview` |
|
|
| `gemini-flash-lite` | `google/gemini-3.1-flash-lite` |
|
|
|
|
Your configured aliases always win over defaults.
|
|
|
|
Z.AI GLM-4.x models automatically enable thinking mode unless you set `--thinking off` or define `agents.defaults.models["zai/<model>"].params.thinking` yourself.
|
|
Z.AI models enable `tool_stream` by default for tool call streaming. Set `agents.defaults.models["zai/<model>"].params.tool_stream` to `false` to disable it.
|
|
Anthropic Claude Opus 4.8 keeps thinking off by default in OpenClaw; when adaptive thinking is explicitly enabled, Anthropic's provider-owned effort default is `high`. Claude 4.6 models default to `adaptive` when no explicit thinking level is set.
|
|
|
|
### CLI backend selection
|
|
|
|
CLI adapter mechanics are registered by plugins, not configured under agent
|
|
defaults. Select a registered CLI backend with model-scoped `agentRuntime.id`,
|
|
as shown above. See [CLI backends](/gateway/cli-backends) for operations and
|
|
[building CLI backend plugins](/plugins/cli-backend-plugins) for command,
|
|
session, image, and parser registration.
|
|
|
|
### OpenAI GPT-5 personality
|
|
|
|
The bundled OpenAI plugin owns the GPT-5 friendly interaction-style setting. Matching GPT-5-family prompts receive the shared behavior contract; `personality` controls only the friendly style layer. Native Codex app-server routes keep Codex-owned base/model instructions instead of this OpenClaw GPT-5 contribution, and OpenClaw disables Codex's built-in personality for native threads.
|
|
|
|
```json5
|
|
{
|
|
plugins: {
|
|
entries: {
|
|
openai: {
|
|
config: {
|
|
personality: "friendly", // friendly | on | off
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- `"friendly"` (default) and `"on"` enable the friendly interaction-style layer.
|
|
- `"off"` disables only the friendly layer; the tagged GPT-5 behavior contract remains enabled.
|
|
|
|
See [OpenAI GPT-5 prompt contribution](/providers/openai#gpt-5-prompt-contribution) for provider and native Codex behavior.
|
|
|
|
### `agents.defaults.heartbeat`
|
|
|
|
Periodic heartbeat runs.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
heartbeat: {
|
|
agentId: "ops", // ambient owner when no per-agent heartbeat is configured
|
|
every: "30m", // 0m disables
|
|
activeHours: { start: "08:00", end: "24:00" },
|
|
model: "openai/gpt-5.4-mini",
|
|
session: "main",
|
|
target: "owner", // default | options: last | none | whatsapp | telegram | discord | ...
|
|
directPolicy: "allow", // allow (default) | block
|
|
to: "+15555550123",
|
|
accountId: "ops-bot",
|
|
prompt: "Follow the heartbeat monitor scratch context...",
|
|
timeoutSeconds: 45,
|
|
lightContext: false, // default: false; true skips workspace bootstrap files for heartbeat runs
|
|
isolatedSession: false, // default: false; true runs each heartbeat in a fresh session (no conversation history)
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- `every`: duration string (ms/s/m/h). Default: `30m` (API-key auth) or `1h` (OAuth auth). Set to `0m` to disable.
|
|
- `agentId`: explicit owner for ambient heartbeat runs when no `agents.entries.*.heartbeat` block exists. A shared heartbeat block without `agentId` keeps the existing all-agent enrollment behavior.
|
|
- Cadence is written into a system-owned cron monitor row. Run `openclaw doctor --fix` to materialize a missing or stale row. If cron is disabled, scheduled heartbeats do not run and the gateway logs a startup warning.
|
|
- The heartbeat object is strict. Its supported fields are `every`, `activeHours`, `model`, `session`, `target`, `directPolicy`, `to`, `accountId`, `prompt`, `timeoutSeconds`, `lightContext`, and `isolatedSession`.
|
|
- `timeoutSeconds`: maximum time in seconds allowed for a heartbeat agent turn before it is aborted. Leave unset to use `agents.defaults.timeoutSeconds` when set, otherwise the heartbeat cadence capped at 600 seconds.
|
|
- `directPolicy`: direct/DM delivery policy. `allow` (default) permits direct-target delivery. `block` suppresses direct-target delivery and emits `reason=dm-blocked`.
|
|
- `target`: `owner` (default) sends only to a direct-message identity from `commands.ownerAllowFrom` or channel `allowFrom`. `last` explicitly follows the latest conversation, including groups. `none` keeps results internal.
|
|
- `to`: used only with an explicit channel target. `owner` and an unset target ignore it.
|
|
- `lightContext`: when true, heartbeat runs use lightweight bootstrap context and skip workspace bootstrap files. Monitor scratch is injected by the heartbeat runner either way.
|
|
- `isolatedSession`: when true, each heartbeat runs in a fresh session with no prior conversation history. Same isolation pattern as cron `sessionTarget: "isolated"`. Reduces per-heartbeat token cost from ~100K to ~2-5K tokens.
|
|
- Busy deferral is automatic: scheduled heartbeats wait for main/cron activity, same-agent active runs, and target-session work. Immediate and manual wakes bypass only the broad same-agent active-run precheck.
|
|
- An enrolled agent's Heartbeats system-prompt section is included automatically while that agent's cadence is enabled. Ack suppression uses a fixed 300-character remainder budget, reasoning payloads remain internal, and tool error warnings remain enabled.
|
|
- Per-agent: set `agents.entries.*.heartbeat`. When any agent defines `heartbeat`, **only those agents** run heartbeats.
|
|
- Heartbeats run full agent turns — shorter intervals burn more tokens.
|
|
|
|
### `agents.defaults.systemAgent`
|
|
|
|
Selects the agent whose model and credentials own ambient OpenClaw system-agent and Custodian consults:
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
systemAgent: { agentId: "ops" },
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Delegated consults with a requesting agent keep that requester as their owner. When `agentId` is absent, a sole configured agent resolves implicitly; ambient consults in a multi-agent fleet fail with an actionable error. Upgrade-only ownership lives at `agents.defaults.authInheritance.agentId` for inherited credentials and `agents.defaults.sessionStore.agentId` for unscoped rows in a fixed `session.store`.
|
|
|
|
### `agents.defaults.compaction`
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
compaction: {
|
|
enabled: false, // disable embedded proactive auto-compaction (default: true)
|
|
mode: "safeguard", // default | safeguard
|
|
provider: "my-provider", // id of a registered compaction provider plugin (optional)
|
|
thinkingLevel: "low", // optional compaction-only thinking override
|
|
timeoutSeconds: 180,
|
|
keepRecentTokens: 50000,
|
|
recentTurnsPreserve: 3,
|
|
identifierPolicy: "strict", // strict | off
|
|
qualityGuard: { enabled: true, maxRetries: 1 },
|
|
midTurnPrecheck: { enabled: false }, // optional tool-loop pressure check
|
|
postIndexSync: "async", // off | async | await
|
|
postCompactionSections: ["Session Startup", "Red Lines"],
|
|
model: "openrouter/anthropic/claude-sonnet-4-6", // optional compaction-only model override
|
|
maxActiveTranscriptBytes: "20mb", // opt in to preflight local compaction
|
|
notifyUser: true, // notices when compaction starts/completes and on memory-flush degradation (default: false)
|
|
memoryFlush: {
|
|
enabled: true,
|
|
model: "ollama/qwen3:8b", // optional memory-flush-only model override
|
|
softThresholdTokens: 6000,
|
|
forceFlushTranscriptBytes: "2mb",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- `enabled`: when `false`, disables threshold-driven auto-compaction inside the embedded agent runtime. OpenClaw's preflight and overflow-recovery compaction paths and manual `/compact` remain available. Default: `true`.
|
|
- `mode`: `default` or `safeguard` (chunked summarization for long histories). See [Compaction](/concepts/compaction).
|
|
- `provider`: id of a registered compaction provider plugin. When set, the provider's `summarize()` is called instead of built-in LLM summarization. Falls back to built-in on failure. Setting a provider forces `mode: "safeguard"`. See [Compaction](/concepts/compaction).
|
|
- `thinkingLevel`: optional thinking level used only for embedded OpenClaw compaction summaries (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `adaptive`, `max`, or `ultra`). It overrides the session's current thinking level and is clamped to the selected compaction model/runtime. Leave unset to inherit the session level. Native Codex app-server compaction ignores this setting because the native compact request has no per-operation thinking override; OpenClaw logs a warning when configured.
|
|
- `timeoutSeconds`: maximum seconds allowed for a single compaction operation before OpenClaw aborts it. Default: `180`.
|
|
- `keepRecentTokens`: agent cut-point budget for keeping the most recent transcript tail verbatim. Default: `20000`.
|
|
- `recentTurnsPreserve`: number of most recent user/assistant turns kept verbatim outside safeguard summarization. Default: `3`.
|
|
- `identifierPolicy`: `strict` (default) or `off`. `strict` prepends built-in opaque identifier retention guidance during compaction summarization.
|
|
- `qualityGuard`: bounded validation for built-in safeguard summaries. Enabled by default in safeguard mode. After final budgeting, required headings must remain in the retained generated body, while pending asks and exact identifiers must remain in the exact artifact to be stored. When no attempt passes, OpenClaw preserves the original history and returns a compaction failure instead of storing known-invalid context. Set `enabled: false` to skip the audit. Configured compaction-provider output keeps its existing provider-owned validation behavior.
|
|
- `midTurnPrecheck`: optional tool-loop pressure check. When `enabled: true`, OpenClaw checks context pressure after tool results are appended and before the next model call. If the context no longer fits, it aborts the current attempt before submitting the prompt and reuses the existing precheck recovery path to truncate tool results or compact and retry. Works with both `default` and `safeguard` compaction modes. Default: disabled.
|
|
- `postIndexSync`: post-compaction session-memory reindex mode. Default: `"async"`. Use `"await"` for strongest freshness, `"async"` for lower compaction latency, or `"off"` only when session-memory sync is handled elsewhere.
|
|
- `postCompactionSections`: optional AGENTS.md H2/H3 section names to re-inject after compaction. Leave unset or use `[]` to disable.
|
|
- `model`: optional `provider/model-id` or bare alias from `agents.defaults.models` for compaction summarization only. Bare aliases resolve before dispatch; configured literal model IDs retain precedence on collisions. Use this when the main session should keep one model but compaction summaries should run on another; when unset, compaction uses the session's primary model.
|
|
- `maxActiveTranscriptBytes`: byte threshold (`number` or strings like `"20mb"`) that opts in to normal local compaction before a run when transcript history reaches the threshold. For Codex app-server sessions, the same threshold caps native rollout transcripts and oversized native threads restart fresh. Disabled when unset or `0`. When a context engine returns an explicit compacted successor identity, OpenClaw adopts it; the built-in SQLite compactor keeps the current identity.
|
|
- `notifyUser`: when `true`, sends brief context-maintenance notices to the user: when compaction starts and completes (for example, "Compacting context..." and "Compaction complete"), and when a pre-compaction memory flush is exhausted so the reply continues in a degraded state (for example, "Memory maintenance temporarily failed; continuing your reply."). Disabled by default to keep these notices silent.
|
|
- `memoryFlush`: silent agentic turn before auto-compaction to store durable memories. Set `model` to an exact provider/model such as `ollama/qwen3:8b` when this housekeeping turn should stay on a local model; the override does not inherit the active session fallback chain. `forceFlushTranscriptBytes` forces the flush when transcript size reaches the threshold even if token counters are stale. Skipped when workspace is read-only.
|
|
|
|
Custom compaction instructions are code-owned. Implement a compaction provider
|
|
plugin with `summarize()` for custom summary construction, and use
|
|
`before_prompt_build` when post-compaction context must be injected into later
|
|
model prompts. Doctor strips the retired instruction fields and points to these
|
|
seams.
|
|
|
|
### `agents.defaults.contextPruning`
|
|
|
|
Prunes **old tool results** from in-memory context before sending to the LLM. Does **not** modify session history on disk. Disabled by default; set `mode: "cache-ttl"` to enable.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
contextPruning: {
|
|
mode: "cache-ttl", // off (default) | cache-ttl
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
<Accordion title="cache-ttl mode behavior">
|
|
|
|
- `mode: "cache-ttl"` enables pruning passes.
|
|
- Pruning soft-trims oversized tool results first, then hard-clears older tool results if needed.
|
|
|
|
**Soft-trim** keeps beginning + end and inserts `...` in the middle.
|
|
|
|
**Hard-clear** replaces the entire tool result with the placeholder.
|
|
|
|
Notes:
|
|
|
|
- Image blocks are never trimmed/cleared.
|
|
- Ratios are character-based (approximate), not exact token counts.
|
|
- The most recent assistant messages are preserved.
|
|
|
|
</Accordion>
|
|
|
|
See [Session Pruning](/concepts/session-pruning) for behavior details.
|
|
|
|
### Block streaming
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
blockStreamingDefault: "off", // on | off
|
|
blockStreamingBreak: "text_end", // text_end | message_end
|
|
blockStreamingChunk: { minChars: 800, maxChars: 1200, breakPreference: "paragraph" },
|
|
blockStreamingCoalesce: { idleMs: 1000 },
|
|
humanDelay: { mode: "natural" }, // off (default) | natural | custom (use minMs/maxMs)
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- Non-Telegram channels require explicit `*.streaming.block.enabled: true` to enable block replies. QQ Bot is the exception: it has no `streaming.block` keys and streams block replies unless `channels.qqbot.streaming.mode` is `"off"`.
|
|
- Channel overrides: `channels.<channel>.streaming.block.coalesce` (and per-account variants). Discord, Google Chat, Mattermost, MS Teams, Signal, and Slack default `minChars: 1500` / `idleMs: 1000`.
|
|
- `blockStreamingChunk.breakPreference`: preferred chunk boundary (`"paragraph" | "newline" | "sentence"`).
|
|
- `humanDelay`: randomized pause between block replies. Default: `off`. `natural` = 800-2500ms. `custom` uses `minMs`/`maxMs` (falls back to the natural range for any unset bound). Per-agent override: `agents.entries.*.humanDelay`.
|
|
|
|
See [Streaming](/concepts/streaming) for behavior + chunking details.
|
|
|
|
### Typing indicators
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
typingMode: "instant", // never | instant | thinking | message
|
|
typingIntervalSeconds: 6,
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- Defaults: `instant` for direct chats/mentions, `message` for unmentioned group chats.
|
|
- `typingIntervalSeconds` default: `6`.
|
|
- Per-agent override: `agents.entries.*.typingMode`.
|
|
|
|
See [Typing Indicators](/concepts/typing-indicators).
|
|
|
|
<a id="agentsdefaultssandbox"></a>
|
|
|
|
### `agents.defaults.sandbox`
|
|
|
|
Optional sandboxing for the embedded agent. See [Sandboxing](/gateway/sandboxing) for the full guide.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
defaults: {
|
|
sandbox: {
|
|
mode: "non-main", // off (default) | non-main | all
|
|
backend: "docker", // docker (default) | podman | openshell | ssh
|
|
scope: "agent", // session | agent (default) | shared
|
|
workspaceAccess: "none", // none (default) | ro | rw
|
|
workspaceRoot: "~/.openclaw/sandboxes",
|
|
docker: {
|
|
image: "openclaw-sandbox:bookworm-slim",
|
|
containerPrefix: "openclaw-sbx-",
|
|
workdir: "/workspace",
|
|
readOnlyRoot: true,
|
|
tmpfs: ["/tmp", "/var/tmp", "/run"],
|
|
network: "none",
|
|
user: "1000:1000",
|
|
capDrop: ["ALL"],
|
|
env: { LANG: "C.UTF-8" },
|
|
setupCommand: "apt-get update && apt-get install -y git curl jq",
|
|
pidsLimit: 256,
|
|
memory: "1g",
|
|
memorySwap: "2g",
|
|
cpus: 1,
|
|
gpus: "all",
|
|
ulimits: {
|
|
nofile: { soft: 1024, hard: 2048 },
|
|
nproc: 256,
|
|
},
|
|
seccompProfile: "/path/to/seccomp.json",
|
|
apparmorProfile: "openclaw-sandbox",
|
|
dns: ["1.1.1.1", "8.8.8.8"],
|
|
extraHosts: ["internal.service:10.0.0.5"],
|
|
binds: ["/home/user/source:/source:rw"],
|
|
},
|
|
ssh: {
|
|
target: "user@gateway-host:22",
|
|
command: "ssh",
|
|
workspaceRoot: "/tmp/openclaw-sandboxes",
|
|
strictHostKeyChecking: true,
|
|
updateHostKeys: true,
|
|
identityFile: "~/.ssh/id_ed25519",
|
|
certificateFile: "~/.ssh/id_ed25519-cert.pub",
|
|
knownHostsFile: "~/.ssh/known_hosts",
|
|
// SecretRefs / inline contents also supported:
|
|
// identityData: { source: "env", provider: "default", id: "SSH_IDENTITY" },
|
|
// certificateData: { source: "env", provider: "default", id: "SSH_CERTIFICATE" },
|
|
// knownHostsData: { source: "env", provider: "default", id: "SSH_KNOWN_HOSTS" },
|
|
},
|
|
browser: {
|
|
enabled: false,
|
|
image: "openclaw-sandbox-browser:bookworm-slim",
|
|
network: "openclaw-sandbox-browser",
|
|
cdpPort: 9222,
|
|
cdpSourceRange: "172.21.0.1/32",
|
|
vncPort: 5900,
|
|
noVncPort: 6080,
|
|
headless: false,
|
|
noVncEnabled: true,
|
|
allowHostControl: false,
|
|
autoStart: true,
|
|
autoStartTimeoutMs: 12000,
|
|
},
|
|
prune: {
|
|
idleHours: 24,
|
|
maxAgeDays: 7,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
tools: {
|
|
sandbox: {
|
|
tools: {
|
|
allow: [
|
|
"exec",
|
|
"process",
|
|
"read",
|
|
"write",
|
|
"edit",
|
|
"apply_patch",
|
|
"sessions_list",
|
|
"sessions_history",
|
|
"sessions_send",
|
|
"sessions_spawn",
|
|
"session_status",
|
|
],
|
|
deny: ["browser", "canvas", "nodes", "cron", "discord", "gateway"],
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
Defaults shown above (`off`/`docker`/`agent`/`none`/`bookworm-slim` image/`none` network/etc.) are the actual OpenClaw defaults, not just illustrative values.
|
|
|
|
<Accordion title="Sandbox details">
|
|
|
|
**Backend:**
|
|
|
|
- `docker`: local Docker runtime (default)
|
|
- `ssh`: generic SSH-backed remote runtime
|
|
- `openshell`: OpenShell runtime
|
|
|
|
When `backend: "openshell"` is selected, runtime-specific settings move to
|
|
`plugins.entries.openshell.config`.
|
|
|
|
**SSH backend config:**
|
|
|
|
- `target`: SSH target in `user@host[:port]` form
|
|
- `command`: SSH client command (default: `ssh`)
|
|
- `workspaceRoot`: absolute remote root used for per-scope workspaces (default: `/tmp/openclaw-sandboxes`)
|
|
- `identityFile` / `certificateFile` / `knownHostsFile`: existing local files passed to OpenSSH
|
|
- `identityData` / `certificateData` / `knownHostsData`: inline contents or SecretRefs that OpenClaw materializes into temp files at runtime
|
|
- `strictHostKeyChecking` / `updateHostKeys`: OpenSSH host-key policy knobs (both default `true`)
|
|
|
|
**SSH auth precedence:**
|
|
|
|
- `identityData` wins over `identityFile`
|
|
- `certificateData` wins over `certificateFile`
|
|
- `knownHostsData` wins over `knownHostsFile`
|
|
- SecretRef-backed `*Data` values are resolved from the active secrets runtime snapshot before the sandbox session starts
|
|
|
|
**SSH backend behavior:**
|
|
|
|
- seeds the remote workspace once after create or recreate
|
|
- then keeps the remote SSH workspace canonical
|
|
- routes `exec`, file tools, and media paths over SSH
|
|
- does not sync remote changes back to the host automatically
|
|
- does not support sandbox browser containers
|
|
|
|
**Workspace access:**
|
|
|
|
- `none`: per-scope sandbox workspace under `~/.openclaw/sandboxes` (default)
|
|
- `ro`: sandbox workspace at `/workspace`, agent workspace mounted read-only at `/agent`
|
|
- `rw`: agent workspace mounted read/write at `/workspace`
|
|
|
|
**Scope:**
|
|
|
|
- `session`: per-session container + workspace
|
|
- `agent`: one container + workspace per agent (default)
|
|
- `shared`: shared container and workspace (no cross-session isolation)
|
|
|
|
**OpenShell plugin config:**
|
|
|
|
```json5
|
|
{
|
|
plugins: {
|
|
entries: {
|
|
openshell: {
|
|
enabled: true,
|
|
config: {
|
|
mode: "mirror", // mirror (default) | remote
|
|
command: "openshell",
|
|
from: "openclaw",
|
|
remoteWorkspaceDir: "/sandbox",
|
|
remoteAgentWorkspaceDir: "/agent",
|
|
gateway: "lab", // optional
|
|
gatewayEndpoint: "https://lab.example", // optional
|
|
policy: "strict", // optional OpenShell policy id
|
|
providers: ["openai"], // optional
|
|
autoProviders: true,
|
|
timeoutSeconds: 120,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
**OpenShell mode:**
|
|
|
|
- `mirror`: seed remote from local before exec, sync back after exec; local workspace stays canonical
|
|
- `remote`: seed remote once when the sandbox is created, then keep the remote workspace canonical
|
|
|
|
In `remote` mode, host-local edits made outside OpenClaw are not synced into the sandbox automatically after the seed step.
|
|
Transport is SSH into the OpenShell sandbox, but the plugin owns sandbox lifecycle and optional mirror sync.
|
|
|
|
**`setupCommand`** runs once after container creation (via `sh -lc`). Needs network egress, writable root, root user.
|
|
|
|
**Containers default to `network: "none"`** — set to `"bridge"` (or a custom bridge network) if the agent needs outbound access.
|
|
`"host"` is blocked. `"container:<id>"` is blocked by default unless you explicitly set
|
|
`sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true` (break-glass).
|
|
Codex app-server turns in an active OpenClaw sandbox use this same egress setting for their native code-mode network access.
|
|
|
|
**Inbound attachments** are staged into `media/inbound/*` in the active workspace.
|
|
|
|
**`docker.binds`** mounts additional host directories; global and per-agent binds are merged.
|
|
|
|
**Sandboxed browser** (`sandbox.browser.enabled`, default `false`): Chromium + CDP in a container. Does not require `browser.enabled` in `openclaw.json`.
|
|
noVNC observer access is password-protected and brokered through a one-time, authenticated bootstrap URL. The observer URL is deliberately omitted from model-visible system prompt context.
|
|
|
|
- `allowHostControl: false` (default) blocks sandboxed sessions from targeting the host browser.
|
|
- `network` defaults to `openclaw-sandbox-browser` (dedicated bridge network). Set to `bridge` only when you explicitly want global bridge connectivity. `"none"` is unsupported because CDP ports must be published to the host; `"host"` is blocked too. On upgrade, `openclaw doctor --fix` disables sidecars affected by a persisted `"none"` value and restores the dedicated network without silently enabling egress.
|
|
- `cdpSourceRange` optionally restricts CDP ingress at the container edge to a CIDR range (for example `172.21.0.1/32`).
|
|
- `sandbox.browser.binds` mounts additional host directories into the sandbox browser container only. When set (including `[]`), it replaces `docker.binds` for the browser container.
|
|
- The sandbox browser container's Chromium always launches with `--no-sandbox --disable-setuid-sandbox` (containers do not have the kernel primitives Chrome's own sandbox needs); there is no config toggle for this.
|
|
- Launch defaults are defined in `scripts/sandbox-browser-entrypoint.sh` and tuned for container hosts:
|
|
- `--remote-debugging-address=127.0.0.1`
|
|
- `--remote-debugging-port=<derived from OPENCLAW_BROWSER_CDP_PORT>`
|
|
- `--user-data-dir=${HOME}/.chrome`
|
|
- `--no-first-run`
|
|
- `--no-default-browser-check`
|
|
- `--disable-dev-shm-usage`
|
|
- `--disable-background-networking`
|
|
- `--disable-breakpad`
|
|
- `--disable-crash-reporter`
|
|
- `--no-zygote`
|
|
- `--metrics-recording-only`
|
|
- `--password-store=basic`
|
|
- `--use-mock-keychain`
|
|
- `--disable-3d-apis`, `--disable-gpu`, and `--disable-software-rasterizer` are
|
|
enabled by default and can be disabled with
|
|
`OPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0` if WebGL/3D usage requires it.
|
|
- `--disable-extensions` (default enabled); `OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0`
|
|
re-enables extensions if your workflow depends on them.
|
|
- `--renderer-process-limit=2` by default; change with
|
|
`OPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=<N>`, set `0` to use Chromium's
|
|
default process limit.
|
|
- `--headless=new` only when `headless` is enabled.
|
|
- Defaults are the container image baseline; use a custom browser image with a custom
|
|
entrypoint to change container defaults.
|
|
|
|
</Accordion>
|
|
|
|
Browser sandboxing requires the Docker engine. `sandbox.docker.binds` applies to both the Docker and Podman backends.
|
|
|
|
Build images (from a source checkout):
|
|
|
|
```bash
|
|
scripts/sandbox-setup.sh # main sandbox image
|
|
scripts/sandbox-browser-setup.sh # optional browser image
|
|
```
|
|
|
|
For npm installs without a source checkout, see [Sandboxing § Images and setup](/gateway/sandboxing#images-and-setup) for inline `docker build` commands.
|
|
|
|
### `agents.entries` (per-agent overrides)
|
|
|
|
Use `agents.entries.*.tts` to give an agent its own TTS provider, voice, model,
|
|
style, or auto-TTS mode. The agent block deep-merges over global
|
|
`tts`, so shared credentials can stay in one place while individual
|
|
agents override only the voice or provider fields they need. The active agent's
|
|
override applies to automatic spoken replies, `/tts audio`, `/tts status`, and
|
|
the `tts` agent tool. See [Text-to-speech](/tools/tts#per-agent-voice-overrides)
|
|
for provider examples and precedence.
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
entries: {
|
|
main: {
|
|
name: "Main Agent",
|
|
workspace: "~/.openclaw/workspace",
|
|
agentDir: "~/.openclaw/agents/main/agent",
|
|
model: "anthropic/claude-opus-4-6", // or { primary, fallbacks }
|
|
utilityModel: "openai/gpt-5.4-mini",
|
|
thinkingDefault: "high", // per-agent thinking level override
|
|
reasoningDefault: "on", // per-agent reasoning visibility override
|
|
fastModeDefault: false, // per-agent fast mode override
|
|
params: { cacheRetention: "none" }, // overrides matching defaults.models params by key
|
|
tts: {
|
|
providers: {
|
|
elevenlabs: { speakerVoiceId: "EXAVITQu4vr4xnSDxMaL" },
|
|
},
|
|
},
|
|
skills: ["docs-search"], // replaces agents.defaults.skills when set
|
|
identity: {
|
|
name: "Samantha",
|
|
theme: "helpful sloth",
|
|
emoji: "🦥",
|
|
avatar: "avatars/samantha.png",
|
|
},
|
|
groupChat: { mentionPatterns: ["@openclaw"] },
|
|
sandbox: { mode: "off" },
|
|
runtime: {
|
|
type: "acp",
|
|
acp: {
|
|
agent: "codex",
|
|
backend: "acpx",
|
|
mode: "persistent", // persistent | oneshot
|
|
cwd: "/workspace/openclaw",
|
|
},
|
|
},
|
|
subagents: { allowAgents: ["*"] },
|
|
tools: {
|
|
profile: "coding",
|
|
allow: ["browser"],
|
|
deny: ["canvas"],
|
|
elevated: { enabled: true },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- The `agents.entries` object key is the stable agent id.
|
|
- `default` is retired. Exactly one configured agent resolves implicitly; multi-agent operations require a binding, surface `agentId` target, scoped session/store owner, or explicit `--agent`/request field.
|
|
- `model`: string form sets a strict per-agent primary with no model fallback; object form `{ primary }` is also strict unless you add `fallbacks`. Use `{ primary, fallbacks: [...] }` to opt that agent into fallback, or `{ primary, fallbacks: [] }` to make strict behavior explicit. Cron jobs that only override `primary` still inherit default fallbacks unless you set `fallbacks: []`.
|
|
- `utilityModel`: optional per-agent override for short internal tasks such as generated session and thread titles. Falls back to `agents.defaults.utilityModel`, then the effective session provider's declared small-model default. Dashboard titles retry once with the effective regular session model. An empty string skips the alternate utility route for this agent without disabling dashboard title generation.
|
|
- `params`: per-agent stream params merged over the selected model entry in `agents.defaults.models`. Use this for agent-specific overrides like `cacheRetention`, `temperature`, or `maxTokens` without duplicating the whole model catalog.
|
|
- `tts`: optional per-agent text-to-speech overrides. The block deep-merges over `tts`, so keep shared provider credentials and fallback policy in `tts` and set only persona-specific values such as provider, voice, model, style, or auto mode here.
|
|
- `skills`: optional per-agent skill allowlist. If omitted, the agent inherits `agents.defaults.skills` when set; an explicit list replaces defaults instead of merging, and `[]` means no skills.
|
|
- `thinkingDefault`: optional per-agent default thinking level (`off | minimal | low | medium | high | xhigh | adaptive | max`). Overrides `agents.defaults.thinkingDefault` for this agent when no per-message or session override is set. The selected provider/model profile controls which values are valid; for Google Gemini, `adaptive` keeps provider-owned dynamic thinking (`thinkingLevel` omitted on Gemini 3/3.1, `thinkingBudget: -1` on Gemini 2.5).
|
|
- `reasoningDefault`: optional per-agent default reasoning visibility (`on | off | stream`). Overrides `agents.defaults.reasoningDefault` for this agent when no per-message or session reasoning override is set.
|
|
- `fastModeDefault`: optional per-agent default for fast mode (`"auto" | true | false`). Overrides `agents.defaults.fastModeDefault` for this agent when no per-message or session fast-mode override is set.
|
|
- `models`: optional per-agent model catalog/runtime overrides keyed by full `provider/model` ids. Use `models["provider/model"].agentRuntime` for per-agent runtime exceptions.
|
|
- `runtime`: optional per-agent runtime descriptor. Use `type: "acp"` with `runtime.acp` defaults (`agent`, `backend`, `mode`, `cwd`) when the agent should default to ACP harness sessions.
|
|
- `identity.avatar`: workspace-relative path, `http(s)` URL, or `data:` URI.
|
|
- Local workspace-relative `identity.avatar` image files are limited to 2 MB. `http(s)` URLs and `data:` URIs are not checked against the local file-size limit.
|
|
- `identity` derives defaults: `ackReaction` from `emoji`, `mentionPatterns` from `name`/`emoji`.
|
|
- `subagents.allowAgents`: allowlist of configured agent ids for explicit `sessions_spawn.agentId` targets (`["*"]` = any configured target; default: same agent only). Include the requester id when self-targeted `agentId` calls should be allowed. Stale entries whose agent config was deleted are rejected by `sessions_spawn` and omitted from `agents_list`; run `openclaw doctor --fix` to clean them up, or add a minimal `agents.entries.*` entry if that target should remain spawnable while inheriting defaults.
|
|
- Sandbox inheritance guard: if the requester session is sandboxed, `sessions_spawn` rejects targets that would run unsandboxed.
|
|
- `subagents.requireAgentId`: when true, block `sessions_spawn` calls that omit `agentId` (forces explicit profile selection; default: false).
|
|
- `subagents.maxConcurrent`: max concurrent child-agent runs across subagent execution. Default: `8`.
|
|
- `subagents.maxChildrenPerAgent`: max active children a single agent session can spawn. Default: `5`.
|
|
- `subagents.maxSpawnDepth`: max nesting depth for sub-agent spawning (`1`-`5`). Default: `1` (no nesting).
|
|
- `subagents.archiveAfterMinutes`: age before completed subagent state is archived. Default: `60`.
|
|
|
|
---
|
|
|
|
## Multi-agent routing
|
|
|
|
Run multiple isolated agents inside one Gateway. See [Multi-Agent](/concepts/multi-agent).
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
ownership: "explicit",
|
|
defaults: { heartbeat: { agentId: "home" }, systemAgent: { agentId: "home" } },
|
|
entries: {
|
|
home: { workspace: "~/.openclaw/workspace-home" },
|
|
work: { workspace: "~/.openclaw/workspace-work" },
|
|
},
|
|
},
|
|
bindings: [
|
|
{ agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
|
|
{ agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
|
|
],
|
|
talk: { agentId: "home" },
|
|
}
|
|
```
|
|
|
|
### Binding match fields
|
|
|
|
- `type` (optional): `route` for normal routing (missing type defaults to route), `acp` for persistent ACP conversation bindings.
|
|
- `match.channel` (required)
|
|
- `match.accountId` (optional; `*` = any account; omitted = default account)
|
|
- `match.peer` (optional; `{ kind: direct|group|channel, id }`)
|
|
- `match.guildId` / `match.teamId` (optional; channel-specific)
|
|
- `acp` (optional; only for `type: "acp"`): `{ mode, label, cwd, backend }`
|
|
|
|
**Deterministic match order:**
|
|
|
|
1. `match.peer`
|
|
2. `match.guildId`
|
|
3. `match.teamId`
|
|
4. `match.accountId` (exact, no peer/guild/team)
|
|
5. `match.accountId: "*"` (channel-wide)
|
|
6. Sole-agent fallback (only when exactly one agent is configured; explicit multi-agent fleets without a matching binding fail closed)
|
|
|
|
Within each tier, the first matching `bindings` entry wins.
|
|
|
|
For `type: "acp"` entries, OpenClaw resolves by exact conversation identity (`match.channel` + account + `match.peer.id`) and does not use the route binding tier order above.
|
|
|
|
### Per-agent access profiles
|
|
|
|
<Accordion title="Full access (no sandbox)">
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
entries: {
|
|
personal: {
|
|
workspace: "~/.openclaw/workspace-personal",
|
|
sandbox: { mode: "off" },
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
</Accordion>
|
|
|
|
<Accordion title="Read-only tools + workspace">
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
entries: {
|
|
family: {
|
|
workspace: "~/.openclaw/workspace-family",
|
|
sandbox: { mode: "all", scope: "agent", workspaceAccess: "ro" },
|
|
tools: {
|
|
allow: [
|
|
"read",
|
|
"sessions_list",
|
|
"sessions_history",
|
|
"sessions_send",
|
|
"sessions_spawn",
|
|
"session_status",
|
|
],
|
|
deny: ["write", "edit", "apply_patch", "exec", "process", "browser"],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
</Accordion>
|
|
|
|
<Accordion title="No filesystem access (messaging only)">
|
|
|
|
```json5
|
|
{
|
|
agents: {
|
|
entries: {
|
|
public: {
|
|
workspace: "~/.openclaw/workspace-public",
|
|
sandbox: { mode: "all", scope: "agent", workspaceAccess: "none" },
|
|
tools: {
|
|
allow: [
|
|
"sessions_list",
|
|
"sessions_history",
|
|
"sessions_send",
|
|
"sessions_spawn",
|
|
"session_status",
|
|
"whatsapp",
|
|
"telegram",
|
|
"slack",
|
|
"discord",
|
|
"gateway",
|
|
],
|
|
deny: [
|
|
"read",
|
|
"write",
|
|
"edit",
|
|
"apply_patch",
|
|
"exec",
|
|
"process",
|
|
"browser",
|
|
"canvas",
|
|
"nodes",
|
|
"cron",
|
|
"gateway",
|
|
"image",
|
|
],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
</Accordion>
|
|
|
|
See [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) for precedence details.
|
|
|
|
---
|
|
|
|
## Session
|
|
|
|
```json5
|
|
{
|
|
session: {
|
|
scope: "per-sender",
|
|
dmScope: "main", // main | per-peer | per-channel-peer | per-account-channel-peer
|
|
identityLinks: {
|
|
alice: ["telegram:123456789", "discord:987654321012345678"],
|
|
},
|
|
reset: {
|
|
mode: "daily", // daily | idle
|
|
atHour: 4,
|
|
idleMinutes: 60,
|
|
},
|
|
resetByType: {
|
|
thread: { mode: "daily", atHour: 4 },
|
|
direct: { mode: "idle", idleMinutes: 240 },
|
|
group: { mode: "idle", idleMinutes: 120 },
|
|
},
|
|
resetByChannel: {
|
|
discord: { mode: "idle", idleMinutes: 30 },
|
|
},
|
|
resetTriggers: ["/new", "/reset"],
|
|
store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
|
|
maintenance: {
|
|
mode: "enforce", // enforce (default) | warn
|
|
pruneAfter: "30d",
|
|
maxEntries: 500,
|
|
resetArchiveRetention: "30d", // duration or false
|
|
maxDiskBytes: "500mb", // optional hard budget
|
|
highWaterBytes: "400mb", // optional cleanup target
|
|
},
|
|
threadBindings: {
|
|
enabled: true,
|
|
idleHours: 24, // default inactivity auto-unfocus in hours (`0` disables)
|
|
maxAgeHours: 0, // default hard max age in hours (`0` disables)
|
|
},
|
|
sharing: {
|
|
readOnly: true,
|
|
suggest: true,
|
|
drafts: true,
|
|
},
|
|
mainKey: "main", // legacy (runtime always uses "main")
|
|
sendPolicy: {
|
|
rules: [{ action: "deny", match: { channel: "discord", chatType: "group" } }],
|
|
default: "allow",
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
<Accordion title="Session field details">
|
|
|
|
- **`scope`**: base session grouping strategy for group-chat contexts.
|
|
- `per-sender` (default): each sender gets an isolated session within a channel context.
|
|
- `global`: all participants in a channel context share a single session (use only when shared context is intended).
|
|
- **`dmScope`**: how DMs are grouped.
|
|
- `main`: all DMs share the main session.
|
|
- `per-peer`: isolate by sender id across channels.
|
|
- `per-channel-peer`: isolate per channel + sender (recommended for multi-user inboxes).
|
|
- `per-account-channel-peer`: isolate per account + channel + sender (recommended for multi-account).
|
|
- **`identityLinks`**: map canonical ids to provider-prefixed peers for cross-channel session sharing. Dock commands such as `/dock_discord` use the same map to switch the active session's reply route to another linked channel peer; see [Channel docking](/concepts/channel-docking).
|
|
- **`reset`**: primary reset policy. `none` disables automatic reset and is the default; compaction bounds active context instead. `daily` resets at `atHour` local time; `idle` resets after `idleMinutes`. When both configured, whichever expires first wins. `/new` and `/reset` remain available in every mode. Daily reset freshness uses the session row's `sessionStartedAt`; idle reset freshness uses `lastInteractionAt`. Background/system-event writes such as heartbeat, cron wakeups, exec notifications, and gateway bookkeeping can update `updatedAt`, but they do not keep daily/idle sessions fresh.
|
|
- **`resetByType`**: per-type overrides (`direct`, `group`, `thread`). Doctor migrates legacy `dm` entries to `direct`; the schema rejects `dm`.
|
|
- **`resetByChannel`**: per-channel reset overrides keyed by provider/channel id. When the session's channel has a matching entry, it wins outright over `resetByType`/`reset` for that session. Use only when one channel needs reset behavior different from the type-level policy.
|
|
- **`mainKey`**: legacy field. Runtime always uses `"main"` for the main direct-chat bucket.
|
|
- **`sendPolicy`**: match by `channel`, `chatType` (`direct|group|channel`, with legacy `dm` alias), `keyPrefix`, or `rawKeyPrefix`. First deny wins.
|
|
- **`maintenance`**: session-store cleanup + retention controls.
|
|
- `mode`: `enforce` applies cleanup and is the default; `warn` emits warnings only.
|
|
- `pruneAfter`: age cutoff for stale entries (default `30d`).
|
|
- `maxEntries`: maximum number of SQLite session entries (default `500`). Runtime writes batch cleanup with a small high-water buffer for production-sized caps; `openclaw sessions cleanup --enforce` applies the cap immediately.
|
|
- Short-lived gateway model-run probe sessions use fixed `24h` retention, but cleanup is pressure-gated: it only removes stale strict model-run probe rows when session-entry maintenance/cap pressure is reached. Only strict explicit probe keys matching `agent:*:explicit:model-run-<uuid>` are eligible; normal direct, group, thread, cron, hook, heartbeat, ACP, and sub-agent sessions do not inherit this 24h retention. When model-run cleanup runs, it runs before the broader `pruneAfter` stale-entry cleanup and `maxEntries` cap.
|
|
- Legacy `rotateBytes` is rejected by the current schema; `openclaw doctor --fix` removes it from older configs.
|
|
- `resetArchiveRetention`: age-based retention for reset/deleted transcript archives. By default, archives remain until disk-budget eviction; set a duration to opt into wall-clock deletion, or `false` to disable it explicitly.
|
|
- `maxDiskBytes`: optional sessions-directory disk budget. In `warn` mode it logs warnings; in `enforce` mode it removes oldest artifacts/sessions first. Set `false`, `0`, or `"0"` to disable the budget entirely.
|
|
- `highWaterBytes`: optional target after budget cleanup. Defaults to `80%` of `maxDiskBytes`. A value that resolves to zero falls back to the default; negative values are invalid. Disable the budget with `maxDiskBytes`, not with a zero high-water mark.
|
|
- **`threadBindings`**: global defaults for thread-bound session features.
|
|
- `enabled`: master switch for supported channel thread bindings
|
|
- `idleHours`: default inactivity auto-unfocus in hours (`0` disables; providers can override)
|
|
- `maxAgeHours`: default hard max age in hours (`0` disables; providers can override)
|
|
- `spawnSessions`: default gate for creating thread-bound work sessions from `sessions_spawn` and ACP thread spawns. Defaults to `true` when thread bindings are enabled; providers/accounts can override.
|
|
- `defaultSpawnContext`: default native subagent context for thread-bound spawns (`"fork"` or `"isolated"`). Defaults to `"fork"`.
|
|
- **`sharing`**: controls which per-session collaboration modes owners and `operator.admin` connections may select. Every flag defaults to `true`; setting one to `false` removes that choice from the Control UI and makes create-time visibility or `session.visibility.set` reject it. New sessions start `shared` unless the Control UI starts one as a draft.
|
|
- `readOnly`: allow `read-only`, where non-members can watch but cannot send, steer, abort, approve, or mutate session state.
|
|
- `suggest`: allow `suggest`. In this phase it enforces the same admission behavior as `read-only`; the suggestion queue is a later feature.
|
|
- `drafts`: allow `draft`, which hides the session from non-admin, non-owner session lists and event broadcasts.
|
|
|
|
Membership and visibility changes are written into the session transcript as system notes. These controls coordinate operators sharing one agent; they are not a security boundary between tenants. Use separate Gateways or agents when work requires isolation.
|
|
|
|
</Accordion>
|
|
|
|
---
|
|
|
|
## Messages
|
|
|
|
```json5
|
|
{
|
|
messages: {
|
|
responsePrefix: "🦞", // or "auto"
|
|
ackReaction: "👀",
|
|
ackReactionScope: "group-mentions", // group-mentions | group-all | direct | all | off | none
|
|
queue: {
|
|
mode: "steer", // steer (default) | followup | collect | interrupt
|
|
cap: 20,
|
|
drop: "summarize", // old | new | summarize (default)
|
|
byChannel: {
|
|
whatsapp: "followup",
|
|
telegram: "followup",
|
|
},
|
|
},
|
|
inbound: {
|
|
debounceMs: 2000, // 0 disables
|
|
byChannel: {
|
|
whatsapp: 5000,
|
|
slack: 1500,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
### Response prefix
|
|
|
|
Per-channel/account overrides: `channels.<channel>.responsePrefix`, `channels.<channel>.accounts.<id>.responsePrefix`.
|
|
|
|
Resolution (most specific wins): account → channel → global. `""` disables and stops cascade. `"auto"` derives `[{identity.name}]`.
|
|
|
|
**Template variables:**
|
|
|
|
| Variable | Description | Example |
|
|
| ----------------- | ---------------------- | --------------------------- |
|
|
| `{model}` | Short model name | `claude-opus-4-6` |
|
|
| `{modelFull}` | Full model identifier | `anthropic/claude-opus-4-6` |
|
|
| `{provider}` | Provider name | `anthropic` |
|
|
| `{thinkingLevel}` | Current thinking level | `high`, `low`, `off` |
|
|
| `{identity.name}` | Agent identity name | (same as `"auto"`) |
|
|
|
|
Variables are case-insensitive. `{think}` is an alias for `{thinkingLevel}`.
|
|
|
|
### Ack reaction
|
|
|
|
- Defaults to active agent's `identity.emoji`, otherwise `"👀"`. Set `""` to disable.
|
|
- Per-channel overrides: `channels.<channel>.ackReaction`, `channels.<channel>.accounts.<id>.ackReaction`.
|
|
- Resolution order: account → channel → `messages.ackReaction` → identity fallback.
|
|
- Scope: `group-mentions` (default), `group-all`, `direct`, `all`, or `off`/`none` (disables ack reactions entirely).
|
|
- `group-mentions` acks group messages that mention the agent, including in groups with `requireMention: false`. Use `group-all` to ack every group message.
|
|
- `messages.statusReactions.enabled`: enables lifecycle status reactions on Slack, Discord, Signal, Telegram, and WhatsApp.
|
|
On Discord, unset keeps status reactions enabled when ack reactions are active.
|
|
On Slack, Signal, Telegram, and WhatsApp, set it explicitly to `true` to enable lifecycle status reactions.
|
|
Slack uses its native assistant thread status and rotating loading messages for progress by default, while keeping the configured ack reaction static.
|
|
|
|
### Queue
|
|
|
|
- `mode`: queue strategy for inbound messages that arrive while a session run is active. Default: `"steer"`.
|
|
- `steer`: inject the new prompt into the active run.
|
|
- `followup`: run the new prompt after the active run finishes.
|
|
- `collect`: batch compatible messages and run them together later.
|
|
- `interrupt`: abort the active run before starting the newest prompt.
|
|
- The queue uses a built-in 500ms debounce for steer, followup, and collect batching.
|
|
- `cap`: maximum queued messages before the drop policy applies. Default: `20`.
|
|
- `drop`: strategy when the cap is exceeded. `"summarize"` (default) drops oldest entries but keeps compact summaries; `"old"` drops oldest without summaries; `"new"` rejects the newest item.
|
|
- `byChannel`: per-channel `mode` overrides keyed by provider id.
|
|
- `debounceMsByChannel`: per-channel debounce overrides in milliseconds, keyed by provider id.
|
|
|
|
Use `messages.inbound.debounceMs` for the global pre-queue debounce window.
|
|
|
|
### Inbound debounce
|
|
|
|
Batches rapid text-only messages from the same sender into a single agent turn. Media/attachments flush immediately. Control commands bypass debouncing. Default `debounceMs`: `2000`.
|
|
|
|
### Other message keys
|
|
|
|
- `channels.whatsapp.responsePrefix`: outbound WhatsApp reply prefix. Doctor moves the retired inbound `messagePrefix` value here only when this canonical value is unset.
|
|
- `messages.visibleReplies`: controls visible source replies across direct, group, and channel conversations (`"message_tool"` requires `message(action=send)` for visible output; `"automatic"` posts normal replies as before).
|
|
- `messages.usageTemplate` / `messages.responseUsage`: custom `/usage` footer template and default per-reply usage mode (`off | tokens | full`, plus legacy `on` alias for `tokens`).
|
|
- `messages.groupChat.mentionPatterns` / `historyLimit`: group-message mention triggers and history window sizing.
|
|
- `messages.suppressToolErrors`: when `true`, suppresses `⚠️` tool-error warnings shown to the user (the agent still sees errors in context and can retry). Default: `false`.
|
|
|
|
### TTS (text-to-speech)
|
|
|
|
```json5
|
|
{
|
|
tts: {
|
|
auto: "off", // off (default) | always | inbound | tagged
|
|
mode: "final", // final | all
|
|
provider: "elevenlabs",
|
|
summaryModel: "openai/gpt-5.4-mini",
|
|
modelOverrides: { enabled: true },
|
|
maxTextLength: 4000,
|
|
timeoutMs: 30000,
|
|
providers: {
|
|
elevenlabs: {
|
|
apiKey: "example-elevenlabs-api-key",
|
|
baseUrl: "https://api.elevenlabs.io",
|
|
speakerVoiceId: "voice_id",
|
|
modelId: "eleven_multilingual_v2",
|
|
seed: 42,
|
|
applyTextNormalization: "auto",
|
|
languageCode: "en",
|
|
voiceSettings: {
|
|
stability: 0.5,
|
|
similarityBoost: 0.75,
|
|
style: 0.0,
|
|
useSpeakerBoost: true,
|
|
speed: 1.0,
|
|
},
|
|
},
|
|
microsoft: {
|
|
speakerVoice: "en-US-MichelleNeural",
|
|
lang: "en-US",
|
|
outputFormat: "audio-24khz-48kbitrate-mono-mp3",
|
|
},
|
|
openai: {
|
|
apiKey: "example-openai-api-key",
|
|
baseUrl: "https://api.openai.com/v1",
|
|
model: "gpt-4o-mini-tts",
|
|
speakerVoice: "coral",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
The global preferences path is machine state (default
|
|
`~/.openclaw/settings/tts.json`; override with `OPENCLAW_TTS_PREFS`). Advanced
|
|
multi-agent setups can set `agents.entries.<id>.tts.prefsPath` for distinct
|
|
per-agent preference stores.
|
|
|
|
- `auto` controls the default auto-TTS mode: `off`, `always`, `inbound`, or `tagged`. `/tts on|off` can override local prefs, and `/tts status` shows the effective state.
|
|
- `summaryModel` overrides `agents.defaults.model.primary` for auto-summary.
|
|
- `modelOverrides` is enabled by default (`enabled !== false`); `modelOverrides.allowProvider` is opt-in.
|
|
- API keys fall back to `ELEVENLABS_API_KEY`/`XI_API_KEY` and `OPENAI_API_KEY`.
|
|
- Bundled speech providers are plugin-owned. If `plugins.allow` is set, include each TTS provider plugin you want to use, for example `microsoft` for Edge TTS. The legacy `edge` provider id is accepted as an alias for `microsoft`.
|
|
- `providers.openai.baseUrl` overrides the OpenAI TTS endpoint. Resolution order is config, then `OPENAI_TTS_BASE_URL`, then `https://api.openai.com/v1`.
|
|
- When `providers.openai.baseUrl` points to a non-OpenAI endpoint, OpenClaw treats it as an OpenAI-compatible TTS server and relaxes model/voice validation.
|
|
|
|
---
|
|
|
|
## Talk
|
|
|
|
Defaults for Talk mode (macOS/iOS/Android and the browser Control UI).
|
|
|
|
```json5
|
|
{
|
|
talk: {
|
|
agentId: "ops",
|
|
provider: "elevenlabs",
|
|
providers: {
|
|
elevenlabs: {
|
|
speakerVoiceId: "elevenlabs_voice_id",
|
|
voiceAliases: {
|
|
Clawd: "EXAVITQu4vr4xnSDxMaL",
|
|
Roger: "CwhRBWXzGAHq8TQ4Fs17",
|
|
},
|
|
modelId: "eleven_multilingual_v2",
|
|
outputFormat: "mp3_44100_128",
|
|
apiKey: "elevenlabs_api_key",
|
|
},
|
|
mlx: {
|
|
modelId: "mlx-community/Soprano-80M-bf16",
|
|
},
|
|
system: {},
|
|
},
|
|
consultThinkingLevel: "low",
|
|
consultFastMode: true,
|
|
speechLocale: "ru-RU",
|
|
silenceTimeoutMs: 1500,
|
|
interruptOnSpeech: true,
|
|
realtime: {
|
|
provider: "openai",
|
|
providers: {
|
|
openai: {
|
|
model: "gpt-realtime-2.1",
|
|
speakerVoice: "cedar",
|
|
},
|
|
},
|
|
instructions: "Speak warmly and keep answers brief.",
|
|
mode: "realtime", // realtime | stt-tts | transcription
|
|
transport: "webrtc", // webrtc | provider-websocket | gateway-relay | managed-room
|
|
vadThreshold: 0.5,
|
|
silenceDurationMs: 500,
|
|
prefixPaddingMs: 300,
|
|
reasoningEffort: "medium",
|
|
brain: "agent-consult", // agent-consult | direct-tools | none
|
|
},
|
|
},
|
|
}
|
|
```
|
|
|
|
- `talk.provider` must match a key in `talk.providers` when multiple Talk providers are configured.
|
|
- `talk.agentId` owns Talk sessions created without an explicit agent-scoped session key. Session-scoped Talk calls continue to use the agent encoded in that key. Doctor may create a minimal `talk` block containing only this owner for an existing multi-agent config.
|
|
- Legacy flat Talk keys (`talk.voiceId`, `talk.voiceAliases`, `talk.modelId`, `talk.outputFormat`, `talk.apiKey`) are compatibility-only. Run `openclaw doctor --fix` to rewrite persisted config into `talk.providers.<provider>`.
|
|
- Voice IDs fall back to `ELEVENLABS_VOICE_ID` or `SAG_VOICE_ID` (macOS Talk client behavior).
|
|
- `providers.*.apiKey` accepts plaintext strings or SecretRef objects.
|
|
- `ELEVENLABS_API_KEY` fallback applies only when no Talk API key is configured.
|
|
- `providers.*.voiceAliases` lets Talk directives use friendly names.
|
|
- `providers.mlx.modelId` selects the Hugging Face repo used by the macOS local MLX helper. If omitted, macOS uses `mlx-community/Soprano-80M-bf16`.
|
|
- macOS MLX playback runs through the bundled `openclaw-mlx-tts` helper when present, or an executable on `PATH`; `OPENCLAW_MLX_TTS_BIN` overrides the helper path for development.
|
|
- `consultThinkingLevel` controls the thinking level for the full OpenClaw agent run behind Control UI Talk realtime `openclaw_agent_consult` calls. Leave unset to preserve normal session/model behavior.
|
|
- `consultFastMode` sets a one-shot fast-mode override for Control UI Talk realtime consults without changing the session's normal fast-mode setting.
|
|
- `speechLocale` sets the BCP 47 locale id used by Android, iOS, and macOS Talk speech recognition and by the iOS system-voice fallback. Android also uses its language component to guide realtime input transcription. Leave unset to use the device default.
|
|
- `silenceTimeoutMs` controls how long Talk mode waits after user silence before it sends the transcript. Unset keeps the platform default pause window (`700 ms on macOS and Android, 900 ms on iOS`).
|
|
- `realtime.instructions` appends provider-facing system instructions to OpenClaw's built-in realtime prompt, so voice style can be configured without losing default `openclaw_agent_consult` guidance.
|
|
- `realtime.vadThreshold` sets the provider voice-activity threshold from `0` (most sensitive) to `1` (least sensitive). Unset keeps the provider default.
|
|
- `realtime.silenceDurationMs` sets the positive whole-number silence window before the provider commits a realtime user turn. Unset keeps the provider default.
|
|
- `realtime.prefixPaddingMs` sets the non-negative whole-number amount of audio retained before detected speech begins. Unset keeps the provider default.
|
|
- `realtime.reasoningEffort` sets the provider-specific reasoning level for realtime sessions. Unset keeps the provider default.
|
|
- `realtime.consultRouting`: `"provider-direct"` (default) preserves direct provider replies when the realtime provider produces a final user transcript without `openclaw_agent_consult`. `"force-agent-consult"` routes the finalized request through OpenClaw instead.
|
|
|
|
---
|
|
|
|
## Related
|
|
|
|
- [Configuration reference](/gateway/configuration-reference) — all other config keys
|
|
- [Configuration](/gateway/configuration) — common tasks and quick setup
|
|
- [Configuration examples](/gateway/configuration-examples)
|