Agent Configuration: Defaults, Routing, Sessions, and Talk
Learn how to configure agents in OpenClaw, including defaults, multi-agent routing, session handling, messages, and talk settings. Essential for operators managing fleets or sole agents.
Read this when
- Tuning agent defaults (models, thinking, workspace, heartbeat, media, skills)
- Configuring multi-agent routing and bindings
- Adjusting session, message delivery, and talk-mode behavior
Agent-scoped configuration keys live under agents.*, multiAgent.*, session.*, messages.*, and talk.*. For channel, tool, gateway runtime, and other top-level settings, check the Configuration reference.
When OpenClaw creates a multi-agent fleet, it writes agents.ownership: "explicit". Fleets have no default: channels and ambient services require bindings or surface-specific agentId targets. During upgrades, Doctor materializes legacy owners; sole-agent configs need no marker.
On a fresh install, interactive onboarding prompts for the first agent's name and suggests main by default. Automated onboarding keeps the historical main default unless openclaw onboard --non-interactive --agent-name <name> ... is passed. A sole named agent uses the same default workspace and shared auth store as main; onboarding also migrates legacy agent:main:* session history to that sole owner before finishing.
main is an ordinary agent id. Reusing it after a named agent owns the install is guarded so old data is never silently adopted: legacy-session-migration-required means openclaw doctor --fix must finish or quarantine legacy agent:main:* claims, while shared-auth-store-owned-by-main means Doctor must first relocate the shared auth store into state/openclaw.sqlite. After both repairs, the new main gets fresh agent-scoped session and auth storage like any other agent.
Agent defaults
agents.defaults.workspace
Default: OPENCLAW_WORKSPACE_DIR when set, otherwise <state-dir>/workspace. This is ~/.openclaw/workspace for the default install and ~/.openclaw-<profile>/workspace for a named profile. A custom OPENCLAW_STATE_DIR keeps the workspace under that state directory.
{
agents: { defaults: { workspace: "~/.openclaw/workspace" } },
}
An explicit agents.defaults.workspace value takes precedence over OPENCLAW_WORKSPACE_DIR. A sole agent uses this path directly. In a multi-agent fleet, agents without their own workspace use an agent-id subdirectory so no implicit owner claims the shared root.
agents.defaults.repoRoot
Optional repository root shown in the system prompt's Runtime line. If unset, OpenClaw auto-detects by walking upward from the workspace.
{
agents: { defaults: { repoRoot: "~/Projects/openclaw" } },
}
agents.defaults.skills
Optional default skill allowlist for agents that do not set agents.entries.*.skills.
{
agents: {
ownership: "explicit",
defaults: { skills: ["github", "weather"] },
entries: {
writer: {}, // inherits github, weather
docs: { skills: ["docs-search"] }, // replaces defaults
"locked-down": { skills: [] }, // no skills
},
},
}
- Omit
agents.defaults.skillsfor unrestricted skills by default. - Omit
agents.entries.*.skillsto inherit the defaults. - Set
agents.entries.*.skills: []for no skills. - A non-empty
agents.entries.*.skillslist is the final set for that agent; it does not merge with defaults.
agents.defaults.skipBootstrap
Disables automatic creation of workspace bootstrap files (AGENTS.md, SOUL.md, IDENTITY.md, USER.md, BOOTSTRAP.md).
{
agents: { defaults: { skipBootstrap: true } },
}
agents.defaults.skipOptionalBootstrapFiles
Skips creation of selected optional workspace files while still writing required bootstrap files (AGENTS.md, BOOTSTRAP.md). Valid values: SOUL.md, USER.md, and IDENTITY.md (HEARTBEAT.md is accepted but a no-op since heartbeat context moved to cron monitor scratch).
{
agents: {
defaults: {
skipOptionalBootstrapFiles: ["SOUL.md", "USER.md"],
},
},
}
agents.defaults.contextInjection
Controls when workspace bootstrap files are injected into the system prompt. Default: "always".
"continuation-skip": safe continuation turns (after a completed assistant response) skip workspace bootstrap re-injection, reducing prompt size. Heartbeat runs and post-compaction retries still rebuild context."never": disable workspace bootstrap and context-file injection on every turn. Use this only for agents that fully own their prompt lifecycle (custom context engines, native runtimes that build their own context, or specialized bootstrap-free workflows). Heartbeat and compaction-recovery turns also skip injection.
{
agents: { defaults: { contextInjection: "continuation-skip" } },
}
Per-agent override: agents.entries.*.contextInjection. Any omitted values fall back to
agents.defaults.contextInjection.
agents.defaults.bootstrapMaxChars
Character ceiling for a single workspace bootstrap file before it gets truncated. Default: 20000.
{
agents: { defaults: { bootstrapMaxChars: 20000 } },
}
Per-agent override: agents.entries.*.bootstrapMaxChars. Values not supplied inherit
agents.defaults.bootstrapMaxChars.
agents.defaults.bootstrapTotalMaxChars
Total character limit applied across all workspace bootstrap files combined. Default: 60000.
{
agents: { defaults: { bootstrapTotalMaxChars: 60000 } },
}
Per-agent override: agents.entries.*.bootstrapTotalMaxChars. Fields left out
inherit agents.defaults.bootstrapTotalMaxChars.
Per-agent bootstrap profile overrides
Turn on per-agent bootstrap profile overrides when a single agent needs prompt
injection behavior that differs from the shared defaults. Any field not specified inherits from
agents.defaults.
{
agents: {
defaults: {
contextInjection: "continuation-skip",
bootstrapMaxChars: 20000,
bootstrapTotalMaxChars: 60000,
},
entries: {
"strict-worker": {
contextInjection: "always",
bootstrapMaxChars: 50000,
bootstrapTotalMaxChars: 300000,
},
},
},
}
Bootstrap truncation notice
When bootstrap context gets truncated, OpenClaw always appends a short agent-visible note to the system prompt indicating that some bootstrap files were truncated and advising direct reading of the affected files. This note is fixed and cannot be customized, and it intentionally leaves out per-file details: file names, raw vs injected counts, and limit causes remain in diagnostics such as context/status reports and logs.
Context budget ownership map
OpenClaw maintains several high-volume prompt/context budgets, deliberately separated by subsystem rather than funneled through a single generic control.
| Budget | Covers |
|---|---|
agents.defaults.bootstrapMaxChars / bootstrapTotalMaxChars | Standard workspace bootstrap injection |
agents.defaults.startupContext.* | One-shot reset/startup model-run prelude, including recent daily memory/*.md files. Bare chat /new and /reset are acknowledged without invoking the model |
skills.limits.* | The compact skills list injected into the system prompt |
agents.defaults.contextLimits.* | Bounded runtime excerpts and injected runtime-owned blocks |
Corresponding per-agent overrides:
agents.entries.*.skillsLimits.maxSkillsPromptCharsagents.entries.*.contextInjectionagents.entries.*.bootstrapMaxCharsagents.entries.*.bootstrapTotalMaxCharsagents.entries.*.contextLimits.*
agents.defaults.startupContext
Governs the first-turn startup prelude injected on reset/startup model runs.
Bare chat /new and /reset commands acknowledge the reset without invoking
the model, so they skip loading this prelude.
{
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.
{
agents: {
defaults: {
contextLimits: {
memoryGetMaxChars: 12000,
postCompactionMaxChars: 1800,
},
},
},
}
memoryGetMaxChars: defaultmemory_getexcerpt cap before truncation metadata and continuation notice are added.- When
memory_getomitslines, OpenClaw falls back to a built-in 120-line window and then appliesmemoryGetMaxChars. - Live tool results use a model-context auto cap:
16000chars below 100K tokens,32000chars at 100K+ tokens, and64000chars at 200K+ tokens. postCompactionMaxChars: AGENTS.md excerpt cap used during post-compaction refresh injection.
agents.entries.*.contextLimits
Per-agent override for the shared contextLimits knobs. Fields not supplied inherit
from agents.defaults.contextLimits.
{
agents: {
defaults: {
contextLimits: { memoryGetMaxChars: 12000 },
},
entries: {
"tiny-local": {
contextLimits: {
memoryGetMaxChars: 6000,
},
},
},
},
}
skills.limits.maxSkillsPromptChars
Global cap for the compact skills list injected into the system prompt. This
does not affect reading SKILL.md files on demand.
{
skills: { limits: { maxSkillsPromptChars: 18000 } },
}
agents.entries.*.skillsLimits.maxSkillsPromptChars
Per-agent override for the skills prompt budget.
{
agents: {
entries: {
"tiny-local": { skillsLimits: { maxSkillsPromptChars: 6000 } },
},
},
}
agents.defaults.imageMaxDimensionPx
Max pixel size for the longest image side in transcript/tool image blocks before provider calls.
Default: 1200.
Lower values usually reduce vision-token usage and request payload size for screenshot-heavy runs. Higher values preserve more visual detail.
{
agents: { defaults: { imageMaxDimensionPx: 1200 } },
}
agents.defaults.imageQuality
Image-tool compression/detail preference for images loaded from file paths, URLs, and media references.
Default: auto.
OpenClaw adapts the resize ladder to the selected image model. For example, Claude Opus 4.8, OpenAI GPT-5.6 Sol, Qwen VL, and hosted Llama 4 vision models can use larger images than older/default high-detail vision paths, while multi-image turns are compressed more aggressively in auto mode to control token and latency cost.
Values:
auto: adjust to constraints from the model and the number of images.efficient: choose smaller images to cut down on tokens and bytes.balanced: rely on the default intermediate ladder.high: keep extra detail for screenshots, diagrams, and scanned documents.
{
agents: { defaults: { imageQuality: "auto" } },
}
agents.defaults.userTimezone
Sets the timezone used for message envelopes, queued system events, and the local date in the system prompt. If not set, the host timezone applies.
{
agents: { defaults: { userTimezone: "America/Chicago" } },
}
agents.defaults.model
{
agents: {
defaults: {
models: {
"anthropic/claude-opus-4-6": { alias: "opus" },
"minimax/MiniMax-M2.7": { alias: "minimax" },
},
model: {
primary: "anthropic/claude-opus-4-6",
fallbacks: ["minimax/MiniMax-M2.7"],
},
utilityModel: "openai/gpt-5.4-mini",
imageModel: {
primary: "openrouter/qwen/qwen-2.5-vl-72b-instruct:free",
fallbacks: ["openrouter/google/gemini-2.0-flash-vision:free"],
},
mediaModels: {
image: {
primary: "openai/gpt-image-2",
fallbacks: ["google/gemini-3.1-flash-image"],
},
video: {
primary: "qwen/wan2.6-t2v",
fallbacks: ["qwen/wan2.6-i2v"],
},
},
pdfModel: {
primary: "anthropic/claude-opus-4-6",
fallbacks: ["openai/gpt-5.4-mini"],
},
params: { cacheRetention: "long" }, // global default provider params
pdfMaxMb: 10,
pdfMaxPages: 20,
thinkingDefault: "low",
fastModeDefault: false,
verboseDefault: "off",
toolProgressDetail: "explain",
reasoningDefault: "off",
elevatedDefault: "on",
timeoutSeconds: 600,
mediaMaxMb: 5,
maxConcurrent: 4,
},
},
}
model: takes either a string ("provider/model") or an object ({ primary, fallbacks }).- With the string form, only the primary model gets set.
- The object form configures the primary model along with an ordered list of failover models.
utilityModel: an optionalprovider/modelref or alias meant for brief internal jobs. Right now it backs the generated Control UI session titles, Telegram DM topic titles, Discord auto-thread titles, and progress-draft narration. When nothing is set, OpenClaw pulls the primary provider's declared small-model default if one exists (OpenAI →gpt-5.6-luna, Anthropic →claude-haiku-4-5); otherwise title tasks rely on the agent's primary model, and narration stays disabled. If a separate utility model fails to prepare or finish a generated title, OpenClaw retries that title once using the primary model. For dashboard titles, automatic utility derivation and the standard fallback rely on the effective session provider and auth profile; an explicit utility model keeps its own configured provider/auth. SettingutilityModel: ""disables the alternate utility route, and dashboard title generation then goes straight to the regular session model.agents.entries.*.utilityModelreplaces the default, and an operation-specific model override takes precedence over both. Utility tasks issue separate model calls and deliver task-specific content to the chosen model provider. Dashboard title generation sends no more than the first 1,000 characters of the first non-command message; narration forwards the inbound request plus compact redacted tool summaries. Pick a provider that fits your cost and data-handling needs.imageModel: takes either a string ("provider/model") or an object ({ primary, fallbacks }).- Serves as the vision-model config for the
view_imagetool path when the active model can't handle images. Native-vision models get loaded image bytes directly instead. - Also acts as fallback routing when the selected/default model rejects image input.
- Explicit
provider/modelrefs are preferred. Bare IDs work for compatibility; if a bare ID uniquely matches a configured image-capable entry inmodels.providers.*.models, OpenClaw qualifies it to that provider. Ambiguous configured matches demand an explicit provider prefix.
- Serves as the vision-model config for the
mediaModels.image: takes either a string ("provider/model") or an object ({ primary, fallbacks }).- Applies to the shared image-generation capability and any future tool/plugin surface that produces images.
- Common values:
google/gemini-3.1-flash-imagefor native Gemini image generation,fal/fal-ai/flux/devfor fal,openai/gpt-image-2for OpenAI Images, oropenai/gpt-image-1.5for transparent-background OpenAI PNG/WebP output. - Picking a provider/model directly means configuring matching provider auth too (for example
GEMINI_API_KEYorGOOGLE_API_KEYforgoogle/*,OPENAI_API_KEYor OpenAI Codex OAuth foropenai/gpt-image-2/openai/gpt-image-1.5,FAL_KEYforfal/*). - Leaving it out lets
image_generatestill infer an auth-backed provider default. It checks the current default provider first, then the remaining registered image-generation providers in provider-id order.
mediaModels.music: takes either a string ("provider/model") or an object ({ primary, fallbacks }).- Applies to the shared music-generation capability and the built-in
music_generatetool. - Common values:
google/lyria-3-clip-preview,google/lyria-3-pro-preview, orminimax/music-2.6. - Leaving it out lets
music_generatestill infer an auth-backed provider default. It checks the current default provider first, then the remaining registered music-generation providers in provider-id order. - Picking a provider/model directly means configuring the matching provider auth/API key too.
- Applies to the shared music-generation capability and the built-in
mediaModels.video: takes either a string ("provider/model") or an object ({ primary, fallbacks }).- Applies to the shared video-generation capability and the built-in
video_generatetool. - Common values:
qwen/wan2.6-t2v,qwen/wan2.6-i2v,qwen/wan2.6-r2v,qwen/wan2.6-r2v-flash, orqwen/wan2.7-r2v. - Leaving it out lets
video_generatestill infer an auth-backed provider default. It checks the current default provider first, then the remaining registered video-generation providers in provider-id order. - Picking a provider/model directly means configuring the matching provider auth/API key too.
- The official Qwen video-generation plugin handles up to 1 output video, 1 input image, 4 input videos, 10 seconds duration, and provider-level
size,aspectRatio,resolution,audio, andwatermarkoptions.
- Applies to the shared video-generation capability and the built-in
pdfModel: takes either a string ("provider/model") or an object ({ primary, fallbacks }).- Handles model routing for the
pdftool. - Leaving it out makes the PDF tool fall back to
imageModel, then to the resolved session/default model.
- Handles model routing for the
pdfMaxMb: the default cap on PDF size for thepdftool whenmaxBytesMbis omitted at invocation.pdfMaxPages: the default upper bound on pages scanned by extraction fallback within thepdftool.fastModeDefault: the default fast-mode setting applied to agents. Acceptable values are"auto",true, andfalse. A per-agentagents.entries.*.fastModeDefaulttakes precedence when neither a per-message nor a session-level fast-mode override exists.verboseDefault: the default verbosity level for agents. Acceptable values are"off","on", and"full". The fallback is"off".toolProgressDetail: the detail mode governing/verbosetool summaries and progress-draft tool lines. Either"explain"(the default, using compact human-readable labels) or"raw"(appending raw command or detail data when present) is allowed. A per-agentagents.entries.*.toolProgressDetailsupersedes this default.reasoningDefault: the default reasoning visibility for agents. Acceptable values are"off","on", and"stream". A per-agentagents.entries.*.reasoningDefaultoverrides this default. Reasoning defaults take effect only for owners, authorized senders, or operator-admin gateway contexts when no per-message or session reasoning override is supplied.elevatedDefault: the default elevated-output level for agents. Acceptable values are"off","on","ask", and"full". The fallback is"on".model.primary: the formatprovider/model(for instance,openai/gpt-5.6-solfor Codex OAuth access). Leaving the provider out makes OpenClaw check an alias first, then a unique configured-provider match for that exact model id, and only afterward fall back to the configured default provider (deprecated compatibility behavior, so explicitprovider/modelis recommended). If that provider no longer offers the configured default model, OpenClaw falls back to the first configured provider/model rather than exposing a stale removed-provider default.- To limit active input for a single model, set
models.providers.<provider>.models[].contextTokens; on the same entry, applycontextWindowfor its native window. Refer to OpenAI context window defaults. models: configured aliases and per-model settings. Each entry may carryalias(shortcut) andparams(provider-specific, such astemperature,maxTokens,cacheRetention,context1m,anthropicServerCompaction,anthropicCompactThreshold,responsesServerCompaction,responsesCompactThreshold, OpenRouterproviderrouting,chat_template_kwargs, andextra_body/extraBody). Adding entries never restricts model overrides.- Use
provider/*entries like"openai/*": {}or"vllm/*": {}to display all discovered models for selected providers without enumerating every model id manually. - Attach
agentRuntimeto aprovider/*entry when every dynamically discovered model for that provider should share the same runtime. An exactprovider/modelruntime policy still takes precedence over the wildcard.
- Use
- Safe metadata edits: add entries with
openclaw config set agents.defaults.models '<json>' --strict-json --merge.config setblocks replacements that would drop existing entries unless--replaceis supplied. modelPolicy.allow: explicit override allowlist. Handles aliases, exactprovider/modelrefs, and trailing prefix wildcards likeopenai/*orclawrouter/anthropic/*. Leave it out or pass[]to permit any model.agents.entries.*.modelPolicy.allowswaps the default policy for that agent; an explicit empty list opts that agent into allow-any.- Provider-scoped configure/onboarding flows fold selected provider models into this map and keep unrelated providers already set up.
- For direct Anthropic models with API-key auth, set
params.anthropicServerCompaction: trueto turn on server-side compaction. Useparams.anthropicCompactThresholdto change the input-token trigger; the default sits atmax(50000, floor(contextWindow * 0.7)), and lower configured values clamp to50000. OAuth/subscription and non-direct endpoints are excluded. Check Anthropic server-side compaction. - For store-capable direct OpenAI Responses models, server-side compaction activates automatically, and the same effective threshold delays local preflight compaction. Use
params.responsesServerCompaction: falseto halt injection ofcontext_management, orparams.responsesCompactThresholdto override the default of 70% of the resolved context window (80,000 when unavailable). ChatGPT OAuth, custom proxies, and routes withcompat.supportsStore: falsedo not enable this path. See OpenAI server-side compaction.
params: global default provider parameters applied to all models. Set atagents.defaults.params(e.g.{ cacheRetention: "long" }).paramsmerge precedence (config):agents.defaults.params(global base) is overridden byagents.defaults.models["provider/model"].params(per-model), thenagents.entries.*.params(matching agent id) overrides by key. See Prompt Caching for details.models.providers.openrouter.params.provider: OpenRouter-wide default provider-routing policy. OpenClaw forwards this to OpenRouter's requestproviderobject; per-modelagents.defaults.models["openrouter/<model>"].params.providerand agent params override by key. See OpenRouter provider routing.params.extra_body/params.extraBody: advanced pass-through JSON merged intoapi: "openai-completions"request bodies for OpenAI-compatible proxies. If it collides with generated request keys, the extra body wins; non-native completions routes still strip OpenAI-onlystoreafterward.params.chat_template_kwargs: vLLM/OpenAI-compatible chat-template arguments merged into top-levelapi: "openai-completions"request bodies. Forvllm/nemotron-3-*with thinking off, the bundled vLLM plugin automatically sendsenable_thinking: falseandforce_nonempty_content: true; explicitchat_template_kwargsoverride generated defaults, andextra_body.chat_template_kwargsstill has final precedence. Configured vLLM Qwen and Nemotron thinking models expose binary/thinkchoices (off,on) instead of the multi-level effort ladder.compat.thinkingFormat: OpenAI-compatible thinking payload style. Use"together"for Together-stylereasoning.enabled,"qwen"for Qwen-style top-levelenable_thinking, or"qwen-chat-template"forchat_template_kwargs.enable_thinkingon Qwen-family backends that support request-level chat-template kwargs, such as vLLM. OpenClaw maps disabled thinking tofalseand enabled thinking totrue, and configured vLLM Qwen models expose binary/thinkchoices for these formats.compat.supportedReasoningEfforts: per-model OpenAI-compatible reasoning effort list. Include"xhigh"for custom endpoints that truly accept it; OpenClaw then exposes/think xhighin command menus, Gateway session rows, session patch validation, agent CLI validation, andllm-taskvalidation for that configured provider/model. Usecompat.reasoningEffortMapwhen the backend wants a provider-specific value for a canonical level.params.preserveThinking: Z.AI-only opt-in for preserved thinking. With this enabled and thinking active, OpenClaw transmitsthinking.clear_thinking: falseand replays earlierreasoning_content; refer to Z.AI thinking and preserved thinking.localService: optional provider-level process manager for local/self-hosted model servers. If the chosen model belongs to that provider, OpenClaw checkshealthUrl(orbaseUrl + "/models"), launchescommandwithargswhen the endpoint is unreachable, waits up toreadyTimeoutMs, then issues the model request.commandmust be an absolute path.idleStopMs: 0maintains the process until OpenClaw terminates; a positive value ends the OpenClaw-started process after that many idle milliseconds. Consult Local model services.- Runtime policy applies at the provider or model level, not at
agents.defaults. For provider-wide rules, usemodels.providers.<provider>.agentRuntime; for model-specific rules, useagents.defaults.models["provider/model"].agentRuntime/agents.entries.*.models["provider/model"].agentRuntime. A provider/model prefix by itself never selects a harness. With runtime unset orauto, OpenAI may implicitly select Codex only for an exact official HTTPS Platform Responses or ChatGPT Responses route with no authored request override. See OpenAI implicit agent runtime. - Config writers that modify these fields (such as
/models set,/models set-image, and fallback add/remove commands) save canonical object form and retain existing fallback lists whenever possible. maxConcurrent: max parallel agent runs across sessions (each session remains serialized). OpenClaw defaults tomin(16, max(8, available CPU parallelism)), derived fromos.availableParallelism()withos.cpus().lengthas the fallback.
Runtime policy
{
models: {
providers: {
openai: {
agentRuntime: { id: "codex" },
},
},
},
agents: {
defaults: {
model: "openai/gpt-5.6-sol",
models: {
"anthropic/claude-opus-5": {
agentRuntime: { id: "claude-cli" },
},
"vllm/*": {
agentRuntime: { id: "openclaw" },
},
},
},
},
}
id:"auto","openclaw", a registered plugin harness id, or a supported CLI backend alias. The bundled Codex plugin registerscodex; the bundled Anthropic plugin supplies theclaude-cliCLI backend.id: "auto"allows registered plugin harnesses to claim effective routes that declare or otherwise satisfy their support contract, and falls back to OpenClaw when no harness matches. An explicit plugin runtime likeid: "codex"demands that harness and a compatible effective route; it fails closed if either is missing or execution errors.id: "pi"is accepted solely as a deprecated alias foropenclawto keep shipped configs from v2026.5.22 and earlier working. New config should adoptopenclaw.- Runtime precedence: exact model policy first (
agents.entries.*.models["provider/model"],agents.defaults.models["provider/model"], ormodels.providers.<provider>.models[]), thenagents.entries.*/agents.defaults.models["provider/*"], then provider-wide policy atmodels.providers.<provider>.agentRuntime. - Whole-agent runtime keys are outdated.
agents.defaults.agentRuntime,agents.entries.*.agentRuntime, session runtime pins, andOPENCLAW_AGENT_RUNTIMEare disregarded by runtime selection. Executeopenclaw doctor --fixto clear stale values. - Exact official HTTPS OpenAI Responses/ChatGPT routes with no authored request override may implicitly use the Codex harness. Provider/model
agentRuntime.id: "codex"turns Codex into a fail-closed requirement but does not make an incompatible route compatible. - For Claude CLI deployments, choose
model: "anthropic/claude-opus-5"with model-scopedagentRuntime.id: "claude-cli". Legacyclaude-cli/<model>refs remain functional for compatibility, but new config should keep provider/model selection canonical and place the execution backend in provider/model runtime policy. - This governs only text agent-turn execution. Media generation, vision, PDF, music, video, and TTS continue to use their provider/model settings.
Built-in alias shorthands (apply only when the model falls within agents.defaults.models):
| Alias | Model |
|---|---|
opus | anthropic/claude-opus-5 |
sonnet | anthropic/claude-sonnet-5 |
gpt | openai/gpt-5.4 |
gpt-mini | openai/gpt-5.4-mini |
gpt-nano | openai/gpt-5.4-nano |
gemini | google/gemini-3.1-pro-preview |
gemini-flash | google/gemini-3-flash-preview |
gemini-flash-lite | google/gemini-3.1-flash-lite |
Defaults never override aliases you have configured.
Unless you specify --thinking off or provide your own agents.defaults.models["zai/<model>"].params.thinking, Z.AI GLM-4.x models automatically switch on thinking mode. For tool call streaming, Z.AI models turn on tool_stream as the standard setting; to turn it off, set agents.defaults.models["zai/<model>"].params.tool_stream to false. In OpenClaw, Anthropic Claude Opus 4.8 starts with thinking disabled; when you explicitly enable adaptive thinking, Anthropic's provider-controlled effort default is high. Claude 4.6 models fall back to adaptive when no explicit thinking level is given.
CLI backend selection
Plugins register CLI adapter mechanics; agent defaults do not configure them. Use model-scoped agentRuntime.id to pick a registered CLI backend, as demonstrated earlier. For operations, refer to CLI backends, and for command, session, image, and parser registration, see building CLI backend plugins.
OpenAI GPT-5 personality
The bundled OpenAI plugin handles the GPT-5 friendly interaction-style setting. Prompts that match the GPT-5 family receive the shared behavior contract; personality only manages the friendly style layer. Native Codex app-server routes keep Codex-owned base and model instructions rather than this OpenClaw GPT-5 addition, and OpenClaw turns off Codex's built-in personality for native threads.
{
plugins: {
entries: {
openai: {
config: {
personality: "friendly", // friendly | on | off
},
},
},
},
}
- The friendly interaction-style layer is activated by
"friendly"(the default) and"on". - Only the friendly layer is deactivated by
"off"; the tagged GPT-5 behavior contract stays on.
Provider and native Codex behavior is covered in OpenAI GPT-5 prompt contribution.
agents.defaults.heartbeat
Heartbeats run periodically.
{
agents: {
defaults: {
heartbeat: {
agentId: "ops", // ambient owner when no per-agent heartbeat is configured
every: "30m", // 0m disables recurring cadence
activeHours: { start: "08:00", end: "24:00" },
model: "openai/gpt-5.4-mini",
session: "main",
target: "owner", // default | options: last | none | whatsapp | telegram | discord | ...
directPolicy: "allow", // allow (default) | block
to: "+15555550123",
accountId: "ops-bot",
prompt: "Follow the heartbeat monitor scratch context...",
timeoutSeconds: 45,
lightContext: false, // default: false; true skips workspace bootstrap files for heartbeat runs
isolatedSession: false, // default: false; true runs each heartbeat in a fresh session (no conversation history)
},
},
},
}
every: a duration string expressed in ms, s, m, or h. The default is30mwhen using API-key auth, or1hfor OAuth auth. To turn off the recurring cadence, set it to0m. Targeted event-driven wakes, including follow-ups from background exec completion, can still execute a single agent turn.agentId: specifies an explicit owner for ambient heartbeat runs when noagents.entries.*.heartbeatblock is present. If a shared heartbeat block exists withoutagentId, the prior all-agent enrollment behavior remains in effect.- The cadence gets recorded in a cron monitor row owned by the system. Running
openclaw doctor --fixmaterializes a missing or outdated row. When cron is disabled, scheduled heartbeats won't execute, and the gateway logs a warning at startup. - The heartbeat object is strictly defined. Its accepted fields are
agentId,every,activeHours,model,session,target,directPolicy,to,accountId,prompt,timeoutSeconds,lightContext, andisolatedSession. timeoutSeconds: the maximum seconds an agent turn for a heartbeat may run before being terminated. If left unset,agents.defaults.timeoutSecondsapplies when it's configured; otherwise, the heartbeat cadence is capped at 600 seconds.directPolicy: governs direct/DM delivery.allow(the default) allows delivery to a direct target.blockblocks direct-target delivery and instead emitsreason=dm-blocked.target: withowner(the default), messages go only to a direct-message identity fromcommands.ownerAllowFromor channelallowFrom.lastexplicitly tracks the latest conversation, including groups.nonekeeps results private.to: applies solely when an explicit channel target is set. Withowneror no target, it's ignored.lightContext: when true, heartbeat runs rely on a lightweight bootstrap context and skip workspace bootstrap files. The heartbeat runner injects monitor scratch regardless.isolatedSession: when true, every heartbeat starts a fresh session with no prior conversation history. This mirrors the isolation used by cronsessionTarget: "isolated". Per-heartbeat token usage drops from roughly 100K to about 2-5K tokens.- Busy deferral happens automatically: scheduled heartbeats pause for main/cron activity, active runs of the same agent, and work on the target session. Immediate and manual wakes bypass only the broad same-agent active-run precheck.
- While an agent's cadence is enabled, its Heartbeats system-prompt section is added automatically. Ack suppression uses a fixed 300-character remainder budget, reasoning payloads stay internal, and tool error warnings remain on.
- Per-agent configuration uses
agents.entries.*.heartbeat. When any agent setsheartbeat, only those agents execute heartbeats. - Heartbeats run complete agent turns, so shorter intervals consume more tokens.
agents.defaults.systemAgent
Picks the agent whose model and credentials handle ambient OpenClaw system work: system-agent and Custodian consults, plus the fallback owner when an ambient path leaves out agentId. This covers models.list, models.authStatus, skills.status, and doctor.memory.status, the default agent directory and workspace behind auth, model-catalog, and doctor resolution, outbound channel bootstrap and queued-delivery recovery, unscoped main-session routing, Talk relay ownership, and first-run onboarding:
{
agents: {
defaults: {
systemAgent: { agentId: "ops" },
},
},
}
An explicit request agentId takes precedence, then systemAgent.agentId, a retained legacy default owner, and finally the sole configured agent. Delegated consults with a requesting agent keep that requester as owner. The four reads above opt in individually; other agent-scoped Gateway methods, such as tools.*, commands.*, chat history, and session-catalog reads, don't use this setting as a general default. Surfaces that pick one agent's view still demand an explicit choice, because silently adopting this owner would conceal the other agents: openclaw sessions (add --agent <id> or --all-agents), openclaw hooks status, openclaw models, stored session lookup by id, and TUI startup. Ambient work in an ownerless multi-agent fleet fails with an actionable error, except queued-delivery recovery, which logs the failing delivery and keeps draining the rest of the queue. Upgrade-only ownership sits at agents.defaults.authInheritance.agentId for inherited credentials and agents.defaults.sessionStore.agentId for retired main session rows or unscoped rows in a fixed session.store.
agents.defaults.compaction
{
agents: {
defaults: {
compaction: {
enabled: false, // disable embedded proactive auto-compaction (default: true)
mode: "safeguard", // default | safeguard
provider: "my-provider", // id of a registered compaction provider plugin (optional)
thinkingLevel: "low", // default; use "inherit" to reuse the session level
timeoutSeconds: 180,
keepRecentTokens: 50000,
recentTurnsPreserve: 3,
identifierPolicy: "strict", // strict | off
qualityGuard: { enabled: true, maxRetries: 1 },
midTurnPrecheck: { enabled: false }, // optional tool-loop pressure check
postIndexSync: "async", // off | async | await
postCompactionSections: ["Session Startup", "Red Lines"],
model: "openrouter/anthropic/claude-sonnet-4-6", // optional compaction-only model override
maxActiveTranscriptBytes: "20mb", // opt in to preflight local compaction
notifyUser: true, // notices when compaction starts/completes and on memory-flush degradation (default: false)
memoryFlush: {
enabled: true,
model: "ollama/qwen3:8b", // optional memory-flush-only model override
softThresholdTokens: 6000,
forceFlushTranscriptBytes: "2mb",
},
},
},
},
}
enabled: whenfalse, threshold-triggered automatic compaction within the embedded agent runtime is turned off. OpenClaw's preflight and overflow-recovery compaction paths, along with manual/compact, stay functional. Default:true.mode: set todefaultorsafeguard(chunked summarization for extended histories). Refer to Compaction.provider: the ID of a registered compaction provider plugin. If configured, the provider'ssummarize()gets invoked instead of the default LLM summarization. On failure, it reverts to built-in behavior. Enabling a provider forcesmode: "safeguard". See Compaction.thinkingLevel: the thinking level applied solely to embedded OpenClaw compaction summaries (off,minimal,low,medium,high,xhigh,adaptive,max,ultra, orinherit). It defaults tolow; setinheritto adopt the session's current thinking level. The chosen level gets clamped to the compaction model/runtime. Native Codex app-server compaction ignores this setting, since the native compact request lacks a per-operation thinking override; OpenClaw emits a warning when this is configured.timeoutSeconds: the maximum seconds a single compaction operation may run before OpenClaw terminates it. Default:180.keepRecentTokens: the agent cut-point budget for preserving the most recent transcript tail verbatim. Default:20000.recentTurnsPreserve: the count of the most recent user/assistant turns kept verbatim outside safeguard summarization. Default:3.identifierPolicy:strict(default) oroff.strictadds built-in opaque identifier retention guidance at the start of compaction summarization.qualityGuard: bounded validation for built-in safeguard summaries. Enabled by default in safeguard mode. After final budgeting, required headings must stay in the retained generated body, while pending asks and exact identifiers must remain in the exact artifact to be stored. If no attempt passes, OpenClaw keeps the original history and reports a compaction failure rather than storing known-invalid context. Setenabled: falseto bypass the audit. Configured compaction-provider output retains its existing provider-owned validation behavior.midTurnPrecheck: an optional tool-loop pressure check. Whenenabled: true, OpenClaw evaluates context pressure after tool results are appended and before the next model call. If the context no longer fits, it cancels the current attempt before submitting the prompt and reuses the existing precheck recovery path to truncate tool results or compact and retry. Works with bothdefaultandsafeguardcompaction modes. Default: disabled.postIndexSync: post-compaction session-memory reindex mode. Default:"async". Choose"await"for maximum freshness,"async"for reduced compaction latency, or"off"only when session-memory sync is managed elsewhere.postCompactionSections: optional AGENTS.md H2/H3 section names to re-inject after compaction. Leave unset or use[]to disable.model: optionalprovider/model-idor bare alias fromagents.defaults.modelsfor compaction summarization only. Bare aliases resolve before dispatch; configured literal model IDs take precedence on collisions. Use this when the main session should retain one model but compaction summaries should run on another; when unset, compaction uses the session's primary model.maxActiveTranscriptBytes: byte threshold (numberor strings like"20mb") that opts in to normal local compaction before a run when transcript history reaches the threshold. For Codex app-server sessions, the same threshold caps native rollout transcripts and oversized native threads restart fresh. Disabled when unset or0. When a context engine returns an explicit compacted successor identity, OpenClaw adopts it; the built-in SQLite compactor keeps the current identity.notifyUser: whentrue, sends brief context-maintenance notices to the user: when compaction starts and completes (for example, "Compacting context..." and "Compaction complete"), and when a pre-compaction memory flush is exhausted so the reply continues in a degraded state (for example, "Memory maintenance temporarily failed; continuing your reply."). Disabled by default to keep these notices silent.memoryFlush: a silent agentic turn runs before auto-compaction so durable memories get stored. Assignmodelan exact provider/model pair likeollama/qwen3:8bwhen this housekeeping step must remain on a local model; the override does not pick up the active session fallback chain.forceFlushTranscriptBytestriggers the flush at the transcript size threshold even if token counters are outdated. Skipped when the workspace is read-only.
Custom compaction instructions belong to code. Build a compaction provider plugin with summarize() for custom summary construction, and rely on before_prompt_build when post-compaction context needs to be injected into subsequent model prompts. Doctor removes the retired instruction fields and directs you to these seams.
agents.defaults.contextPruning
Trims old tool results from in-memory context prior to sending to the LLM. Session history on disk stays untouched. Off by default; turn on with mode: "cache-ttl".
{
agents: {
defaults: {
contextPruning: {
mode: "cache-ttl", // off (default) | cache-ttl
},
},
},
}
cache-ttl mode behavior
mode: "cache-ttl"activates pruning passes.- Pruning first soft-trims oversized tool results, then hard-clears older tool results when necessary.
Soft-trim preserves the beginning and end, placing ... in between.
Hard-clear swaps the whole tool result for the placeholder.
Notes:
- Image blocks are never trimmed or cleared.
- Ratios are character-based (approximate), not exact token counts.
- The most recent assistant messages are kept.
See Session Pruning for behavior details.
Block streaming
{
agents: {
defaults: {
blockStreamingDefault: "off", // on | off
blockStreamingBreak: "text_end", // text_end | message_end
blockStreamingChunk: { minChars: 800, maxChars: 1200, breakPreference: "paragraph" },
blockStreamingCoalesce: { idleMs: 1000 },
humanDelay: { mode: "natural" }, // off (default) | natural | custom (use minMs/maxMs)
},
},
}
- Non-Telegram channels need explicit
*.streaming.block.enabled: trueto enable block replies. QQ Bot is the exception: it has nostreaming.blockkeys and streams block replies unlesschannels.qqbot.streaming.modeis"off". - Channel overrides:
channels.<channel>.streaming.block.coalesce(and per-account variants). Discord, Google Chat, Mattermost, MS Teams, Signal, and Slack defaultminChars: 1500/idleMs: 1000. blockStreamingChunk.breakPreference: preferred chunk boundary ("paragraph" | "newline" | "sentence").humanDelay: randomized pause between block replies. Default:off.natural= 800-2500ms.customusesminMs/maxMs(falls back to the natural range for any unset bound). Per-agent override:agents.entries.*.humanDelay.
See Streaming for behavior + chunking details.
Typing indicators
{
agents: {
defaults: {
typingMode: "instant", // never | instant | thinking | message
typingIntervalSeconds: 6,
},
},
}
- Defaults:
instantfor direct chats/mentions,messagefor unmentioned group chats. typingIntervalSecondsdefault:6.- Per-agent override:
agents.entries.*.typingMode.
See Typing Indicators.
agents.defaults.sandbox
Optional sandboxing for the embedded agent. See Sandboxing for the full guide.
{
agents: {
defaults: {
sandbox: {
mode: "non-main", // off (default) | non-main | all
backend: "docker", // docker (default) | podman | openshell | ssh
scope: "agent", // session | agent (default) | shared
workspaceAccess: "none", // none (default) | ro | rw
workspaceRoot: "~/.openclaw/sandboxes",
docker: {
image: "openclaw-sandbox:bookworm-slim",
containerPrefix: "openclaw-sbx-",
workdir: "/workspace",
readOnlyRoot: true,
tmpfs: ["/tmp", "/var/tmp", "/run"],
network: "none",
user: "1000:1000",
capDrop: ["ALL"],
env: { LANG: "C.UTF-8" },
setupCommand: "apt-get update && apt-get install -y git curl jq",
pidsLimit: 256,
memory: "1g",
memorySwap: "2g",
cpus: 1,
gpus: "all",
ulimits: {
nofile: { soft: 1024, hard: 2048 },
nproc: 256,
},
seccompProfile: "/path/to/seccomp.json",
apparmorProfile: "openclaw-sandbox",
dns: ["1.1.1.1", "8.8.8.8"],
extraHosts: ["internal.service:10.0.0.5"],
binds: ["/home/user/source:/source:rw"],
},
ssh: {
target: "user@gateway-host:22",
command: "ssh",
workspaceRoot: "/tmp/openclaw-sandboxes",
strictHostKeyChecking: true,
updateHostKeys: true,
identityFile: "~/.ssh/id_ed25519",
certificateFile: "~/.ssh/id_ed25519-cert.pub",
knownHostsFile: "~/.ssh/known_hosts",
// SecretRefs / inline contents also supported:
// identityData: { source: "env", provider: "default", id: "SSH_IDENTITY" },
// certificateData: { source: "env", provider: "default", id: "SSH_CERTIFICATE" },
// knownHostsData: { source: "env", provider: "default", id: "SSH_KNOWN_HOSTS" },
},
browser: {
enabled: false,
image: "openclaw-sandbox-browser:bookworm-slim",
network: "openclaw-sandbox-browser",
cdpPort: 9222,
cdpSourceRange: "172.21.0.1/32",
vncPort: 5900,
noVncPort: 6080,
headless: false,
noVncEnabled: true,
allowHostControl: false,
autoStart: true,
autoStartTimeoutMs: 12000,
},
prune: {
idleHours: 24,
maxAgeDays: 7,
},
},
},
},
tools: {
sandbox: {
tools: {
allow: [
"exec",
"process",
"read",
"write",
"edit",
"apply_patch",
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
],
deny: ["browser", "canvas", "nodes", "cron", "discord", "gateway"],
},
},
},
}
Defaults shown above (off/docker/agent/none/bookworm-slim image/none network/etc.) are the actual OpenClaw defaults, not just illustrative values.
Sandbox details
Backend:
docker: local Docker runtime (default)ssh: generic SSH-backed remote runtimeopenshell: OpenShell runtime
When backend: "openshell" is selected, runtime-specific settings move to
plugins.entries.openshell.config.
SSH backend config:
target: SSH destination expressed asuser@host[:port]command: command for the SSH client, falling back tosshif unsetworkspaceRoot: absolute path on the remote host that serves as the root for per-scope workspaces, with/tmp/openclaw-sandboxesas the defaultidentityFile/certificateFile/knownHostsFile: pre-existing local files handed to OpenSSHidentityData/certificateData/knownHostsData: inline data or SecretRefs that OpenClaw writes into temporary files during executionstrictHostKeyChecking/updateHostKeys: controls for OpenSSH host-key verification, both preset totrue
Order of SSH authentication:
identityDatatakes priority overidentityFilecertificateDatatakes priority overcertificateFileknownHostsDatatakes priority overknownHostsFile- Before the sandbox session launches, any SecretRef-backed
*Dataentries are pulled from the current secrets runtime snapshot
How the SSH backend operates:
- after a create or recreate, the remote workspace is seeded once
- from that point on, the remote SSH workspace is treated as the source of truth
exec, file tools, and media paths all travel over SSH- changes made on the remote side are never automatically pushed back to the host
- sandbox browser containers are not supported
Reaching the workspace:
none: per-scope sandbox workspace located under~/.openclaw/sandboxes, which is the defaultro: sandbox workspace found at/workspace, with the agent workspace attached read-only at/agentrw: agent workspace attached with read/write access at/workspace
Isolation levels:
session: a fresh container and workspace for every sessionagent: a single container and workspace per agent, which is the defaultshared: one shared container and workspace, offering no isolation between sessions
OpenShell plugin configuration:
{
plugins: {
entries: {
openshell: {
enabled: true,
config: {
mode: "mirror", // mirror (default) | remote
command: "openshell",
from: "openclaw",
remoteWorkspaceDir: "/sandbox",
remoteAgentWorkspaceDir: "/agent",
gateway: "lab", // optional
gatewayEndpoint: "https://lab.example", // optional
policy: "strict", // optional OpenShell policy id
providers: ["openai"], // optional
autoProviders: true,
timeoutSeconds: 120,
},
},
},
},
}
OpenShell operating modes:
mirror: the remote is seeded from local before each exec, then synced back afterward; the local workspace remains authoritativeremote: seeding happens once at sandbox creation, after which the remote workspace becomes authoritative
When running in remote mode, local edits made outside OpenClaw are not propagated into the sandbox automatically once the seed step completes.
The transport layer is SSH into the OpenShell sandbox, yet lifecycle management and optional mirror syncing belong to the plugin.
setupCommand executes a single time following container creation, triggered via sh -lc. It demands outbound network access, a writable root, and root-level privileges.
Containers come up on network: "none" by default, switch to "bridge" (or a custom bridge network) when the agent requires external connectivity.
"host" is disallowed. Unless you explicitly set sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true (break-glass), "container:<id>" remains blocked.
Codex app-server processes running inside an active OpenClaw sandbox rely on this same egress setting for their native code-mode network access.
Inbound attachments get staged into media/inbound/* inside the active workspace.
docker.binds attaches extra host directories; global and per-agent bind mounts are combined.
Browser in a sandbox (sandbox.browser.enabled, preset to false): Chromium with CDP running inside a container. No browser.enabled is needed in openclaw.json.
Observer access through noVNC is guarded by a password and routed via a single-use, authenticated bootstrap URL. That observer URL is intentionally kept out of the model-visible system prompt context.
allowHostControl: false(default) prevents sandboxed sessions from reaching the host browser.- By default,
networkis set toopenclaw-sandbox-browser(dedicated bridge network). Choosebridgeonly when global bridge connectivity is deliberately required."none"cannot be used because CDP ports have to be exposed to the host;"host"is likewise prohibited. After an upgrade,openclaw doctor --fixturns off sidecars impacted by a stored"none"value and brings back the dedicated network without quietly enabling egress. - Optionally,
cdpSourceRangelimits CDP access at the container boundary to a CIDR range (such as172.21.0.1/32). sandbox.browser.bindsadds extra host directories exclusively into the sandbox browser container. When it is set (including[]), it takes the place ofdocker.bindsfor that container.- Chromium in the sandbox browser container always starts with
--no-sandbox --disable-setuid-sandbox(containers lack the kernel primitives Chrome's own sandbox depends on); no configuration option exists to change this. - Launch defaults live in
scripts/sandbox-browser-entrypoint.shand are adjusted for container hosts:--remote-debugging-address=127.0.0.1--remote-debugging-port=<derived from OPENCLAW_BROWSER_CDP_PORT>--user-data-dir=${HOME}/.chrome--no-first-run--no-default-browser-check--disable-dev-shm-usage--disable-background-networking--disable-breakpad--disable-crash-reporter--no-zygote--metrics-recording-only--password-store=basic--use-mock-keychain--disable-3d-apis,--disable-gpu, and--disable-software-rasterizerstart enabled and can be turned off withOPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0when WebGL/3D usage calls for it.--disable-extensions(enabled by default);OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0brings back extensions if your workflow relies on them.--renderer-process-limit=2is the default; adjust it withOPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=<N>, or set0to apply Chromium's default process cap.--headless=newapplies only whenheadlessis active.- The defaults come from the container image baseline; swap in a custom browser image with a custom entrypoint to alter container defaults.
Browser sandboxing needs the Docker engine. sandbox.docker.binds covers both the Docker and Podman backends.
Build images (from a source checkout):
scripts/sandbox-setup.sh # main sandbox image
scripts/sandbox-browser-setup.sh # optional browser image
For npm installs without a source checkout, check Sandboxing § Images and setup for inline docker build commands.
agents.entries (per-agent overrides)
Hand an agent its own TTS provider, voice, model,
style, or auto-TTS mode with agents.entries.*.tts. The agent block deep-merges over global
tts, letting shared credentials live in one spot while individual
agents override just the voice or provider fields they require. The active agent's
override governs automatic spoken replies, /tts audio, /tts status, and
the tts agent tool. See Text-to-speech
for provider examples and precedence.
{
agents: {
entries: {
main: {
name: "Main Agent",
workspace: "~/.openclaw/workspace",
agentDir: "~/.openclaw/agents/main/agent",
model: "anthropic/claude-opus-4-6", // or { primary, fallbacks }
utilityModel: "openai/gpt-5.4-mini",
thinkingDefault: "high", // per-agent thinking level override
reasoningDefault: "on", // per-agent reasoning visibility override
fastModeDefault: false, // per-agent fast mode override
params: { cacheRetention: "none" }, // overrides matching defaults.models params by key
tts: {
providers: {
elevenlabs: { speakerVoiceId: "EXAVITQu4vr4xnSDxMaL" },
},
},
skills: ["docs-search"], // replaces agents.defaults.skills when set
identity: {
name: "Samantha",
theme: "helpful sloth",
emoji: "🦥",
avatar: "avatars/samantha.png",
},
groupChat: { mentionPatterns: ["@openclaw"] },
sandbox: { mode: "off" },
runtime: {
type: "acp",
acp: {
agent: "codex",
backend: "acpx",
mode: "persistent", // persistent | oneshot
cwd: "/workspace/openclaw",
},
},
subagents: { allowAgents: ["*"] },
tools: {
profile: "coding",
allow: ["browser"],
deny: ["canvas"],
elevated: { enabled: true },
},
},
},
},
}
- The
agents.entriesobject key serves as the stable identifier for the agent. defaulthas been deprecated. Only one configured agent resolves automatically; any multi-agent scenario needs a binding, aagentIdsurface target, a scoped session/store owner, or an explicit--agent/request field.model: a string value enforces a strict per-agent primary without model fallback; the object form{ primary }is equally strict unlessfallbacksis added. To allow fallback for that agent, apply{ primary, fallbacks: [...] }; to make strictness explicit, use{ primary, fallbacks: [] }. Cron jobs overriding onlyprimarystill receive default fallbacks unlessfallbacks: []is configured.utilityModel: an optional per-agent override for brief internal tasks like generated session and thread titles. It falls back toagents.defaults.utilityModel, then to the effective session provider's declared small-model default. Dashboard titles retry once using the effective regular session model. An empty string disables the alternate utility route for this agent without turning off dashboard title generation.params: per-agent stream parameters merged over the chosen model entry inagents.defaults.models. This allows agent-specific adjustments such ascacheRetention,temperature, ormaxTokenswithout replicating the entire model catalog.tts: optional per-agent text-to-speech overrides. The block deep-merges overtts, so place shared provider credentials and fallback policy inttsand set only persona-specific values here, like provider, voice, model, style, or auto mode.skills: optional per-agent skill allowlist. When omitted, the agent inheritsagents.defaults.skillsif set; an explicit list replaces defaults rather than merging, and[]indicates no skills.thinkingDefault: optional per-agent default thinking level (off | minimal | low | medium | high | xhigh | adaptive | max). It overridesagents.defaults.thinkingDefaultfor this agent when no per-message or session override exists. The selected provider/model profile determines valid values; for Google Gemini,adaptivepreserves provider-owned dynamic thinking (thinkingLevelomitted on Gemini 3/3.1,thinkingBudget: -1on Gemini 2.5).reasoningDefault: optional per-agent default reasoning visibility (on | off | stream). It overridesagents.defaults.reasoningDefaultfor this agent when no per-message or session reasoning override is set.fastModeDefault: optional per-agent default for fast mode ("auto" | true | false). It overridesagents.defaults.fastModeDefaultfor this agent when no per-message or session fast-mode override is set.models: optional per-agent model catalog/runtime overrides keyed by fullprovider/modelids. Applymodels["provider/model"].agentRuntimefor per-agent runtime exceptions.runtime: optional per-agent runtime descriptor. Usetype: "acp"withruntime.acpdefaults (agent,backend,mode,cwd) when the agent should default to ACP harness sessions.identity.avatar: workspace-relative path,http(s)URL, ordata:URI.- Local workspace-relative
identity.avatarimage files are capped at 2 MB.http(s)URLs anddata:URIs bypass the local file-size check. identityderives defaults:ackReactionfromemoji,mentionPatternsfromname/emoji.subagents.allowAgents: an allowlist of agent IDs that are valid for explicitsessions_spawn.agentIdtargets (["*"]means any configured target; by default, only the same agent is allowed). If self-targetedagentIdcalls should be permitted, include the requester ID. Entries that are outdated, because their agent config was removed, get rejected bysessions_spawnand are not listed inagents_list; executeopenclaw doctor --fixto purge them, or insert a minimalagents.entries.*entry when that target should stay spawnable while taking on default settings.- Sandbox inheritance guard: when the requester session is sandboxed,
sessions_spawnblocks targets that would run without a sandbox. subagents.requireAgentId: when enabled,sessions_spawncalls that leave outagentIdare refused (this forces an explicit profile choice; default: false).subagents.maxConcurrent: the maximum number of concurrent child-agent runs allowed during subagent execution. Default:8.subagents.maxChildrenPerAgent: the maximum number of active children a single agent session can create. Default:5.subagents.maxSpawnDepth: the maximum nesting depth for sub-agent spawning (1-5). Default:1(no nesting allowed).subagents.archiveAfterMinutes: how long completed subagent state is kept before being archived. Default:60.
Multi-agent routing
Within one Gateway, you can run multiple isolated agents. Check Multi-Agent for details.
{
agents: {
ownership: "explicit",
defaults: { heartbeat: { agentId: "home" }, systemAgent: { agentId: "home" } },
entries: {
home: { workspace: "~/.openclaw/workspace-home" },
work: { workspace: "~/.openclaw/workspace-work" },
},
},
bindings: [
{ agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
{ agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
],
talk: { agentId: "home" },
}
Binding match fields
type(optional):routefor standard routing (when the type is missing, route is assumed),acpfor persistent ACP conversation bindings.match.channel(required)match.accountId(optional;*= any account; if omitted, the default account is used)match.peer(optional;{ kind: direct|group|channel, id })match.guildId/match.teamId(optional; specific to the channel)session(optional; route bindings only):{ dmScope, groupScope }overrides session routing for peers that matchacp(optional; only fortype: "acp"):{ mode, label, cwd, backend }
Deterministic match order:
match.peermatch.guildIdmatch.teamIdmatch.accountId(exact, with no peer/guild/team)match.accountId: "*"(applies to the whole channel)- Sole-agent fallback (only when exactly one agent is configured; multi-agent fleets without a matching binding fail closed)
Within each tier, the first bindings entry that matches wins.
For type: "acp" entries, OpenClaw resolves based on the exact conversation identity (match.channel + account + match.peer.id) and skips the route binding tier order above.
Per-agent access profiles
Full access (no sandbox)
{
agents: {
entries: {
personal: {
workspace: "~/.openclaw/workspace-personal",
sandbox: { mode: "off" },
},
},
},
}
Read-only tools + workspace
{
agents: {
entries: {
family: {
workspace: "~/.openclaw/workspace-family",
sandbox: { mode: "all", scope: "agent", workspaceAccess: "ro" },
tools: {
allow: [
"read",
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
],
deny: ["write", "edit", "apply_patch", "exec", "process", "browser"],
},
},
},
},
}
No filesystem access (messaging only)
{
agents: {
entries: {
public: {
workspace: "~/.openclaw/workspace-public",
sandbox: { mode: "all", scope: "agent", workspaceAccess: "none" },
tools: {
allow: [
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
"whatsapp",
"telegram",
"slack",
"discord",
"gateway",
],
deny: [
"read",
"write",
"edit",
"apply_patch",
"exec",
"process",
"browser",
"canvas",
"nodes",
"cron",
"gateway",
"image",
],
},
},
},
},
}
For precedence details, see Multi-Agent Sandbox & Tools.
Session
{
session: {
scope: "per-sender",
dmScope: "main", // main | per-peer | per-channel-peer | per-account-channel-peer
groupScope: "per-group", // main | per-group
identityLinks: {
alice: ["telegram:123456789", "discord:987654321012345678"],
},
reset: {
mode: "daily", // daily | idle
atHour: 4,
idleMinutes: 60,
},
resetByType: {
thread: { mode: "daily", atHour: 4 },
direct: { mode: "idle", idleMinutes: 240 },
group: { mode: "idle", idleMinutes: 120 },
},
resetByChannel: {
discord: { mode: "idle", idleMinutes: 30 },
},
resetTriggers: ["/new", "/reset"],
store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
maintenance: {
mode: "enforce", // enforce (default) | warn
pruneAfter: "30d",
archiveDashboardAfter: "7d", // false or 0 disables
maxEntries: 500,
preserveRecent: "7d", // optional duration or false
resetArchiveRetention: "30d", // duration or false
maxDiskBytes: "500mb", // optional hard budget
highWaterBytes: "400mb", // optional cleanup target
},
threadBindings: {
enabled: true,
idleHours: 24, // default inactivity auto-unfocus in hours (`0` disables)
maxAgeHours: 0, // default hard max age in hours (`0` disables)
},
sharing: {
readOnly: true,
suggest: true,
drafts: true,
},
mainKey: "main", // canonical main-session suffix
sendPolicy: {
rules: [{ action: "deny", match: { channel: "discord", chatType: "group" } }],
default: "allow",
},
},
}
Session field details
scope: determines how sessions are grouped by default in group-chat contexts.per-sender(default): every sender gets their own isolated session inside a channel context.global: all participants within a channel context share one session (only use when shared context is intended).
dmScope: controls how direct messages are grouped.main: all DMs share the main session.per-peer: isolate by sender id across channels.per-channel-peer: isolate per channel and sender (recommended for multi-user inboxes).per-account-channel-peer: isolate per account, channel, and sender (recommended for multi-account setups).
groupScope: defines grouping for groups, rooms, and channels.per-group(default): keep each non-direct peer in its channel-scoped session.main: send non-direct peers to the agent main session. Prefer a narrowbindings[].session.groupScopeoverride when only selected trusted rooms should share main context.
identityLinks: maps canonical ids to provider-prefixed peers for cross-channel session sharing. Dock commands such as/dock_discorduse the same map to switch the active session's reply route to another linked channel peer; see Channel docking.reset: primary reset policy.nonedisables automatic reset and is the default; compaction bounds active context instead.dailyresets atatHourlocal time;idleresets afteridleMinutes. When both configured, whichever expires first wins./newand/resetremain available in every mode. Daily reset freshness uses the session row'ssessionStartedAt; idle reset freshness useslastInteractionAt. Background/system-event writes such as heartbeat, cron wakeups, exec notifications, and gateway bookkeeping can updateupdatedAt, but they do not keep daily/idle sessions fresh.resetByType: per-type overrides (direct,group,thread). Doctor migrates legacydmentries todirect; the schema rejectsdm.
resetByChannel: per-channel reset overrides keyed by provider/channel id. When the session's channel has a matching entry, it wins outright overresetByType/resetfor that session. Use only when one channel needs reset behavior different from the type-level policy.mainKey: canonical main-session suffix. Keep it stable unless you intentionally need a custom main-session key.sendPolicy: match bychannel,chatType(direct|group|channel, with legacydmalias),keyPrefix, orrawKeyPrefix. First deny wins.maintenance: session-store cleanup and retention controls.mode:enforceapplies cleanup and is the default;warnemits warnings only.pruneAfter: age cutoff for stale entries (default30d).archiveDashboardAfter: inactivity cutoff for archiving visible dashboard sessions (default7d);falseor0disables automatic archiving.maxEntries: maximum total number of live SQLite session entries (default500). Every row counts toward the cap, but archived or pinned sessions, active or admitted work, model-locked sessions, and durable external conversation pointers are never automatic eviction targets. Cleanup removes the oldest unprotected rows; if protection prevents reaching the cap, the store remains above it. Runtime writes batch cleanup with a small high-water buffer for production-sized caps;openclaw sessions cleanup --enforceapplies the cap immediately but does not unprotect rows. Unarchive, unpin, wait for active work to finish, or explicitly delete protected sessions to reduce the total.preserveRecent: optional inactivity window that protects recently active interactive sessions and all of their SQLite history generations from automatic age, count, and disk-budget history eviction (for example"7d"). Unset orfalsedisables this protection. Synthetic model-run, cron, hook, heartbeat, ACP, and sub-agent sessions remain eligible for bounded cleanup. Protection can temporarily keep the store above configured entry or disk targets and does not archive sessions.
- Gateway model-run probe sessions that live briefly rely on a fixed
24hretention window, yet cleanup is triggered by pressure: stale strict model-run probe rows are only purged once session-entry maintenance or capacity pressure hits the threshold. Only strict explicit probe keys that matchagent:*:explicit:model-run-<uuid>qualify; regular direct, group, thread, cron, hook, heartbeat, ACP, and sub-agent sessions do not carry this 24-hour retention. When model-run cleanup does fire, it precedes the broaderpruneAfterstale-entry sweep and themaxEntriescap.- The current schema refuses legacy
rotateBytes; older configs get it stripped out byopenclaw doctor --fix. resetArchiveRetention: retention based on age for reset or deleted transcript archives. Archives stay put until disk-budget eviction by default; opting into wall-clock deletion means setting a duration, orfalseto turn it off explicitly.maxDiskBytes: an optional disk budget for the sessions directory. Inwarnmode, warnings are logged; inenforcemode, the oldest artifacts and sessions get removed first. Setfalse,0, or"0"to switch the budget off completely.highWaterBytes: an optional target following budget cleanup. The default is80%ofmaxDiskBytes. A value resolving to zero reverts to the default; negative values are not accepted. Disable the budget withmaxDiskBytes, never with a zero high-water mark.
- The current schema refuses legacy
threadBindings: global defaults applied to thread-bound session features.enabled: the master toggle for supported channel thread bindingsidleHours: the default inactivity auto-unfocus measured in hours (0turns it off; providers may override)maxAgeHours: the default hard max age in hours (0turns it off; providers may override)spawnSessions: the default gate for spawning thread-bound work sessions fromsessions_spawnand ACP thread spawns. Defaults totruewhen thread bindings are active; providers or accounts may override.defaultSpawnContext: the default native subagent context for thread-bound spawns (either"fork"or"isolated"). Defaults to"fork".
sharing: dictates which per-session collaboration modes owners andoperator.adminconnections can pick. Every flag defaults totrue; flipping one tofalsedrops that option from the Control UI and makes create-time visibility orsession.visibility.setreject it. New sessions beginsharedunless the Control UI starts one as a draft.readOnly: permitsread-only, where non-members can observe but cannot send, steer, abort, approve, or alter session state.suggest: permitssuggest, where viewers can offer suggestions for the session owner or anoperator.adminconnection to send, queue, edit, or discard, without granting direct send or manage access to the session.drafts: permitsdraft, which keeps the session out of non-admin, non-owner session lists and event broadcasts.
Session visibility and membership live as canonical sharing state. Structured session.sharing and session.suggestion change events refresh connected clients without injecting administrative commentary into conversation transcripts. These controls coordinate operators sharing one agent; they do not act as a security boundary between tenants. When isolation is required, use separate Gateways or agents.
Messages
{
messages: {
responsePrefix: "🦞", // or "auto"
ackReaction: "👀",
ackReactionScope: "group-mentions", // group-mentions | group-all | direct | all | off | none
queue: {
mode: "steer", // steer (default) | followup | collect | interrupt
cap: 20,
drop: "summarize", // old | new | summarize (default)
byChannel: {
whatsapp: "followup",
telegram: "followup",
},
},
inbound: {
debounceMs: 2000, // 0 disables
byChannel: {
whatsapp: 5000,
slack: 1500,
},
},
},
}
Response prefix
Per-channel/account overrides: channels.<channel>.responsePrefix, channels.<channel>.accounts.<id>.responsePrefix.
Resolution (most specific wins): account → channel → global. "" disables and stops cascade. "auto" derives [{identity.name}].
Template variables:
| Variable | Description | Example |
|---|---|---|
{model} | Brief model name | claude-opus-4-6 |
{modelFull} | Complete model spec | anthropic/claude-opus-4-6 |
{provider} | Provider designation | anthropic |
{thinkingLevel} | Active reasoning tier | high, low, off |
{identity.name} | Agent label | (identical to "auto") |
Case does not matter for these variables. {think} serves as a synonym for {thinkingLevel}.
Ack reaction
- Unless overridden, it falls back to the active agent's
identity.emoji, with"👀"as the alternative. To turn it off, set"". - Discord, Matrix, Slack, and Telegram each allow channel-level overrides via
channels.<channel>.ackReactionandchannels.<channel>.accounts.<id>.ackReaction. For any other platform that supports acknowledgment reactions, applymessages.ackReaction. - The lookup sequence runs account first, then channel, then
messages.ackReaction, and finally the identity fallback. - WhatsApp breaks both patterns. It pulls the emoji and scope exclusively from
messages.ackReactionandmessages.ackReactionScope, and whenmessages.ackReactionis left empty it sends no acknowledgment whatsoever, so the identity fallback never kicks in. Even so, assigningchannels.whatsapp.reactionLevel(or its per-account variant) the value"off"disables all automatic reactions, including acknowledgments. More details in WhatsApp acknowledgment reactions. - Scope options:
group-mentions(the default),group-all,direct,all, oroff/none(which disables ack reactions entirely). - With
group-mentions, group messages that mention the agent get acknowledged, including groups usingrequireMention: false. To acknowledge every group message, setgroup-all. messages.statusReactions.enabled: turns on lifecycle status reactions for Slack, Discord, Signal, Telegram, and WhatsApp. On Discord, leaving it unset still shows status reactions while ack reactions are active. On Slack, Signal, Telegram, and WhatsApp, you must explicitly set it totrueto activate lifecycle status reactions. Slack defaults to its native assistant thread status and rotating loading messages for progress, with the configured ack reaction held static.
Queue
mode: how inbound messages are queued while a session run is in progress. The default is"steer".steer: feed the new prompt straight into the running session.followup: wait for the current run to complete, then execute the new prompt.collect: group compatible messages and process them together later.interrupt: halt the active run and start the newest prompt immediately.
- A built-in 500ms debounce governs steer, followup, and collect batching in the queue.
cap: the ceiling on queued messages before the drop policy takes effect. Default:20.drop: what happens when that ceiling is hit. With"summarize"(the default), the oldest entries are discarded but compact summaries are preserved;"old"drops the oldest without summaries;"new"refuses the newest item.byChannel: provider-id-keyedmodeoverrides applied per channel.debounceMsByChannel: per-channel debounce overrides in milliseconds, also keyed by provider id.
The global pre-queue debounce window is set with messages.inbound.debounceMs.
Inbound debounce
Quick, text-only messages from one sender get batched into a single agent turn. Media and attachments flush right away. Control commands skip debouncing entirely. Default debounceMs: 2000.
Other message keys
channels.whatsapp.responsePrefix: prefix for outbound WhatsApp replies. Only when the canonical value is not set does Doctor shift the retired inboundmessagePrefixvalue here.messages.visibleReplies: manages visible source replies in direct, group, and channel settings ("message_tool"needsmessage(action=send)to show output;"automatic"sends standard replies as before).messages.usageTemplate/messages.responseUsage: tailored/usagefooter template plus the default mode for each reply (off | tokens | full, with the olderonalias fortokens).messages.groupChat.mentionPatterns/historyLimit: mention triggers in group messages and the size of the history window.messages.suppressToolErrors: whentrue, hides⚠️tool-error alerts from the user (the agent still sees errors in context and can attempt again). Default:false.
TTS (text-to-speech)
{
tts: {
auto: "off", // off (default) | always | inbound | tagged
mode: "final", // final | all
provider: "elevenlabs",
summaryModel: "openai/gpt-5.4-mini",
modelOverrides: { enabled: true },
maxTextLength: 4000,
timeoutMs: 30000,
providers: {
elevenlabs: {
apiKey: "example-elevenlabs-api-key",
baseUrl: "https://api.elevenlabs.io",
speakerVoiceId: "voice_id",
modelId: "eleven_multilingual_v2",
seed: 42,
applyTextNormalization: "auto",
languageCode: "en",
voiceSettings: {
stability: 0.5,
similarityBoost: 0.75,
style: 0.0,
useSpeakerBoost: true,
speed: 1.0,
},
},
microsoft: {
speakerVoice: "en-US-MichelleNeural",
lang: "en-US",
outputFormat: "audio-24khz-48kbitrate-mono-mp3",
},
openai: {
apiKey: "example-openai-api-key",
baseUrl: "https://api.openai.com/v1",
model: "gpt-4o-mini-tts",
speakerVoice: "coral",
},
},
},
}
The global preferences path is machine state (default
~/.openclaw/settings/tts.json; use OPENCLAW_TTS_PREFS to override). For advanced
multi-agent setups, agents.entries.<id>.tts.prefsPath can be set for separate
per-agent preference stores.
autosets the default auto-TTS mode:off,always,inbound, ortagged. Local prefs can be overridden by/tts on|off, and/tts statusdisplays the effective state.- For auto-summary,
summaryModelreplacesagents.defaults.model.primary. modelOverridesis on by default (enabled !== false);modelOverrides.allowProviderrequires opting in.- API keys fall back to
ELEVENLABS_API_KEY/XI_API_KEYandOPENAI_API_KEY. - Bundled speech providers belong to plugins. If
plugins.allowis set, add every TTS provider plugin you intend to use, such asmicrosoftfor Edge TTS. The legacyedgeprovider id is recognized as an alias formicrosoft. - The OpenAI TTS endpoint is overridden by
providers.openai.baseUrl. The resolution order is config, thenOPENAI_TTS_BASE_URL, thenhttps://api.openai.com/v1. - When
providers.openai.baseUrltargets a non-OpenAI endpoint, OpenClaw treats it as an OpenAI-compatible TTS server and eases model/voice checks.
Talk
Defaults for Talk mode (macOS/iOS/Android and the browser Control UI).
{
talk: {
agentId: "ops",
provider: "elevenlabs",
providers: {
elevenlabs: {
speakerVoiceId: "elevenlabs_voice_id",
voiceAliases: {
Clawd: "EXAVITQu4vr4xnSDxMaL",
Roger: "CwhRBWXzGAHq8TQ4Fs17",
},
modelId: "eleven_multilingual_v2",
outputFormat: "mp3_44100_128",
apiKey: "elevenlabs_api_key",
},
mlx: {
modelId: "mlx-community/Soprano-80M-bf16",
},
system: {},
},
consultThinkingLevel: "low",
consultFastMode: true,
speechLocale: "ru-RU",
silenceTimeoutMs: 1500,
interruptOnSpeech: true,
realtime: {
provider: "openai",
providers: {
openai: {
model: "gpt-realtime-2.1",
speakerVoice: "cedar",
},
},
instructions: "Speak warmly and keep answers brief.",
mode: "realtime", // realtime | stt-tts | transcription
transport: "webrtc", // webrtc | provider-websocket | gateway-relay | managed-room
vadThreshold: 0.5,
silenceDurationMs: 500,
prefixPaddingMs: 300,
reasoningEffort: "medium",
brain: "agent-consult", // agent-consult | direct-tools | none
},
},
}
talk.providermust correspond to an entry intalk.providerswhen several Talk providers are set up.talk.agentIdis responsible for Talk sessions that are initiated without a session key tied to a specific agent. Talk calls scoped to a session keep using the agent encoded in that key. For an existing multi-agent setup, Doctor can generate a minimaltalkblock that includes only this owner.- The older flat Talk keys (
talk.voiceId,talk.voiceAliases,talk.modelId,talk.outputFormat,talk.apiKey) exist solely for backward compatibility. Executeopenclaw doctor --fixto convert persisted configuration intotalk.providers.<provider>. - Voice IDs revert to
ELEVENLABS_VOICE_IDorSAG_VOICE_ID(as seen in the macOS Talk client). providers.*.apiKeyaccepts either plaintext strings or SecretRef objects.- The
ELEVENLABS_API_KEYfallback is active only when no Talk API key has been set. providers.*.voiceAliasesenables friendly names for Talk directives.providers.mlx.modelIdpicks the Hugging Face repo that the macOS local MLX helper relies on. When omitted, macOS defaults tomlx-community/Soprano-80M-bf16.- On macOS, MLX playback uses the bundled
openclaw-mlx-ttshelper if it exists, otherwise it looks for an executable inPATH;OPENCLAW_MLX_TTS_BINoverrides the helper path during development. consultThinkingLeveldetermines the thinking level for the complete OpenClaw agent run behind Control UI Talk realtimeopenclaw_agent_consultcalls. Leave it empty to keep the session's normal behavior.consultFastModeprovides a one-time fast-mode override for Control UI Talk realtime queries without altering the session's usual fast-mode setting.speechLocaledefines the BCP 47 locale id for Talk speech recognition on Android, iOS, and macOS, as well as for the iOS system-voice fallback. Android also uses its language part to steer realtime input transcription. Leave it empty to rely on the device default.silenceTimeoutMsdictates how long Talk mode waits after user silence before sending the transcript. Leaving it unset uses the platform's default pause window (700 ms on macOS and Android, 900 ms on iOS).realtime.instructionsappends provider-facing system instructions to OpenClaw's built-in realtime prompt, allowing voice style changes without dropping the defaultopenclaw_agent_consultguidance.realtime.vadThresholdadjusts the provider voice-activity threshold from0(most sensitive) to1(least sensitive). Leaving it unset keeps the provider default.realtime.silenceDurationMsspecifies the positive whole-number silence window before the provider finalizes a realtime user turn. Leaving it unset keeps the provider default.realtime.prefixPaddingMsspecifies the non-negative whole-number amount of audio kept before detected speech starts. Leaving it unset keeps the provider default.realtime.reasoningEffortsets the provider-specific reasoning level for realtime sessions. Leaving it unset keeps the provider default.realtime.consultRouting:"provider-direct"(default) keeps direct provider replies when the realtime provider delivers a final user transcript withoutopenclaw_agent_consult."force-agent-consult"sends the finalized request through OpenClaw instead.
Related
- Configuration reference, every other config key
- Configuration, routine tasks and quick start
- Configuration examples