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.skills for unrestricted skills by default.
  • Omit agents.entries.*.skills to inherit the defaults.
  • Set agents.entries.*.skills: [] for no skills.
  • A non-empty agents.entries.*.skills list is the final set for that agent; it does not merge with defaults.

agents.defaults.skipBootstrap

Disables automatic creation of workspace bootstrap files (AGENTS.md, SOUL.md, IDENTITY.md, USER.md, BOOTSTRAP.md).

{
  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.

BudgetCovers
agents.defaults.bootstrapMaxChars / bootstrapTotalMaxCharsStandard 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.maxSkillsPromptChars
  • agents.entries.*.contextInjection
  • agents.entries.*.bootstrapMaxChars
  • agents.entries.*.bootstrapTotalMaxChars
  • agents.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: default memory_get excerpt cap before truncation metadata and continuation notice are added.
  • When memory_get omits lines, OpenClaw falls back to a built-in 120-line window and then applies memoryGetMaxChars.
  • Live tool results use a model-context auto cap: 16000 chars below 100K tokens, 32000 chars at 100K+ tokens, and 64000 chars at 200K+ tokens.
  • postCompactionMaxChars: AGENTS.md excerpt cap used during post-compaction refresh injection.

agents.entries.*.contextLimits

Per-agent override for the shared contextLimits knobs. 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 optional provider/model ref 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. Setting utilityModel: "" disables the alternate utility route, and dashboard title generation then goes straight to the regular session model. agents.entries.*.utilityModel replaces 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_image tool 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/model refs are preferred. Bare IDs work for compatibility; if a bare ID uniquely matches a configured image-capable entry in models.providers.*.models, OpenClaw qualifies it to that provider. Ambiguous configured matches demand an explicit provider prefix.
  • 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-image for native Gemini image generation, fal/fal-ai/flux/dev for fal, openai/gpt-image-2 for OpenAI Images, or openai/gpt-image-1.5 for transparent-background OpenAI PNG/WebP output.
    • Picking a provider/model directly means configuring matching provider auth too (for example GEMINI_API_KEY or GOOGLE_API_KEY for google/*, OPENAI_API_KEY or OpenAI Codex OAuth for openai/gpt-image-2 / openai/gpt-image-1.5, FAL_KEY for fal/*).
    • Leaving it out lets image_generate still 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_generate tool.
    • Common values: google/lyria-3-clip-preview, google/lyria-3-pro-preview, or minimax/music-2.6.
    • Leaving it out lets music_generate still 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.
  • 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_generate tool.
    • Common values: qwen/wan2.6-t2v, qwen/wan2.6-i2v, qwen/wan2.6-r2v, qwen/wan2.6-r2v-flash, or qwen/wan2.7-r2v.
    • Leaving it out lets video_generate still 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, and watermark options.
  • pdfModel: takes either a string ("provider/model") or an object ({ primary, fallbacks }).
    • Handles model routing for the pdf tool.
    • Leaving it out makes the PDF tool fall back to imageModel, then to the resolved session/default model.
  • pdfMaxMb: the default cap on PDF size for the pdf tool when maxBytesMb is omitted at invocation.
  • pdfMaxPages: the default upper bound on pages scanned by extraction fallback within the pdf tool.
  • fastModeDefault: the default fast-mode setting applied to agents. Acceptable values are "auto", true, and false. A per-agent agents.entries.*.fastModeDefault takes 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 /verbose tool 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-agent agents.entries.*.toolProgressDetail supersedes this default.
  • reasoningDefault: the default reasoning visibility for agents. Acceptable values are "off", "on", and "stream". A per-agent agents.entries.*.reasoningDefault overrides 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 format provider/model (for instance, openai/gpt-5.6-sol for 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 explicit provider/model is 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, apply contextWindow for its native window. Refer to OpenAI context window defaults.
  • models: configured aliases and per-model settings. Each entry may carry alias (shortcut) and params (provider-specific, such as temperature, maxTokens, cacheRetention, context1m, anthropicServerCompaction, anthropicCompactThreshold, responsesServerCompaction, responsesCompactThreshold, OpenRouter provider routing, chat_template_kwargs, and extra_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 agentRuntime to a provider/* entry when every dynamically discovered model for that provider should share the same runtime. An exact provider/model runtime policy still takes precedence over the wildcard.
  • Safe metadata edits: add entries with openclaw config set agents.defaults.models '<json>' --strict-json --merge. config set blocks replacements that would drop existing entries unless --replace is supplied.
  • modelPolicy.allow: explicit override allowlist. Handles aliases, exact provider/model refs, and trailing prefix wildcards like openai/* or clawrouter/anthropic/*. Leave it out or pass [] to permit any model. agents.entries.*.modelPolicy.allow swaps 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: true to turn on server-side compaction. Use params.anthropicCompactThreshold to change the input-token trigger; the default sits at max(50000, floor(contextWindow * 0.7)), and lower configured values clamp to 50000. 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: false to halt injection of context_management, or params.responsesCompactThreshold to override the default of 70% of the resolved context window (80,000 when unavailable). ChatGPT OAuth, custom proxies, and routes with compat.supportsStore: false do not enable this path. See OpenAI server-side compaction.
  • params: global default provider parameters applied to all models. Set at agents.defaults.params (e.g. { cacheRetention: "long" }).
  • params merge precedence (config): agents.defaults.params (global base) is overridden by agents.defaults.models["provider/model"].params (per-model), then agents.entries.*.params (matching agent id) overrides by key. See Prompt Caching for details.
  • models.providers.openrouter.params.provider: OpenRouter-wide default provider-routing policy. OpenClaw forwards this to OpenRouter's request provider object; per-model agents.defaults.models["openrouter/<model>"].params.provider and agent params override by key. See OpenRouter provider routing.
  • params.extra_body/params.extraBody: advanced pass-through JSON merged into api: "openai-completions" request bodies for OpenAI-compatible proxies. If it collides with generated request keys, the extra body wins; non-native completions routes still strip OpenAI-only store afterward.
  • params.chat_template_kwargs: vLLM/OpenAI-compatible chat-template arguments merged into top-level api: "openai-completions" request bodies. For vllm/nemotron-3-* with thinking off, the bundled vLLM plugin automatically sends enable_thinking: false and force_nonempty_content: true; explicit chat_template_kwargs override generated defaults, and extra_body.chat_template_kwargs still has final precedence. Configured vLLM Qwen and Nemotron thinking models expose binary /think choices (off, on) instead of the multi-level effort ladder.
  • compat.thinkingFormat: OpenAI-compatible thinking payload style. Use "together" for Together-style reasoning.enabled, "qwen" for Qwen-style top-level enable_thinking, or "qwen-chat-template" for chat_template_kwargs.enable_thinking on Qwen-family backends that support request-level chat-template kwargs, such as vLLM. OpenClaw maps disabled thinking to false and enabled thinking to true, and configured vLLM Qwen models expose binary /think choices for these formats.
  • compat.supportedReasoningEfforts: per-model OpenAI-compatible reasoning effort list. Include "xhigh" for custom endpoints that truly accept it; OpenClaw then exposes /think xhigh in command menus, Gateway session rows, session patch validation, agent CLI validation, and llm-task validation for that configured provider/model. Use compat.reasoningEffortMap when the backend wants a provider-specific value for a canonical level.
  • params.preserveThinking: Z.AI-only opt-in for preserved thinking. With this enabled and thinking active, OpenClaw transmits thinking.clear_thinking: false and replays earlier reasoning_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 checks healthUrl (or baseUrl + "/models"), launches command with args when the endpoint is unreachable, waits up to readyTimeoutMs, then issues the model request. command must be an absolute path. idleStopMs: 0 maintains 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, use models.providers.<provider>.agentRuntime; for model-specific rules, use agents.defaults.models["provider/model"].agentRuntime / agents.entries.*.models["provider/model"].agentRuntime. A provider/model prefix by itself never selects a harness. With runtime unset or auto, 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 to min(16, max(8, available CPU parallelism)), derived from os.availableParallelism() with os.cpus().length as 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 registers codex; the bundled Anthropic plugin supplies the claude-cli CLI 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 like id: "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 for openclaw to keep shipped configs from v2026.5.22 and earlier working. New config should adopt openclaw.
  • Runtime precedence: exact model policy first (agents.entries.*.models["provider/model"], agents.defaults.models["provider/model"], or models.providers.<provider>.models[]), then agents.entries.* / agents.defaults.models["provider/*"], then provider-wide policy at models.providers.<provider>.agentRuntime.
  • Whole-agent runtime keys are outdated. agents.defaults.agentRuntime, agents.entries.*.agentRuntime, session runtime pins, and OPENCLAW_AGENT_RUNTIME are disregarded by runtime selection. Execute openclaw doctor --fix to 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-scoped agentRuntime.id: "claude-cli". Legacy claude-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):

AliasModel
opusanthropic/claude-opus-5
sonnetanthropic/claude-sonnet-5
gptopenai/gpt-5.4
gpt-miniopenai/gpt-5.4-mini
gpt-nanoopenai/gpt-5.4-nano
geminigoogle/gemini-3.1-pro-preview
gemini-flashgoogle/gemini-3-flash-preview
gemini-flash-litegoogle/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 is 30m when using API-key auth, or 1h for OAuth auth. To turn off the recurring cadence, set it to 0m. 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 no agents.entries.*.heartbeat block is present. If a shared heartbeat block exists without agentId, 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 --fix materializes 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, and isolatedSession.
  • timeoutSeconds: the maximum seconds an agent turn for a heartbeat may run before being terminated. If left unset, agents.defaults.timeoutSeconds applies 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. block blocks direct-target delivery and instead emits reason=dm-blocked.
  • target: with owner (the default), messages go only to a direct-message identity from commands.ownerAllowFrom or channel allowFrom. last explicitly tracks the latest conversation, including groups. none keeps results private.
  • to: applies solely when an explicit channel target is set. With owner or 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 cron sessionTarget: "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 sets heartbeat, 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: when false, 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 to default or safeguard (chunked summarization for extended histories). Refer to Compaction.
  • provider: the ID of a registered compaction provider plugin. If configured, the provider's summarize() gets invoked instead of the default LLM summarization. On failure, it reverts to built-in behavior. Enabling a provider forces mode: "safeguard". See Compaction.
  • thinkingLevel: the thinking level applied solely to embedded OpenClaw compaction summaries (off, minimal, low, medium, high, xhigh, adaptive, max, ultra, or inherit). It defaults to low; set inherit to 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) or off. strict adds 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. Set enabled: false to bypass the audit. Configured compaction-provider output retains its existing provider-owned validation behavior.
  • midTurnPrecheck: an optional tool-loop pressure check. When enabled: 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 both default and safeguard compaction 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: optional provider/model-id or bare alias from agents.defaults.models for 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 (number or strings like "20mb") that opts in to normal local compaction before a run when transcript history reaches the threshold. For Codex app-server sessions, the same threshold caps native rollout transcripts and oversized native threads restart fresh. Disabled when unset or 0. When a context engine returns an explicit compacted successor identity, OpenClaw adopts it; the built-in SQLite compactor keeps the current identity.
  • notifyUser: when true, sends brief context-maintenance notices to the user: when compaction starts and completes (for example, "Compacting context..." and "Compaction complete"), and when a pre-compaction memory flush is exhausted so the reply continues in a degraded state (for example, "Memory maintenance temporarily failed; continuing your reply."). Disabled by default to keep these notices silent.
  • memoryFlush: a silent agentic turn runs before auto-compaction so durable memories get stored. Assign model an exact provider/model pair like ollama/qwen3:8b when this housekeeping step must remain on a local model; the override does not pick up the active session fallback chain. forceFlushTranscriptBytes triggers 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: true to enable block replies. QQ Bot is the exception: it has no streaming.block keys and streams block replies unless channels.qqbot.streaming.mode is "off".
  • Channel overrides: channels.<channel>.streaming.block.coalesce (and per-account variants). Discord, Google Chat, Mattermost, MS Teams, Signal, and Slack default minChars: 1500 / idleMs: 1000.
  • blockStreamingChunk.breakPreference: preferred chunk boundary ("paragraph" | "newline" | "sentence").
  • humanDelay: randomized pause between block replies. Default: off. natural = 800-2500ms. custom uses minMs/maxMs (falls back to the natural range for any unset bound). Per-agent override: agents.entries.*.humanDelay.

See Streaming for behavior + chunking details.

Typing indicators

{
  agents: {
    defaults: {
      typingMode: "instant", // never | instant | thinking | message
      typingIntervalSeconds: 6,
    },
  },
}
  • Defaults: instant for direct chats/mentions, message for unmentioned group chats.
  • typingIntervalSeconds default: 6.
  • Per-agent override: agents.entries.*.typingMode.

See Typing Indicators.

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 runtime
  • openshell: OpenShell runtime

When backend: "openshell" is selected, runtime-specific settings move to plugins.entries.openshell.config.

SSH backend config:

  • target: SSH destination expressed as user@host[:port]
  • command: command for the SSH client, falling back to ssh if unset
  • workspaceRoot: absolute path on the remote host that serves as the root for per-scope workspaces, with /tmp/openclaw-sandboxes as the default
  • identityFile / certificateFile / knownHostsFile: pre-existing local files handed to OpenSSH
  • identityData / certificateData / knownHostsData: inline data or SecretRefs that OpenClaw writes into temporary files during execution
  • strictHostKeyChecking / updateHostKeys: controls for OpenSSH host-key verification, both preset to true

Order of SSH authentication:

  • identityData takes priority over identityFile
  • certificateData takes priority over certificateFile
  • knownHostsData takes priority over knownHostsFile
  • Before the sandbox session launches, any SecretRef-backed *Data entries 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 default
  • ro: sandbox workspace found at /workspace, with the agent workspace attached read-only at /agent
  • rw: agent workspace attached with read/write access at /workspace

Isolation levels:

  • session: a fresh container and workspace for every session
  • agent: a single container and workspace per agent, which is the default
  • shared: 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 authoritative
  • remote: 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, network is set to openclaw-sandbox-browser (dedicated bridge network). Choose bridge only 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 --fix turns off sidecars impacted by a stored "none" value and brings back the dedicated network without quietly enabling egress.
  • Optionally, cdpSourceRange limits CDP access at the container boundary to a CIDR range (such as 172.21.0.1/32).
  • sandbox.browser.binds adds extra host directories exclusively into the sandbox browser container. When it is set (including []), it takes the place of docker.binds for 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.sh and 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-rasterizer start enabled and can be turned off with OPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0 when WebGL/3D usage calls for it.
    • --disable-extensions (enabled by default); OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0 brings back extensions if your workflow relies on them.
    • --renderer-process-limit=2 is the default; adjust it with OPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=<N>, or set 0 to apply Chromium's default process cap.
    • --headless=new applies only when headless is 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.entries object key serves as the stable identifier for the agent.
  • default has been deprecated. Only one configured agent resolves automatically; any multi-agent scenario needs a binding, a agentId surface 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 unless fallbacks is added. To allow fallback for that agent, apply { primary, fallbacks: [...] }; to make strictness explicit, use { primary, fallbacks: [] }. Cron jobs overriding only primary still receive default fallbacks unless fallbacks: [] is configured.
  • utilityModel: an optional per-agent override for brief internal tasks like generated session and thread titles. It falls back to agents.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 in agents.defaults.models. This allows agent-specific adjustments such as cacheRetention, temperature, or maxTokens without replicating the entire model catalog.
  • tts: optional per-agent text-to-speech overrides. The block deep-merges over tts, so place shared provider credentials and fallback policy in tts and set only persona-specific values here, like provider, voice, model, style, or auto mode.
  • skills: optional per-agent skill allowlist. When omitted, the agent inherits agents.defaults.skills if 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 overrides agents.defaults.thinkingDefault for this agent when no per-message or session override exists. The selected provider/model profile determines valid values; for Google Gemini, adaptive preserves provider-owned dynamic thinking (thinkingLevel omitted on Gemini 3/3.1, thinkingBudget: -1 on Gemini 2.5).
  • reasoningDefault: optional per-agent default reasoning visibility (on | off | stream). It overrides agents.defaults.reasoningDefault for this agent when no per-message or session reasoning override is set.
  • fastModeDefault: optional per-agent default for fast mode ("auto" | true | false). It overrides agents.defaults.fastModeDefault for this agent when no per-message or session fast-mode override is set.
  • models: optional per-agent model catalog/runtime overrides keyed by full provider/model ids. Apply models["provider/model"].agentRuntime for per-agent runtime exceptions.
  • runtime: optional per-agent runtime descriptor. Use type: "acp" with runtime.acp defaults (agent, backend, mode, cwd) when the agent should default to ACP harness sessions.
  • identity.avatar: workspace-relative path, http(s) URL, or data: URI.
  • Local workspace-relative identity.avatar image files are capped at 2 MB. http(s) URLs and data: URIs bypass the local file-size check.
  • identity derives defaults: ackReaction from emoji, mentionPatterns from name/emoji.
  • subagents.allowAgents: an allowlist of agent IDs that are valid for explicit sessions_spawn.agentId targets (["*"] means any configured target; by default, only the same agent is allowed). If self-targeted agentId calls should be permitted, include the requester ID. Entries that are outdated, because their agent config was removed, get rejected by sessions_spawn and are not listed in agents_list; execute openclaw doctor --fix to purge them, or insert a minimal agents.entries.* entry when that target should stay spawnable while taking on default settings.
  • Sandbox inheritance guard: when the requester session is sandboxed, sessions_spawn blocks targets that would run without a sandbox.
  • subagents.requireAgentId: when enabled, sessions_spawn calls that leave out agentId are 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): route for standard routing (when the type is missing, route is assumed), acp for 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 match
  • 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, with no peer/guild/team)
  5. match.accountId: "*" (applies to the whole channel)
  6. 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 narrow bindings[].session.groupScope override 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_discord use the same map to switch the active session's reply route to another linked channel peer; see Channel docking.
  • reset: primary reset policy. none disables automatic reset and is the default; compaction bounds active context instead. daily resets at atHour local time; idle resets after idleMinutes. When both configured, whichever expires first wins. /new and /reset remain available in every mode. Daily reset freshness uses the session row's sessionStartedAt; idle reset freshness uses lastInteractionAt. Background/system-event writes such as heartbeat, cron wakeups, exec notifications, and gateway bookkeeping can update updatedAt, but they do not keep daily/idle sessions fresh.
    • resetByType: per-type overrides (direct, group, thread). Doctor migrates legacy dm entries to direct; the schema rejects dm.
  • resetByChannel: per-channel reset overrides keyed by provider/channel id. When the session's channel has a matching entry, it wins outright over resetByType/reset for that session. Use only when one channel needs reset behavior different from the type-level policy.
  • mainKey: canonical main-session suffix. Keep it stable unless you intentionally need a custom main-session key.
  • sendPolicy: match by channel, chatType (direct|group|channel, with legacy dm alias), keyPrefix, or rawKeyPrefix. First deny wins.
  • maintenance: session-store cleanup and retention controls.
    • mode: enforce applies cleanup and is the default; warn emits warnings only.
    • pruneAfter: age cutoff for stale entries (default 30d).
    • archiveDashboardAfter: inactivity cutoff for archiving visible dashboard sessions (default 7d); false or 0 disables automatic archiving.
    • maxEntries: maximum total number of live SQLite session entries (default 500). 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 --enforce applies 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 or false disables 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 24h retention 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 match agent:*: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 broader pruneAfter stale-entry sweep and the maxEntries cap.
    • The current schema refuses legacy rotateBytes; older configs get it stripped out by openclaw 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, or false to turn it off explicitly.
    • maxDiskBytes: an optional disk budget for the sessions directory. In warn mode, warnings are logged; in enforce mode, the oldest artifacts and sessions get removed first. Set false, 0, or "0" to switch the budget off completely.
    • highWaterBytes: an optional target following budget cleanup. The default is 80% of maxDiskBytes. A value resolving to zero reverts to the default; negative values are not accepted. Disable the budget with maxDiskBytes, never with a zero high-water mark.
  • threadBindings: global defaults applied to thread-bound session features.
    • enabled: the master toggle for supported channel thread bindings
    • idleHours: the default inactivity auto-unfocus measured in hours (0 turns it off; providers may override)
    • maxAgeHours: the default hard max age in hours (0 turns it off; providers may override)
    • spawnSessions: the default gate for spawning thread-bound work sessions from sessions_spawn and ACP thread spawns. Defaults to true when 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 and operator.admin connections can pick. Every flag defaults to true; flipping one to false drops that option from the Control UI and makes create-time visibility or session.visibility.set reject it. New sessions begin shared unless the Control UI starts one as a draft.
    • readOnly: permits read-only, where non-members can observe but cannot send, steer, abort, approve, or alter session state.
    • suggest: permits suggest, where viewers can offer suggestions for the session owner or an operator.admin connection to send, queue, edit, or discard, without granting direct send or manage access to the session.
    • drafts: permits draft, 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:

VariableDescriptionExample
{model}Brief model nameclaude-opus-4-6
{modelFull}Complete model specanthropic/claude-opus-4-6
{provider}Provider designationanthropic
{thinkingLevel}Active reasoning tierhigh, 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>.ackReaction and channels.<channel>.accounts.<id>.ackReaction. For any other platform that supports acknowledgment reactions, apply messages.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.ackReaction and messages.ackReactionScope, and when messages.ackReaction is left empty it sends no acknowledgment whatsoever, so the identity fallback never kicks in. Even so, assigning channels.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, or off/none (which disables ack reactions entirely).
  • With group-mentions, group messages that mention the agent get acknowledged, including groups using requireMention: false. To acknowledge every group message, set group-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 to true to 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-keyed mode overrides 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 inbound messagePrefix value here.
  • messages.visibleReplies: manages visible source replies in direct, group, and channel settings ("message_tool" needs message(action=send) to show output; "automatic" sends standard replies as before).
  • messages.usageTemplate / messages.responseUsage: tailored /usage footer template plus the default mode for each reply (off | tokens | full, with the older on alias for tokens).
  • messages.groupChat.mentionPatterns / historyLimit: mention triggers in group messages and the size of the history window.
  • messages.suppressToolErrors: when true, 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.

  • auto sets the default auto-TTS mode: off, always, inbound, or tagged. Local prefs can be overridden by /tts on|off, and /tts status displays the effective state.
  • For auto-summary, summaryModel replaces agents.defaults.model.primary.
  • modelOverrides is on by default (enabled !== false); modelOverrides.allowProvider requires opting in.
  • API keys fall back to ELEVENLABS_API_KEY/XI_API_KEY and OPENAI_API_KEY.
  • Bundled speech providers belong to plugins. If plugins.allow is set, add every TTS provider plugin you intend to use, such as microsoft for Edge TTS. The legacy edge provider id is recognized as an alias for microsoft.
  • The OpenAI TTS endpoint is overridden by providers.openai.baseUrl. The resolution order is config, then OPENAI_TTS_BASE_URL, then https://api.openai.com/v1.
  • When providers.openai.baseUrl targets 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.provider must correspond to an entry in talk.providers when several Talk providers are set up.
  • talk.agentId is 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 minimal talk block 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. Execute openclaw doctor --fix to convert persisted configuration into talk.providers.<provider>.
  • Voice IDs revert to ELEVENLABS_VOICE_ID or SAG_VOICE_ID (as seen in the macOS Talk client).
  • providers.*.apiKey accepts either plaintext strings or SecretRef objects.
  • The ELEVENLABS_API_KEY fallback is active only when no Talk API key has been set.
  • providers.*.voiceAliases enables friendly names for Talk directives.
  • providers.mlx.modelId picks the Hugging Face repo that the macOS local MLX helper relies on. When omitted, macOS defaults to mlx-community/Soprano-80M-bf16.
  • On macOS, MLX playback uses the bundled openclaw-mlx-tts helper if it exists, otherwise it looks for an executable in PATH; OPENCLAW_MLX_TTS_BIN overrides the helper path during development.
  • consultThinkingLevel determines the thinking level for the complete OpenClaw agent run behind Control UI Talk realtime openclaw_agent_consult calls. Leave it empty to keep the session's normal behavior.
  • consultFastMode provides a one-time fast-mode override for Control UI Talk realtime queries without altering the session's usual fast-mode setting.
  • speechLocale defines 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.
  • silenceTimeoutMs dictates 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.instructions appends provider-facing system instructions to OpenClaw's built-in realtime prompt, allowing voice style changes without dropping the default openclaw_agent_consult guidance.
  • realtime.vadThreshold adjusts the provider voice-activity threshold from 0 (most sensitive) to 1 (least sensitive). Leaving it unset keeps the provider default.
  • realtime.silenceDurationMs specifies the positive whole-number silence window before the provider finalizes a realtime user turn. Leaving it unset keeps the provider default.
  • realtime.prefixPaddingMs specifies the non-negative whole-number amount of audio kept before detected speech starts. Leaving it unset keeps the provider default.
  • realtime.reasoningEffort sets 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 without openclaw_agent_consult. "force-agent-consult" sends the finalized request through OpenClaw instead.

10,861 words · updated Aug 24, 2026