diff --git a/docs/channels/groups.md b/docs/channels/groups.md index 6f7bbe56181..feae2f6e92f 100644 --- a/docs/channels/groups.md +++ b/docs/channels/groups.md @@ -138,7 +138,7 @@ Want “groups can only see folder X” instead of “no host access”? Keep `w Related: -- Configuration keys and defaults: [Gateway configuration](/gateway/configuration-reference#agentsdefaultssandbox) +- Configuration keys and defaults: [Gateway configuration](/gateway/config-agents#agentsdefaultssandbox) - Debugging why a tool is blocked: [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) - Bind mounts details: [Sandboxing](/gateway/sandboxing#custom-bind-mounts) diff --git a/docs/cli/agents.md b/docs/cli/agents.md index c58e074f619..1071f1a5cad 100644 --- a/docs/cli/agents.md +++ b/docs/cli/agents.md @@ -37,7 +37,7 @@ Use routing bindings to pin inbound channel traffic to a specific agent. If you also want different visible skills per agent, configure `agents.defaults.skills` and `agents.list[].skills` in `openclaw.json`. See [Skills config](/tools/skills-config) and -[Configuration Reference](/gateway/configuration-reference#agents-defaults-skills). +[Configuration Reference](/gateway/config-agents#agents-defaults-skills). List bindings: diff --git a/docs/cli/sessions.md b/docs/cli/sessions.md index fd13c033efa..719ba782e58 100644 --- a/docs/cli/sessions.md +++ b/docs/cli/sessions.md @@ -110,7 +110,7 @@ openclaw sessions cleanup --json Related: -- Session config: [Configuration reference](/gateway/configuration-reference#session) +- Session config: [Configuration reference](/gateway/config-agents#session) ## Related diff --git a/docs/concepts/messages.md b/docs/concepts/messages.md index 293de2096ca..98279ae79a7 100644 --- a/docs/concepts/messages.md +++ b/docs/concepts/messages.md @@ -149,7 +149,7 @@ Outbound message formatting is centralized in `messages`: - `messages.responsePrefix`, `channels..responsePrefix`, and `channels..accounts..responsePrefix` (outbound prefix cascade), plus `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix) - Reply threading via `replyToMode` and per-channel defaults -Details: [Configuration](/gateway/configuration-reference#messages) and channel docs. +Details: [Configuration](/gateway/config-agents#messages) and channel docs. ## Silent replies diff --git a/docs/concepts/model-providers.md b/docs/concepts/model-providers.md index cc2055c02ac..56513fd9032 100644 --- a/docs/concepts/model-providers.md +++ b/docs/concepts/model-providers.md @@ -630,5 +630,5 @@ See also: [/gateway/configuration](/gateway/configuration) for full configuratio - [Models](/concepts/models) — model configuration and aliases - [Model Failover](/concepts/model-failover) — fallback chains and retry behavior -- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — model config keys +- [Configuration Reference](/gateway/config-agents#agent-defaults) — model config keys - [Providers](/providers) — per-provider setup guides diff --git a/docs/concepts/models.md b/docs/concepts/models.md index 9fad0bb65c1..4a07dd1449d 100644 --- a/docs/concepts/models.md +++ b/docs/concepts/models.md @@ -288,4 +288,4 @@ This applies whenever OpenClaw regenerates `models.json`, including command-driv - [Image Generation](/tools/image-generation) — image model configuration - [Music Generation](/tools/music-generation) — music model configuration - [Video Generation](/tools/video-generation) — video model configuration -- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — model config keys +- [Configuration Reference](/gateway/config-agents#agent-defaults) — model config keys diff --git a/docs/docs.json b/docs/docs.json index 4b9e6162c49..c7abba3e189 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1366,6 +1366,7 @@ "pages": [ "gateway/configuration", "gateway/configuration-reference", + "gateway/config-agents", "gateway/configuration-examples", "gateway/authentication", "auth-credential-semantics", diff --git a/docs/gateway/config-agents.md b/docs/gateway/config-agents.md new file mode 100644 index 00000000000..6204bb38383 --- /dev/null +++ b/docs/gateway/config-agents.md @@ -0,0 +1,1335 @@ +--- +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). + +## Agent defaults + +### `agents.defaults.workspace` + +Default: `~/.openclaw/workspace`. + +```json5 +{ + agents: { defaults: { workspace: "~/.openclaw/workspace" } }, +} +``` + +### `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.list[].skills`. + +```json5 +{ + agents: { + defaults: { skills: ["github", "weather"] }, + list: [ + { id: "writer" }, // inherits github, weather + { id: "docs", skills: ["docs-search"] }, // replaces defaults + { id: "locked-down", skills: [] }, // no skills + ], + }, +} +``` + +- Omit `agents.defaults.skills` for unrestricted skills by default. +- Omit `agents.list[].skills` to inherit the defaults. +- Set `agents.list[].skills: []` for no skills. +- A non-empty `agents.list[].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`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`). + +```json5 +{ + agents: { defaults: { skipBootstrap: true } }, +} +``` + +### `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. + +```json5 +{ + agents: { defaults: { contextInjection: "continuation-skip" } }, +} +``` + +### `agents.defaults.bootstrapMaxChars` + +Max characters per workspace bootstrap file before truncation. Default: `12000`. + +```json5 +{ + agents: { defaults: { bootstrapMaxChars: 12000 } }, +} +``` + +### `agents.defaults.bootstrapTotalMaxChars` + +Max total characters injected across all workspace bootstrap files. Default: `60000`. + +```json5 +{ + agents: { defaults: { bootstrapTotalMaxChars: 60000 } }, +} +``` + +### `agents.defaults.bootstrapPromptTruncationWarning` + +Controls agent-visible warning text when bootstrap context is truncated. +Default: `"once"`. + +- `"off"`: never inject warning text into the system prompt. +- `"once"`: inject warning once per unique truncation signature (recommended). +- `"always"`: inject warning on every run when truncation exists. + +```json5 +{ + agents: { defaults: { bootstrapPromptTruncationWarning: "once" } }, // off | once | always +} +``` + +### 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. + +- `agents.defaults.bootstrapMaxChars` / + `agents.defaults.bootstrapTotalMaxChars`: + normal workspace bootstrap injection. +- `agents.defaults.startupContext.*`: + one-shot `/new` and `/reset` startup prelude, including recent daily + `memory/*.md` files. +- `skills.limits.*`: + the compact skills list injected into the system prompt. +- `agents.defaults.contextLimits.*`: + bounded runtime excerpts and injected runtime-owned blocks. +- `memory.qmd.limits.*`: + indexed memory-search snippet and injection sizing. + +Use the matching per-agent override only when one agent needs a different +budget: + +- `agents.list[].skillsLimits.maxSkillsPromptChars` +- `agents.list[].contextLimits.*` + +#### `agents.defaults.startupContext` + +Controls the first-turn startup prelude injected on bare `/new` and `/reset` +runs. + +```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, + memoryGetDefaultLines: 120, + toolResultMaxChars: 16000, + postCompactionMaxChars: 1800, + }, + }, + }, +} +``` + +- `memoryGetMaxChars`: default `memory_get` excerpt cap before truncation + metadata and continuation notice are added. +- `memoryGetDefaultLines`: default `memory_get` line window when `lines` is + omitted. +- `toolResultMaxChars`: live tool-result cap used for persisted results and + overflow recovery. +- `postCompactionMaxChars`: AGENTS.md excerpt cap used during post-compaction + refresh injection. + +#### `agents.list[].contextLimits` + +Per-agent override for the shared `contextLimits` knobs. Omitted fields inherit +from `agents.defaults.contextLimits`. + +```json5 +{ + agents: { + defaults: { + contextLimits: { + memoryGetMaxChars: 12000, + toolResultMaxChars: 16000, + }, + }, + list: [ + { + id: "tiny-local", + contextLimits: { + memoryGetMaxChars: 6000, + toolResultMaxChars: 8000, + }, + }, + ], + }, +} +``` + +#### `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.list[].skillsLimits.maxSkillsPromptChars` + +Per-agent override for the skills prompt budget. + +```json5 +{ + agents: { + list: [ + { + id: "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.userTimezone` + +Timezone for system prompt context (not message timestamps). Falls back to host timezone. + +```json5 +{ + agents: { defaults: { userTimezone: "America/Chicago" } }, +} +``` + +### `agents.defaults.timeFormat` + +Time format in system prompt. Default: `auto` (OS preference). + +```json5 +{ + agents: { defaults: { timeFormat: "auto" } }, // auto | 12 | 24 +} +``` + +### `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"], + }, + imageModel: { + primary: "openrouter/qwen/qwen-2.5-vl-72b-instruct:free", + fallbacks: ["openrouter/google/gemini-2.0-flash-vision:free"], + }, + imageGenerationModel: { + primary: "openai/gpt-image-2", + fallbacks: ["google/gemini-3.1-flash-image-preview"], + }, + videoGenerationModel: { + 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 + embeddedHarness: { + runtime: "auto", // auto | pi | registered harness id, e.g. codex + fallback: "pi", // pi | none + }, + pdfMaxBytesMb: 10, + pdfMaxPages: 20, + thinkingDefault: "low", + verboseDefault: "off", + elevatedDefault: "on", + timeoutSeconds: 600, + mediaMaxMb: 5, + contextTokens: 200000, + maxConcurrent: 3, + }, + }, +} +``` + +- `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. +- `imageModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`). + - Used by the `image` tool path as its vision-model config. + - Also used as fallback routing when the selected/default model cannot accept image input. +- `imageGenerationModel`: 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-preview` for native Gemini image generation, `fal/fal-ai/flux/dev` for fal, or `openai/gpt-image-2` for OpenAI Images. + - 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`, `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. +- `musicGenerationModel`: 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.5+`. + - 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. +- `videoGenerationModel`: 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 bundled Qwen video-generation provider 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. +- `pdfMaxBytesMb`: 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. +- `verboseDefault`: default verbose level for agents. Values: `"off"`, `"on"`, `"full"`. Default: `"off"`. +- `elevatedDefault`: default elevated-output level for agents. Values: `"off"`, `"on"`, `"ask"`, `"full"`. Default: `"on"`. +- `model.primary`: format `provider/model` (e.g. `openai/gpt-5.4` for API-key access or `openai-codex/gpt-5.5` for Codex OAuth). 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. +- `models`: the configured model catalog and allowlist for `/model`. Each entry can include `alias` (shortcut) and `params` (provider-specific, for example `temperature`, `maxTokens`, `cacheRetention`, `context1m`, `responsesServerCompaction`, `responsesCompactThreshold`). + - Safe edits: use `openclaw config set agents.defaults.models '' --strict-json --merge` to add entries. `config set` refuses replacements that would remove existing allowlist entries unless you pass `--replace`. + - 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#server-side-compaction-responses-api). +- `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.list[].params` (matching agent id) overrides by key. See [Prompt Caching](/reference/prompt-caching) for details. +- `embeddedHarness`: default low-level embedded agent runtime policy. Use `runtime: "auto"` to let registered plugin harnesses claim supported models, `runtime: "pi"` to force the built-in PI harness, or a registered harness id such as `runtime: "codex"`. Set `fallback: "none"` to disable automatic PI fallback. +- 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). Default: 4. + +### `agents.defaults.embeddedHarness` + +`embeddedHarness` controls which low-level executor runs embedded agent turns. +Most deployments should keep the default `{ runtime: "auto", fallback: "pi" }`. +Use it when a trusted plugin provides a native harness, such as the bundled +Codex app-server harness. + +```json5 +{ + agents: { + defaults: { + model: "openai/gpt-5.5", + embeddedHarness: { + runtime: "codex", + fallback: "none", + }, + }, + }, +} +``` + +- `runtime`: `"auto"`, `"pi"`, or a registered plugin harness id. The bundled Codex plugin registers `codex`. +- `fallback`: `"pi"` or `"none"`. `"pi"` keeps the built-in PI harness as the compatibility fallback when no plugin harness is selected. `"none"` makes missing or unsupported plugin harness selection fail instead of silently using PI. Selected plugin harness failures always surface directly. +- Environment overrides: `OPENCLAW_AGENT_RUNTIME=` overrides `runtime`; `OPENCLAW_AGENT_HARNESS_FALLBACK=none` disables PI fallback for that process. +- For Codex-only deployments, set `model: "openai/gpt-5.5"`, `embeddedHarness.runtime: "codex"`, and `embeddedHarness.fallback: "none"`. +- Harness choice is pinned per session id after the first embedded run. Config/env changes affect new or reset sessions, not an existing transcript. Legacy sessions with transcript history but no recorded pin are treated as PI-pinned. `/status` shows non-PI harness ids such as `codex` next to `Fast`. +- This only controls the embedded chat harness. 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-4-6` | +| `sonnet` | `anthropic/claude-sonnet-4-6` | +| `gpt` | `openai/gpt-5.4` or configured Codex OAuth GPT-5.5 | +| `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-preview` | + +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/"].params.thinking` yourself. +Z.AI models enable `tool_stream` by default for tool call streaming. Set `agents.defaults.models["zai/"].params.tool_stream` to `false` to disable it. +Anthropic Claude 4.6 models default to `adaptive` thinking when no explicit thinking level is set. + +### `agents.defaults.cliBackends` + +Optional CLI backends for text-only fallback runs (no tool calls). Useful as a backup when API providers fail. + +```json5 +{ + agents: { + defaults: { + cliBackends: { + "codex-cli": { + command: "/opt/homebrew/bin/codex", + }, + "my-cli": { + command: "my-cli", + args: ["--json"], + output: "json", + modelArg: "--model", + sessionArg: "--session", + sessionMode: "existing", + systemPromptArg: "--system", + systemPromptWhen: "first", + imageArg: "--image", + imageMode: "repeat", + }, + }, + }, + }, +} +``` + +- CLI backends are text-first; tools are always disabled. +- Sessions supported when `sessionArg` is set. +- Image pass-through supported when `imageArg` accepts file paths. + +### `agents.defaults.systemPromptOverride` + +Replace the entire OpenClaw-assembled system prompt with a fixed string. Set at the default level (`agents.defaults.systemPromptOverride`) or per agent (`agents.list[].systemPromptOverride`). Per-agent values take precedence; an empty or whitespace-only value is ignored. Useful for controlled prompt experiments. + +```json5 +{ + agents: { + defaults: { + systemPromptOverride: "You are a helpful assistant.", + }, + }, +} +``` + +### `agents.defaults.promptOverlays` + +Provider-independent prompt overlays applied by model family. GPT-5-family model ids receive the shared behavior contract across providers; `personality` controls only the friendly interaction-style layer. + +```json5 +{ + agents: { + defaults: { + promptOverlays: { + gpt5: { + 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. +- Legacy `plugins.entries.openai.config.personality` is still read when this shared setting is unset. + +### `agents.defaults.heartbeat` + +Periodic heartbeat runs. + +```json5 +{ + agents: { + defaults: { + heartbeat: { + every: "30m", // 0m disables + model: "openai/gpt-5.4-mini", + includeReasoning: false, + includeSystemPromptSection: true, // default: true; false omits the Heartbeat section from the system prompt + lightContext: false, // default: false; true keeps only HEARTBEAT.md from workspace bootstrap files + isolatedSession: false, // default: false; true runs each heartbeat in a fresh session (no conversation history) + session: "main", + to: "+15555550123", + directPolicy: "allow", // allow (default) | block + target: "none", // default: none | options: last | whatsapp | telegram | discord | ... + prompt: "Read HEARTBEAT.md if it exists...", + ackMaxChars: 300, + suppressToolErrorWarnings: false, + timeoutSeconds: 45, + }, + }, + }, +} +``` + +- `every`: duration string (ms/s/m/h). Default: `30m` (API-key auth) or `1h` (OAuth auth). Set to `0m` to disable. +- `includeSystemPromptSection`: when false, omits the Heartbeat section from the system prompt and skips `HEARTBEAT.md` injection into bootstrap context. Default: `true`. +- `suppressToolErrorWarnings`: when true, suppresses tool error warning payloads during heartbeat runs. +- `timeoutSeconds`: maximum time in seconds allowed for a heartbeat agent turn before it is aborted. Leave unset to use `agents.defaults.timeoutSeconds`. +- `directPolicy`: direct/DM delivery policy. `allow` (default) permits direct-target delivery. `block` suppresses direct-target delivery and emits `reason=dm-blocked`. +- `lightContext`: when true, heartbeat runs use lightweight bootstrap context and keep only `HEARTBEAT.md` from workspace bootstrap files. +- `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. +- Per-agent: set `agents.list[].heartbeat`. When any agent defines `heartbeat`, **only those agents** run heartbeats. +- Heartbeats run full agent turns — shorter intervals burn more tokens. + +### `agents.defaults.compaction` + +```json5 +{ + agents: { + defaults: { + compaction: { + mode: "safeguard", // default | safeguard + provider: "my-provider", // id of a registered compaction provider plugin (optional) + timeoutSeconds: 900, + reserveTokensFloor: 24000, + identifierPolicy: "strict", // strict | off | custom + identifierInstructions: "Preserve deployment IDs, ticket IDs, and host:port pairs exactly.", // used when identifierPolicy=custom + postCompactionSections: ["Session Startup", "Red Lines"], // [] disables reinjection + model: "openrouter/anthropic/claude-sonnet-4-6", // optional compaction-only model override + notifyUser: true, // send brief notices when compaction starts and completes (default: false) + memoryFlush: { + enabled: true, + softThresholdTokens: 6000, + systemPrompt: "Session nearing compaction. Store durable memories now.", + prompt: "Write any lasting notes to memory/YYYY-MM-DD.md; reply with the exact silent token NO_REPLY if nothing to store.", + }, + }, + }, + }, +} +``` + +- `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). +- `timeoutSeconds`: maximum seconds allowed for a single compaction operation before OpenClaw aborts it. Default: `900`. +- `identifierPolicy`: `strict` (default), `off`, or `custom`. `strict` prepends built-in opaque identifier retention guidance during compaction summarization. +- `identifierInstructions`: optional custom identifier-preservation text used when `identifierPolicy=custom`. +- `postCompactionSections`: optional AGENTS.md H2/H3 section names to re-inject after compaction. Defaults to `["Session Startup", "Red Lines"]`; set `[]` to disable reinjection. When unset or explicitly set to that default pair, older `Every Session`/`Safety` headings are also accepted as a legacy fallback. +- `model`: optional `provider/model-id` override for compaction summarization only. 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. +- `notifyUser`: when `true`, sends brief notices to the user when compaction starts and when it completes (for example, "Compacting context..." and "Compaction complete"). Disabled by default to keep compaction silent. +- `memoryFlush`: silent agentic turn before auto-compaction to store durable memories. Skipped when workspace is read-only. + +### `agents.defaults.contextPruning` + +Prunes **old tool results** from in-memory context before sending to the LLM. Does **not** modify session history on disk. + +```json5 +{ + agents: { + defaults: { + contextPruning: { + mode: "cache-ttl", // off | cache-ttl + ttl: "1h", // duration (ms/s/m/h), default unit: minutes + keepLastAssistants: 3, + softTrimRatio: 0.3, + hardClearRatio: 0.5, + minPrunableToolChars: 50000, + softTrim: { maxChars: 4000, headChars: 1500, tailChars: 1500 }, + hardClear: { enabled: true, placeholder: "[Old tool result content cleared]" }, + tools: { deny: ["browser", "canvas"] }, + }, + }, + }, +} +``` + + + +- `mode: "cache-ttl"` enables pruning passes. +- `ttl` controls how often pruning can run again (after the last cache touch). +- 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. +- If fewer than `keepLastAssistants` assistant messages exist, pruning is skipped. + + + +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 }, + blockStreamingCoalesce: { idleMs: 1000 }, + humanDelay: { mode: "natural" }, // off | natural | custom (use minMs/maxMs) + }, + }, +} +``` + +- Non-Telegram channels require explicit `*.blockStreaming: true` to enable block replies. +- Channel overrides: `channels..blockStreamingCoalesce` (and per-account variants). Signal/Slack/Discord/Google Chat default `minChars: 1500`. +- `humanDelay`: randomized pause between block replies. `natural` = 800–2500ms. Per-agent override: `agents.list[].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. +- Per-session overrides: `session.typingMode`, `session.typingIntervalSeconds`. + +See [Typing Indicators](/concepts/typing-indicators). + + + +### `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 | non-main | all + backend: "docker", // docker | ssh | openshell + scope: "agent", // session | agent | shared + workspaceAccess: "none", // none | 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, + 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, + enableNoVnc: 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"], + }, + }, + }, +} +``` + + + +**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 +- `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 + +**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` +- `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 | remote + 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:"` is blocked by default unless you explicitly set +`sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true` (break-glass). + +**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`): Chromium + CDP in a container. noVNC URL injected into system prompt. Does not require `browser.enabled` in `openclaw.json`. +noVNC observer access uses VNC auth by default and OpenClaw emits a short-lived token URL (instead of exposing the password in the shared URL). + +- `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. +- `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. +- 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=` + - `--user-data-dir=${HOME}/.chrome` + - `--no-first-run` + - `--no-default-browser-check` + - `--disable-3d-apis` + - `--disable-gpu` + - `--disable-software-rasterizer` + - `--disable-dev-shm-usage` + - `--disable-background-networking` + - `--disable-features=TranslateUI` + - `--disable-breakpad` + - `--disable-crash-reporter` + - `--renderer-process-limit=2` + - `--no-zygote` + - `--metrics-recording-only` + - `--disable-extensions` (default enabled) + - `--disable-3d-apis`, `--disable-software-rasterizer`, and `--disable-gpu` are + enabled by default and can be disabled with + `OPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0` if WebGL/3D usage requires it. + - `OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0` re-enables extensions if your workflow + depends on them. + - `--renderer-process-limit=2` can be changed with + `OPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=`; set `0` to use Chromium's + default process limit. + - plus `--no-sandbox` and `--disable-setuid-sandbox` when `noSandbox` is enabled. + - Defaults are the container image baseline; use a custom browser image with a custom + entrypoint to change container defaults. + + + +Browser sandboxing and `sandbox.docker.binds` are Docker-only. + +Build images: + +```bash +scripts/sandbox-setup.sh # main sandbox image +scripts/sandbox-browser-setup.sh # optional browser image +``` + +### `agents.list` (per-agent overrides) + +```json5 +{ + agents: { + list: [ + { + id: "main", + default: true, + name: "Main Agent", + workspace: "~/.openclaw/workspace", + agentDir: "~/.openclaw/agents/main/agent", + model: "anthropic/claude-opus-4-6", // or { primary, fallbacks } + thinkingDefault: "high", // per-agent thinking level override + reasoningDefault: "on", // per-agent reasoning visibility override + fastModeDefault: false, // per-agent fast mode override + embeddedHarness: { runtime: "auto", fallback: "pi" }, + params: { cacheRetention: "none" }, // overrides matching defaults.models params by key + 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", + cwd: "/workspace/openclaw", + }, + }, + subagents: { allowAgents: ["*"] }, + tools: { + profile: "coding", + allow: ["browser"], + deny: ["canvas"], + elevated: { enabled: true }, + }, + }, + ], + }, +} +``` + +- `id`: stable agent id (required). +- `default`: when multiple are set, first wins (warning logged). If none set, first list entry is default. +- `model`: string form overrides `primary` only; object form `{ primary, fallbacks }` overrides both (`[]` disables global fallbacks). Cron jobs that only override `primary` still inherit default fallbacks unless you set `fallbacks: []`. +- `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. +- `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. +- `reasoningDefault`: optional per-agent default reasoning visibility (`on | off | stream`). Applies when no per-message or session reasoning override is set. +- `fastModeDefault`: optional per-agent default for fast mode (`true | false`). Applies when no per-message or session fast-mode override is set. +- `embeddedHarness`: optional per-agent low-level harness policy override. Use `{ runtime: "codex", fallback: "none" }` to make one agent Codex-only while other agents keep the default PI fallback. +- `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. +- `identity` derives defaults: `ackReaction` from `emoji`, `mentionPatterns` from `name`/`emoji`. +- `subagents.allowAgents`: allowlist of agent ids for `sessions_spawn` (`["*"]` = any; default: same agent only). +- 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). + +--- + +## Multi-agent routing + +Run multiple isolated agents inside one Gateway. See [Multi-Agent](/concepts/multi-agent). + +```json5 +{ + agents: { + list: [ + { id: "home", default: true, workspace: "~/.openclaw/workspace-home" }, + { id: "work", workspace: "~/.openclaw/workspace-work" }, + ], + }, + bindings: [ + { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } }, + { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } }, + ], +} +``` + +### 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. Default agent + +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 + + + +```json5 +{ + agents: { + list: [ + { + id: "personal", + workspace: "~/.openclaw/workspace-personal", + sandbox: { mode: "off" }, + }, + ], + }, +} +``` + + + + + +```json5 +{ + agents: { + list: [ + { + id: "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"], + }, + }, + ], + }, +} +``` + + + + + +```json5 +{ + agents: { + list: [ + { + id: "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", + ], + }, + }, + ], + }, +} +``` + + + +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 }, + }, + resetTriggers: ["/new", "/reset"], + store: "~/.openclaw/agents/{agentId}/sessions/sessions.json", + parentForkMaxTokens: 100000, // skip parent-thread fork above this token count (0 disables) + maintenance: { + mode: "warn", // warn | enforce + pruneAfter: "30d", + maxEntries: 500, + rotateBytes: "10mb", + 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) + }, + mainKey: "main", // legacy (runtime always uses "main") + agentToAgent: { maxPingPongTurns: 5 }, + sendPolicy: { + rules: [{ action: "deny", match: { channel: "discord", chatType: "group" } }], + default: "allow", + }, + }, +} +``` + + + +- **`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. +- **`reset`**: primary reset policy. `daily` resets at `atHour` local time; `idle` resets after `idleMinutes`. When both configured, whichever expires first wins. +- **`resetByType`**: per-type overrides (`direct`, `group`, `thread`). Legacy `dm` accepted as alias for `direct`. +- **`parentForkMaxTokens`**: max parent-session `totalTokens` allowed when creating a forked thread session (default `100000`). + - If parent `totalTokens` is above this value, OpenClaw starts a fresh thread session instead of inheriting parent transcript history. + - Set `0` to disable this guard and always allow parent forking. +- **`mainKey`**: legacy field. Runtime always uses `"main"` for the main direct-chat bucket. +- **`agentToAgent.maxPingPongTurns`**: maximum reply-back turns between agents during agent-to-agent exchanges (integer, range: `0`–`5`). `0` disables ping-pong chaining. +- **`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`: `warn` emits warnings only; `enforce` applies cleanup. + - `pruneAfter`: age cutoff for stale entries (default `30d`). + - `maxEntries`: maximum number of entries in `sessions.json` (default `500`). + - `rotateBytes`: rotate `sessions.json` when it exceeds this size (default `10mb`). + - `resetArchiveRetention`: retention for `*.reset.` transcript archives. Defaults to `pruneAfter`; set `false` to disable. + - `maxDiskBytes`: optional sessions-directory disk budget. In `warn` mode it logs warnings; in `enforce` mode it removes oldest artifacts/sessions first. + - `highWaterBytes`: optional target after budget cleanup. Defaults to `80%` of `maxDiskBytes`. +- **`threadBindings`**: global defaults for thread-bound session features. + - `enabled`: master default switch (providers can override; Discord uses `channels.discord.threadBindings.enabled`) + - `idleHours`: default inactivity auto-unfocus in hours (`0` disables; providers can override) + - `maxAgeHours`: default hard max age in hours (`0` disables; providers can override) + + + +--- + +## Messages + +```json5 +{ + messages: { + responsePrefix: "🦞", // or "auto" + ackReaction: "👀", + ackReactionScope: "group-mentions", // group-mentions | group-all | direct | all + removeAckAfterReply: false, + queue: { + mode: "collect", // steer | followup | collect | steer-backlog | steer+backlog | queue | interrupt + debounceMs: 1000, + cap: 20, + drop: "summarize", // old | new | summarize + byChannel: { + whatsapp: "collect", + telegram: "collect", + }, + }, + inbound: { + debounceMs: 2000, // 0 disables + byChannel: { + whatsapp: 5000, + slack: 1500, + }, + }, + }, +} +``` + +### Response prefix + +Per-channel/account overrides: `channels..responsePrefix`, `channels..accounts..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..ackReaction`, `channels..accounts..ackReaction`. +- Resolution order: account → channel → `messages.ackReaction` → identity fallback. +- Scope: `group-mentions` (default), `group-all`, `direct`, `all`. +- `removeAckAfterReply`: removes ack after reply on Slack, Discord, and Telegram. +- `messages.statusReactions.enabled`: enables lifecycle status reactions on Slack, Discord, and Telegram. + On Slack and Discord, unset keeps status reactions enabled when ack reactions are active. + On Telegram, set it explicitly to `true` to enable lifecycle status reactions. + +### Inbound debounce + +Batches rapid text-only messages from the same sender into a single agent turn. Media/attachments flush immediately. Control commands bypass debouncing. + +### TTS (text-to-speech) + +```json5 +{ + messages: { + tts: { + auto: "always", // off | always | inbound | tagged + mode: "final", // final | all + provider: "elevenlabs", + summaryModel: "openai/gpt-4.1-mini", + modelOverrides: { enabled: true }, + maxTextLength: 4000, + timeoutMs: 30000, + prefsPath: "~/.openclaw/settings/tts.json", + elevenlabs: { + apiKey: "elevenlabs_api_key", + baseUrl: "https://api.elevenlabs.io", + voiceId: "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, + }, + }, + openai: { + apiKey: "openai_api_key", + baseUrl: "https://api.openai.com/v1", + model: "gpt-4o-mini-tts", + voice: "alloy", + }, + }, + }, +} +``` + +- `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; `modelOverrides.allowProvider` defaults to `false` (opt-in). +- API keys fall back to `ELEVENLABS_API_KEY`/`XI_API_KEY` and `OPENAI_API_KEY`. +- `openai.baseUrl` overrides the OpenAI TTS endpoint. Resolution order is config, then `OPENAI_TTS_BASE_URL`, then `https://api.openai.com/v1`. +- When `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). + +```json5 +{ + talk: { + provider: "elevenlabs", + providers: { + elevenlabs: { + voiceId: "elevenlabs_voice_id", + voiceAliases: { + Clawd: "EXAVITQu4vr4xnSDxMaL", + Roger: "CwhRBWXzGAHq8TQ4Fs17", + }, + modelId: "eleven_v3", + outputFormat: "mp3_44100_128", + apiKey: "elevenlabs_api_key", + }, + }, + silenceTimeoutMs: 1500, + interruptOnSpeech: true, + }, +} +``` + +- `talk.provider` must match a key in `talk.providers` when multiple Talk providers are configured. +- Legacy flat Talk keys (`talk.voiceId`, `talk.voiceAliases`, `talk.modelId`, `talk.outputFormat`, `talk.apiKey`) are compatibility-only and are auto-migrated into `talk.providers.`. +- Voice IDs fall back to `ELEVENLABS_VOICE_ID` or `SAG_VOICE_ID`. +- `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. +- `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`). + +--- + +## Related + +- [Configuration reference](/gateway/configuration-reference) — all other config keys +- [Configuration](/gateway/configuration) — common tasks and quick setup +- [Configuration examples](/gateway/configuration-examples) diff --git a/docs/gateway/configuration-reference.md b/docs/gateway/configuration-reference.md index 4b038712a0f..9825ca3a3dd 100644 --- a/docs/gateway/configuration-reference.md +++ b/docs/gateway/configuration-reference.md @@ -883,1322 +883,16 @@ Include your own number in `allowFrom` to enable self-chat mode (ignores native --- -## Agent defaults +## Agent defaults, multi-agent, sessions, and messages -### `agents.defaults.workspace` +Moved to a dedicated page — see +[Configuration — agents](/gateway/config-agents) for: -Default: `~/.openclaw/workspace`. - -```json5 -{ - agents: { defaults: { workspace: "~/.openclaw/workspace" } }, -} -``` - -### `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.list[].skills`. - -```json5 -{ - agents: { - defaults: { skills: ["github", "weather"] }, - list: [ - { id: "writer" }, // inherits github, weather - { id: "docs", skills: ["docs-search"] }, // replaces defaults - { id: "locked-down", skills: [] }, // no skills - ], - }, -} -``` - -- Omit `agents.defaults.skills` for unrestricted skills by default. -- Omit `agents.list[].skills` to inherit the defaults. -- Set `agents.list[].skills: []` for no skills. -- A non-empty `agents.list[].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`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`). - -```json5 -{ - agents: { defaults: { skipBootstrap: true } }, -} -``` - -### `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. - -```json5 -{ - agents: { defaults: { contextInjection: "continuation-skip" } }, -} -``` - -### `agents.defaults.bootstrapMaxChars` - -Max characters per workspace bootstrap file before truncation. Default: `12000`. - -```json5 -{ - agents: { defaults: { bootstrapMaxChars: 12000 } }, -} -``` - -### `agents.defaults.bootstrapTotalMaxChars` - -Max total characters injected across all workspace bootstrap files. Default: `60000`. - -```json5 -{ - agents: { defaults: { bootstrapTotalMaxChars: 60000 } }, -} -``` - -### `agents.defaults.bootstrapPromptTruncationWarning` - -Controls agent-visible warning text when bootstrap context is truncated. -Default: `"once"`. - -- `"off"`: never inject warning text into the system prompt. -- `"once"`: inject warning once per unique truncation signature (recommended). -- `"always"`: inject warning on every run when truncation exists. - -```json5 -{ - agents: { defaults: { bootstrapPromptTruncationWarning: "once" } }, // off | once | always -} -``` - -### 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. - -- `agents.defaults.bootstrapMaxChars` / - `agents.defaults.bootstrapTotalMaxChars`: - normal workspace bootstrap injection. -- `agents.defaults.startupContext.*`: - one-shot `/new` and `/reset` startup prelude, including recent daily - `memory/*.md` files. -- `skills.limits.*`: - the compact skills list injected into the system prompt. -- `agents.defaults.contextLimits.*`: - bounded runtime excerpts and injected runtime-owned blocks. -- `memory.qmd.limits.*`: - indexed memory-search snippet and injection sizing. - -Use the matching per-agent override only when one agent needs a different -budget: - -- `agents.list[].skillsLimits.maxSkillsPromptChars` -- `agents.list[].contextLimits.*` - -#### `agents.defaults.startupContext` - -Controls the first-turn startup prelude injected on bare `/new` and `/reset` -runs. - -```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, - memoryGetDefaultLines: 120, - toolResultMaxChars: 16000, - postCompactionMaxChars: 1800, - }, - }, - }, -} -``` - -- `memoryGetMaxChars`: default `memory_get` excerpt cap before truncation - metadata and continuation notice are added. -- `memoryGetDefaultLines`: default `memory_get` line window when `lines` is - omitted. -- `toolResultMaxChars`: live tool-result cap used for persisted results and - overflow recovery. -- `postCompactionMaxChars`: AGENTS.md excerpt cap used during post-compaction - refresh injection. - -#### `agents.list[].contextLimits` - -Per-agent override for the shared `contextLimits` knobs. Omitted fields inherit -from `agents.defaults.contextLimits`. - -```json5 -{ - agents: { - defaults: { - contextLimits: { - memoryGetMaxChars: 12000, - toolResultMaxChars: 16000, - }, - }, - list: [ - { - id: "tiny-local", - contextLimits: { - memoryGetMaxChars: 6000, - toolResultMaxChars: 8000, - }, - }, - ], - }, -} -``` - -#### `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.list[].skillsLimits.maxSkillsPromptChars` - -Per-agent override for the skills prompt budget. - -```json5 -{ - agents: { - list: [ - { - id: "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.userTimezone` - -Timezone for system prompt context (not message timestamps). Falls back to host timezone. - -```json5 -{ - agents: { defaults: { userTimezone: "America/Chicago" } }, -} -``` - -### `agents.defaults.timeFormat` - -Time format in system prompt. Default: `auto` (OS preference). - -```json5 -{ - agents: { defaults: { timeFormat: "auto" } }, // auto | 12 | 24 -} -``` - -### `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"], - }, - imageModel: { - primary: "openrouter/qwen/qwen-2.5-vl-72b-instruct:free", - fallbacks: ["openrouter/google/gemini-2.0-flash-vision:free"], - }, - imageGenerationModel: { - primary: "openai/gpt-image-2", - fallbacks: ["google/gemini-3.1-flash-image-preview"], - }, - videoGenerationModel: { - 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 - embeddedHarness: { - runtime: "auto", // auto | pi | registered harness id, e.g. codex - fallback: "pi", // pi | none - }, - pdfMaxBytesMb: 10, - pdfMaxPages: 20, - thinkingDefault: "low", - verboseDefault: "off", - elevatedDefault: "on", - timeoutSeconds: 600, - mediaMaxMb: 5, - contextTokens: 200000, - maxConcurrent: 3, - }, - }, -} -``` - -- `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. -- `imageModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`). - - Used by the `image` tool path as its vision-model config. - - Also used as fallback routing when the selected/default model cannot accept image input. -- `imageGenerationModel`: 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-preview` for native Gemini image generation, `fal/fal-ai/flux/dev` for fal, or `openai/gpt-image-2` for OpenAI Images. - - 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`, `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. -- `musicGenerationModel`: 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.5+`. - - 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. -- `videoGenerationModel`: 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 bundled Qwen video-generation provider 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. -- `pdfMaxBytesMb`: 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. -- `verboseDefault`: default verbose level for agents. Values: `"off"`, `"on"`, `"full"`. Default: `"off"`. -- `elevatedDefault`: default elevated-output level for agents. Values: `"off"`, `"on"`, `"ask"`, `"full"`. Default: `"on"`. -- `model.primary`: format `provider/model` (e.g. `openai/gpt-5.4` for API-key access or `openai-codex/gpt-5.5` for Codex OAuth). 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. -- `models`: the configured model catalog and allowlist for `/model`. Each entry can include `alias` (shortcut) and `params` (provider-specific, for example `temperature`, `maxTokens`, `cacheRetention`, `context1m`, `responsesServerCompaction`, `responsesCompactThreshold`). - - Safe edits: use `openclaw config set agents.defaults.models '' --strict-json --merge` to add entries. `config set` refuses replacements that would remove existing allowlist entries unless you pass `--replace`. - - 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#server-side-compaction-responses-api). -- `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.list[].params` (matching agent id) overrides by key. See [Prompt Caching](/reference/prompt-caching) for details. -- `embeddedHarness`: default low-level embedded agent runtime policy. Use `runtime: "auto"` to let registered plugin harnesses claim supported models, `runtime: "pi"` to force the built-in PI harness, or a registered harness id such as `runtime: "codex"`. Set `fallback: "none"` to disable automatic PI fallback. -- 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). Default: 4. - -### `agents.defaults.embeddedHarness` - -`embeddedHarness` controls which low-level executor runs embedded agent turns. -Most deployments should keep the default `{ runtime: "auto", fallback: "pi" }`. -Use it when a trusted plugin provides a native harness, such as the bundled -Codex app-server harness. - -```json5 -{ - agents: { - defaults: { - model: "openai/gpt-5.5", - embeddedHarness: { - runtime: "codex", - fallback: "none", - }, - }, - }, -} -``` - -- `runtime`: `"auto"`, `"pi"`, or a registered plugin harness id. The bundled Codex plugin registers `codex`. -- `fallback`: `"pi"` or `"none"`. `"pi"` keeps the built-in PI harness as the compatibility fallback when no plugin harness is selected. `"none"` makes missing or unsupported plugin harness selection fail instead of silently using PI. Selected plugin harness failures always surface directly. -- Environment overrides: `OPENCLAW_AGENT_RUNTIME=` overrides `runtime`; `OPENCLAW_AGENT_HARNESS_FALLBACK=none` disables PI fallback for that process. -- For Codex-only deployments, set `model: "openai/gpt-5.5"`, `embeddedHarness.runtime: "codex"`, and `embeddedHarness.fallback: "none"`. -- Harness choice is pinned per session id after the first embedded run. Config/env changes affect new or reset sessions, not an existing transcript. Legacy sessions with transcript history but no recorded pin are treated as PI-pinned. `/status` shows non-PI harness ids such as `codex` next to `Fast`. -- This only controls the embedded chat harness. 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-4-6` | -| `sonnet` | `anthropic/claude-sonnet-4-6` | -| `gpt` | `openai/gpt-5.4` or configured Codex OAuth GPT-5.5 | -| `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-preview` | - -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/"].params.thinking` yourself. -Z.AI models enable `tool_stream` by default for tool call streaming. Set `agents.defaults.models["zai/"].params.tool_stream` to `false` to disable it. -Anthropic Claude 4.6 models default to `adaptive` thinking when no explicit thinking level is set. - -### `agents.defaults.cliBackends` - -Optional CLI backends for text-only fallback runs (no tool calls). Useful as a backup when API providers fail. - -```json5 -{ - agents: { - defaults: { - cliBackends: { - "codex-cli": { - command: "/opt/homebrew/bin/codex", - }, - "my-cli": { - command: "my-cli", - args: ["--json"], - output: "json", - modelArg: "--model", - sessionArg: "--session", - sessionMode: "existing", - systemPromptArg: "--system", - systemPromptWhen: "first", - imageArg: "--image", - imageMode: "repeat", - }, - }, - }, - }, -} -``` - -- CLI backends are text-first; tools are always disabled. -- Sessions supported when `sessionArg` is set. -- Image pass-through supported when `imageArg` accepts file paths. - -### `agents.defaults.systemPromptOverride` - -Replace the entire OpenClaw-assembled system prompt with a fixed string. Set at the default level (`agents.defaults.systemPromptOverride`) or per agent (`agents.list[].systemPromptOverride`). Per-agent values take precedence; an empty or whitespace-only value is ignored. Useful for controlled prompt experiments. - -```json5 -{ - agents: { - defaults: { - systemPromptOverride: "You are a helpful assistant.", - }, - }, -} -``` - -### `agents.defaults.promptOverlays` - -Provider-independent prompt overlays applied by model family. GPT-5-family model ids receive the shared behavior contract across providers; `personality` controls only the friendly interaction-style layer. - -```json5 -{ - agents: { - defaults: { - promptOverlays: { - gpt5: { - 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. -- Legacy `plugins.entries.openai.config.personality` is still read when this shared setting is unset. - -### `agents.defaults.heartbeat` - -Periodic heartbeat runs. - -```json5 -{ - agents: { - defaults: { - heartbeat: { - every: "30m", // 0m disables - model: "openai/gpt-5.4-mini", - includeReasoning: false, - includeSystemPromptSection: true, // default: true; false omits the Heartbeat section from the system prompt - lightContext: false, // default: false; true keeps only HEARTBEAT.md from workspace bootstrap files - isolatedSession: false, // default: false; true runs each heartbeat in a fresh session (no conversation history) - session: "main", - to: "+15555550123", - directPolicy: "allow", // allow (default) | block - target: "none", // default: none | options: last | whatsapp | telegram | discord | ... - prompt: "Read HEARTBEAT.md if it exists...", - ackMaxChars: 300, - suppressToolErrorWarnings: false, - timeoutSeconds: 45, - }, - }, - }, -} -``` - -- `every`: duration string (ms/s/m/h). Default: `30m` (API-key auth) or `1h` (OAuth auth). Set to `0m` to disable. -- `includeSystemPromptSection`: when false, omits the Heartbeat section from the system prompt and skips `HEARTBEAT.md` injection into bootstrap context. Default: `true`. -- `suppressToolErrorWarnings`: when true, suppresses tool error warning payloads during heartbeat runs. -- `timeoutSeconds`: maximum time in seconds allowed for a heartbeat agent turn before it is aborted. Leave unset to use `agents.defaults.timeoutSeconds`. -- `directPolicy`: direct/DM delivery policy. `allow` (default) permits direct-target delivery. `block` suppresses direct-target delivery and emits `reason=dm-blocked`. -- `lightContext`: when true, heartbeat runs use lightweight bootstrap context and keep only `HEARTBEAT.md` from workspace bootstrap files. -- `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. -- Per-agent: set `agents.list[].heartbeat`. When any agent defines `heartbeat`, **only those agents** run heartbeats. -- Heartbeats run full agent turns — shorter intervals burn more tokens. - -### `agents.defaults.compaction` - -```json5 -{ - agents: { - defaults: { - compaction: { - mode: "safeguard", // default | safeguard - provider: "my-provider", // id of a registered compaction provider plugin (optional) - timeoutSeconds: 900, - reserveTokensFloor: 24000, - identifierPolicy: "strict", // strict | off | custom - identifierInstructions: "Preserve deployment IDs, ticket IDs, and host:port pairs exactly.", // used when identifierPolicy=custom - postCompactionSections: ["Session Startup", "Red Lines"], // [] disables reinjection - model: "openrouter/anthropic/claude-sonnet-4-6", // optional compaction-only model override - notifyUser: true, // send brief notices when compaction starts and completes (default: false) - memoryFlush: { - enabled: true, - softThresholdTokens: 6000, - systemPrompt: "Session nearing compaction. Store durable memories now.", - prompt: "Write any lasting notes to memory/YYYY-MM-DD.md; reply with the exact silent token NO_REPLY if nothing to store.", - }, - }, - }, - }, -} -``` - -- `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). -- `timeoutSeconds`: maximum seconds allowed for a single compaction operation before OpenClaw aborts it. Default: `900`. -- `identifierPolicy`: `strict` (default), `off`, or `custom`. `strict` prepends built-in opaque identifier retention guidance during compaction summarization. -- `identifierInstructions`: optional custom identifier-preservation text used when `identifierPolicy=custom`. -- `postCompactionSections`: optional AGENTS.md H2/H3 section names to re-inject after compaction. Defaults to `["Session Startup", "Red Lines"]`; set `[]` to disable reinjection. When unset or explicitly set to that default pair, older `Every Session`/`Safety` headings are also accepted as a legacy fallback. -- `model`: optional `provider/model-id` override for compaction summarization only. 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. -- `notifyUser`: when `true`, sends brief notices to the user when compaction starts and when it completes (for example, "Compacting context..." and "Compaction complete"). Disabled by default to keep compaction silent. -- `memoryFlush`: silent agentic turn before auto-compaction to store durable memories. Skipped when workspace is read-only. - -### `agents.defaults.contextPruning` - -Prunes **old tool results** from in-memory context before sending to the LLM. Does **not** modify session history on disk. - -```json5 -{ - agents: { - defaults: { - contextPruning: { - mode: "cache-ttl", // off | cache-ttl - ttl: "1h", // duration (ms/s/m/h), default unit: minutes - keepLastAssistants: 3, - softTrimRatio: 0.3, - hardClearRatio: 0.5, - minPrunableToolChars: 50000, - softTrim: { maxChars: 4000, headChars: 1500, tailChars: 1500 }, - hardClear: { enabled: true, placeholder: "[Old tool result content cleared]" }, - tools: { deny: ["browser", "canvas"] }, - }, - }, - }, -} -``` - - - -- `mode: "cache-ttl"` enables pruning passes. -- `ttl` controls how often pruning can run again (after the last cache touch). -- 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. -- If fewer than `keepLastAssistants` assistant messages exist, pruning is skipped. - - - -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 }, - blockStreamingCoalesce: { idleMs: 1000 }, - humanDelay: { mode: "natural" }, // off | natural | custom (use minMs/maxMs) - }, - }, -} -``` - -- Non-Telegram channels require explicit `*.blockStreaming: true` to enable block replies. -- Channel overrides: `channels..blockStreamingCoalesce` (and per-account variants). Signal/Slack/Discord/Google Chat default `minChars: 1500`. -- `humanDelay`: randomized pause between block replies. `natural` = 800–2500ms. Per-agent override: `agents.list[].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. -- Per-session overrides: `session.typingMode`, `session.typingIntervalSeconds`. - -See [Typing Indicators](/concepts/typing-indicators). - - - -### `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 | non-main | all - backend: "docker", // docker | ssh | openshell - scope: "agent", // session | agent | shared - workspaceAccess: "none", // none | 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, - 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, - enableNoVnc: 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"], - }, - }, - }, -} -``` - - - -**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 -- `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 - -**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` -- `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 | remote - 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:"` is blocked by default unless you explicitly set -`sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true` (break-glass). - -**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`): Chromium + CDP in a container. noVNC URL injected into system prompt. Does not require `browser.enabled` in `openclaw.json`. -noVNC observer access uses VNC auth by default and OpenClaw emits a short-lived token URL (instead of exposing the password in the shared URL). - -- `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. -- `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. -- 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=` - - `--user-data-dir=${HOME}/.chrome` - - `--no-first-run` - - `--no-default-browser-check` - - `--disable-3d-apis` - - `--disable-gpu` - - `--disable-software-rasterizer` - - `--disable-dev-shm-usage` - - `--disable-background-networking` - - `--disable-features=TranslateUI` - - `--disable-breakpad` - - `--disable-crash-reporter` - - `--renderer-process-limit=2` - - `--no-zygote` - - `--metrics-recording-only` - - `--disable-extensions` (default enabled) - - `--disable-3d-apis`, `--disable-software-rasterizer`, and `--disable-gpu` are - enabled by default and can be disabled with - `OPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0` if WebGL/3D usage requires it. - - `OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0` re-enables extensions if your workflow - depends on them. - - `--renderer-process-limit=2` can be changed with - `OPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=`; set `0` to use Chromium's - default process limit. - - plus `--no-sandbox` and `--disable-setuid-sandbox` when `noSandbox` is enabled. - - Defaults are the container image baseline; use a custom browser image with a custom - entrypoint to change container defaults. - - - -Browser sandboxing and `sandbox.docker.binds` are Docker-only. - -Build images: - -```bash -scripts/sandbox-setup.sh # main sandbox image -scripts/sandbox-browser-setup.sh # optional browser image -``` - -### `agents.list` (per-agent overrides) - -```json5 -{ - agents: { - list: [ - { - id: "main", - default: true, - name: "Main Agent", - workspace: "~/.openclaw/workspace", - agentDir: "~/.openclaw/agents/main/agent", - model: "anthropic/claude-opus-4-6", // or { primary, fallbacks } - thinkingDefault: "high", // per-agent thinking level override - reasoningDefault: "on", // per-agent reasoning visibility override - fastModeDefault: false, // per-agent fast mode override - embeddedHarness: { runtime: "auto", fallback: "pi" }, - params: { cacheRetention: "none" }, // overrides matching defaults.models params by key - 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", - cwd: "/workspace/openclaw", - }, - }, - subagents: { allowAgents: ["*"] }, - tools: { - profile: "coding", - allow: ["browser"], - deny: ["canvas"], - elevated: { enabled: true }, - }, - }, - ], - }, -} -``` - -- `id`: stable agent id (required). -- `default`: when multiple are set, first wins (warning logged). If none set, first list entry is default. -- `model`: string form overrides `primary` only; object form `{ primary, fallbacks }` overrides both (`[]` disables global fallbacks). Cron jobs that only override `primary` still inherit default fallbacks unless you set `fallbacks: []`. -- `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. -- `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. -- `reasoningDefault`: optional per-agent default reasoning visibility (`on | off | stream`). Applies when no per-message or session reasoning override is set. -- `fastModeDefault`: optional per-agent default for fast mode (`true | false`). Applies when no per-message or session fast-mode override is set. -- `embeddedHarness`: optional per-agent low-level harness policy override. Use `{ runtime: "codex", fallback: "none" }` to make one agent Codex-only while other agents keep the default PI fallback. -- `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. -- `identity` derives defaults: `ackReaction` from `emoji`, `mentionPatterns` from `name`/`emoji`. -- `subagents.allowAgents`: allowlist of agent ids for `sessions_spawn` (`["*"]` = any; default: same agent only). -- 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). - ---- - -## Multi-agent routing - -Run multiple isolated agents inside one Gateway. See [Multi-Agent](/concepts/multi-agent). - -```json5 -{ - agents: { - list: [ - { id: "home", default: true, workspace: "~/.openclaw/workspace-home" }, - { id: "work", workspace: "~/.openclaw/workspace-work" }, - ], - }, - bindings: [ - { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } }, - { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } }, - ], -} -``` - -### 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. Default agent - -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 - - - -```json5 -{ - agents: { - list: [ - { - id: "personal", - workspace: "~/.openclaw/workspace-personal", - sandbox: { mode: "off" }, - }, - ], - }, -} -``` - - - - - -```json5 -{ - agents: { - list: [ - { - id: "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"], - }, - }, - ], - }, -} -``` - - - - - -```json5 -{ - agents: { - list: [ - { - id: "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", - ], - }, - }, - ], - }, -} -``` - - - -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 }, - }, - resetTriggers: ["/new", "/reset"], - store: "~/.openclaw/agents/{agentId}/sessions/sessions.json", - parentForkMaxTokens: 100000, // skip parent-thread fork above this token count (0 disables) - maintenance: { - mode: "warn", // warn | enforce - pruneAfter: "30d", - maxEntries: 500, - rotateBytes: "10mb", - 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) - }, - mainKey: "main", // legacy (runtime always uses "main") - agentToAgent: { maxPingPongTurns: 5 }, - sendPolicy: { - rules: [{ action: "deny", match: { channel: "discord", chatType: "group" } }], - default: "allow", - }, - }, -} -``` - - - -- **`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. -- **`reset`**: primary reset policy. `daily` resets at `atHour` local time; `idle` resets after `idleMinutes`. When both configured, whichever expires first wins. -- **`resetByType`**: per-type overrides (`direct`, `group`, `thread`). Legacy `dm` accepted as alias for `direct`. -- **`parentForkMaxTokens`**: max parent-session `totalTokens` allowed when creating a forked thread session (default `100000`). - - If parent `totalTokens` is above this value, OpenClaw starts a fresh thread session instead of inheriting parent transcript history. - - Set `0` to disable this guard and always allow parent forking. -- **`mainKey`**: legacy field. Runtime always uses `"main"` for the main direct-chat bucket. -- **`agentToAgent.maxPingPongTurns`**: maximum reply-back turns between agents during agent-to-agent exchanges (integer, range: `0`–`5`). `0` disables ping-pong chaining. -- **`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`: `warn` emits warnings only; `enforce` applies cleanup. - - `pruneAfter`: age cutoff for stale entries (default `30d`). - - `maxEntries`: maximum number of entries in `sessions.json` (default `500`). - - `rotateBytes`: rotate `sessions.json` when it exceeds this size (default `10mb`). - - `resetArchiveRetention`: retention for `*.reset.` transcript archives. Defaults to `pruneAfter`; set `false` to disable. - - `maxDiskBytes`: optional sessions-directory disk budget. In `warn` mode it logs warnings; in `enforce` mode it removes oldest artifacts/sessions first. - - `highWaterBytes`: optional target after budget cleanup. Defaults to `80%` of `maxDiskBytes`. -- **`threadBindings`**: global defaults for thread-bound session features. - - `enabled`: master default switch (providers can override; Discord uses `channels.discord.threadBindings.enabled`) - - `idleHours`: default inactivity auto-unfocus in hours (`0` disables; providers can override) - - `maxAgeHours`: default hard max age in hours (`0` disables; providers can override) - - - ---- - -## Messages - -```json5 -{ - messages: { - responsePrefix: "🦞", // or "auto" - ackReaction: "👀", - ackReactionScope: "group-mentions", // group-mentions | group-all | direct | all - removeAckAfterReply: false, - queue: { - mode: "collect", // steer | followup | collect | steer-backlog | steer+backlog | queue | interrupt - debounceMs: 1000, - cap: 20, - drop: "summarize", // old | new | summarize - byChannel: { - whatsapp: "collect", - telegram: "collect", - }, - }, - inbound: { - debounceMs: 2000, // 0 disables - byChannel: { - whatsapp: 5000, - slack: 1500, - }, - }, - }, -} -``` - -### Response prefix - -Per-channel/account overrides: `channels..responsePrefix`, `channels..accounts..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..ackReaction`, `channels..accounts..ackReaction`. -- Resolution order: account → channel → `messages.ackReaction` → identity fallback. -- Scope: `group-mentions` (default), `group-all`, `direct`, `all`. -- `removeAckAfterReply`: removes ack after reply on Slack, Discord, and Telegram. -- `messages.statusReactions.enabled`: enables lifecycle status reactions on Slack, Discord, and Telegram. - On Slack and Discord, unset keeps status reactions enabled when ack reactions are active. - On Telegram, set it explicitly to `true` to enable lifecycle status reactions. - -### Inbound debounce - -Batches rapid text-only messages from the same sender into a single agent turn. Media/attachments flush immediately. Control commands bypass debouncing. - -### TTS (text-to-speech) - -```json5 -{ - messages: { - tts: { - auto: "always", // off | always | inbound | tagged - mode: "final", // final | all - provider: "elevenlabs", - summaryModel: "openai/gpt-4.1-mini", - modelOverrides: { enabled: true }, - maxTextLength: 4000, - timeoutMs: 30000, - prefsPath: "~/.openclaw/settings/tts.json", - elevenlabs: { - apiKey: "elevenlabs_api_key", - baseUrl: "https://api.elevenlabs.io", - voiceId: "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, - }, - }, - openai: { - apiKey: "openai_api_key", - baseUrl: "https://api.openai.com/v1", - model: "gpt-4o-mini-tts", - voice: "alloy", - }, - }, - }, -} -``` - -- `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; `modelOverrides.allowProvider` defaults to `false` (opt-in). -- API keys fall back to `ELEVENLABS_API_KEY`/`XI_API_KEY` and `OPENAI_API_KEY`. -- `openai.baseUrl` overrides the OpenAI TTS endpoint. Resolution order is config, then `OPENAI_TTS_BASE_URL`, then `https://api.openai.com/v1`. -- When `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). - -```json5 -{ - talk: { - provider: "elevenlabs", - providers: { - elevenlabs: { - voiceId: "elevenlabs_voice_id", - voiceAliases: { - Clawd: "EXAVITQu4vr4xnSDxMaL", - Roger: "CwhRBWXzGAHq8TQ4Fs17", - }, - modelId: "eleven_v3", - outputFormat: "mp3_44100_128", - apiKey: "elevenlabs_api_key", - }, - }, - silenceTimeoutMs: 1500, - interruptOnSpeech: true, - }, -} -``` - -- `talk.provider` must match a key in `talk.providers` when multiple Talk providers are configured. -- Legacy flat Talk keys (`talk.voiceId`, `talk.voiceAliases`, `talk.modelId`, `talk.outputFormat`, `talk.apiKey`) are compatibility-only and are auto-migrated into `talk.providers.`. -- Voice IDs fall back to `ELEVENLABS_VOICE_ID` or `SAG_VOICE_ID`. -- `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. -- `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`). - ---- +- `agents.defaults.*` (workspace, model, thinking, heartbeat, memory, media, skills, sandbox) +- `multiAgent.*` (multi-agent routing and bindings) +- `session.*` (session lifecycle, compaction, pruning) +- `messages.*` (message delivery, TTS, markdown rendering) +- `talk.*` (Talk mode) ## Tools diff --git a/docs/gateway/configuration.md b/docs/gateway/configuration.md index afa60e1e37a..35b0f00da77 100644 --- a/docs/gateway/configuration.md +++ b/docs/gateway/configuration.md @@ -221,7 +221,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`. - Omit `agents.list[].skills` to inherit the defaults. - Set `agents.list[].skills: []` for no skills. - See [Skills](/tools/skills), [Skills config](/tools/skills-config), and - the [Configuration Reference](/gateway/configuration-reference#agents-defaults-skills). + the [Configuration Reference](/gateway/config-agents#agents-defaults-skills). @@ -279,7 +279,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`. - `dmScope`: `main` (shared) | `per-peer` | `per-channel-peer` | `per-account-channel-peer` - `threadBindings`: global defaults for thread-bound session routing (Discord supports `/focus`, `/unfocus`, `/agents`, `/session idle`, and `/session max-age`). - See [Session Management](/concepts/session) for scoping, identity links, and send policy. - - See [full reference](/gateway/configuration-reference#session) for all fields. + - See [full reference](/gateway/config-agents#session) for all fields. @@ -301,7 +301,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`. Build the image first: `scripts/sandbox-setup.sh` - See [Sandboxing](/gateway/sandboxing) for the full guide and [full reference](/gateway/configuration-reference#agentsdefaultssandbox) for all options. + See [Sandboxing](/gateway/sandboxing) for the full guide and [full reference](/gateway/config-agents#agentsdefaultssandbox) for all options. @@ -459,7 +459,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`. } ``` - See [Multi-Agent](/concepts/multi-agent) and [full reference](/gateway/configuration-reference#multi-agent-routing) for binding rules and per-agent access profiles. + See [Multi-Agent](/concepts/multi-agent) and [full reference](/gateway/config-agents#multi-agent-routing) for binding rules and per-agent access profiles. diff --git a/docs/gateway/sandboxing.md b/docs/gateway/sandboxing.md index 7ffa7e423da..a45871dedce 100644 --- a/docs/gateway/sandboxing.md +++ b/docs/gateway/sandboxing.md @@ -480,7 +480,7 @@ See [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) for preceden ## Related docs - [OpenShell](/gateway/openshell) -- managed sandbox backend setup, workspace modes, and config reference -- [Sandbox Configuration](/gateway/configuration-reference#agentsdefaultssandbox) +- [Sandbox Configuration](/gateway/config-agents#agentsdefaultssandbox) - [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) -- debugging "why is this blocked?" - [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) -- per-agent overrides and precedence - [Security](/gateway/security) diff --git a/docs/help/faq.md b/docs/help/faq.md index 9a1134ea7e2..b571001de45 100644 --- a/docs/help/faq.md +++ b/docs/help/faq.md @@ -1308,7 +1308,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS, Setup walkthrough + example config: [Groups: personal DMs + public groups](/channels/groups#pattern-personal-dms-public-groups-single-agent) - Key config reference: [Gateway configuration](/gateway/configuration-reference#agentsdefaultssandbox) + Key config reference: [Gateway configuration](/gateway/config-agents#agentsdefaultssandbox) diff --git a/docs/providers/alibaba.md b/docs/providers/alibaba.md index 75690e96390..3476f727be5 100644 --- a/docs/providers/alibaba.md +++ b/docs/providers/alibaba.md @@ -108,7 +108,7 @@ Reference image/video mode currently requires **remote http(s) URLs**. Local fil Qwen provider setup and DashScope integration. - + Agent defaults and model configuration. diff --git a/docs/providers/comfy.md b/docs/providers/comfy.md index e8fd23e50c6..b5d47fe7efc 100644 --- a/docs/providers/comfy.md +++ b/docs/providers/comfy.md @@ -346,7 +346,7 @@ The `image` and `video` sections also support: Overview of all providers and model refs. - + Full config reference including agent defaults. diff --git a/docs/providers/fal.md b/docs/providers/fal.md index 9bdb1c2fac7..ebae2f52565 100644 --- a/docs/providers/fal.md +++ b/docs/providers/fal.md @@ -137,7 +137,7 @@ models, including any recently added entries. Shared video tool parameters and provider selection. - + Agent defaults including image and video model selection. diff --git a/docs/providers/runway.md b/docs/providers/runway.md index 021a80f2c64..e9000e66b47 100644 --- a/docs/providers/runway.md +++ b/docs/providers/runway.md @@ -85,7 +85,7 @@ Video-to-video currently requires `runway/gen4_aleph` specifically. Shared tool parameters, provider selection, and async behavior. - + Agent default settings including video generation model. diff --git a/docs/providers/vydra.md b/docs/providers/vydra.md index 3a1b43d4d33..8ce1ea5043c 100644 --- a/docs/providers/vydra.md +++ b/docs/providers/vydra.md @@ -166,7 +166,7 @@ Vydra's apex host (`https://vydra.ai/api/v1`) currently redirects to `www`. Some Shared video tool parameters and provider selection. - + Agent defaults and model configuration. diff --git a/docs/reference/memory-config.md b/docs/reference/memory-config.md index fdd5667fa7d..855e955ab5a 100644 --- a/docs/reference/memory-config.md +++ b/docs/reference/memory-config.md @@ -436,7 +436,7 @@ runtime environment. ### Scope Controls which sessions can receive QMD search results. Same schema as -[`session.sendPolicy`](/gateway/configuration-reference#session): +[`session.sendPolicy`](/gateway/config-agents#session): ```json5 { diff --git a/docs/tools/image-generation.md b/docs/tools/image-generation.md index 8a16233f147..87527183a61 100644 --- a/docs/tools/image-generation.md +++ b/docs/tools/image-generation.md @@ -305,5 +305,5 @@ cross-provider `image_generate` contract. - [OpenAI](/providers/openai) — OpenAI Images provider setup - [Vydra](/providers/vydra) — Vydra image, video, and speech setup - [xAI](/providers/xai) — Grok image, video, search, code execution, and TTS setup -- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — `imageGenerationModel` config +- [Configuration Reference](/gateway/config-agents#agent-defaults) — `imageGenerationModel` config - [Models](/concepts/models) — model configuration and failover diff --git a/docs/tools/multi-agent-sandbox-tools.md b/docs/tools/multi-agent-sandbox-tools.md index 150f08266d6..1995fab656d 100644 --- a/docs/tools/multi-agent-sandbox-tools.md +++ b/docs/tools/multi-agent-sandbox-tools.md @@ -369,5 +369,5 @@ After configuring multi-agent sandbox and tools: - [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) -- debugging "why is this blocked?" - [Elevated Mode](/tools/elevated) - [Multi-Agent Routing](/concepts/multi-agent) -- [Sandbox Configuration](/gateway/configuration-reference#agentsdefaultssandbox) +- [Sandbox Configuration](/gateway/config-agents#agentsdefaultssandbox) - [Session Management](/concepts/session) diff --git a/docs/tools/music-generation.md b/docs/tools/music-generation.md index b6c0ef8a386..5636a06e6aa 100644 --- a/docs/tools/music-generation.md +++ b/docs/tools/music-generation.md @@ -283,7 +283,7 @@ sections are configured. ## Related - [Background Tasks](/automation/tasks) - task tracking for detached `music_generate` runs -- [Configuration Reference](/gateway/configuration-reference#agent-defaults) - `musicGenerationModel` config +- [Configuration Reference](/gateway/config-agents#agent-defaults) - `musicGenerationModel` config - [ComfyUI](/providers/comfy) - [Google (Gemini)](/providers/google) - [MiniMax](/providers/minimax) diff --git a/docs/tools/pdf.md b/docs/tools/pdf.md index 6b7c23c7807..9384ced7b15 100644 --- a/docs/tools/pdf.md +++ b/docs/tools/pdf.md @@ -188,4 +188,4 @@ Page-filtered fallback model: ## Related - [Tools Overview](/tools) — all available agent tools -- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — pdfMaxBytesMb and pdfMaxPages config +- [Configuration Reference](/gateway/config-agents#agent-defaults) — pdfMaxBytesMb and pdfMaxPages config diff --git a/docs/tools/video-generation.md b/docs/tools/video-generation.md index ee4f532d9aa..1deb0aa436a 100644 --- a/docs/tools/video-generation.md +++ b/docs/tools/video-generation.md @@ -437,5 +437,5 @@ openclaw config set agents.defaults.videoGenerationModel.primary "qwen/wan2.6-t2 - [Together AI](/providers/together) - [Vydra](/providers/vydra) - [xAI](/providers/xai) -- [Configuration Reference](/gateway/configuration-reference#agent-defaults) +- [Configuration Reference](/gateway/config-agents#agent-defaults) - [Models](/concepts/models)