mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-10 04:00:44 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
849
openclaw/docs/tools/acp-agents.md
Normal file
849
openclaw/docs/tools/acp-agents.md
Normal file
|
|
@ -0,0 +1,849 @@
|
|||
---
|
||||
summary: "Use ACP runtime sessions for Codex, Claude Code, Cursor, Gemini CLI, OpenClaw ACP, and other harness agents"
|
||||
read_when:
|
||||
- Running coding harnesses through ACP
|
||||
- Setting up conversation-bound ACP sessions on messaging channels
|
||||
- Binding a message channel conversation to a persistent ACP session
|
||||
- Troubleshooting ACP backend and plugin wiring
|
||||
- Operating /acp commands from chat
|
||||
title: "ACP Agents"
|
||||
---
|
||||
|
||||
# ACP agents
|
||||
|
||||
[Agent Client Protocol (ACP)](https://agentclientprotocol.com/) sessions let OpenClaw run external coding harnesses (for example Pi, Claude Code, Codex, Cursor, Copilot, OpenClaw ACP, OpenCode, Gemini CLI, and other supported ACPX harnesses) through an ACP backend plugin.
|
||||
|
||||
If you ask OpenClaw in plain language to "run this in Codex" or "start Claude Code in a thread", OpenClaw should route that request to the ACP runtime (not the native sub-agent runtime). Each ACP session spawn is tracked as a [background task](/automation/tasks).
|
||||
|
||||
If you want Codex or Claude Code to connect as an external MCP client directly
|
||||
to existing OpenClaw channel conversations, use [`openclaw mcp serve`](/cli/mcp)
|
||||
instead of ACP.
|
||||
|
||||
## Which page do I want?
|
||||
|
||||
There are three nearby surfaces that are easy to confuse:
|
||||
|
||||
| You want to... | Use this | Notes |
|
||||
| ---------------------------------------------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| Run Codex, Claude Code, Gemini CLI, or another external harness _through_ OpenClaw | This page: ACP agents | Chat-bound sessions, `/acp spawn`, `sessions_spawn({ runtime: "acp" })`, background tasks, runtime controls |
|
||||
| Expose an OpenClaw Gateway session _as_ an ACP server for an editor or client | [`openclaw acp`](/cli/acp) | Bridge mode. IDE/client talks ACP to OpenClaw over stdio/WebSocket |
|
||||
| Reuse a local AI CLI as a text-only fallback model | [CLI Backends](/gateway/cli-backends) | Not ACP. No OpenClaw tools, no ACP controls, no harness runtime |
|
||||
|
||||
## Does this work out of the box?
|
||||
|
||||
Usually, yes.
|
||||
|
||||
- Fresh installs now ship the bundled `acpx` runtime plugin enabled by default.
|
||||
- The bundled `acpx` plugin prefers its plugin-local pinned `acpx` binary.
|
||||
- On startup, OpenClaw probes that binary and self-repairs it if needed.
|
||||
- Start with `/acp doctor` if you want a fast readiness check.
|
||||
|
||||
What can still happen on first use:
|
||||
|
||||
- A target harness adapter may be fetched on demand with `npx` the first time you use that harness.
|
||||
- Vendor auth still has to exist on the host for that harness.
|
||||
- If the host has no npm/network access, first-run adapter fetches can fail until caches are pre-warmed or the adapter is installed another way.
|
||||
|
||||
Examples:
|
||||
|
||||
- `/acp spawn codex`: OpenClaw should be ready to bootstrap `acpx`, but the Codex ACP adapter may still need a first-run fetch.
|
||||
- `/acp spawn claude`: same story for the Claude ACP adapter, plus Claude-side auth on that host.
|
||||
|
||||
## Fast operator flow
|
||||
|
||||
Use this when you want a practical `/acp` runbook:
|
||||
|
||||
1. Spawn a session:
|
||||
- `/acp spawn codex --bind here`
|
||||
- `/acp spawn codex --mode persistent --thread auto`
|
||||
2. Work in the bound conversation or thread (or target that session key explicitly).
|
||||
3. Check runtime state:
|
||||
- `/acp status`
|
||||
4. Tune runtime options as needed:
|
||||
- `/acp model <provider/model>`
|
||||
- `/acp permissions <profile>`
|
||||
- `/acp timeout <seconds>`
|
||||
5. Nudge an active session without replacing context:
|
||||
- `/acp steer tighten logging and continue`
|
||||
6. Stop work:
|
||||
- `/acp cancel` (stop current turn), or
|
||||
- `/acp close` (close session + remove bindings)
|
||||
|
||||
## Quick start for humans
|
||||
|
||||
Examples of natural requests:
|
||||
|
||||
- "Bind this Discord channel to Codex."
|
||||
- "Start a persistent Codex session in a thread here and keep it focused."
|
||||
- "Run this as a one-shot Claude Code ACP session and summarize the result."
|
||||
- "Bind this iMessage chat to Codex and keep follow-ups in the same workspace."
|
||||
- "Use Gemini CLI for this task in a thread, then keep follow-ups in that same thread."
|
||||
|
||||
What OpenClaw should do:
|
||||
|
||||
1. Pick `runtime: "acp"`.
|
||||
2. Resolve the requested harness target (`agentId`, for example `codex`).
|
||||
3. If current-conversation binding is requested and the active channel supports it, bind the ACP session to that conversation.
|
||||
4. Otherwise, if thread binding is requested and the current channel supports it, bind the ACP session to the thread.
|
||||
5. Route follow-up bound messages to that same ACP session until unfocused/closed/expired.
|
||||
|
||||
## ACP versus sub-agents
|
||||
|
||||
Use ACP when you want an external harness runtime. Use sub-agents when you want OpenClaw-native delegated runs.
|
||||
|
||||
| Area | ACP session | Sub-agent run |
|
||||
| ------------- | ------------------------------------- | ---------------------------------- |
|
||||
| Runtime | ACP backend plugin (for example acpx) | OpenClaw native sub-agent runtime |
|
||||
| Session key | `agent:<agentId>:acp:<uuid>` | `agent:<agentId>:subagent:<uuid>` |
|
||||
| Main commands | `/acp ...` | `/subagents ...` |
|
||||
| Spawn tool | `sessions_spawn` with `runtime:"acp"` | `sessions_spawn` (default runtime) |
|
||||
|
||||
See also [Sub-agents](/tools/subagents).
|
||||
|
||||
## How ACP runs Claude Code
|
||||
|
||||
For Claude Code through ACP, the stack is:
|
||||
|
||||
1. OpenClaw ACP session control plane
|
||||
2. bundled `acpx` runtime plugin
|
||||
3. Claude ACP adapter
|
||||
4. Claude-side runtime/session machinery
|
||||
|
||||
Important distinction:
|
||||
|
||||
- ACP Claude is a harness session with ACP controls, session resume, background-task tracking, and optional conversation/thread binding.
|
||||
- CLI backends are separate text-only local fallback runtimes. See [CLI Backends](/gateway/cli-backends).
|
||||
|
||||
For operators, the practical rule is:
|
||||
|
||||
- want `/acp spawn`, bindable sessions, runtime controls, or persistent harness work: use ACP
|
||||
- want simple local text fallback through the raw CLI: use CLI backends
|
||||
|
||||
## Bound sessions
|
||||
|
||||
### Current-conversation binds
|
||||
|
||||
Use `/acp spawn <harness> --bind here` when you want the current conversation to become a durable ACP workspace without creating a child thread.
|
||||
|
||||
Behavior:
|
||||
|
||||
- OpenClaw keeps owning the channel transport, auth, safety, and delivery.
|
||||
- The current conversation is pinned to the spawned ACP session key.
|
||||
- Follow-up messages in that conversation route to the same ACP session.
|
||||
- `/new` and `/reset` reset the same bound ACP session in place.
|
||||
- `/acp close` closes the session and removes the current-conversation binding.
|
||||
|
||||
What this means in practice:
|
||||
|
||||
- `--bind here` keeps the same chat surface. On Discord, the current channel stays the current channel.
|
||||
- `--bind here` can still create a new ACP session if you are spawning fresh work. The bind attaches that session to the current conversation.
|
||||
- `--bind here` does not create a child Discord thread or Telegram topic by itself.
|
||||
- The ACP runtime can still have its own working directory (`cwd`) or backend-managed workspace on disk. That runtime workspace is separate from the chat surface and does not imply a new messaging thread.
|
||||
- If you spawn to a different ACP agent and do not pass `--cwd`, OpenClaw inherits the **target agent's** workspace by default, not the requester's.
|
||||
- If that inherited workspace path is missing (`ENOENT`/`ENOTDIR`), OpenClaw falls back to the backend default cwd instead of silently reusing the wrong tree.
|
||||
- If the inherited workspace exists but cannot be accessed (for example `EACCES`), spawn returns the real access error instead of dropping `cwd`.
|
||||
|
||||
Mental model:
|
||||
|
||||
- chat surface: where people keep talking (`Discord channel`, `Telegram topic`, `iMessage chat`)
|
||||
- ACP session: the durable Codex/Claude/Gemini runtime state OpenClaw routes to
|
||||
- child thread/topic: an optional extra messaging surface created only by `--thread ...`
|
||||
- runtime workspace: the filesystem location where the harness runs (`cwd`, repo checkout, backend workspace)
|
||||
|
||||
Examples:
|
||||
|
||||
- `/acp spawn codex --bind here`: keep this chat, spawn or attach a Codex ACP session, and route future messages here to it
|
||||
- `/acp spawn codex --thread auto`: OpenClaw may create a child thread/topic and bind the ACP session there
|
||||
- `/acp spawn codex --bind here --cwd /workspace/repo`: same chat binding as above, but Codex runs in `/workspace/repo`
|
||||
|
||||
Current-conversation binding support:
|
||||
|
||||
- Chat/message channels that advertise current-conversation binding support can use `--bind here` through the shared conversation-binding path.
|
||||
- Channels with custom thread/topic semantics can still provide channel-specific canonicalization behind the same shared interface.
|
||||
- `--bind here` always means "bind the current conversation in place".
|
||||
- Generic current-conversation binds use the shared OpenClaw binding store and survive normal gateway restarts.
|
||||
|
||||
Notes:
|
||||
|
||||
- `--bind here` and `--thread ...` are mutually exclusive on `/acp spawn`.
|
||||
- On Discord, `--bind here` binds the current channel or thread in place. `spawnAcpSessions` is only required when OpenClaw needs to create a child thread for `--thread auto|here`.
|
||||
- If the active channel does not expose current-conversation ACP bindings, OpenClaw returns a clear unsupported message.
|
||||
- `resume` and "new session" questions are ACP-session questions, not channel questions. You can reuse or replace runtime state without changing the current chat surface.
|
||||
|
||||
### Thread-bound sessions
|
||||
|
||||
When thread bindings are enabled for a channel adapter, ACP sessions can be bound to threads:
|
||||
|
||||
- OpenClaw binds a thread to a target ACP session.
|
||||
- Follow-up messages in that thread route to the bound ACP session.
|
||||
- ACP output is delivered back to the same thread.
|
||||
- Unfocus/close/archive/idle-timeout or max-age expiry removes the binding.
|
||||
|
||||
Thread binding support is adapter-specific. If the active channel adapter does not support thread bindings, OpenClaw returns a clear unsupported/unavailable message.
|
||||
|
||||
Required feature flags for thread-bound ACP:
|
||||
|
||||
- `acp.enabled=true`
|
||||
- `acp.dispatch.enabled` is on by default (set `false` to pause ACP dispatch)
|
||||
- Channel-adapter ACP thread-spawn flag enabled (adapter-specific)
|
||||
- Discord: `channels.discord.threadBindings.spawnAcpSessions=true`
|
||||
- Telegram: `channels.telegram.threadBindings.spawnAcpSessions=true`
|
||||
|
||||
### Thread supporting channels
|
||||
|
||||
- Any channel adapter that exposes session/thread binding capability.
|
||||
- Current built-in support:
|
||||
- Discord threads/channels
|
||||
- Telegram topics (forum topics in groups/supergroups and DM topics)
|
||||
- Plugin channels can add support through the same binding interface.
|
||||
|
||||
## Channel specific settings
|
||||
|
||||
For non-ephemeral workflows, configure persistent ACP bindings in top-level `bindings[]` entries.
|
||||
|
||||
### Binding model
|
||||
|
||||
- `bindings[].type="acp"` marks a persistent ACP conversation binding.
|
||||
- `bindings[].match` identifies the target conversation:
|
||||
- Discord channel or thread: `match.channel="discord"` + `match.peer.id="<channelOrThreadId>"`
|
||||
- Telegram forum topic: `match.channel="telegram"` + `match.peer.id="<chatId>:topic:<topicId>"`
|
||||
- BlueBubbles DM/group chat: `match.channel="bluebubbles"` + `match.peer.id="<handle|chat_id:*|chat_guid:*|chat_identifier:*>"`
|
||||
Prefer `chat_id:*` or `chat_identifier:*` for stable group bindings.
|
||||
- iMessage DM/group chat: `match.channel="imessage"` + `match.peer.id="<handle|chat_id:*|chat_guid:*|chat_identifier:*>"`
|
||||
Prefer `chat_id:*` for stable group bindings.
|
||||
- `bindings[].agentId` is the owning OpenClaw agent id.
|
||||
- Optional ACP overrides live under `bindings[].acp`:
|
||||
- `mode` (`persistent` or `oneshot`)
|
||||
- `label`
|
||||
- `cwd`
|
||||
- `backend`
|
||||
|
||||
### Runtime defaults per agent
|
||||
|
||||
Use `agents.list[].runtime` to define ACP defaults once per agent:
|
||||
|
||||
- `agents.list[].runtime.type="acp"`
|
||||
- `agents.list[].runtime.acp.agent` (harness id, for example `codex` or `claude`)
|
||||
- `agents.list[].runtime.acp.backend`
|
||||
- `agents.list[].runtime.acp.mode`
|
||||
- `agents.list[].runtime.acp.cwd`
|
||||
|
||||
Override precedence for ACP bound sessions:
|
||||
|
||||
1. `bindings[].acp.*`
|
||||
2. `agents.list[].runtime.acp.*`
|
||||
3. global ACP defaults (for example `acp.backend`)
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "codex",
|
||||
runtime: {
|
||||
type: "acp",
|
||||
acp: {
|
||||
agent: "codex",
|
||||
backend: "acpx",
|
||||
mode: "persistent",
|
||||
cwd: "/workspace/openclaw",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "claude",
|
||||
runtime: {
|
||||
type: "acp",
|
||||
acp: { agent: "claude", backend: "acpx", mode: "persistent" },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
bindings: [
|
||||
{
|
||||
type: "acp",
|
||||
agentId: "codex",
|
||||
match: {
|
||||
channel: "discord",
|
||||
accountId: "default",
|
||||
peer: { kind: "channel", id: "222222222222222222" },
|
||||
},
|
||||
acp: { label: "codex-main" },
|
||||
},
|
||||
{
|
||||
type: "acp",
|
||||
agentId: "claude",
|
||||
match: {
|
||||
channel: "telegram",
|
||||
accountId: "default",
|
||||
peer: { kind: "group", id: "-1001234567890:topic:42" },
|
||||
},
|
||||
acp: { cwd: "/workspace/repo-b" },
|
||||
},
|
||||
{
|
||||
type: "route",
|
||||
agentId: "main",
|
||||
match: { channel: "discord", accountId: "default" },
|
||||
},
|
||||
{
|
||||
type: "route",
|
||||
agentId: "main",
|
||||
match: { channel: "telegram", accountId: "default" },
|
||||
},
|
||||
],
|
||||
channels: {
|
||||
discord: {
|
||||
guilds: {
|
||||
"111111111111111111": {
|
||||
channels: {
|
||||
"222222222222222222": { requireMention: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
telegram: {
|
||||
groups: {
|
||||
"-1001234567890": {
|
||||
topics: { "42": { requireMention: false } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Behavior:
|
||||
|
||||
- OpenClaw ensures the configured ACP session exists before use.
|
||||
- Messages in that channel or topic route to the configured ACP session.
|
||||
- In bound conversations, `/new` and `/reset` reset the same ACP session key in place.
|
||||
- Temporary runtime bindings (for example created by thread-focus flows) still apply where present.
|
||||
- For cross-agent ACP spawns without an explicit `cwd`, OpenClaw inherits the target agent workspace from agent config.
|
||||
- Missing inherited workspace paths fall back to the backend default cwd; non-missing access failures surface as spawn errors.
|
||||
|
||||
## Start ACP sessions (interfaces)
|
||||
|
||||
### From `sessions_spawn`
|
||||
|
||||
Use `runtime: "acp"` to start an ACP session from an agent turn or tool call.
|
||||
|
||||
```json
|
||||
{
|
||||
"task": "Open the repo and summarize failing tests",
|
||||
"runtime": "acp",
|
||||
"agentId": "codex",
|
||||
"thread": true,
|
||||
"mode": "session"
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `runtime` defaults to `subagent`, so set `runtime: "acp"` explicitly for ACP sessions.
|
||||
- If `agentId` is omitted, OpenClaw uses `acp.defaultAgent` when configured.
|
||||
- `mode: "session"` requires `thread: true` to keep a persistent bound conversation.
|
||||
|
||||
Interface details:
|
||||
|
||||
- `task` (required): initial prompt sent to the ACP session.
|
||||
- `runtime` (required for ACP): must be `"acp"`.
|
||||
- `agentId` (optional): ACP target harness id. Falls back to `acp.defaultAgent` if set.
|
||||
- `thread` (optional, default `false`): request thread binding flow where supported.
|
||||
- `mode` (optional): `run` (one-shot) or `session` (persistent).
|
||||
- default is `run`
|
||||
- if `thread: true` and mode omitted, OpenClaw may default to persistent behavior per runtime path
|
||||
- `mode: "session"` requires `thread: true`
|
||||
- `cwd` (optional): requested runtime working directory (validated by backend/runtime policy). If omitted, ACP spawn inherits the target agent workspace when configured; missing inherited paths fall back to backend defaults, while real access errors are returned.
|
||||
- `label` (optional): operator-facing label used in session/banner text.
|
||||
- `resumeSessionId` (optional): resume an existing ACP session instead of creating a new one. The agent replays its conversation history via `session/load`. Requires `runtime: "acp"`.
|
||||
- `streamTo` (optional): `"parent"` streams initial ACP run progress summaries back to the requester session as system events.
|
||||
- When available, accepted responses include `streamLogPath` pointing to a session-scoped JSONL log (`<sessionId>.acp-stream.jsonl`) you can tail for full relay history.
|
||||
|
||||
### Resume an existing session
|
||||
|
||||
Use `resumeSessionId` to continue a previous ACP session instead of starting fresh. The agent replays its conversation history via `session/load`, so it picks up with full context of what came before.
|
||||
|
||||
```json
|
||||
{
|
||||
"task": "Continue where we left off — fix the remaining test failures",
|
||||
"runtime": "acp",
|
||||
"agentId": "codex",
|
||||
"resumeSessionId": "<previous-session-id>"
|
||||
}
|
||||
```
|
||||
|
||||
Common use cases:
|
||||
|
||||
- Hand off a Codex session from your laptop to your phone — tell your agent to pick up where you left off
|
||||
- Continue a coding session you started interactively in the CLI, now headlessly through your agent
|
||||
- Pick up work that was interrupted by a gateway restart or idle timeout
|
||||
|
||||
Notes:
|
||||
|
||||
- `resumeSessionId` requires `runtime: "acp"` — returns an error if used with the sub-agent runtime.
|
||||
- `resumeSessionId` restores the upstream ACP conversation history; `thread` and `mode` still apply normally to the new OpenClaw session you are creating, so `mode: "session"` still requires `thread: true`.
|
||||
- The target agent must support `session/load` (Codex and Claude Code do).
|
||||
- If the session ID isn't found, the spawn fails with a clear error — no silent fallback to a new session.
|
||||
|
||||
### Operator smoke test
|
||||
|
||||
Use this after a gateway deploy when you want a quick live check that ACP spawn
|
||||
is actually working end-to-end, not just passing unit tests.
|
||||
|
||||
Recommended gate:
|
||||
|
||||
1. Verify the deployed gateway version/commit on the target host.
|
||||
2. Confirm the deployed source includes the ACP lineage acceptance in
|
||||
`src/gateway/sessions-patch.ts` (`subagent:* or acp:* sessions`).
|
||||
3. Open a temporary ACPX bridge session to a live agent (for example
|
||||
`razor(main)` on `jpclawhq`).
|
||||
4. Ask that agent to call `sessions_spawn` with:
|
||||
- `runtime: "acp"`
|
||||
- `agentId: "codex"`
|
||||
- `mode: "run"`
|
||||
- task: `Reply with exactly LIVE-ACP-SPAWN-OK`
|
||||
5. Verify the agent reports:
|
||||
- `accepted=yes`
|
||||
- a real `childSessionKey`
|
||||
- no validator error
|
||||
6. Clean up the temporary ACPX bridge session.
|
||||
|
||||
Example prompt to the live agent:
|
||||
|
||||
```text
|
||||
Use the sessions_spawn tool now with runtime: "acp", agentId: "codex", and mode: "run".
|
||||
Set the task to: "Reply with exactly LIVE-ACP-SPAWN-OK".
|
||||
Then report only: accepted=<yes/no>; childSessionKey=<value or none>; error=<exact text or none>.
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Keep this smoke test on `mode: "run"` unless you are intentionally testing
|
||||
thread-bound persistent ACP sessions.
|
||||
- Do not require `streamTo: "parent"` for the basic gate. That path depends on
|
||||
requester/session capabilities and is a separate integration check.
|
||||
- Treat thread-bound `mode: "session"` testing as a second, richer integration
|
||||
pass from a real Discord thread or Telegram topic.
|
||||
|
||||
## Sandbox compatibility
|
||||
|
||||
ACP sessions currently run on the host runtime, not inside the OpenClaw sandbox.
|
||||
|
||||
Current limitations:
|
||||
|
||||
- If the requester session is sandboxed, ACP spawns are blocked for both `sessions_spawn({ runtime: "acp" })` and `/acp spawn`.
|
||||
- Error: `Sandboxed sessions cannot spawn ACP sessions because runtime="acp" runs on the host. Use runtime="subagent" from sandboxed sessions.`
|
||||
- `sessions_spawn` with `runtime: "acp"` does not support `sandbox: "require"`.
|
||||
- Error: `sessions_spawn sandbox="require" is unsupported for runtime="acp" because ACP sessions run outside the sandbox. Use runtime="subagent" or sandbox="inherit".`
|
||||
|
||||
Use `runtime: "subagent"` when you need sandbox-enforced execution.
|
||||
|
||||
### From `/acp` command
|
||||
|
||||
Use `/acp spawn` for explicit operator control from chat when needed.
|
||||
|
||||
```text
|
||||
/acp spawn codex --mode persistent --thread auto
|
||||
/acp spawn codex --mode oneshot --thread off
|
||||
/acp spawn codex --bind here
|
||||
/acp spawn codex --thread here
|
||||
```
|
||||
|
||||
Key flags:
|
||||
|
||||
- `--mode persistent|oneshot`
|
||||
- `--bind here|off`
|
||||
- `--thread auto|here|off`
|
||||
- `--cwd <absolute-path>`
|
||||
- `--label <name>`
|
||||
|
||||
See [Slash Commands](/tools/slash-commands).
|
||||
|
||||
## Session target resolution
|
||||
|
||||
Most `/acp` actions accept an optional session target (`session-key`, `session-id`, or `session-label`).
|
||||
|
||||
Resolution order:
|
||||
|
||||
1. Explicit target argument (or `--session` for `/acp steer`)
|
||||
- tries key
|
||||
- then UUID-shaped session id
|
||||
- then label
|
||||
2. Current thread binding (if this conversation/thread is bound to an ACP session)
|
||||
3. Current requester session fallback
|
||||
|
||||
Current-conversation bindings and thread bindings both participate in step 2.
|
||||
|
||||
If no target resolves, OpenClaw returns a clear error (`Unable to resolve session target: ...`).
|
||||
|
||||
## Spawn bind modes
|
||||
|
||||
`/acp spawn` supports `--bind here|off`.
|
||||
|
||||
| Mode | Behavior |
|
||||
| ------ | ---------------------------------------------------------------------- |
|
||||
| `here` | Bind the current active conversation in place; fail if none is active. |
|
||||
| `off` | Do not create a current-conversation binding. |
|
||||
|
||||
Notes:
|
||||
|
||||
- `--bind here` is the simplest operator path for "make this channel or chat Codex-backed."
|
||||
- `--bind here` does not create a child thread.
|
||||
- `--bind here` is only available on channels that expose current-conversation binding support.
|
||||
- `--bind` and `--thread` cannot be combined in the same `/acp spawn` call.
|
||||
|
||||
## Spawn thread modes
|
||||
|
||||
`/acp spawn` supports `--thread auto|here|off`.
|
||||
|
||||
| Mode | Behavior |
|
||||
| ------ | --------------------------------------------------------------------------------------------------- |
|
||||
| `auto` | In an active thread: bind that thread. Outside a thread: create/bind a child thread when supported. |
|
||||
| `here` | Require current active thread; fail if not in one. |
|
||||
| `off` | No binding. Session starts unbound. |
|
||||
|
||||
Notes:
|
||||
|
||||
- On non-thread binding surfaces, default behavior is effectively `off`.
|
||||
- Thread-bound spawn requires channel policy support:
|
||||
- Discord: `channels.discord.threadBindings.spawnAcpSessions=true`
|
||||
- Telegram: `channels.telegram.threadBindings.spawnAcpSessions=true`
|
||||
- Use `--bind here` when you want to pin the current conversation without creating a child thread.
|
||||
|
||||
## ACP controls
|
||||
|
||||
Available command family:
|
||||
|
||||
- `/acp spawn`
|
||||
- `/acp cancel`
|
||||
- `/acp steer`
|
||||
- `/acp close`
|
||||
- `/acp status`
|
||||
- `/acp set-mode`
|
||||
- `/acp set`
|
||||
- `/acp cwd`
|
||||
- `/acp permissions`
|
||||
- `/acp timeout`
|
||||
- `/acp model`
|
||||
- `/acp reset-options`
|
||||
- `/acp sessions`
|
||||
- `/acp doctor`
|
||||
- `/acp install`
|
||||
|
||||
`/acp status` shows the effective runtime options and, when available, both runtime-level and backend-level session identifiers.
|
||||
|
||||
Some controls depend on backend capabilities. If a backend does not support a control, OpenClaw returns a clear unsupported-control error.
|
||||
|
||||
## ACP command cookbook
|
||||
|
||||
| Command | What it does | Example |
|
||||
| -------------------- | --------------------------------------------------------- | ------------------------------------------------------------- |
|
||||
| `/acp spawn` | Create ACP session; optional current bind or thread bind. | `/acp spawn codex --bind here --cwd /repo` |
|
||||
| `/acp cancel` | Cancel in-flight turn for target session. | `/acp cancel agent:codex:acp:<uuid>` |
|
||||
| `/acp steer` | Send steer instruction to running session. | `/acp steer --session support inbox prioritize failing tests` |
|
||||
| `/acp close` | Close session and unbind thread targets. | `/acp close` |
|
||||
| `/acp status` | Show backend, mode, state, runtime options, capabilities. | `/acp status` |
|
||||
| `/acp set-mode` | Set runtime mode for target session. | `/acp set-mode plan` |
|
||||
| `/acp set` | Generic runtime config option write. | `/acp set model openai/gpt-5.4` |
|
||||
| `/acp cwd` | Set runtime working directory override. | `/acp cwd /Users/user/Projects/repo` |
|
||||
| `/acp permissions` | Set approval policy profile. | `/acp permissions strict` |
|
||||
| `/acp timeout` | Set runtime timeout (seconds). | `/acp timeout 120` |
|
||||
| `/acp model` | Set runtime model override. | `/acp model anthropic/claude-opus-4-6` |
|
||||
| `/acp reset-options` | Remove session runtime option overrides. | `/acp reset-options` |
|
||||
| `/acp sessions` | List recent ACP sessions from store. | `/acp sessions` |
|
||||
| `/acp doctor` | Backend health, capabilities, actionable fixes. | `/acp doctor` |
|
||||
| `/acp install` | Print deterministic install and enable steps. | `/acp install` |
|
||||
|
||||
`/acp sessions` reads the store for the current bound or requester session. Commands that accept `session-key`, `session-id`, or `session-label` tokens resolve targets through gateway session discovery, including custom per-agent `session.store` roots.
|
||||
|
||||
## Runtime options mapping
|
||||
|
||||
`/acp` has convenience commands and a generic setter.
|
||||
|
||||
Equivalent operations:
|
||||
|
||||
- `/acp model <id>` maps to runtime config key `model`.
|
||||
- `/acp permissions <profile>` maps to runtime config key `approval_policy`.
|
||||
- `/acp timeout <seconds>` maps to runtime config key `timeout`.
|
||||
- `/acp cwd <path>` updates runtime cwd override directly.
|
||||
- `/acp set <key> <value>` is the generic path.
|
||||
- Special case: `key=cwd` uses the cwd override path.
|
||||
- `/acp reset-options` clears all runtime overrides for target session.
|
||||
|
||||
## acpx harness support (current)
|
||||
|
||||
Current acpx built-in harness aliases:
|
||||
|
||||
- `claude`
|
||||
- `codex`
|
||||
- `copilot`
|
||||
- `cursor` (Cursor CLI: `cursor-agent acp`)
|
||||
- `droid`
|
||||
- `gemini`
|
||||
- `iflow`
|
||||
- `kilocode`
|
||||
- `kimi`
|
||||
- `kiro`
|
||||
- `openclaw`
|
||||
- `opencode`
|
||||
- `pi`
|
||||
- `qwen`
|
||||
|
||||
When OpenClaw uses the acpx backend, prefer these values for `agentId` unless your acpx config defines custom agent aliases.
|
||||
If your local Cursor install still exposes ACP as `agent acp`, override the `cursor` agent command in your acpx config instead of changing the built-in default.
|
||||
|
||||
Direct acpx CLI usage can also target arbitrary adapters via `--agent <command>`, but that raw escape hatch is an acpx CLI feature (not the normal OpenClaw `agentId` path).
|
||||
|
||||
## Required config
|
||||
|
||||
Core ACP baseline:
|
||||
|
||||
```json5
|
||||
{
|
||||
acp: {
|
||||
enabled: true,
|
||||
// Optional. Default is true; set false to pause ACP dispatch while keeping /acp controls.
|
||||
dispatch: { enabled: true },
|
||||
backend: "acpx",
|
||||
defaultAgent: "codex",
|
||||
allowedAgents: [
|
||||
"claude",
|
||||
"codex",
|
||||
"copilot",
|
||||
"cursor",
|
||||
"droid",
|
||||
"gemini",
|
||||
"iflow",
|
||||
"kilocode",
|
||||
"kimi",
|
||||
"kiro",
|
||||
"openclaw",
|
||||
"opencode",
|
||||
"pi",
|
||||
"qwen",
|
||||
],
|
||||
maxConcurrentSessions: 8,
|
||||
stream: {
|
||||
coalesceIdleMs: 300,
|
||||
maxChunkChars: 1200,
|
||||
},
|
||||
runtime: {
|
||||
ttlMinutes: 120,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Thread binding config is channel-adapter specific. Example for Discord:
|
||||
|
||||
```json5
|
||||
{
|
||||
session: {
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
idleHours: 24,
|
||||
maxAgeHours: 0,
|
||||
},
|
||||
},
|
||||
channels: {
|
||||
discord: {
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
spawnAcpSessions: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If thread-bound ACP spawn does not work, verify the adapter feature flag first:
|
||||
|
||||
- Discord: `channels.discord.threadBindings.spawnAcpSessions=true`
|
||||
|
||||
Current-conversation binds do not require child-thread creation. They require an active conversation context and a channel adapter that exposes ACP conversation bindings.
|
||||
|
||||
See [Configuration Reference](/gateway/configuration-reference).
|
||||
|
||||
## Plugin setup for acpx backend
|
||||
|
||||
Fresh installs ship the bundled `acpx` runtime plugin enabled by default, so ACP
|
||||
usually works without a manual plugin install step.
|
||||
|
||||
Start with:
|
||||
|
||||
```text
|
||||
/acp doctor
|
||||
```
|
||||
|
||||
If you disabled `acpx`, denied it via `plugins.allow` / `plugins.deny`, or want
|
||||
to switch to a local development checkout, use the explicit plugin path:
|
||||
|
||||
```bash
|
||||
openclaw plugins install acpx
|
||||
openclaw config set plugins.entries.acpx.enabled true
|
||||
```
|
||||
|
||||
Local workspace install during development:
|
||||
|
||||
```bash
|
||||
openclaw plugins install ./path/to/local/acpx-plugin
|
||||
```
|
||||
|
||||
Then verify backend health:
|
||||
|
||||
```text
|
||||
/acp doctor
|
||||
```
|
||||
|
||||
### acpx command and version configuration
|
||||
|
||||
By default, the bundled acpx backend plugin (`acpx`) uses the plugin-local pinned binary:
|
||||
|
||||
1. Command defaults to the plugin-local `node_modules/.bin/acpx` inside the ACPX plugin package.
|
||||
2. Expected version defaults to the extension pin.
|
||||
3. Startup registers ACP backend immediately as not-ready.
|
||||
4. A background ensure job verifies `acpx --version`.
|
||||
5. If the plugin-local binary is missing or mismatched, it runs:
|
||||
`npm install --omit=dev --no-save acpx@<pinned>` and re-verifies.
|
||||
|
||||
You can override command/version in plugin config:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"acpx": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"command": "../acpx/dist/cli.js",
|
||||
"expectedVersion": "any"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `command` accepts an absolute path, relative path, or command name (`acpx`).
|
||||
- Relative paths resolve from OpenClaw workspace directory.
|
||||
- `expectedVersion: "any"` disables strict version matching.
|
||||
- When `command` points to a custom binary/path, plugin-local auto-install is disabled.
|
||||
- OpenClaw startup remains non-blocking while the backend health check runs.
|
||||
|
||||
See [Plugins](/tools/plugin).
|
||||
|
||||
### Automatic dependency install
|
||||
|
||||
When you install OpenClaw globally with `npm install -g openclaw`, the acpx
|
||||
runtime dependencies (platform-specific binaries) are installed automatically
|
||||
via a postinstall hook. If the automatic install fails, the gateway still starts
|
||||
normally and reports the missing dependency through `openclaw acp doctor`.
|
||||
|
||||
### Plugin tools MCP bridge
|
||||
|
||||
By default, ACPX sessions do **not** expose OpenClaw plugin-registered tools to
|
||||
the ACP harness.
|
||||
|
||||
If you want ACP agents such as Codex or Claude Code to call installed
|
||||
OpenClaw plugin tools such as memory recall/store, enable the dedicated bridge:
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.acpx.config.pluginToolsMcpBridge true
|
||||
```
|
||||
|
||||
What this does:
|
||||
|
||||
- Injects a built-in MCP server named `openclaw-plugin-tools` into ACPX session
|
||||
bootstrap.
|
||||
- Exposes plugin tools already registered by installed and enabled OpenClaw
|
||||
plugins.
|
||||
- Keeps the feature explicit and default-off.
|
||||
|
||||
Security and trust notes:
|
||||
|
||||
- This expands the ACP harness tool surface.
|
||||
- ACP agents get access only to plugin tools already active in the gateway.
|
||||
- Treat this as the same trust boundary as letting those plugins execute in
|
||||
OpenClaw itself.
|
||||
- Review installed plugins before enabling it.
|
||||
|
||||
Custom `mcpServers` still work as before. The built-in plugin-tools bridge is an
|
||||
additional opt-in convenience, not a replacement for generic MCP server config.
|
||||
|
||||
### Runtime timeout configuration
|
||||
|
||||
The bundled `acpx` plugin defaults embedded runtime turns to a 120-second
|
||||
timeout. This gives slower harnesses such as Gemini CLI enough time to complete
|
||||
ACP startup and initialization. Override it if your host needs a different
|
||||
runtime limit:
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.acpx.config.timeoutSeconds 180
|
||||
```
|
||||
|
||||
Restart the gateway after changing this value.
|
||||
|
||||
## Permission configuration
|
||||
|
||||
ACP sessions run non-interactively — there is no TTY to approve or deny file-write and shell-exec permission prompts. The acpx plugin provides two config keys that control how permissions are handled:
|
||||
|
||||
These ACPX harness permissions are separate from OpenClaw exec approvals and separate from CLI-backend vendor bypass flags such as Claude CLI `--permission-mode bypassPermissions`. ACPX `approve-all` is the harness-level break-glass switch for ACP sessions.
|
||||
|
||||
### `permissionMode`
|
||||
|
||||
Controls which operations the harness agent can perform without prompting.
|
||||
|
||||
| Value | Behavior |
|
||||
| --------------- | --------------------------------------------------------- |
|
||||
| `approve-all` | Auto-approve all file writes and shell commands. |
|
||||
| `approve-reads` | Auto-approve reads only; writes and exec require prompts. |
|
||||
| `deny-all` | Deny all permission prompts. |
|
||||
|
||||
### `nonInteractivePermissions`
|
||||
|
||||
Controls what happens when a permission prompt would be shown but no interactive TTY is available (which is always the case for ACP sessions).
|
||||
|
||||
| Value | Behavior |
|
||||
| ------ | ----------------------------------------------------------------- |
|
||||
| `fail` | Abort the session with `AcpRuntimeError`. **(default)** |
|
||||
| `deny` | Silently deny the permission and continue (graceful degradation). |
|
||||
|
||||
### Configuration
|
||||
|
||||
Set via plugin config:
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.acpx.config.permissionMode approve-all
|
||||
openclaw config set plugins.entries.acpx.config.nonInteractivePermissions fail
|
||||
```
|
||||
|
||||
Restart the gateway after changing these values.
|
||||
|
||||
> **Important:** OpenClaw currently defaults to `permissionMode=approve-reads` and `nonInteractivePermissions=fail`. In non-interactive ACP sessions, any write or exec that triggers a permission prompt can fail with `AcpRuntimeError: Permission prompt unavailable in non-interactive mode`.
|
||||
>
|
||||
> If you need to restrict permissions, set `nonInteractivePermissions` to `deny` so sessions degrade gracefully instead of crashing.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Likely cause | Fix |
|
||||
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `ACP runtime backend is not configured` | Backend plugin missing or disabled. | Install and enable backend plugin, then run `/acp doctor`. |
|
||||
| `ACP is disabled by policy (acp.enabled=false)` | ACP globally disabled. | Set `acp.enabled=true`. |
|
||||
| `ACP dispatch is disabled by policy (acp.dispatch.enabled=false)` | Dispatch from normal thread messages disabled. | Set `acp.dispatch.enabled=true`. |
|
||||
| `ACP agent "<id>" is not allowed by policy` | Agent not in allowlist. | Use allowed `agentId` or update `acp.allowedAgents`. |
|
||||
| `Unable to resolve session target: ...` | Bad key/id/label token. | Run `/acp sessions`, copy exact key/label, retry. |
|
||||
| `--bind here requires running /acp spawn inside an active ... conversation` | `--bind here` used without an active bindable conversation. | Move to the target chat/channel and retry, or use unbound spawn. |
|
||||
| `Conversation bindings are unavailable for <channel>.` | Adapter lacks current-conversation ACP binding capability. | Use `/acp spawn ... --thread ...` where supported, configure top-level `bindings[]`, or move to a supported channel. |
|
||||
| `--thread here requires running /acp spawn inside an active ... thread` | `--thread here` used outside a thread context. | Move to target thread or use `--thread auto`/`off`. |
|
||||
| `Only <user-id> can rebind this channel/conversation/thread.` | Another user owns the active binding target. | Rebind as owner or use a different conversation or thread. |
|
||||
| `Thread bindings are unavailable for <channel>.` | Adapter lacks thread binding capability. | Use `--thread off` or move to supported adapter/channel. |
|
||||
| `Sandboxed sessions cannot spawn ACP sessions ...` | ACP runtime is host-side; requester session is sandboxed. | Use `runtime="subagent"` from sandboxed sessions, or run ACP spawn from a non-sandboxed session. |
|
||||
| `sessions_spawn sandbox="require" is unsupported for runtime="acp" ...` | `sandbox="require"` requested for ACP runtime. | Use `runtime="subagent"` for required sandboxing, or use ACP with `sandbox="inherit"` from a non-sandboxed session. |
|
||||
| Missing ACP metadata for bound session | Stale/deleted ACP session metadata. | Recreate with `/acp spawn`, then rebind/focus thread. |
|
||||
| `AcpRuntimeError: Permission prompt unavailable in non-interactive mode` | `permissionMode` blocks writes/exec in non-interactive ACP session. | Set `plugins.entries.acpx.config.permissionMode` to `approve-all` and restart gateway. See [Permission configuration](#permission-configuration). |
|
||||
| ACP session fails early with little output | Permission prompts are blocked by `permissionMode`/`nonInteractivePermissions`. | Check gateway logs for `AcpRuntimeError`. For full permissions, set `permissionMode=approve-all`; for graceful degradation, set `nonInteractivePermissions=deny`. |
|
||||
| ACP session stalls indefinitely after completing work | Harness process finished but ACP session did not report completion. | Monitor with `ps aux \| grep acpx`; kill stale processes manually. |
|
||||
100
openclaw/docs/tools/agent-send.md
Normal file
100
openclaw/docs/tools/agent-send.md
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
summary: "Run agent turns from the CLI and optionally deliver replies to channels"
|
||||
read_when:
|
||||
- You want to trigger agent runs from scripts or the command line
|
||||
- You need to deliver agent replies to a chat channel programmatically
|
||||
title: "Agent Send"
|
||||
---
|
||||
|
||||
# Agent Send
|
||||
|
||||
`openclaw agent` runs a single agent turn from the command line without needing
|
||||
an inbound chat message. Use it for scripted workflows, testing, and
|
||||
programmatic delivery.
|
||||
|
||||
## Quick start
|
||||
|
||||
<Steps>
|
||||
<Step title="Run a simple agent turn">
|
||||
```bash
|
||||
openclaw agent --message "What is the weather today?"
|
||||
```
|
||||
|
||||
This sends the message through the Gateway and prints the reply.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Target a specific agent or session">
|
||||
```bash
|
||||
# Target a specific agent
|
||||
openclaw agent --agent ops --message "Summarize logs"
|
||||
|
||||
# Target a phone number (derives session key)
|
||||
openclaw agent --to +15555550123 --message "Status update"
|
||||
|
||||
# Reuse an existing session
|
||||
openclaw agent --session-id abc123 --message "Continue the task"
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Deliver the reply to a channel">
|
||||
```bash
|
||||
# Deliver to WhatsApp (default channel)
|
||||
openclaw agent --to +15555550123 --message "Report ready" --deliver
|
||||
|
||||
# Deliver to Slack
|
||||
openclaw agent --agent ops --message "Generate report" \
|
||||
--deliver --reply-channel slack --reply-to "#reports"
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Flags
|
||||
|
||||
| Flag | Description |
|
||||
| ----------------------------- | ----------------------------------------------------------- |
|
||||
| `--message \<text\>` | Message to send (required) |
|
||||
| `--to \<dest\>` | Derive session key from a target (phone, chat id) |
|
||||
| `--agent \<id\>` | Target a configured agent (uses its `main` session) |
|
||||
| `--session-id \<id\>` | Reuse an existing session by id |
|
||||
| `--local` | Force local embedded runtime (skip Gateway) |
|
||||
| `--deliver` | Send the reply to a chat channel |
|
||||
| `--channel \<name\>` | Delivery channel (whatsapp, telegram, discord, slack, etc.) |
|
||||
| `--reply-to \<target\>` | Delivery target override |
|
||||
| `--reply-channel \<name\>` | Delivery channel override |
|
||||
| `--reply-account \<id\>` | Delivery account id override |
|
||||
| `--thinking \<level\>` | Set thinking level (off, minimal, low, medium, high, xhigh) |
|
||||
| `--verbose \<on\|full\|off\>` | Set verbose level |
|
||||
| `--timeout \<seconds\>` | Override agent timeout |
|
||||
| `--json` | Output structured JSON |
|
||||
|
||||
## Behavior
|
||||
|
||||
- By default, the CLI goes **through the Gateway**. Add `--local` to force the
|
||||
embedded runtime on the current machine.
|
||||
- If the Gateway is unreachable, the CLI **falls back** to the local embedded run.
|
||||
- Session selection: `--to` derives the session key (group/channel targets
|
||||
preserve isolation; direct chats collapse to `main`).
|
||||
- Thinking and verbose flags persist into the session store.
|
||||
- Output: plain text by default, or `--json` for structured payload + metadata.
|
||||
|
||||
## Examples
|
||||
|
||||
```bash
|
||||
# Simple turn with JSON output
|
||||
openclaw agent --to +15555550123 --message "Trace logs" --verbose on --json
|
||||
|
||||
# Turn with thinking level
|
||||
openclaw agent --session-id 1234 --message "Summarize inbox" --thinking medium
|
||||
|
||||
# Deliver to a different channel than the session
|
||||
openclaw agent --agent ops --message "Alert" --deliver --reply-channel telegram --reply-to "@admin"
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Agent CLI reference](/cli/agent)
|
||||
- [Sub-agents](/tools/subagents) — background sub-agent spawning
|
||||
- [Sessions](/concepts/session) — how session keys work
|
||||
52
openclaw/docs/tools/apply-patch.md
Normal file
52
openclaw/docs/tools/apply-patch.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
summary: "Apply multi-file patches with the apply_patch tool"
|
||||
read_when:
|
||||
- You need structured file edits across multiple files
|
||||
- You want to document or debug patch-based edits
|
||||
title: "apply_patch Tool"
|
||||
---
|
||||
|
||||
# apply_patch tool
|
||||
|
||||
Apply file changes using a structured patch format. This is ideal for multi-file
|
||||
or multi-hunk edits where a single `edit` call would be brittle.
|
||||
|
||||
The tool accepts a single `input` string that wraps one or more file operations:
|
||||
|
||||
```
|
||||
*** Begin Patch
|
||||
*** Add File: path/to/file.txt
|
||||
+line 1
|
||||
+line 2
|
||||
*** Update File: src/app.ts
|
||||
@@
|
||||
-old line
|
||||
+new line
|
||||
*** Delete File: obsolete.txt
|
||||
*** End Patch
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
- `input` (required): Full patch contents including `*** Begin Patch` and `*** End Patch`.
|
||||
|
||||
## Notes
|
||||
|
||||
- Patch paths support relative paths (from the workspace directory) and absolute paths.
|
||||
- `tools.exec.applyPatch.workspaceOnly` defaults to `true` (workspace-contained). Set it to `false` only if you intentionally want `apply_patch` to write/delete outside the workspace directory.
|
||||
- Use `*** Move to:` within an `*** Update File:` hunk to rename files.
|
||||
- `*** End of File` marks an EOF-only insert when needed.
|
||||
- Available by default for OpenAI and OpenAI Codex models. Set
|
||||
`tools.exec.applyPatch.enabled: false` to disable it.
|
||||
- Optionally gate by model via
|
||||
`tools.exec.applyPatch.allowModels`.
|
||||
- Config is only under `tools.exec`.
|
||||
|
||||
## Example
|
||||
|
||||
```json
|
||||
{
|
||||
"tool": "apply_patch",
|
||||
"input": "*** Begin Patch\n*** Update File: src/index.ts\n@@\n-const foo = 1\n+const foo = 2\n*** End Patch"
|
||||
}
|
||||
```
|
||||
107
openclaw/docs/tools/brave-search.md
Normal file
107
openclaw/docs/tools/brave-search.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
---
|
||||
summary: "Brave Search API setup for web_search"
|
||||
read_when:
|
||||
- You want to use Brave Search for web_search
|
||||
- You need a BRAVE_API_KEY or plan details
|
||||
title: "Brave Search"
|
||||
---
|
||||
|
||||
# Brave Search API
|
||||
|
||||
OpenClaw supports Brave Search API as a `web_search` provider.
|
||||
|
||||
## Get an API key
|
||||
|
||||
1. Create a Brave Search API account at [https://brave.com/search/api/](https://brave.com/search/api/)
|
||||
2. In the dashboard, choose the **Search** plan and generate an API key.
|
||||
3. Store the key in config or set `BRAVE_API_KEY` in the Gateway environment.
|
||||
|
||||
## Config example
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
brave: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "BRAVE_API_KEY_HERE",
|
||||
mode: "web", // or "llm-context"
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "brave",
|
||||
maxResults: 5,
|
||||
timeoutSeconds: 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Provider-specific Brave search settings now live under `plugins.entries.brave.config.webSearch.*`.
|
||||
Legacy `tools.web.search.apiKey` still loads through the compatibility shim, but it is no longer the canonical config path.
|
||||
|
||||
`webSearch.mode` controls the Brave transport:
|
||||
|
||||
- `web` (default): normal Brave web search with titles, URLs, and snippets
|
||||
- `llm-context`: Brave LLM Context API with pre-extracted text chunks and sources for grounding
|
||||
|
||||
## Tool parameters
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ------------------------------------------------------------------- |
|
||||
| `query` | Search query (required) |
|
||||
| `count` | Number of results to return (1-10, default: 5) |
|
||||
| `country` | 2-letter ISO country code (e.g., "US", "DE") |
|
||||
| `language` | ISO 639-1 language code for search results (e.g., "en", "de", "fr") |
|
||||
| `search_lang` | Brave search-language code (e.g., `en`, `en-gb`, `zh-hans`) |
|
||||
| `ui_lang` | ISO language code for UI elements |
|
||||
| `freshness` | Time filter: `day` (24h), `week`, `month`, or `year` |
|
||||
| `date_after` | Only results published after this date (YYYY-MM-DD) |
|
||||
| `date_before` | Only results published before this date (YYYY-MM-DD) |
|
||||
|
||||
**Examples:**
|
||||
|
||||
```javascript
|
||||
// Country and language-specific search
|
||||
await web_search({
|
||||
query: "renewable energy",
|
||||
country: "DE",
|
||||
language: "de",
|
||||
});
|
||||
|
||||
// Recent results (past week)
|
||||
await web_search({
|
||||
query: "AI news",
|
||||
freshness: "week",
|
||||
});
|
||||
|
||||
// Date range search
|
||||
await web_search({
|
||||
query: "AI developments",
|
||||
date_after: "2024-01-01",
|
||||
date_before: "2024-06-30",
|
||||
});
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- OpenClaw uses the Brave **Search** plan. If you have a legacy subscription (e.g. the original Free plan with 2,000 queries/month), it remains valid but does not include newer features like LLM Context or higher rate limits.
|
||||
- Each Brave plan includes **\$5/month in free credit** (renewing). The Search plan costs \$5 per 1,000 requests, so the credit covers 1,000 queries/month. Set your usage limit in the Brave dashboard to avoid unexpected charges. See the [Brave API portal](https://brave.com/search/api/) for current plans.
|
||||
- The Search plan includes the LLM Context endpoint and AI inference rights. Storing results to train or tune models requires a plan with explicit storage rights. See the Brave [Terms of Service](https://api-dashboard.search.brave.com/terms-of-service).
|
||||
- `llm-context` mode returns grounded source entries instead of the normal web-search snippet shape.
|
||||
- `llm-context` mode does not support `ui_lang`, `freshness`, `date_after`, or `date_before`.
|
||||
- `ui_lang` must include a region subtag like `en-US`.
|
||||
- Results are cached for 15 minutes by default (configurable via `cacheTtlMinutes`).
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Perplexity Search](/tools/perplexity-search) -- structured results with domain filtering
|
||||
- [Exa Search](/tools/exa-search) -- neural search with content extraction
|
||||
145
openclaw/docs/tools/browser-linux-troubleshooting.md
Normal file
145
openclaw/docs/tools/browser-linux-troubleshooting.md
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
summary: "Fix Chrome/Brave/Edge/Chromium CDP startup issues for OpenClaw browser control on Linux"
|
||||
read_when: "Browser control fails on Linux, especially with snap Chromium"
|
||||
title: "Browser Troubleshooting"
|
||||
---
|
||||
|
||||
# Browser Troubleshooting (Linux)
|
||||
|
||||
## Problem: "Failed to start Chrome CDP on port 18800"
|
||||
|
||||
OpenClaw's browser control server fails to launch Chrome/Brave/Edge/Chromium with the error:
|
||||
|
||||
```
|
||||
{"error":"Error: Failed to start Chrome CDP on port 18800 for profile \"openclaw\"."}
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
|
||||
On Ubuntu (and many Linux distros), the default Chromium installation is a **snap package**. Snap's AppArmor confinement interferes with how OpenClaw spawns and monitors the browser process.
|
||||
|
||||
The `apt install chromium` command installs a stub package that redirects to snap:
|
||||
|
||||
```
|
||||
Note, selecting 'chromium-browser' instead of 'chromium'
|
||||
chromium-browser is already the newest version (2:1snap1-0ubuntu2).
|
||||
```
|
||||
|
||||
This is NOT a real browser - it's just a wrapper.
|
||||
|
||||
### Solution 1: Install Google Chrome (Recommended)
|
||||
|
||||
Install the official Google Chrome `.deb` package, which is not sandboxed by snap:
|
||||
|
||||
```bash
|
||||
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
sudo dpkg -i google-chrome-stable_current_amd64.deb
|
||||
sudo apt --fix-broken install -y # if there are dependency errors
|
||||
```
|
||||
|
||||
Then update your OpenClaw config (`~/.openclaw/openclaw.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"browser": {
|
||||
"enabled": true,
|
||||
"executablePath": "/usr/bin/google-chrome-stable",
|
||||
"headless": true,
|
||||
"noSandbox": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Solution 2: Use Snap Chromium with Attach-Only Mode
|
||||
|
||||
If you must use snap Chromium, configure OpenClaw to attach to a manually-started browser:
|
||||
|
||||
1. Update config:
|
||||
|
||||
```json
|
||||
{
|
||||
"browser": {
|
||||
"enabled": true,
|
||||
"attachOnly": true,
|
||||
"headless": true,
|
||||
"noSandbox": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Start Chromium manually:
|
||||
|
||||
```bash
|
||||
chromium-browser --headless --no-sandbox --disable-gpu \
|
||||
--remote-debugging-port=18800 \
|
||||
--user-data-dir=$HOME/.openclaw/browser/openclaw/user-data \
|
||||
about:blank &
|
||||
```
|
||||
|
||||
3. Optionally create a systemd user service to auto-start Chrome:
|
||||
|
||||
```ini
|
||||
# ~/.config/systemd/user/openclaw-browser.service
|
||||
[Unit]
|
||||
Description=OpenClaw Browser (Chrome CDP)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/snap/bin/chromium --headless --no-sandbox --disable-gpu --remote-debugging-port=18800 --user-data-dir=%h/.openclaw/browser/openclaw/user-data about:blank
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
Enable with: `systemctl --user enable --now openclaw-browser.service`
|
||||
|
||||
### Verifying the Browser Works
|
||||
|
||||
Check status:
|
||||
|
||||
```bash
|
||||
curl -s http://127.0.0.1:18791/ | jq '{running, pid, chosenBrowser}'
|
||||
```
|
||||
|
||||
Test browsing:
|
||||
|
||||
```bash
|
||||
curl -s -X POST http://127.0.0.1:18791/start
|
||||
curl -s http://127.0.0.1:18791/tabs
|
||||
```
|
||||
|
||||
### Config Reference
|
||||
|
||||
| Option | Description | Default |
|
||||
| ------------------------ | -------------------------------------------------------------------- | ----------------------------------------------------------- |
|
||||
| `browser.enabled` | Enable browser control | `true` |
|
||||
| `browser.executablePath` | Path to a Chromium-based browser binary (Chrome/Brave/Edge/Chromium) | auto-detected (prefers default browser when Chromium-based) |
|
||||
| `browser.headless` | Run without GUI | `false` |
|
||||
| `browser.noSandbox` | Add `--no-sandbox` flag (needed for some Linux setups) | `false` |
|
||||
| `browser.attachOnly` | Don't launch browser, only attach to existing | `false` |
|
||||
| `browser.cdpPort` | Chrome DevTools Protocol port | `18800` |
|
||||
|
||||
### Problem: "No Chrome tabs found for profile=\"user\""
|
||||
|
||||
You're using an `existing-session` / Chrome MCP profile. OpenClaw can see local Chrome,
|
||||
but there are no open tabs available to attach to.
|
||||
|
||||
Fix options:
|
||||
|
||||
1. **Use the managed browser:** `openclaw browser start --browser-profile openclaw`
|
||||
(or set `browser.defaultProfile: "openclaw"`).
|
||||
2. **Use Chrome MCP:** make sure local Chrome is running with at least one open tab, then retry with `--browser-profile user`.
|
||||
|
||||
Notes:
|
||||
|
||||
- `user` is host-only. For Linux servers, containers, or remote hosts, prefer CDP profiles.
|
||||
- `user` / other `existing-session` profiles keep the current Chrome MCP limits:
|
||||
ref-driven actions, one-file upload hooks, no dialog timeout overrides, no
|
||||
`wait --load networkidle`, and no `responsebody`, PDF export, download
|
||||
interception, or batch actions.
|
||||
- Local `openclaw` profiles auto-assign `cdpPort`/`cdpUrl`; only set those for remote CDP.
|
||||
- Remote CDP profiles accept `http://`, `https://`, `ws://`, and `wss://`.
|
||||
Use HTTP(S) for `/json/version` discovery, or WS(S) when your browser
|
||||
service gives you a direct DevTools socket URL.
|
||||
73
openclaw/docs/tools/browser-login.md
Normal file
73
openclaw/docs/tools/browser-login.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
summary: "Manual logins for browser automation + X/Twitter posting"
|
||||
read_when:
|
||||
- You need to log into sites for browser automation
|
||||
- You want to post updates to X/Twitter
|
||||
title: "Browser Login"
|
||||
---
|
||||
|
||||
# Browser login + X/Twitter posting
|
||||
|
||||
## Manual login (recommended)
|
||||
|
||||
When a site requires login, **sign in manually** in the **host** browser profile (the openclaw browser).
|
||||
|
||||
Do **not** give the model your credentials. Automated logins often trigger anti‑bot defenses and can lock the account.
|
||||
|
||||
Back to the main browser docs: [Browser](/tools/browser).
|
||||
|
||||
## Which Chrome profile is used?
|
||||
|
||||
OpenClaw controls a **dedicated Chrome profile** (named `openclaw`, orange‑tinted UI). This is separate from your daily browser profile.
|
||||
|
||||
For agent browser tool calls:
|
||||
|
||||
- Default choice: the agent should use its isolated `openclaw` browser.
|
||||
- Use `profile="user"` only when existing logged-in sessions matter and the user is at the computer to click/approve any attach prompt.
|
||||
- If you have multiple user-browser profiles, specify the profile explicitly instead of guessing.
|
||||
|
||||
Two easy ways to access it:
|
||||
|
||||
1. **Ask the agent to open the browser** and then log in yourself.
|
||||
2. **Open it via CLI**:
|
||||
|
||||
```bash
|
||||
openclaw browser start
|
||||
openclaw browser open https://x.com
|
||||
```
|
||||
|
||||
If you have multiple profiles, pass `--browser-profile <name>` (the default is `openclaw`).
|
||||
|
||||
## X/Twitter: recommended flow
|
||||
|
||||
- **Read/search/threads:** use the **host** browser (manual login).
|
||||
- **Post updates:** use the **host** browser (manual login).
|
||||
|
||||
## Sandboxing + host browser access
|
||||
|
||||
Sandboxed browser sessions are **more likely** to trigger bot detection. For X/Twitter (and other strict sites), prefer the **host** browser.
|
||||
|
||||
If the agent is sandboxed, the browser tool defaults to the sandbox. To allow host control:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
sandbox: {
|
||||
mode: "non-main",
|
||||
browser: {
|
||||
allowHostControl: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then target the host browser:
|
||||
|
||||
```bash
|
||||
openclaw browser open https://x.com --browser-profile openclaw --target host
|
||||
```
|
||||
|
||||
Or disable sandboxing for the agent that posts updates.
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
---
|
||||
summary: "Troubleshoot WSL2 Gateway + Windows Chrome remote CDP in layers"
|
||||
read_when:
|
||||
- Running OpenClaw Gateway in WSL2 while Chrome lives on Windows
|
||||
- Seeing overlapping browser/control-ui errors across WSL2 and Windows
|
||||
- Deciding between host-local Chrome MCP and raw remote CDP in split-host setups
|
||||
title: "WSL2 + Windows + remote Chrome CDP troubleshooting"
|
||||
---
|
||||
|
||||
# WSL2 + Windows + remote Chrome CDP troubleshooting
|
||||
|
||||
This guide covers the common split-host setup where:
|
||||
|
||||
- OpenClaw Gateway runs inside WSL2
|
||||
- Chrome runs on Windows
|
||||
- browser control must cross the WSL2/Windows boundary
|
||||
|
||||
It also covers the layered failure pattern from [issue #39369](https://github.com/openclaw/openclaw/issues/39369): several independent problems can show up at once, which makes the wrong layer look broken first.
|
||||
|
||||
## Choose the right browser mode first
|
||||
|
||||
You have two valid patterns:
|
||||
|
||||
### Option 1: Raw remote CDP from WSL2 to Windows
|
||||
|
||||
Use a remote browser profile that points from WSL2 to a Windows Chrome CDP endpoint.
|
||||
|
||||
Choose this when:
|
||||
|
||||
- the Gateway stays inside WSL2
|
||||
- Chrome runs on Windows
|
||||
- you need browser control to cross the WSL2/Windows boundary
|
||||
|
||||
### Option 2: Host-local Chrome MCP
|
||||
|
||||
Use `existing-session` / `user` only when the Gateway itself runs on the same host as Chrome.
|
||||
|
||||
Choose this when:
|
||||
|
||||
- OpenClaw and Chrome are on the same machine
|
||||
- you want the local signed-in browser state
|
||||
- you do not need cross-host browser transport
|
||||
- you do not need advanced managed/raw-CDP-only routes like `responsebody`, PDF
|
||||
export, download interception, or batch actions
|
||||
|
||||
For WSL2 Gateway + Windows Chrome, prefer raw remote CDP. Chrome MCP is host-local, not a WSL2-to-Windows bridge.
|
||||
|
||||
## Working architecture
|
||||
|
||||
Reference shape:
|
||||
|
||||
- WSL2 runs the Gateway on `127.0.0.1:18789`
|
||||
- Windows opens the Control UI in a normal browser at `http://127.0.0.1:18789/`
|
||||
- Windows Chrome exposes a CDP endpoint on port `9222`
|
||||
- WSL2 can reach that Windows CDP endpoint
|
||||
- OpenClaw points a browser profile at the address that is reachable from WSL2
|
||||
|
||||
## Why this setup is confusing
|
||||
|
||||
Several failures can overlap:
|
||||
|
||||
- WSL2 cannot reach the Windows CDP endpoint
|
||||
- the Control UI is opened from a non-secure origin
|
||||
- `gateway.controlUi.allowedOrigins` does not match the page origin
|
||||
- token or pairing is missing
|
||||
- the browser profile points at the wrong address
|
||||
|
||||
Because of that, fixing one layer can still leave a different error visible.
|
||||
|
||||
## Critical rule for the Control UI
|
||||
|
||||
When the UI is opened from Windows, use Windows localhost unless you have a deliberate HTTPS setup.
|
||||
|
||||
Use:
|
||||
|
||||
`http://127.0.0.1:18789/`
|
||||
|
||||
Do not default to a LAN IP for the Control UI. Plain HTTP on a LAN or tailnet address can trigger insecure-origin/device-auth behavior that is unrelated to CDP itself. See [Control UI](/web/control-ui).
|
||||
|
||||
## Validate in layers
|
||||
|
||||
Work top to bottom. Do not skip ahead.
|
||||
|
||||
### Layer 1: Verify Chrome is serving CDP on Windows
|
||||
|
||||
Start Chrome on Windows with remote debugging enabled:
|
||||
|
||||
```powershell
|
||||
chrome.exe --remote-debugging-port=9222
|
||||
```
|
||||
|
||||
From Windows, verify Chrome itself first:
|
||||
|
||||
```powershell
|
||||
curl http://127.0.0.1:9222/json/version
|
||||
curl http://127.0.0.1:9222/json/list
|
||||
```
|
||||
|
||||
If this fails on Windows, OpenClaw is not the problem yet.
|
||||
|
||||
### Layer 2: Verify WSL2 can reach that Windows endpoint
|
||||
|
||||
From WSL2, test the exact address you plan to use in `cdpUrl`:
|
||||
|
||||
```bash
|
||||
curl http://WINDOWS_HOST_OR_IP:9222/json/version
|
||||
curl http://WINDOWS_HOST_OR_IP:9222/json/list
|
||||
```
|
||||
|
||||
Good result:
|
||||
|
||||
- `/json/version` returns JSON with Browser / Protocol-Version metadata
|
||||
- `/json/list` returns JSON (empty array is fine if no pages are open)
|
||||
|
||||
If this fails:
|
||||
|
||||
- Windows is not exposing the port to WSL2 yet
|
||||
- the address is wrong for the WSL2 side
|
||||
- firewall / port forwarding / local proxying is still missing
|
||||
|
||||
Fix that before touching OpenClaw config.
|
||||
|
||||
### Layer 3: Configure the correct browser profile
|
||||
|
||||
For raw remote CDP, point OpenClaw at the address that is reachable from WSL2:
|
||||
|
||||
```json5
|
||||
{
|
||||
browser: {
|
||||
enabled: true,
|
||||
defaultProfile: "remote",
|
||||
profiles: {
|
||||
remote: {
|
||||
cdpUrl: "http://WINDOWS_HOST_OR_IP:9222",
|
||||
attachOnly: true,
|
||||
color: "#00AA00",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- use the WSL2-reachable address, not whatever only works on Windows
|
||||
- keep `attachOnly: true` for externally managed browsers
|
||||
- `cdpUrl` can be `http://`, `https://`, `ws://`, or `wss://`
|
||||
- use HTTP(S) when you want OpenClaw to discover `/json/version`
|
||||
- use WS(S) only when the browser provider gives you a direct DevTools socket URL
|
||||
- test the same URL with `curl` before expecting OpenClaw to succeed
|
||||
|
||||
### Layer 4: Verify the Control UI layer separately
|
||||
|
||||
Open the UI from Windows:
|
||||
|
||||
`http://127.0.0.1:18789/`
|
||||
|
||||
Then verify:
|
||||
|
||||
- the page origin matches what `gateway.controlUi.allowedOrigins` expects
|
||||
- token auth or pairing is configured correctly
|
||||
- you are not debugging a Control UI auth problem as if it were a browser problem
|
||||
|
||||
Helpful page:
|
||||
|
||||
- [Control UI](/web/control-ui)
|
||||
|
||||
### Layer 5: Verify end-to-end browser control
|
||||
|
||||
From WSL2:
|
||||
|
||||
```bash
|
||||
openclaw browser open https://example.com --browser-profile remote
|
||||
openclaw browser tabs --browser-profile remote
|
||||
```
|
||||
|
||||
Good result:
|
||||
|
||||
- the tab opens in Windows Chrome
|
||||
- `openclaw browser tabs` returns the target
|
||||
- later actions (`snapshot`, `screenshot`, `navigate`) work from the same profile
|
||||
|
||||
## Common misleading errors
|
||||
|
||||
Treat each message as a layer-specific clue:
|
||||
|
||||
- `control-ui-insecure-auth`
|
||||
- UI origin / secure-context problem, not a CDP transport problem
|
||||
- `token_missing`
|
||||
- auth configuration problem
|
||||
- `pairing required`
|
||||
- device approval problem
|
||||
- `Remote CDP for profile "remote" is not reachable`
|
||||
- WSL2 cannot reach the configured `cdpUrl`
|
||||
- `Browser attachOnly is enabled and CDP websocket for profile "remote" is not reachable`
|
||||
- the HTTP endpoint answered, but the DevTools WebSocket still could not be opened
|
||||
- stale viewport / dark-mode / locale / offline overrides after a remote session
|
||||
- run `openclaw browser stop --browser-profile remote`
|
||||
- this closes the active control session and releases Playwright/CDP emulation state without restarting the gateway or the external browser
|
||||
- `gateway timeout after 1500ms`
|
||||
- often still CDP reachability or a slow/unreachable remote endpoint
|
||||
- `No Chrome tabs found for profile="user"`
|
||||
- local Chrome MCP profile selected where no host-local tabs are available
|
||||
|
||||
## Fast triage checklist
|
||||
|
||||
1. Windows: does `curl http://127.0.0.1:9222/json/version` work?
|
||||
2. WSL2: does `curl http://WINDOWS_HOST_OR_IP:9222/json/version` work?
|
||||
3. OpenClaw config: does `browser.profiles.<name>.cdpUrl` use that exact WSL2-reachable address?
|
||||
4. Control UI: are you opening `http://127.0.0.1:18789/` instead of a LAN IP?
|
||||
5. Are you trying to use `existing-session` across WSL2 and Windows instead of raw remote CDP?
|
||||
|
||||
## Practical takeaway
|
||||
|
||||
The setup is usually viable. The hard part is that browser transport, Control UI origin security, and token/pairing can each fail independently while looking similar from the user side.
|
||||
|
||||
When in doubt:
|
||||
|
||||
- verify the Windows Chrome endpoint locally first
|
||||
- verify the same endpoint from WSL2 second
|
||||
- only then debug OpenClaw config or Control UI auth
|
||||
983
openclaw/docs/tools/browser.md
Normal file
983
openclaw/docs/tools/browser.md
Normal file
|
|
@ -0,0 +1,983 @@
|
|||
---
|
||||
summary: "Integrated browser control service + action commands"
|
||||
read_when:
|
||||
- Adding agent-controlled browser automation
|
||||
- Debugging why openclaw is interfering with your own Chrome
|
||||
- Implementing browser settings + lifecycle in the macOS app
|
||||
title: "Browser (OpenClaw-managed)"
|
||||
---
|
||||
|
||||
# Browser (openclaw-managed)
|
||||
|
||||
OpenClaw can run a **dedicated Chrome/Brave/Edge/Chromium profile** that the agent controls.
|
||||
It is isolated from your personal browser and is managed through a small local
|
||||
control service inside the Gateway (loopback only).
|
||||
|
||||
Beginner view:
|
||||
|
||||
- Think of it as a **separate, agent-only browser**.
|
||||
- The `openclaw` profile does **not** touch your personal browser profile.
|
||||
- The agent can **open tabs, read pages, click, and type** in a safe lane.
|
||||
- The built-in `user` profile attaches to your real signed-in Chrome session via Chrome MCP.
|
||||
|
||||
## What you get
|
||||
|
||||
- A separate browser profile named **openclaw** (orange accent by default).
|
||||
- Deterministic tab control (list/open/focus/close).
|
||||
- Agent actions (click/type/drag/select), snapshots, screenshots, PDFs.
|
||||
- Optional multi-profile support (`openclaw`, `work`, `remote`, ...).
|
||||
|
||||
This browser is **not** your daily driver. It is a safe, isolated surface for
|
||||
agent automation and verification.
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
openclaw browser --browser-profile openclaw status
|
||||
openclaw browser --browser-profile openclaw start
|
||||
openclaw browser --browser-profile openclaw open https://example.com
|
||||
openclaw browser --browser-profile openclaw snapshot
|
||||
```
|
||||
|
||||
If you get “Browser disabled”, enable it in config (see below) and restart the
|
||||
Gateway.
|
||||
|
||||
If `openclaw browser` is missing entirely, or the agent says the browser tool
|
||||
is unavailable, jump to [Missing browser command or tool](/tools/browser#missing-browser-command-or-tool).
|
||||
|
||||
## Plugin control
|
||||
|
||||
The default `browser` tool is now a bundled plugin that ships enabled by
|
||||
default. That means you can disable or replace it without removing the rest of
|
||||
OpenClaw's plugin system:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
browser: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Disable the bundled plugin before installing another plugin that provides the
|
||||
same `browser` tool name. The default browser experience needs both:
|
||||
|
||||
- `plugins.entries.browser.enabled` not disabled
|
||||
- `browser.enabled=true`
|
||||
|
||||
If you turn off only the plugin, the bundled browser CLI (`openclaw browser`),
|
||||
gateway method (`browser.request`), agent tool, and default browser control
|
||||
service all disappear together. Your `browser.*` config stays intact for a
|
||||
replacement plugin to reuse.
|
||||
|
||||
The bundled browser plugin also owns the browser runtime implementation now.
|
||||
Core keeps only shared Plugin SDK helpers plus compatibility re-exports for
|
||||
older internal import paths. In practice, removing or replacing the browser
|
||||
plugin package removes the browser feature set instead of leaving a second
|
||||
core-owned runtime behind.
|
||||
|
||||
Browser config changes still require a Gateway restart so the bundled plugin
|
||||
can re-register its browser service with the new settings.
|
||||
|
||||
## Missing browser command or tool
|
||||
|
||||
If `openclaw browser` suddenly becomes an unknown command after an upgrade, or
|
||||
the agent reports that the browser tool is missing, the most common cause is a
|
||||
restrictive `plugins.allow` list that does not include `browser`.
|
||||
|
||||
Example broken config:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
allow: ["telegram"],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Fix it by adding `browser` to the plugin allowlist:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
allow: ["telegram", "browser"],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Important notes:
|
||||
|
||||
- `browser.enabled=true` is not enough by itself when `plugins.allow` is set.
|
||||
- `plugins.entries.browser.enabled=true` is also not enough by itself when `plugins.allow` is set.
|
||||
- `tools.alsoAllow: ["browser"]` does **not** load the bundled browser plugin. It only adjusts tool policy after the plugin is already loaded.
|
||||
- If you do not need a restrictive plugin allowlist, removing `plugins.allow` also restores the default bundled browser behavior.
|
||||
|
||||
Typical symptoms:
|
||||
|
||||
- `openclaw browser` is an unknown command.
|
||||
- `browser.request` is missing.
|
||||
- The agent reports the browser tool as unavailable or missing.
|
||||
|
||||
## Profiles: `openclaw` vs `user`
|
||||
|
||||
- `openclaw`: managed, isolated browser (no extension required).
|
||||
- `user`: built-in Chrome MCP attach profile for your **real signed-in Chrome**
|
||||
session.
|
||||
|
||||
For agent browser tool calls:
|
||||
|
||||
- Default: use the isolated `openclaw` browser.
|
||||
- Prefer `profile="user"` when existing logged-in sessions matter and the user
|
||||
is at the computer to click/approve any attach prompt.
|
||||
- `profile` is the explicit override when you want a specific browser mode.
|
||||
|
||||
Set `browser.defaultProfile: "openclaw"` if you want managed mode by default.
|
||||
|
||||
## Configuration
|
||||
|
||||
Browser settings live in `~/.openclaw/openclaw.json`.
|
||||
|
||||
```json5
|
||||
{
|
||||
browser: {
|
||||
enabled: true, // default: true
|
||||
ssrfPolicy: {
|
||||
// dangerouslyAllowPrivateNetwork: true, // opt in only for trusted private-network access
|
||||
// allowPrivateNetwork: true, // legacy alias
|
||||
// hostnameAllowlist: ["*.example.com", "example.com"],
|
||||
// allowedHostnames: ["localhost"],
|
||||
},
|
||||
// cdpUrl: "http://127.0.0.1:18792", // legacy single-profile override
|
||||
remoteCdpTimeoutMs: 1500, // remote CDP HTTP timeout (ms)
|
||||
remoteCdpHandshakeTimeoutMs: 3000, // remote CDP WebSocket handshake timeout (ms)
|
||||
defaultProfile: "openclaw",
|
||||
color: "#FF4500",
|
||||
headless: false,
|
||||
noSandbox: false,
|
||||
attachOnly: false,
|
||||
executablePath: "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
|
||||
profiles: {
|
||||
openclaw: { cdpPort: 18800, color: "#FF4500" },
|
||||
work: { cdpPort: 18801, color: "#0066CC" },
|
||||
user: {
|
||||
driver: "existing-session",
|
||||
attachOnly: true,
|
||||
color: "#00AA00",
|
||||
},
|
||||
brave: {
|
||||
driver: "existing-session",
|
||||
attachOnly: true,
|
||||
userDataDir: "~/Library/Application Support/BraveSoftware/Brave-Browser",
|
||||
color: "#FB542B",
|
||||
},
|
||||
remote: { cdpUrl: "http://10.0.0.42:9222", color: "#00AA00" },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- The browser control service binds to loopback on a port derived from `gateway.port`
|
||||
(default: `18791`, which is gateway + 2).
|
||||
- If you override the Gateway port (`gateway.port` or `OPENCLAW_GATEWAY_PORT`),
|
||||
the derived browser ports shift to stay in the same “family”.
|
||||
- `cdpUrl` defaults to the managed local CDP port when unset.
|
||||
- `remoteCdpTimeoutMs` applies to remote (non-loopback) CDP reachability checks.
|
||||
- `remoteCdpHandshakeTimeoutMs` applies to remote CDP WebSocket reachability checks.
|
||||
- Browser navigation/open-tab is SSRF-guarded before navigation and best-effort re-checked on final `http(s)` URL after navigation.
|
||||
- In strict SSRF mode, remote CDP endpoint discovery/probes (`cdpUrl`, including `/json/version` lookups) are checked too.
|
||||
- `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` is disabled by default. Set it to `true` only when you intentionally trust private-network browser access.
|
||||
- `browser.ssrfPolicy.allowPrivateNetwork` remains supported as a legacy alias for compatibility.
|
||||
- `attachOnly: true` means “never launch a local browser; only attach if it is already running.”
|
||||
- `color` + per-profile `color` tint the browser UI so you can see which profile is active.
|
||||
- Default profile is `openclaw` (OpenClaw-managed standalone browser). Use `defaultProfile: "user"` to opt into the signed-in user browser.
|
||||
- Auto-detect order: system default browser if Chromium-based; otherwise Chrome → Brave → Edge → Chromium → Chrome Canary.
|
||||
- Local `openclaw` profiles auto-assign `cdpPort`/`cdpUrl` — set those only for remote CDP.
|
||||
- `driver: "existing-session"` uses Chrome DevTools MCP instead of raw CDP. Do
|
||||
not set `cdpUrl` for that driver.
|
||||
- Set `browser.profiles.<name>.userDataDir` when an existing-session profile
|
||||
should attach to a non-default Chromium user profile such as Brave or Edge.
|
||||
|
||||
## Use Brave (or another Chromium-based browser)
|
||||
|
||||
If your **system default** browser is Chromium-based (Chrome/Brave/Edge/etc),
|
||||
OpenClaw uses it automatically. Set `browser.executablePath` to override
|
||||
auto-detection:
|
||||
|
||||
CLI example:
|
||||
|
||||
```bash
|
||||
openclaw config set browser.executablePath "/usr/bin/google-chrome"
|
||||
```
|
||||
|
||||
```json5
|
||||
// macOS
|
||||
{
|
||||
browser: {
|
||||
executablePath: "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
|
||||
}
|
||||
}
|
||||
|
||||
// Windows
|
||||
{
|
||||
browser: {
|
||||
executablePath: "C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"
|
||||
}
|
||||
}
|
||||
|
||||
// Linux
|
||||
{
|
||||
browser: {
|
||||
executablePath: "/usr/bin/brave-browser"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Local vs remote control
|
||||
|
||||
- **Local control (default):** the Gateway starts the loopback control service and can launch a local browser.
|
||||
- **Remote control (node host):** run a node host on the machine that has the browser; the Gateway proxies browser actions to it.
|
||||
- **Remote CDP:** set `browser.profiles.<name>.cdpUrl` (or `browser.cdpUrl`) to
|
||||
attach to a remote Chromium-based browser. In this case, OpenClaw will not launch a local browser.
|
||||
|
||||
Stopping behavior differs by profile mode:
|
||||
|
||||
- local managed profiles: `openclaw browser stop` stops the browser process that
|
||||
OpenClaw launched
|
||||
- attach-only and remote CDP profiles: `openclaw browser stop` closes the active
|
||||
control session and releases Playwright/CDP emulation overrides (viewport,
|
||||
color scheme, locale, timezone, offline mode, and similar state), even
|
||||
though no browser process was launched by OpenClaw
|
||||
|
||||
Remote CDP URLs can include auth:
|
||||
|
||||
- Query tokens (e.g., `https://provider.example?token=<token>`)
|
||||
- HTTP Basic auth (e.g., `https://user:pass@provider.example`)
|
||||
|
||||
OpenClaw preserves the auth when calling `/json/*` endpoints and when connecting
|
||||
to the CDP WebSocket. Prefer environment variables or secrets managers for
|
||||
tokens instead of committing them to config files.
|
||||
|
||||
## Node browser proxy (zero-config default)
|
||||
|
||||
If you run a **node host** on the machine that has your browser, OpenClaw can
|
||||
auto-route browser tool calls to that node without any extra browser config.
|
||||
This is the default path for remote gateways.
|
||||
|
||||
Notes:
|
||||
|
||||
- The node host exposes its local browser control server via a **proxy command**.
|
||||
- Profiles come from the node’s own `browser.profiles` config (same as local).
|
||||
- `nodeHost.browserProxy.allowProfiles` is optional. Leave it empty for the legacy/default behavior: all configured profiles remain reachable through the proxy, including profile create/delete routes.
|
||||
- If you set `nodeHost.browserProxy.allowProfiles`, OpenClaw treats it as a least-privilege boundary: only allowlisted profiles can be targeted, and persistent profile create/delete routes are blocked on the proxy surface.
|
||||
- Disable if you don’t want it:
|
||||
- On the node: `nodeHost.browserProxy.enabled=false`
|
||||
- On the gateway: `gateway.nodes.browser.mode="off"`
|
||||
|
||||
## Browserless (hosted remote CDP)
|
||||
|
||||
[Browserless](https://browserless.io) is a hosted Chromium service that exposes
|
||||
CDP connection URLs over HTTPS and WebSocket. OpenClaw can use either form, but
|
||||
for a remote browser profile the simplest option is the direct WebSocket URL
|
||||
from Browserless' connection docs.
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
browser: {
|
||||
enabled: true,
|
||||
defaultProfile: "browserless",
|
||||
remoteCdpTimeoutMs: 2000,
|
||||
remoteCdpHandshakeTimeoutMs: 4000,
|
||||
profiles: {
|
||||
browserless: {
|
||||
cdpUrl: "wss://production-sfo.browserless.io?token=<BROWSERLESS_API_KEY>",
|
||||
color: "#00AA00",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Replace `<BROWSERLESS_API_KEY>` with your real Browserless token.
|
||||
- Choose the region endpoint that matches your Browserless account (see their docs).
|
||||
- If Browserless gives you an HTTPS base URL, you can either convert it to
|
||||
`wss://` for a direct CDP connection or keep the HTTPS URL and let OpenClaw
|
||||
discover `/json/version`.
|
||||
|
||||
## Direct WebSocket CDP providers
|
||||
|
||||
Some hosted browser services expose a **direct WebSocket** endpoint rather than
|
||||
the standard HTTP-based CDP discovery (`/json/version`). OpenClaw accepts three
|
||||
CDP URL shapes and picks the right connection strategy automatically:
|
||||
|
||||
- **HTTP(S) discovery** — `http://host[:port]` or `https://host[:port]`.
|
||||
OpenClaw calls `/json/version` to discover the WebSocket debugger URL, then
|
||||
connects. No WebSocket fallback.
|
||||
- **Direct WebSocket endpoints** — `ws://host[:port]/devtools/<kind>/<id>` or
|
||||
`wss://...` with a `/devtools/browser|page|worker|shared_worker|service_worker/<id>`
|
||||
path. OpenClaw connects directly via a WebSocket handshake and skips
|
||||
`/json/version` entirely.
|
||||
- **Bare WebSocket roots** — `ws://host[:port]` or `wss://host[:port]` with no
|
||||
`/devtools/...` path (e.g. [Browserless](https://browserless.io),
|
||||
[Browserbase](https://www.browserbase.com)). OpenClaw tries HTTP
|
||||
`/json/version` discovery first (normalising the scheme to `http`/`https`);
|
||||
if discovery returns a `webSocketDebuggerUrl` it is used, otherwise OpenClaw
|
||||
falls back to a direct WebSocket handshake at the bare root. This covers
|
||||
both Chrome-style remote debug ports and WebSocket-only providers.
|
||||
|
||||
Plain `ws://host:port` / `wss://host:port` without a `/devtools/...` path
|
||||
pointed at a local Chrome instance is supported via the discovery-first
|
||||
fallback — Chrome only accepts WebSocket upgrades on the specific per-browser
|
||||
or per-target path returned by `/json/version`, so a bare-root handshake alone
|
||||
would fail.
|
||||
|
||||
### Browserbase
|
||||
|
||||
[Browserbase](https://www.browserbase.com) is a cloud platform for running
|
||||
headless browsers with built-in CAPTCHA solving, stealth mode, and residential
|
||||
proxies.
|
||||
|
||||
```json5
|
||||
{
|
||||
browser: {
|
||||
enabled: true,
|
||||
defaultProfile: "browserbase",
|
||||
remoteCdpTimeoutMs: 3000,
|
||||
remoteCdpHandshakeTimeoutMs: 5000,
|
||||
profiles: {
|
||||
browserbase: {
|
||||
cdpUrl: "wss://connect.browserbase.com?apiKey=<BROWSERBASE_API_KEY>",
|
||||
color: "#F97316",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- [Sign up](https://www.browserbase.com/sign-up) and copy your **API Key**
|
||||
from the [Overview dashboard](https://www.browserbase.com/overview).
|
||||
- Replace `<BROWSERBASE_API_KEY>` with your real Browserbase API key.
|
||||
- Browserbase auto-creates a browser session on WebSocket connect, so no
|
||||
manual session creation step is needed.
|
||||
- The free tier allows one concurrent session and one browser hour per month.
|
||||
See [pricing](https://www.browserbase.com/pricing) for paid plan limits.
|
||||
- See the [Browserbase docs](https://docs.browserbase.com) for full API
|
||||
reference, SDK guides, and integration examples.
|
||||
|
||||
## Security
|
||||
|
||||
Key ideas:
|
||||
|
||||
- Browser control is loopback-only; access flows through the Gateway’s auth or node pairing.
|
||||
- The standalone loopback browser HTTP API uses **shared-secret auth only**:
|
||||
gateway token bearer auth, `x-openclaw-password`, or HTTP Basic auth with the
|
||||
configured gateway password.
|
||||
- Tailscale Serve identity headers and `gateway.auth.mode: "trusted-proxy"` do
|
||||
**not** authenticate this standalone loopback browser API.
|
||||
- If browser control is enabled and no shared-secret auth is configured, OpenClaw
|
||||
auto-generates `gateway.auth.token` on startup and persists it to config.
|
||||
- OpenClaw does **not** auto-generate that token when `gateway.auth.mode` is
|
||||
already `password`, `none`, or `trusted-proxy`.
|
||||
- Keep the Gateway and any node hosts on a private network (Tailscale); avoid public exposure.
|
||||
- Treat remote CDP URLs/tokens as secrets; prefer env vars or a secrets manager.
|
||||
|
||||
Remote CDP tips:
|
||||
|
||||
- Prefer encrypted endpoints (HTTPS or WSS) and short-lived tokens where possible.
|
||||
- Avoid embedding long-lived tokens directly in config files.
|
||||
|
||||
## Profiles (multi-browser)
|
||||
|
||||
OpenClaw supports multiple named profiles (routing configs). Profiles can be:
|
||||
|
||||
- **openclaw-managed**: a dedicated Chromium-based browser instance with its own user data directory + CDP port
|
||||
- **remote**: an explicit CDP URL (Chromium-based browser running elsewhere)
|
||||
- **existing session**: your existing Chrome profile via Chrome DevTools MCP auto-connect
|
||||
|
||||
Defaults:
|
||||
|
||||
- The `openclaw` profile is auto-created if missing.
|
||||
- The `user` profile is built-in for Chrome MCP existing-session attach.
|
||||
- Existing-session profiles are opt-in beyond `user`; create them with `--driver existing-session`.
|
||||
- Local CDP ports allocate from **18800–18899** by default.
|
||||
- Deleting a profile moves its local data directory to Trash.
|
||||
|
||||
All control endpoints accept `?profile=<name>`; the CLI uses `--browser-profile`.
|
||||
|
||||
## Existing-session via Chrome DevTools MCP
|
||||
|
||||
OpenClaw can also attach to a running Chromium-based browser profile through the
|
||||
official Chrome DevTools MCP server. This reuses the tabs and login state
|
||||
already open in that browser profile.
|
||||
|
||||
Official background and setup references:
|
||||
|
||||
- [Chrome for Developers: Use Chrome DevTools MCP with your browser session](https://developer.chrome.com/blog/chrome-devtools-mcp-debug-your-browser-session)
|
||||
- [Chrome DevTools MCP README](https://github.com/ChromeDevTools/chrome-devtools-mcp)
|
||||
|
||||
Built-in profile:
|
||||
|
||||
- `user`
|
||||
|
||||
Optional: create your own custom existing-session profile if you want a
|
||||
different name, color, or browser data directory.
|
||||
|
||||
Default behavior:
|
||||
|
||||
- The built-in `user` profile uses Chrome MCP auto-connect, which targets the
|
||||
default local Google Chrome profile.
|
||||
|
||||
Use `userDataDir` for Brave, Edge, Chromium, or a non-default Chrome profile:
|
||||
|
||||
```json5
|
||||
{
|
||||
browser: {
|
||||
profiles: {
|
||||
brave: {
|
||||
driver: "existing-session",
|
||||
attachOnly: true,
|
||||
userDataDir: "~/Library/Application Support/BraveSoftware/Brave-Browser",
|
||||
color: "#FB542B",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then in the matching browser:
|
||||
|
||||
1. Open that browser's inspect page for remote debugging.
|
||||
2. Enable remote debugging.
|
||||
3. Keep the browser running and approve the connection prompt when OpenClaw attaches.
|
||||
|
||||
Common inspect pages:
|
||||
|
||||
- Chrome: `chrome://inspect/#remote-debugging`
|
||||
- Brave: `brave://inspect/#remote-debugging`
|
||||
- Edge: `edge://inspect/#remote-debugging`
|
||||
|
||||
Live attach smoke test:
|
||||
|
||||
```bash
|
||||
openclaw browser --browser-profile user start
|
||||
openclaw browser --browser-profile user status
|
||||
openclaw browser --browser-profile user tabs
|
||||
openclaw browser --browser-profile user snapshot --format ai
|
||||
```
|
||||
|
||||
What success looks like:
|
||||
|
||||
- `status` shows `driver: existing-session`
|
||||
- `status` shows `transport: chrome-mcp`
|
||||
- `status` shows `running: true`
|
||||
- `tabs` lists your already-open browser tabs
|
||||
- `snapshot` returns refs from the selected live tab
|
||||
|
||||
What to check if attach does not work:
|
||||
|
||||
- the target Chromium-based browser is version `144+`
|
||||
- remote debugging is enabled in that browser's inspect page
|
||||
- the browser showed and you accepted the attach consent prompt
|
||||
- `openclaw doctor` migrates old extension-based browser config and checks that
|
||||
Chrome is installed locally for default auto-connect profiles, but it cannot
|
||||
enable browser-side remote debugging for you
|
||||
|
||||
Agent use:
|
||||
|
||||
- Use `profile="user"` when you need the user’s logged-in browser state.
|
||||
- If you use a custom existing-session profile, pass that explicit profile name.
|
||||
- Only choose this mode when the user is at the computer to approve the attach
|
||||
prompt.
|
||||
- the Gateway or node host can spawn `npx chrome-devtools-mcp@latest --autoConnect`
|
||||
|
||||
Notes:
|
||||
|
||||
- This path is higher-risk than the isolated `openclaw` profile because it can
|
||||
act inside your signed-in browser session.
|
||||
- OpenClaw does not launch the browser for this driver; it attaches to an
|
||||
existing session only.
|
||||
- OpenClaw uses the official Chrome DevTools MCP `--autoConnect` flow here. If
|
||||
`userDataDir` is set, OpenClaw passes it through to target that explicit
|
||||
Chromium user data directory.
|
||||
- Existing-session screenshots support page captures and `--ref` element
|
||||
captures from snapshots, but not CSS `--element` selectors.
|
||||
- Existing-session page screenshots work without Playwright through Chrome MCP.
|
||||
Ref-based element screenshots (`--ref`) also work there, but `--full-page`
|
||||
cannot be combined with `--ref` or `--element`.
|
||||
- Existing-session actions are still more limited than the managed browser
|
||||
path:
|
||||
- `click`, `type`, `hover`, `scrollIntoView`, `drag`, and `select` require
|
||||
snapshot refs instead of CSS selectors
|
||||
- `click` is left-button only (no button overrides or modifiers)
|
||||
- `type` does not support `slowly=true`; use `fill` or `press`
|
||||
- `press` does not support `delayMs`
|
||||
- `hover`, `scrollIntoView`, `drag`, `select`, `fill`, and `evaluate` do not
|
||||
support per-call timeout overrides
|
||||
- `select` currently supports a single value only
|
||||
- Existing-session `wait --url` supports exact, substring, and glob patterns
|
||||
like other browser drivers. `wait --load networkidle` is not supported yet.
|
||||
- Existing-session upload hooks require `ref` or `inputRef`, support one file
|
||||
at a time, and do not support CSS `element` targeting.
|
||||
- Existing-session dialog hooks do not support timeout overrides.
|
||||
- Some features still require the managed browser path, including batch
|
||||
actions, PDF export, download interception, and `responsebody`.
|
||||
- Existing-session can attach on the selected host or through a connected
|
||||
browser node. If Chrome lives elsewhere and no browser node is connected, use
|
||||
remote CDP or a node host instead.
|
||||
|
||||
## Isolation guarantees
|
||||
|
||||
- **Dedicated user data dir**: never touches your personal browser profile.
|
||||
- **Dedicated ports**: avoids `9222` to prevent collisions with dev workflows.
|
||||
- **Deterministic tab control**: target tabs by `targetId`, not “last tab”.
|
||||
|
||||
## Browser selection
|
||||
|
||||
When launching locally, OpenClaw picks the first available:
|
||||
|
||||
1. Chrome
|
||||
2. Brave
|
||||
3. Edge
|
||||
4. Chromium
|
||||
5. Chrome Canary
|
||||
|
||||
You can override with `browser.executablePath`.
|
||||
|
||||
Platforms:
|
||||
|
||||
- macOS: checks `/Applications` and `~/Applications`.
|
||||
- Linux: looks for `google-chrome`, `brave`, `microsoft-edge`, `chromium`, etc.
|
||||
- Windows: checks common install locations.
|
||||
|
||||
## Control API (optional)
|
||||
|
||||
For local integrations only, the Gateway exposes a small loopback HTTP API:
|
||||
|
||||
- Status/start/stop: `GET /`, `POST /start`, `POST /stop`
|
||||
- Tabs: `GET /tabs`, `POST /tabs/open`, `POST /tabs/focus`, `DELETE /tabs/:targetId`
|
||||
- Snapshot/screenshot: `GET /snapshot`, `POST /screenshot`
|
||||
- Actions: `POST /navigate`, `POST /act`
|
||||
- Hooks: `POST /hooks/file-chooser`, `POST /hooks/dialog`
|
||||
- Downloads: `POST /download`, `POST /wait/download`
|
||||
- Debugging: `GET /console`, `POST /pdf`
|
||||
- Debugging: `GET /errors`, `GET /requests`, `POST /trace/start`, `POST /trace/stop`, `POST /highlight`
|
||||
- Network: `POST /response/body`
|
||||
- State: `GET /cookies`, `POST /cookies/set`, `POST /cookies/clear`
|
||||
- State: `GET /storage/:kind`, `POST /storage/:kind/set`, `POST /storage/:kind/clear`
|
||||
- Settings: `POST /set/offline`, `POST /set/headers`, `POST /set/credentials`, `POST /set/geolocation`, `POST /set/media`, `POST /set/timezone`, `POST /set/locale`, `POST /set/device`
|
||||
|
||||
All endpoints accept `?profile=<name>`.
|
||||
|
||||
If shared-secret gateway auth is configured, browser HTTP routes require auth too:
|
||||
|
||||
- `Authorization: Bearer <gateway token>`
|
||||
- `x-openclaw-password: <gateway password>` or HTTP Basic auth with that password
|
||||
|
||||
Notes:
|
||||
|
||||
- This standalone loopback browser API does **not** consume trusted-proxy or
|
||||
Tailscale Serve identity headers.
|
||||
- If `gateway.auth.mode` is `none` or `trusted-proxy`, these loopback browser
|
||||
routes do not inherit those identity-bearing modes; keep them loopback-only.
|
||||
|
||||
### `/act` error contract
|
||||
|
||||
`POST /act` uses a structured error response for route-level validation and
|
||||
policy failures:
|
||||
|
||||
```json
|
||||
{ "error": "<message>", "code": "ACT_*" }
|
||||
```
|
||||
|
||||
Current `code` values:
|
||||
|
||||
- `ACT_KIND_REQUIRED` (HTTP 400): `kind` is missing or unrecognized.
|
||||
- `ACT_INVALID_REQUEST` (HTTP 400): action payload failed normalization or validation.
|
||||
- `ACT_SELECTOR_UNSUPPORTED` (HTTP 400): `selector` was used with an unsupported action kind.
|
||||
- `ACT_EVALUATE_DISABLED` (HTTP 403): `evaluate` (or `wait --fn`) is disabled by config.
|
||||
- `ACT_TARGET_ID_MISMATCH` (HTTP 403): top-level or batched `targetId` conflicts with request target.
|
||||
- `ACT_EXISTING_SESSION_UNSUPPORTED` (HTTP 501): action is not supported for existing-session profiles.
|
||||
|
||||
Other runtime failures may still return `{ "error": "<message>" }` without a
|
||||
`code` field.
|
||||
|
||||
### Playwright requirement
|
||||
|
||||
Some features (navigate/act/AI snapshot/role snapshot, element screenshots,
|
||||
PDF) require Playwright. If Playwright isn’t installed, those endpoints return
|
||||
a clear 501 error.
|
||||
|
||||
What still works without Playwright:
|
||||
|
||||
- ARIA snapshots
|
||||
- Page screenshots for the managed `openclaw` browser when a per-tab CDP
|
||||
WebSocket is available
|
||||
- Page screenshots for `existing-session` / Chrome MCP profiles
|
||||
- `existing-session` ref-based screenshots (`--ref`) from snapshot output
|
||||
|
||||
What still needs Playwright:
|
||||
|
||||
- `navigate`
|
||||
- `act`
|
||||
- AI snapshots / role snapshots
|
||||
- CSS-selector element screenshots (`--element`)
|
||||
- full browser PDF export
|
||||
|
||||
Element screenshots also reject `--full-page`; the route returns `fullPage is
|
||||
not supported for element screenshots`.
|
||||
|
||||
If you see `Playwright is not available in this gateway build`, install the full
|
||||
Playwright package (not `playwright-core`) and restart the gateway, or reinstall
|
||||
OpenClaw with browser support.
|
||||
|
||||
#### Docker Playwright install
|
||||
|
||||
If your Gateway runs in Docker, avoid `npx playwright` (npm override conflicts).
|
||||
Use the bundled CLI instead:
|
||||
|
||||
```bash
|
||||
docker compose run --rm openclaw-cli \
|
||||
node /app/node_modules/playwright-core/cli.js install chromium
|
||||
```
|
||||
|
||||
To persist browser downloads, set `PLAYWRIGHT_BROWSERS_PATH` (for example,
|
||||
`/home/node/.cache/ms-playwright`) and make sure `/home/node` is persisted via
|
||||
`OPENCLAW_HOME_VOLUME` or a bind mount. See [Docker](/install/docker).
|
||||
|
||||
## How it works (internal)
|
||||
|
||||
High-level flow:
|
||||
|
||||
- A small **control server** accepts HTTP requests.
|
||||
- It connects to Chromium-based browsers (Chrome/Brave/Edge/Chromium) via **CDP**.
|
||||
- For advanced actions (click/type/snapshot/PDF), it uses **Playwright** on top
|
||||
of CDP.
|
||||
- When Playwright is missing, only non-Playwright operations are available.
|
||||
|
||||
This design keeps the agent on a stable, deterministic interface while letting
|
||||
you swap local/remote browsers and profiles.
|
||||
|
||||
## CLI quick reference
|
||||
|
||||
All commands accept `--browser-profile <name>` to target a specific profile.
|
||||
All commands also accept `--json` for machine-readable output (stable payloads).
|
||||
|
||||
Basics:
|
||||
|
||||
- `openclaw browser status`
|
||||
- `openclaw browser start`
|
||||
- `openclaw browser stop`
|
||||
- `openclaw browser tabs`
|
||||
- `openclaw browser tab`
|
||||
- `openclaw browser tab new`
|
||||
- `openclaw browser tab select 2`
|
||||
- `openclaw browser tab close 2`
|
||||
- `openclaw browser open https://example.com`
|
||||
- `openclaw browser focus abcd1234`
|
||||
- `openclaw browser close abcd1234`
|
||||
|
||||
Inspection:
|
||||
|
||||
- `openclaw browser screenshot`
|
||||
- `openclaw browser screenshot --full-page`
|
||||
- `openclaw browser screenshot --ref 12`
|
||||
- `openclaw browser screenshot --ref e12`
|
||||
- `openclaw browser snapshot`
|
||||
- `openclaw browser snapshot --format aria --limit 200`
|
||||
- `openclaw browser snapshot --interactive --compact --depth 6`
|
||||
- `openclaw browser snapshot --efficient`
|
||||
- `openclaw browser snapshot --labels`
|
||||
- `openclaw browser snapshot --selector "#main" --interactive`
|
||||
- `openclaw browser snapshot --frame "iframe#main" --interactive`
|
||||
- `openclaw browser console --level error`
|
||||
|
||||
Lifecycle note:
|
||||
|
||||
- For attach-only and remote CDP profiles, `openclaw browser stop` is still the
|
||||
right cleanup command after tests. It closes the active control session and
|
||||
clears temporary emulation overrides instead of killing the underlying
|
||||
browser.
|
||||
- `openclaw browser errors --clear`
|
||||
- `openclaw browser requests --filter api --clear`
|
||||
- `openclaw browser pdf`
|
||||
- `openclaw browser responsebody "**/api" --max-chars 5000`
|
||||
|
||||
Actions:
|
||||
|
||||
- `openclaw browser navigate https://example.com`
|
||||
- `openclaw browser resize 1280 720`
|
||||
- `openclaw browser click 12 --double`
|
||||
- `openclaw browser click e12 --double`
|
||||
- `openclaw browser type 23 "hello" --submit`
|
||||
- `openclaw browser press Enter`
|
||||
- `openclaw browser hover 44`
|
||||
- `openclaw browser scrollintoview e12`
|
||||
- `openclaw browser drag 10 11`
|
||||
- `openclaw browser select 9 OptionA OptionB`
|
||||
- `openclaw browser download e12 report.pdf`
|
||||
- `openclaw browser waitfordownload report.pdf`
|
||||
- `openclaw browser upload /tmp/openclaw/uploads/file.pdf`
|
||||
- `openclaw browser fill --fields '[{"ref":"1","type":"text","value":"Ada"}]'`
|
||||
- `openclaw browser dialog --accept`
|
||||
- `openclaw browser wait --text "Done"`
|
||||
- `openclaw browser wait "#main" --url "**/dash" --load networkidle --fn "window.ready===true"`
|
||||
- `openclaw browser evaluate --fn '(el) => el.textContent' --ref 7`
|
||||
- `openclaw browser highlight e12`
|
||||
- `openclaw browser trace start`
|
||||
- `openclaw browser trace stop`
|
||||
|
||||
State:
|
||||
|
||||
- `openclaw browser cookies`
|
||||
- `openclaw browser cookies set session abc123 --url "https://example.com"`
|
||||
- `openclaw browser cookies clear`
|
||||
- `openclaw browser storage local get`
|
||||
- `openclaw browser storage local set theme dark`
|
||||
- `openclaw browser storage session clear`
|
||||
- `openclaw browser set offline on`
|
||||
- `openclaw browser set headers --headers-json '{"X-Debug":"1"}'`
|
||||
- `openclaw browser set credentials user pass`
|
||||
- `openclaw browser set credentials --clear`
|
||||
- `openclaw browser set geo 37.7749 -122.4194 --origin "https://example.com"`
|
||||
- `openclaw browser set geo --clear`
|
||||
- `openclaw browser set media dark`
|
||||
- `openclaw browser set timezone America/New_York`
|
||||
- `openclaw browser set locale en-US`
|
||||
- `openclaw browser set device "iPhone 14"`
|
||||
|
||||
Notes:
|
||||
|
||||
- `upload` and `dialog` are **arming** calls; run them before the click/press
|
||||
that triggers the chooser/dialog.
|
||||
- Download and trace output paths are constrained to OpenClaw temp roots:
|
||||
- traces: `/tmp/openclaw` (fallback: `${os.tmpdir()}/openclaw`)
|
||||
- downloads: `/tmp/openclaw/downloads` (fallback: `${os.tmpdir()}/openclaw/downloads`)
|
||||
- Upload paths are constrained to an OpenClaw temp uploads root:
|
||||
- uploads: `/tmp/openclaw/uploads` (fallback: `${os.tmpdir()}/openclaw/uploads`)
|
||||
- `upload` can also set file inputs directly via `--input-ref` or `--element`.
|
||||
- `snapshot`:
|
||||
- `--format ai` (default when Playwright is installed): returns an AI snapshot with numeric refs (`aria-ref="<n>"`).
|
||||
- `--format aria`: returns the accessibility tree (no refs; inspection only).
|
||||
- `--efficient` (or `--mode efficient`): compact role snapshot preset (interactive + compact + depth + lower maxChars).
|
||||
- Config default (tool/CLI only): set `browser.snapshotDefaults.mode: "efficient"` to use efficient snapshots when the caller does not pass a mode (see [Gateway configuration](/gateway/configuration-reference#browser)).
|
||||
- Role snapshot options (`--interactive`, `--compact`, `--depth`, `--selector`) force a role-based snapshot with refs like `ref=e12`.
|
||||
- `--frame "<iframe selector>"` scopes role snapshots to an iframe (pairs with role refs like `e12`).
|
||||
- `--interactive` outputs a flat, easy-to-pick list of interactive elements (best for driving actions).
|
||||
- `--labels` adds a viewport-only screenshot with overlayed ref labels (prints `MEDIA:<path>`).
|
||||
- `click`/`type`/etc require a `ref` from `snapshot` (either numeric `12` or role ref `e12`).
|
||||
CSS selectors are intentionally not supported for actions.
|
||||
|
||||
## Snapshots and refs
|
||||
|
||||
OpenClaw supports two “snapshot” styles:
|
||||
|
||||
- **AI snapshot (numeric refs)**: `openclaw browser snapshot` (default; `--format ai`)
|
||||
- Output: a text snapshot that includes numeric refs.
|
||||
- Actions: `openclaw browser click 12`, `openclaw browser type 23 "hello"`.
|
||||
- Internally, the ref is resolved via Playwright’s `aria-ref`.
|
||||
|
||||
- **Role snapshot (role refs like `e12`)**: `openclaw browser snapshot --interactive` (or `--compact`, `--depth`, `--selector`, `--frame`)
|
||||
- Output: a role-based list/tree with `[ref=e12]` (and optional `[nth=1]`).
|
||||
- Actions: `openclaw browser click e12`, `openclaw browser highlight e12`.
|
||||
- Internally, the ref is resolved via `getByRole(...)` (plus `nth()` for duplicates).
|
||||
- Add `--labels` to include a viewport screenshot with overlayed `e12` labels.
|
||||
|
||||
Ref behavior:
|
||||
|
||||
- Refs are **not stable across navigations**; if something fails, re-run `snapshot` and use a fresh ref.
|
||||
- If the role snapshot was taken with `--frame`, role refs are scoped to that iframe until the next role snapshot.
|
||||
|
||||
## Wait power-ups
|
||||
|
||||
You can wait on more than just time/text:
|
||||
|
||||
- Wait for URL (globs supported by Playwright):
|
||||
- `openclaw browser wait --url "**/dash"`
|
||||
- Wait for load state:
|
||||
- `openclaw browser wait --load networkidle`
|
||||
- Wait for a JS predicate:
|
||||
- `openclaw browser wait --fn "window.ready===true"`
|
||||
- Wait for a selector to become visible:
|
||||
- `openclaw browser wait "#main"`
|
||||
|
||||
These can be combined:
|
||||
|
||||
```bash
|
||||
openclaw browser wait "#main" \
|
||||
--url "**/dash" \
|
||||
--load networkidle \
|
||||
--fn "window.ready===true" \
|
||||
--timeout-ms 15000
|
||||
```
|
||||
|
||||
## Debug workflows
|
||||
|
||||
When an action fails (e.g. “not visible”, “strict mode violation”, “covered”):
|
||||
|
||||
1. `openclaw browser snapshot --interactive`
|
||||
2. Use `click <ref>` / `type <ref>` (prefer role refs in interactive mode)
|
||||
3. If it still fails: `openclaw browser highlight <ref>` to see what Playwright is targeting
|
||||
4. If the page behaves oddly:
|
||||
- `openclaw browser errors --clear`
|
||||
- `openclaw browser requests --filter api --clear`
|
||||
5. For deep debugging: record a trace:
|
||||
- `openclaw browser trace start`
|
||||
- reproduce the issue
|
||||
- `openclaw browser trace stop` (prints `TRACE:<path>`)
|
||||
|
||||
## JSON output
|
||||
|
||||
`--json` is for scripting and structured tooling.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
openclaw browser status --json
|
||||
openclaw browser snapshot --interactive --json
|
||||
openclaw browser requests --filter api --json
|
||||
openclaw browser cookies --json
|
||||
```
|
||||
|
||||
Role snapshots in JSON include `refs` plus a small `stats` block (lines/chars/refs/interactive) so tools can reason about payload size and density.
|
||||
|
||||
## State and environment knobs
|
||||
|
||||
These are useful for “make the site behave like X” workflows:
|
||||
|
||||
- Cookies: `cookies`, `cookies set`, `cookies clear`
|
||||
- Storage: `storage local|session get|set|clear`
|
||||
- Offline: `set offline on|off`
|
||||
- Headers: `set headers --headers-json '{"X-Debug":"1"}'` (legacy `set headers --json '{"X-Debug":"1"}'` remains supported)
|
||||
- HTTP basic auth: `set credentials user pass` (or `--clear`)
|
||||
- Geolocation: `set geo <lat> <lon> --origin "https://example.com"` (or `--clear`)
|
||||
- Media: `set media dark|light|no-preference|none`
|
||||
- Timezone / locale: `set timezone ...`, `set locale ...`
|
||||
- Device / viewport:
|
||||
- `set device "iPhone 14"` (Playwright device presets)
|
||||
- `set viewport 1280 720`
|
||||
|
||||
## Security & privacy
|
||||
|
||||
- The openclaw browser profile may contain logged-in sessions; treat it as sensitive.
|
||||
- `browser act kind=evaluate` / `openclaw browser evaluate` and `wait --fn`
|
||||
execute arbitrary JavaScript in the page context. Prompt injection can steer
|
||||
this. Disable it with `browser.evaluateEnabled=false` if you do not need it.
|
||||
- For logins and anti-bot notes (X/Twitter, etc.), see [Browser login + X/Twitter posting](/tools/browser-login).
|
||||
- Keep the Gateway/node host private (loopback or tailnet-only).
|
||||
- Remote CDP endpoints are powerful; tunnel and protect them.
|
||||
|
||||
Strict-mode example (block private/internal destinations by default):
|
||||
|
||||
```json5
|
||||
{
|
||||
browser: {
|
||||
ssrfPolicy: {
|
||||
dangerouslyAllowPrivateNetwork: false,
|
||||
hostnameAllowlist: ["*.example.com", "example.com"],
|
||||
allowedHostnames: ["localhost"], // optional exact allow
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For Linux-specific issues (especially snap Chromium), see
|
||||
[Browser troubleshooting](/tools/browser-linux-troubleshooting).
|
||||
|
||||
For WSL2 Gateway + Windows Chrome split-host setups, see
|
||||
[WSL2 + Windows + remote Chrome CDP troubleshooting](/tools/browser-wsl2-windows-remote-cdp-troubleshooting).
|
||||
|
||||
### CDP startup failure vs navigation SSRF block
|
||||
|
||||
These are different failure classes and they point to different code paths.
|
||||
|
||||
- **CDP startup or readiness failure** means OpenClaw cannot confirm that the browser control plane is healthy.
|
||||
- **Navigation SSRF block** means the browser control plane is healthy, but a page navigation target is rejected by policy.
|
||||
|
||||
Common examples:
|
||||
|
||||
- CDP startup or readiness failure:
|
||||
- `Chrome CDP websocket for profile "openclaw" is not reachable after start`
|
||||
- `Remote CDP for profile "<name>" is not reachable at <cdpUrl>`
|
||||
- Navigation SSRF block:
|
||||
- `open`, `navigate`, snapshot, or tab-opening flows fail with a browser/network policy error while `start` and `tabs` still work
|
||||
|
||||
Use this minimal sequence to separate the two:
|
||||
|
||||
```bash
|
||||
openclaw browser --browser-profile openclaw start
|
||||
openclaw browser --browser-profile openclaw tabs
|
||||
openclaw browser --browser-profile openclaw open https://example.com
|
||||
```
|
||||
|
||||
How to read the results:
|
||||
|
||||
- If `start` fails with `not reachable after start`, troubleshoot CDP readiness first.
|
||||
- If `start` succeeds but `tabs` fails, the control plane is still unhealthy. Treat this as a CDP reachability problem, not a page-navigation problem.
|
||||
- If `start` and `tabs` succeed but `open` or `navigate` fails, the browser control plane is up and the failure is in navigation policy or the target page.
|
||||
- If `start`, `tabs`, and `open` all succeed, the basic managed-browser control path is healthy.
|
||||
|
||||
Important behavior details:
|
||||
|
||||
- Browser config defaults to a fail-closed SSRF policy object even when you do not configure `browser.ssrfPolicy`.
|
||||
- For the local loopback `openclaw` managed profile, CDP health checks intentionally skip browser SSRF reachability enforcement for OpenClaw's own local control plane.
|
||||
- Navigation protection is separate. A successful `start` or `tabs` result does not mean a later `open` or `navigate` target is allowed.
|
||||
|
||||
Security guidance:
|
||||
|
||||
- Do **not** relax browser SSRF policy by default.
|
||||
- Prefer narrow host exceptions such as `hostnameAllowlist` or `allowedHostnames` over broad private-network access.
|
||||
- Use `dangerouslyAllowPrivateNetwork: true` only in intentionally trusted environments where private-network browser access is required and reviewed.
|
||||
|
||||
Example: navigation blocked, control plane healthy
|
||||
|
||||
- `start` succeeds
|
||||
- `tabs` succeeds
|
||||
- `open http://internal.example` fails
|
||||
|
||||
That usually means browser startup is fine and the navigation target needs policy review.
|
||||
|
||||
Example: startup blocked before navigation matters
|
||||
|
||||
- `start` fails with `not reachable after start`
|
||||
- `tabs` also fails or cannot run
|
||||
|
||||
That points to browser launch or CDP reachability, not a page URL allowlist problem.
|
||||
|
||||
## Agent tools + how control works
|
||||
|
||||
The agent gets **one tool** for browser automation:
|
||||
|
||||
- `browser` — status/start/stop/tabs/open/focus/close/snapshot/screenshot/navigate/act
|
||||
|
||||
How it maps:
|
||||
|
||||
- `browser snapshot` returns a stable UI tree (AI or ARIA).
|
||||
- `browser act` uses the snapshot `ref` IDs to click/type/drag/select.
|
||||
- `browser screenshot` captures pixels (full page or element).
|
||||
- `browser` accepts:
|
||||
- `profile` to choose a named browser profile (openclaw, chrome, or remote CDP).
|
||||
- `target` (`sandbox` | `host` | `node`) to select where the browser lives.
|
||||
- In sandboxed sessions, `target: "host"` requires `agents.defaults.sandbox.browser.allowHostControl=true`.
|
||||
- If `target` is omitted: sandboxed sessions default to `sandbox`, non-sandbox sessions default to `host`.
|
||||
- If a browser-capable node is connected, the tool may auto-route to it unless you pin `target="host"` or `target="node"`.
|
||||
|
||||
This keeps the agent deterministic and avoids brittle selectors.
|
||||
|
||||
## Related
|
||||
|
||||
- [Tools Overview](/tools) — all available agent tools
|
||||
- [Sandboxing](/gateway/sandboxing) — browser control in sandboxed environments
|
||||
- [Security](/gateway/security) — browser control risks and hardening
|
||||
142
openclaw/docs/tools/btw.md
Normal file
142
openclaw/docs/tools/btw.md
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
---
|
||||
summary: "Ephemeral side questions with /btw"
|
||||
read_when:
|
||||
- You want to ask a quick side question about the current session
|
||||
- You are implementing or debugging BTW behavior across clients
|
||||
title: "BTW Side Questions"
|
||||
---
|
||||
|
||||
# BTW Side Questions
|
||||
|
||||
`/btw` lets you ask a quick side question about the **current session** without
|
||||
turning that question into normal conversation history.
|
||||
|
||||
It is modeled after Claude Code's `/btw` behavior, but adapted to OpenClaw's
|
||||
Gateway and multi-channel architecture.
|
||||
|
||||
## What it does
|
||||
|
||||
When you send:
|
||||
|
||||
```text
|
||||
/btw what changed?
|
||||
```
|
||||
|
||||
OpenClaw:
|
||||
|
||||
1. snapshots the current session context,
|
||||
2. runs a separate **tool-less** model call,
|
||||
3. answers only the side question,
|
||||
4. leaves the main run alone,
|
||||
5. does **not** write the BTW question or answer to session history,
|
||||
6. emits the answer as a **live side result** rather than a normal assistant message.
|
||||
|
||||
The important mental model is:
|
||||
|
||||
- same session context
|
||||
- separate one-shot side query
|
||||
- no tool calls
|
||||
- no future context pollution
|
||||
- no transcript persistence
|
||||
|
||||
## What it does not do
|
||||
|
||||
`/btw` does **not**:
|
||||
|
||||
- create a new durable session,
|
||||
- continue the unfinished main task,
|
||||
- run tools or agent tool loops,
|
||||
- write BTW question/answer data to transcript history,
|
||||
- appear in `chat.history`,
|
||||
- survive a reload.
|
||||
|
||||
It is intentionally **ephemeral**.
|
||||
|
||||
## How context works
|
||||
|
||||
BTW uses the current session as **background context only**.
|
||||
|
||||
If the main run is currently active, OpenClaw snapshots the current message
|
||||
state and includes the in-flight main prompt as background context, while
|
||||
explicitly telling the model:
|
||||
|
||||
- answer only the side question,
|
||||
- do not resume or complete the unfinished main task,
|
||||
- do not emit tool calls or pseudo-tool calls.
|
||||
|
||||
That keeps BTW isolated from the main run while still making it aware of what
|
||||
the session is about.
|
||||
|
||||
## Delivery model
|
||||
|
||||
BTW is **not** delivered as a normal assistant transcript message.
|
||||
|
||||
At the Gateway protocol level:
|
||||
|
||||
- normal assistant chat uses the `chat` event
|
||||
- BTW uses the `chat.side_result` event
|
||||
|
||||
This separation is intentional. If BTW reused the normal `chat` event path,
|
||||
clients would treat it like regular conversation history.
|
||||
|
||||
Because BTW uses a separate live event and is not replayed from
|
||||
`chat.history`, it disappears after reload.
|
||||
|
||||
## Surface behavior
|
||||
|
||||
### TUI
|
||||
|
||||
In TUI, BTW is rendered inline in the current session view, but it remains
|
||||
ephemeral:
|
||||
|
||||
- visibly distinct from a normal assistant reply
|
||||
- dismissible with `Enter` or `Esc`
|
||||
- not replayed on reload
|
||||
|
||||
### External channels
|
||||
|
||||
On channels like Telegram, WhatsApp, and Discord, BTW is delivered as a
|
||||
clearly labeled one-off reply because those surfaces do not have a local
|
||||
ephemeral overlay concept.
|
||||
|
||||
The answer is still treated as a side result, not normal session history.
|
||||
|
||||
### Control UI / web
|
||||
|
||||
The Gateway emits BTW correctly as `chat.side_result`, and BTW is not included
|
||||
in `chat.history`, so the persistence contract is already correct for web.
|
||||
|
||||
The current Control UI still needs a dedicated `chat.side_result` consumer to
|
||||
render BTW live in the browser. Until that client-side support lands, BTW is a
|
||||
Gateway-level feature with full TUI and external-channel behavior, but not yet
|
||||
a complete browser UX.
|
||||
|
||||
## When to use BTW
|
||||
|
||||
Use `/btw` when you want:
|
||||
|
||||
- a quick clarification about the current work,
|
||||
- a factual side answer while a long run is still in progress,
|
||||
- a temporary answer that should not become part of future session context.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/btw what file are we editing?
|
||||
/btw what does this error mean?
|
||||
/btw summarize the current task in one sentence
|
||||
/btw what is 17 * 19?
|
||||
```
|
||||
|
||||
## When not to use BTW
|
||||
|
||||
Do not use `/btw` when you want the answer to become part of the session's
|
||||
future working context.
|
||||
|
||||
In that case, ask normally in the main session instead of using BTW.
|
||||
|
||||
## Related
|
||||
|
||||
- [Slash commands](/tools/slash-commands)
|
||||
- [Thinking Levels](/tools/thinking)
|
||||
- [Session](/concepts/session)
|
||||
119
openclaw/docs/tools/capability-cookbook.md
Normal file
119
openclaw/docs/tools/capability-cookbook.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
summary: "Contributor guide for adding a new shared capability to the OpenClaw plugin system"
|
||||
read_when:
|
||||
- Adding a new core capability and plugin registration surface
|
||||
- Deciding whether code belongs in core, a vendor plugin, or a feature plugin
|
||||
- Wiring a new runtime helper for channels or tools
|
||||
title: "Adding Capabilities (Contributor Guide)"
|
||||
sidebarTitle: "Adding Capabilities"
|
||||
---
|
||||
|
||||
# Adding Capabilities
|
||||
|
||||
<Info>
|
||||
This is a **contributor guide** for OpenClaw core developers. If you are
|
||||
building an external plugin, see [Building Plugins](/plugins/building-plugins)
|
||||
instead.
|
||||
</Info>
|
||||
|
||||
Use this when OpenClaw needs a new domain such as image generation, video
|
||||
generation, or some future vendor-backed feature area.
|
||||
|
||||
The rule:
|
||||
|
||||
- plugin = ownership boundary
|
||||
- capability = shared core contract
|
||||
|
||||
That means you should not start by wiring a vendor directly into a channel or a
|
||||
tool. Start by defining the capability.
|
||||
|
||||
## When to create a capability
|
||||
|
||||
Create a new capability when all of these are true:
|
||||
|
||||
1. more than one vendor could plausibly implement it
|
||||
2. channels, tools, or feature plugins should consume it without caring about
|
||||
the vendor
|
||||
3. core needs to own fallback, policy, config, or delivery behavior
|
||||
|
||||
If the work is vendor-only and no shared contract exists yet, stop and define
|
||||
the contract first.
|
||||
|
||||
## The standard sequence
|
||||
|
||||
1. Define the typed core contract.
|
||||
2. Add plugin registration for that contract.
|
||||
3. Add a shared runtime helper.
|
||||
4. Wire one real vendor plugin as proof.
|
||||
5. Move feature/channel consumers onto the runtime helper.
|
||||
6. Add contract tests.
|
||||
7. Document the operator-facing config and ownership model.
|
||||
|
||||
## What goes where
|
||||
|
||||
Core:
|
||||
|
||||
- request/response types
|
||||
- provider registry + resolution
|
||||
- fallback behavior
|
||||
- config schema plus propagated `title` / `description` docs metadata on nested object, wildcard, array-item, and composition nodes
|
||||
- runtime helper surface
|
||||
|
||||
Vendor plugin:
|
||||
|
||||
- vendor API calls
|
||||
- vendor auth handling
|
||||
- vendor-specific request normalization
|
||||
- registration of the capability implementation
|
||||
|
||||
Feature/channel plugin:
|
||||
|
||||
- calls `api.runtime.*` or the matching `plugin-sdk/*-runtime` helper
|
||||
- never calls a vendor implementation directly
|
||||
|
||||
## File checklist
|
||||
|
||||
For a new capability, expect to touch these areas:
|
||||
|
||||
- `src/<capability>/types.ts`
|
||||
- `src/<capability>/...registry/runtime.ts`
|
||||
- `src/plugins/types.ts`
|
||||
- `src/plugins/registry.ts`
|
||||
- `src/plugins/captured-registration.ts`
|
||||
- `src/plugins/contracts/registry.ts`
|
||||
- `src/plugins/runtime/types-core.ts`
|
||||
- `src/plugins/runtime/index.ts`
|
||||
- `src/plugin-sdk/<capability>.ts`
|
||||
- `src/plugin-sdk/<capability>-runtime.ts`
|
||||
- one or more bundled plugin packages
|
||||
- config/docs/tests
|
||||
|
||||
## Example: image generation
|
||||
|
||||
Image generation follows the standard shape:
|
||||
|
||||
1. core defines `ImageGenerationProvider`
|
||||
2. core exposes `registerImageGenerationProvider(...)`
|
||||
3. core exposes `runtime.imageGeneration.generate(...)`
|
||||
4. the `openai`, `google`, `fal`, and `minimax` plugins register vendor-backed implementations
|
||||
5. future vendors can register the same contract without changing channels/tools
|
||||
|
||||
The config key is separate from vision-analysis routing:
|
||||
|
||||
- `agents.defaults.imageModel` = analyze images
|
||||
- `agents.defaults.imageGenerationModel` = generate images
|
||||
|
||||
Keep those separate so fallback and policy remain explicit.
|
||||
|
||||
## Review checklist
|
||||
|
||||
Before shipping a new capability, verify:
|
||||
|
||||
- no channel/tool imports vendor code directly
|
||||
- the runtime helper is the shared path
|
||||
- at least one contract test asserts bundled ownership
|
||||
- config docs name the new model/config key
|
||||
- plugin docs explain the ownership boundary
|
||||
|
||||
If a PR skips the capability layer and hardcodes vendor behavior into a
|
||||
channel/tool, send it back and define the contract first.
|
||||
348
openclaw/docs/tools/clawhub.md
Normal file
348
openclaw/docs/tools/clawhub.md
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
---
|
||||
summary: "ClawHub guide: public registry, native OpenClaw install flows, and ClawHub CLI workflows"
|
||||
read_when:
|
||||
- Introducing ClawHub to new users
|
||||
- Installing, searching, or publishing skills or plugins
|
||||
- Explaining ClawHub CLI flags and sync behavior
|
||||
title: "ClawHub"
|
||||
---
|
||||
|
||||
# ClawHub
|
||||
|
||||
ClawHub is the public registry for **OpenClaw skills and plugins**.
|
||||
|
||||
- Use native `openclaw` commands to search/install/update skills and install
|
||||
plugins from ClawHub.
|
||||
- Use the separate `clawhub` CLI when you need registry auth, publish, delete,
|
||||
undelete, or sync workflows.
|
||||
|
||||
Site: [clawhub.ai](https://clawhub.ai)
|
||||
|
||||
## Native OpenClaw flows
|
||||
|
||||
Skills:
|
||||
|
||||
```bash
|
||||
openclaw skills search "calendar"
|
||||
openclaw skills install <skill-slug>
|
||||
openclaw skills update --all
|
||||
```
|
||||
|
||||
Plugins:
|
||||
|
||||
```bash
|
||||
openclaw plugins install clawhub:<package>
|
||||
openclaw plugins update --all
|
||||
```
|
||||
|
||||
Bare npm-safe plugin specs are also tried against ClawHub before npm:
|
||||
|
||||
```bash
|
||||
openclaw plugins install openclaw-codex-app-server
|
||||
```
|
||||
|
||||
Native `openclaw` commands install into your active workspace and persist source
|
||||
metadata so later `update` calls can stay on ClawHub.
|
||||
|
||||
Plugin installs validate advertised `pluginApi` and `minGatewayVersion`
|
||||
compatibility before archive install runs, so incompatible hosts fail closed
|
||||
early instead of partially installing the package.
|
||||
|
||||
`openclaw plugins install clawhub:...` only accepts installable plugin families.
|
||||
If a ClawHub package is actually a skill, OpenClaw stops and points you at
|
||||
`openclaw skills install <slug>` instead.
|
||||
|
||||
## What ClawHub is
|
||||
|
||||
- A public registry for OpenClaw skills and plugins.
|
||||
- A versioned store of skill bundles and metadata.
|
||||
- A discovery surface for search, tags, and usage signals.
|
||||
|
||||
## How it works
|
||||
|
||||
1. A user publishes a skill bundle (files + metadata).
|
||||
2. ClawHub stores the bundle, parses metadata, and assigns a version.
|
||||
3. The registry indexes the skill for search and discovery.
|
||||
4. Users browse, download, and install skills in OpenClaw.
|
||||
|
||||
## What you can do
|
||||
|
||||
- Publish new skills and new versions of existing skills.
|
||||
- Discover skills by name, tags, or search.
|
||||
- Download skill bundles and inspect their files.
|
||||
- Report skills that are abusive or unsafe.
|
||||
- If you are a moderator, hide, unhide, delete, or ban.
|
||||
|
||||
## Who this is for (beginner-friendly)
|
||||
|
||||
If you want to add new capabilities to your OpenClaw agent, ClawHub is the easiest way to find and install skills. You do not need to know how the backend works. You can:
|
||||
|
||||
- Search for skills by plain language.
|
||||
- Install a skill into your workspace.
|
||||
- Update skills later with one command.
|
||||
- Back up your own skills by publishing them.
|
||||
|
||||
## Quick start (non-technical)
|
||||
|
||||
1. Search for something you need:
|
||||
- `openclaw skills search "calendar"`
|
||||
2. Install a skill:
|
||||
- `openclaw skills install <skill-slug>`
|
||||
3. Start a new OpenClaw session so it picks up the new skill.
|
||||
4. If you want to publish or manage registry auth, install the separate
|
||||
`clawhub` CLI too.
|
||||
|
||||
## Install the ClawHub CLI
|
||||
|
||||
You only need this for registry-authenticated workflows such as publish/sync:
|
||||
|
||||
```bash
|
||||
npm i -g clawhub
|
||||
```
|
||||
|
||||
```bash
|
||||
pnpm add -g clawhub
|
||||
```
|
||||
|
||||
## How it fits into OpenClaw
|
||||
|
||||
Native `openclaw skills install` installs into the active workspace `skills/`
|
||||
directory. `openclaw plugins install clawhub:...` records a normal managed
|
||||
plugin install plus ClawHub source metadata for updates.
|
||||
|
||||
Anonymous ClawHub plugin installs also fail closed for private packages.
|
||||
Community or other non-official channels can still install, but OpenClaw warns
|
||||
so operators can review source and verification before enabling them.
|
||||
|
||||
The separate `clawhub` CLI also installs skills into `./skills` under your
|
||||
current working directory. If an OpenClaw workspace is configured, `clawhub`
|
||||
falls back to that workspace unless you override `--workdir` (or
|
||||
`CLAWHUB_WORKDIR`). OpenClaw loads workspace skills from `<workspace>/skills`
|
||||
and will pick them up in the **next** session. If you already use
|
||||
`~/.openclaw/skills` or bundled skills, workspace skills take precedence.
|
||||
|
||||
For more detail on how skills are loaded, shared, and gated, see
|
||||
[Skills](/tools/skills).
|
||||
|
||||
## Skill system overview
|
||||
|
||||
A skill is a versioned bundle of files that teaches OpenClaw how to perform a
|
||||
specific task. Each publish creates a new version, and the registry keeps a
|
||||
history of versions so users can audit changes.
|
||||
|
||||
A typical skill includes:
|
||||
|
||||
- A `SKILL.md` file with the primary description and usage.
|
||||
- Optional configs, scripts, or supporting files used by the skill.
|
||||
- Metadata such as tags, summary, and install requirements.
|
||||
|
||||
ClawHub uses metadata to power discovery and safely expose skill capabilities.
|
||||
The registry also tracks usage signals (such as stars and downloads) to improve
|
||||
ranking and visibility.
|
||||
|
||||
## What the service provides (features)
|
||||
|
||||
- **Public browsing** of skills and their `SKILL.md` content.
|
||||
- **Search** powered by embeddings (vector search), not just keywords.
|
||||
- **Versioning** with semver, changelogs, and tags (including `latest`).
|
||||
- **Downloads** as a zip per version.
|
||||
- **Stars and comments** for community feedback.
|
||||
- **Moderation** hooks for approvals and audits.
|
||||
- **CLI-friendly API** for automation and scripting.
|
||||
|
||||
## Security and moderation
|
||||
|
||||
ClawHub is open by default. Anyone can upload skills, but a GitHub account must
|
||||
be at least one week old to publish. This helps slow down abuse without blocking
|
||||
legitimate contributors.
|
||||
|
||||
Reporting and moderation:
|
||||
|
||||
- Any signed in user can report a skill.
|
||||
- Report reasons are required and recorded.
|
||||
- Each user can have up to 20 active reports at a time.
|
||||
- Skills with more than 3 unique reports are auto hidden by default.
|
||||
- Moderators can view hidden skills, unhide them, delete them, or ban users.
|
||||
- Abusing the report feature can result in account bans.
|
||||
|
||||
Interested in becoming a moderator? Ask in the OpenClaw Discord and contact a
|
||||
moderator or maintainer.
|
||||
|
||||
## CLI commands and parameters
|
||||
|
||||
Global options (apply to all commands):
|
||||
|
||||
- `--workdir <dir>`: Working directory (default: current dir; falls back to OpenClaw workspace).
|
||||
- `--dir <dir>`: Skills directory, relative to workdir (default: `skills`).
|
||||
- `--site <url>`: Site base URL (browser login).
|
||||
- `--registry <url>`: Registry API base URL.
|
||||
- `--no-input`: Disable prompts (non-interactive).
|
||||
- `-V, --cli-version`: Print CLI version.
|
||||
|
||||
Auth:
|
||||
|
||||
- `clawhub login` (browser flow) or `clawhub login --token <token>`
|
||||
- `clawhub logout`
|
||||
- `clawhub whoami`
|
||||
|
||||
Options:
|
||||
|
||||
- `--token <token>`: Paste an API token.
|
||||
- `--label <label>`: Label stored for browser login tokens (default: `CLI token`).
|
||||
- `--no-browser`: Do not open a browser (requires `--token`).
|
||||
|
||||
Search:
|
||||
|
||||
- `clawhub search "query"`
|
||||
- `--limit <n>`: Max results.
|
||||
|
||||
Install:
|
||||
|
||||
- `clawhub install <slug>`
|
||||
- `--version <version>`: Install a specific version.
|
||||
- `--force`: Overwrite if the folder already exists.
|
||||
|
||||
Update:
|
||||
|
||||
- `clawhub update <slug>`
|
||||
- `clawhub update --all`
|
||||
- `--version <version>`: Update to a specific version (single slug only).
|
||||
- `--force`: Overwrite when local files do not match any published version.
|
||||
|
||||
List:
|
||||
|
||||
- `clawhub list` (reads `.clawhub/lock.json`)
|
||||
|
||||
Publish skills:
|
||||
|
||||
- `clawhub skill publish <path>`
|
||||
- `--slug <slug>`: Skill slug.
|
||||
- `--name <name>`: Display name.
|
||||
- `--version <version>`: Semver version.
|
||||
- `--changelog <text>`: Changelog text (can be empty).
|
||||
- `--tags <tags>`: Comma-separated tags (default: `latest`).
|
||||
|
||||
Publish plugins:
|
||||
|
||||
- `clawhub package publish <source>`
|
||||
- `<source>` can be a local folder, `owner/repo`, `owner/repo@ref`, or a GitHub URL.
|
||||
- `--dry-run`: Build the exact publish plan without uploading anything.
|
||||
- `--json`: Emit machine-readable output for CI.
|
||||
- `--source-repo`, `--source-commit`, `--source-ref`: Optional overrides when auto-detection is not enough.
|
||||
|
||||
Delete/undelete (owner/admin only):
|
||||
|
||||
- `clawhub delete <slug> --yes`
|
||||
- `clawhub undelete <slug> --yes`
|
||||
|
||||
Sync (scan local skills + publish new/updated):
|
||||
|
||||
- `clawhub sync`
|
||||
- `--root <dir...>`: Extra scan roots.
|
||||
- `--all`: Upload everything without prompts.
|
||||
- `--dry-run`: Show what would be uploaded.
|
||||
- `--bump <type>`: `patch|minor|major` for updates (default: `patch`).
|
||||
- `--changelog <text>`: Changelog for non-interactive updates.
|
||||
- `--tags <tags>`: Comma-separated tags (default: `latest`).
|
||||
- `--concurrency <n>`: Registry checks (default: 4).
|
||||
|
||||
## Common workflows for agents
|
||||
|
||||
### Search for skills
|
||||
|
||||
```bash
|
||||
clawhub search "postgres backups"
|
||||
```
|
||||
|
||||
### Download new skills
|
||||
|
||||
```bash
|
||||
clawhub install my-skill-pack
|
||||
```
|
||||
|
||||
### Update installed skills
|
||||
|
||||
```bash
|
||||
clawhub update --all
|
||||
```
|
||||
|
||||
### Back up your skills (publish or sync)
|
||||
|
||||
For a single skill folder:
|
||||
|
||||
```bash
|
||||
clawhub skill publish ./my-skill --slug my-skill --name "My Skill" --version 1.0.0 --tags latest
|
||||
```
|
||||
|
||||
To scan and back up many skills at once:
|
||||
|
||||
```bash
|
||||
clawhub sync --all
|
||||
```
|
||||
|
||||
### Publish a plugin from GitHub
|
||||
|
||||
```bash
|
||||
clawhub package publish your-org/your-plugin --dry-run
|
||||
clawhub package publish your-org/your-plugin
|
||||
clawhub package publish your-org/your-plugin@v1.0.0
|
||||
clawhub package publish https://github.com/your-org/your-plugin
|
||||
```
|
||||
|
||||
Code plugins must include the required OpenClaw metadata in `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@myorg/openclaw-my-plugin",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"openclaw": {
|
||||
"extensions": ["./index.ts"],
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.3.24-beta.2",
|
||||
"minGatewayVersion": "2026.3.24-beta.2"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.3.24-beta.2",
|
||||
"pluginSdkVersion": "2026.3.24-beta.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced details (technical)
|
||||
|
||||
### Versioning and tags
|
||||
|
||||
- Each publish creates a new **semver** `SkillVersion`.
|
||||
- Tags (like `latest`) point to a version; moving tags lets you roll back.
|
||||
- Changelogs are attached per version and can be empty when syncing or publishing updates.
|
||||
|
||||
### Local changes vs registry versions
|
||||
|
||||
Updates compare the local skill contents to registry versions using a content hash. If local files do not match any published version, the CLI asks before overwriting (or requires `--force` in non-interactive runs).
|
||||
|
||||
### Sync scanning and fallback roots
|
||||
|
||||
`clawhub sync` scans your current workdir first. If no skills are found, it falls back to known legacy locations (for example `~/openclaw/skills` and `~/.openclaw/skills`). This is designed to find older skill installs without extra flags.
|
||||
|
||||
### Storage and lockfile
|
||||
|
||||
- Installed skills are recorded in `.clawhub/lock.json` under your workdir.
|
||||
- Auth tokens are stored in the ClawHub CLI config file (override via `CLAWHUB_CONFIG_PATH`).
|
||||
|
||||
### Telemetry (install counts)
|
||||
|
||||
When you run `clawhub sync` while logged in, the CLI sends a minimal snapshot to compute install counts. You can disable this entirely:
|
||||
|
||||
```bash
|
||||
export CLAWHUB_DISABLE_TELEMETRY=1
|
||||
```
|
||||
|
||||
## Environment variables
|
||||
|
||||
- `CLAWHUB_SITE`: Override the site URL.
|
||||
- `CLAWHUB_REGISTRY`: Override the registry API URL.
|
||||
- `CLAWHUB_CONFIG_PATH`: Override where the CLI stores the token/config.
|
||||
- `CLAWHUB_WORKDIR`: Override the default workdir.
|
||||
- `CLAWHUB_DISABLE_TELEMETRY=1`: Disable telemetry on `sync`.
|
||||
90
openclaw/docs/tools/code-execution.md
Normal file
90
openclaw/docs/tools/code-execution.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
summary: "code_execution -- run sandboxed remote Python analysis with xAI"
|
||||
read_when:
|
||||
- You want to enable or configure code_execution
|
||||
- You want remote analysis without local shell access
|
||||
- You want to combine x_search or web_search with remote Python analysis
|
||||
title: "Code Execution"
|
||||
---
|
||||
|
||||
# Code Execution
|
||||
|
||||
`code_execution` runs sandboxed remote Python analysis on xAI's Responses API.
|
||||
This is different from local [`exec`](/tools/exec):
|
||||
|
||||
- `exec` runs shell commands on your machine or node
|
||||
- `code_execution` runs Python in xAI's remote sandbox
|
||||
|
||||
Use `code_execution` for:
|
||||
|
||||
- calculations
|
||||
- tabulation
|
||||
- quick statistics
|
||||
- chart-style analysis
|
||||
- analyzing data returned by `x_search` or `web_search`
|
||||
|
||||
Do **not** use it when you need local files, your shell, your repo, or paired
|
||||
devices. Use [`exec`](/tools/exec) for that.
|
||||
|
||||
## Setup
|
||||
|
||||
You need an xAI API key. Any of these work:
|
||||
|
||||
- `XAI_API_KEY`
|
||||
- `plugins.entries.xai.config.webSearch.apiKey`
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
xai: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "xai-...",
|
||||
},
|
||||
codeExecution: {
|
||||
enabled: true,
|
||||
model: "grok-4-1-fast",
|
||||
maxTurns: 2,
|
||||
timeoutSeconds: 30,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## How To Use It
|
||||
|
||||
Ask naturally and make the analysis intent explicit:
|
||||
|
||||
```text
|
||||
Use code_execution to calculate the 7-day moving average for these numbers: ...
|
||||
```
|
||||
|
||||
```text
|
||||
Use x_search to find posts mentioning OpenClaw this week, then use code_execution to count them by day.
|
||||
```
|
||||
|
||||
```text
|
||||
Use web_search to gather the latest AI benchmark numbers, then use code_execution to compare percent changes.
|
||||
```
|
||||
|
||||
The tool takes a single `task` parameter internally, so the agent should send
|
||||
the full analysis request and any inline data in one prompt.
|
||||
|
||||
## Limits
|
||||
|
||||
- This is remote xAI execution, not local process execution.
|
||||
- It should be treated as ephemeral analysis, not a persistent notebook.
|
||||
- Do not assume access to local files or your workspace.
|
||||
- For fresh X data, use [`x_search`](/tools/web#x_search) first.
|
||||
|
||||
## See Also
|
||||
|
||||
- [Web tools](/tools/web)
|
||||
- [Exec](/tools/exec)
|
||||
- [xAI](/providers/xai)
|
||||
119
openclaw/docs/tools/creating-skills.md
Normal file
119
openclaw/docs/tools/creating-skills.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
title: "Creating Skills"
|
||||
summary: "Build and test custom workspace skills with SKILL.md"
|
||||
read_when:
|
||||
- You are creating a new custom skill in your workspace
|
||||
- You need a quick starter workflow for SKILL.md-based skills
|
||||
---
|
||||
|
||||
# Creating Skills
|
||||
|
||||
Skills teach the agent how and when to use tools. Each skill is a directory
|
||||
containing a `SKILL.md` file with YAML frontmatter and markdown instructions.
|
||||
|
||||
For how skills are loaded and prioritized, see [Skills](/tools/skills).
|
||||
|
||||
## Create your first skill
|
||||
|
||||
<Steps>
|
||||
<Step title="Create the skill directory">
|
||||
Skills live in your workspace. Create a new folder:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.openclaw/workspace/skills/hello-world
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Write SKILL.md">
|
||||
Create `SKILL.md` inside that directory. The frontmatter defines metadata,
|
||||
and the markdown body contains instructions for the agent.
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: hello_world
|
||||
description: A simple skill that says hello.
|
||||
---
|
||||
|
||||
# Hello World Skill
|
||||
|
||||
When the user asks for a greeting, use the `echo` tool to say
|
||||
"Hello from your custom skill!".
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Add tools (optional)">
|
||||
You can define custom tool schemas in the frontmatter or instruct the agent
|
||||
to use existing system tools (like `exec` or `browser`). Skills can also
|
||||
ship inside plugins alongside the tools they document.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Load the skill">
|
||||
Start a new session so OpenClaw picks up the skill:
|
||||
|
||||
```bash
|
||||
# From chat
|
||||
/new
|
||||
|
||||
# Or restart the gateway
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
Verify the skill loaded:
|
||||
|
||||
```bash
|
||||
openclaw skills list
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Test it">
|
||||
Send a message that should trigger the skill:
|
||||
|
||||
```bash
|
||||
openclaw agent --message "give me a greeting"
|
||||
```
|
||||
|
||||
Or just chat with the agent and ask for a greeting.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Skill metadata reference
|
||||
|
||||
The YAML frontmatter supports these fields:
|
||||
|
||||
| Field | Required | Description |
|
||||
| ----------------------------------- | -------- | ------------------------------------------- |
|
||||
| `name` | Yes | Unique identifier (snake_case) |
|
||||
| `description` | Yes | One-line description shown to the agent |
|
||||
| `metadata.openclaw.os` | No | OS filter (`["darwin"]`, `["linux"]`, etc.) |
|
||||
| `metadata.openclaw.requires.bins` | No | Required binaries on PATH |
|
||||
| `metadata.openclaw.requires.config` | No | Required config keys |
|
||||
|
||||
## Best practices
|
||||
|
||||
- **Be concise** — instruct the model on _what_ to do, not how to be an AI
|
||||
- **Safety first** — if your skill uses `exec`, ensure prompts don't allow arbitrary command injection from untrusted input
|
||||
- **Test locally** — use `openclaw agent --message "..."` to test before sharing
|
||||
- **Use ClawHub** — browse and contribute skills at [ClawHub](https://clawhub.ai)
|
||||
|
||||
## Where skills live
|
||||
|
||||
| Location | Precedence | Scope |
|
||||
| ------------------------------- | ---------- | --------------------- |
|
||||
| `\<workspace\>/skills/` | Highest | Per-agent |
|
||||
| `\<workspace\>/.agents/skills/` | High | Per-workspace agent |
|
||||
| `~/.agents/skills/` | Medium | Shared agent profile |
|
||||
| `~/.openclaw/skills/` | Medium | Shared (all agents) |
|
||||
| Bundled (shipped with OpenClaw) | Low | Global |
|
||||
| `skills.load.extraDirs` | Lowest | Custom shared folders |
|
||||
|
||||
## Related
|
||||
|
||||
- [Skills reference](/tools/skills) — loading, precedence, and gating rules
|
||||
- [Skills config](/tools/skills-config) — `skills.*` config schema
|
||||
- [ClawHub](/tools/clawhub) — public skill registry
|
||||
- [Building Plugins](/plugins/building-plugins) — plugins can ship skills
|
||||
434
openclaw/docs/tools/diffs.md
Normal file
434
openclaw/docs/tools/diffs.md
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
---
|
||||
title: "Diffs"
|
||||
summary: "Read-only diff viewer and file renderer for agents (optional plugin tool)"
|
||||
read_when:
|
||||
- You want agents to show code or markdown edits as diffs
|
||||
- You want a canvas-ready viewer URL or a rendered diff file
|
||||
- You need controlled, temporary diff artifacts with secure defaults
|
||||
---
|
||||
|
||||
# Diffs
|
||||
|
||||
`diffs` is an optional plugin tool with short built-in system guidance and a companion skill that turns change content into a read-only diff artifact for agents.
|
||||
|
||||
It accepts either:
|
||||
|
||||
- `before` and `after` text
|
||||
- a unified `patch`
|
||||
|
||||
It can return:
|
||||
|
||||
- a gateway viewer URL for canvas presentation
|
||||
- a rendered file path (PNG or PDF) for message delivery
|
||||
- both outputs in one call
|
||||
|
||||
When enabled, the plugin prepends concise usage guidance into system-prompt space and also exposes a detailed skill for cases where the agent needs fuller instructions.
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Enable the plugin.
|
||||
2. Call `diffs` with `mode: "view"` for canvas-first flows.
|
||||
3. Call `diffs` with `mode: "file"` for chat file delivery flows.
|
||||
4. Call `diffs` with `mode: "both"` when you need both artifacts.
|
||||
|
||||
## Enable the plugin
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Disable built-in system guidance
|
||||
|
||||
If you want to keep the `diffs` tool enabled but disable its built-in system-prompt guidance, set `plugins.entries.diffs.hooks.allowPromptInjection` to `false`:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
enabled: true,
|
||||
hooks: {
|
||||
allowPromptInjection: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
This blocks the diffs plugin's `before_prompt_build` hook while keeping the plugin, tool, and companion skill available.
|
||||
|
||||
If you want to disable both the guidance and the tool, disable the plugin instead.
|
||||
|
||||
## Typical agent workflow
|
||||
|
||||
1. Agent calls `diffs`.
|
||||
2. Agent reads `details` fields.
|
||||
3. Agent either:
|
||||
- opens `details.viewerUrl` with `canvas present`
|
||||
- sends `details.filePath` with `message` using `path` or `filePath`
|
||||
- does both
|
||||
|
||||
## Input examples
|
||||
|
||||
Before and after:
|
||||
|
||||
```json
|
||||
{
|
||||
"before": "# Hello\n\nOne",
|
||||
"after": "# Hello\n\nTwo",
|
||||
"path": "docs/example.md",
|
||||
"mode": "view"
|
||||
}
|
||||
```
|
||||
|
||||
Patch:
|
||||
|
||||
```json
|
||||
{
|
||||
"patch": "diff --git a/src/example.ts b/src/example.ts\n--- a/src/example.ts\n+++ b/src/example.ts\n@@ -1 +1 @@\n-const x = 1;\n+const x = 2;\n",
|
||||
"mode": "both"
|
||||
}
|
||||
```
|
||||
|
||||
## Tool input reference
|
||||
|
||||
All fields are optional unless noted:
|
||||
|
||||
- `before` (`string`): original text. Required with `after` when `patch` is omitted.
|
||||
- `after` (`string`): updated text. Required with `before` when `patch` is omitted.
|
||||
- `patch` (`string`): unified diff text. Mutually exclusive with `before` and `after`.
|
||||
- `path` (`string`): display filename for before and after mode.
|
||||
- `lang` (`string`): language override hint for before and after mode. Unknown values fall back to plain text.
|
||||
- `title` (`string`): viewer title override.
|
||||
- `mode` (`"view" | "file" | "both"`): output mode. Defaults to plugin default `defaults.mode`.
|
||||
Deprecated alias: `"image"` behaves like `"file"` and is still accepted for backward compatibility.
|
||||
- `theme` (`"light" | "dark"`): viewer theme. Defaults to plugin default `defaults.theme`.
|
||||
- `layout` (`"unified" | "split"`): diff layout. Defaults to plugin default `defaults.layout`.
|
||||
- `expandUnchanged` (`boolean`): expand unchanged sections when full context is available. Per-call option only (not a plugin default key).
|
||||
- `fileFormat` (`"png" | "pdf"`): rendered file format. Defaults to plugin default `defaults.fileFormat`.
|
||||
- `fileQuality` (`"standard" | "hq" | "print"`): quality preset for PNG or PDF rendering.
|
||||
- `fileScale` (`number`): device scale override (`1`-`4`).
|
||||
- `fileMaxWidth` (`number`): max render width in CSS pixels (`640`-`2400`).
|
||||
- `ttlSeconds` (`number`): artifact TTL in seconds for viewer and standalone file outputs. Default 1800, max 21600.
|
||||
- `baseUrl` (`string`): viewer URL origin override. Overrides plugin `viewerBaseUrl`. Must be `http` or `https`, no query/hash.
|
||||
|
||||
Legacy input aliases still accepted for backward compatibility:
|
||||
|
||||
- `format` -> `fileFormat`
|
||||
- `imageFormat` -> `fileFormat`
|
||||
- `imageQuality` -> `fileQuality`
|
||||
- `imageScale` -> `fileScale`
|
||||
- `imageMaxWidth` -> `fileMaxWidth`
|
||||
|
||||
Validation and limits:
|
||||
|
||||
- `before` and `after` each max 512 KiB.
|
||||
- `patch` max 2 MiB.
|
||||
- `path` max 2048 bytes.
|
||||
- `lang` max 128 bytes.
|
||||
- `title` max 1024 bytes.
|
||||
- Patch complexity cap: max 128 files and 120000 total lines.
|
||||
- `patch` and `before` or `after` together are rejected.
|
||||
- Rendered file safety limits (apply to PNG and PDF):
|
||||
- `fileQuality: "standard"`: max 8 MP (8,000,000 rendered pixels).
|
||||
- `fileQuality: "hq"`: max 14 MP (14,000,000 rendered pixels).
|
||||
- `fileQuality: "print"`: max 24 MP (24,000,000 rendered pixels).
|
||||
- PDF also has a max of 50 pages.
|
||||
|
||||
## Output details contract
|
||||
|
||||
The tool returns structured metadata under `details`.
|
||||
|
||||
Shared fields for modes that create a viewer:
|
||||
|
||||
- `artifactId`
|
||||
- `viewerUrl`
|
||||
- `viewerPath`
|
||||
- `title`
|
||||
- `expiresAt`
|
||||
- `inputKind`
|
||||
- `fileCount`
|
||||
- `mode`
|
||||
- `context` (`agentId`, `sessionId`, `messageChannel`, `agentAccountId` when available)
|
||||
|
||||
File fields when PNG or PDF is rendered:
|
||||
|
||||
- `artifactId`
|
||||
- `expiresAt`
|
||||
- `filePath`
|
||||
- `path` (same value as `filePath`, for message tool compatibility)
|
||||
- `fileBytes`
|
||||
- `fileFormat`
|
||||
- `fileQuality`
|
||||
- `fileScale`
|
||||
- `fileMaxWidth`
|
||||
|
||||
Compatibility aliases also returned for existing callers:
|
||||
|
||||
- `format` (same value as `fileFormat`)
|
||||
- `imagePath` (same value as `filePath`)
|
||||
- `imageBytes` (same value as `fileBytes`)
|
||||
- `imageQuality` (same value as `fileQuality`)
|
||||
- `imageScale` (same value as `fileScale`)
|
||||
- `imageMaxWidth` (same value as `fileMaxWidth`)
|
||||
|
||||
Mode behavior summary:
|
||||
|
||||
- `mode: "view"`: viewer fields only.
|
||||
- `mode: "file"`: file fields only, no viewer artifact.
|
||||
- `mode: "both"`: viewer fields plus file fields. If file rendering fails, viewer still returns with `fileError` and compatibility alias `imageError`.
|
||||
|
||||
## Collapsed unchanged sections
|
||||
|
||||
- The viewer can show rows like `N unmodified lines`.
|
||||
- Expand controls on those rows are conditional and not guaranteed for every input kind.
|
||||
- Expand controls appear when the rendered diff has expandable context data, which is typical for before and after input.
|
||||
- For many unified patch inputs, omitted context bodies are not available in the parsed patch hunks, so the row can appear without expand controls. This is expected behavior.
|
||||
- `expandUnchanged` applies only when expandable context exists.
|
||||
|
||||
## Plugin defaults
|
||||
|
||||
Set plugin-wide defaults in `~/.openclaw/openclaw.json`:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
enabled: true,
|
||||
config: {
|
||||
defaults: {
|
||||
fontFamily: "Fira Code",
|
||||
fontSize: 15,
|
||||
lineSpacing: 1.6,
|
||||
layout: "unified",
|
||||
showLineNumbers: true,
|
||||
diffIndicators: "bars",
|
||||
wordWrap: true,
|
||||
background: true,
|
||||
theme: "dark",
|
||||
fileFormat: "png",
|
||||
fileQuality: "standard",
|
||||
fileScale: 2,
|
||||
fileMaxWidth: 960,
|
||||
mode: "both",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Supported defaults:
|
||||
|
||||
- `fontFamily`
|
||||
- `fontSize`
|
||||
- `lineSpacing`
|
||||
- `layout`
|
||||
- `showLineNumbers`
|
||||
- `diffIndicators`
|
||||
- `wordWrap`
|
||||
- `background`
|
||||
- `theme`
|
||||
- `fileFormat`
|
||||
- `fileQuality`
|
||||
- `fileScale`
|
||||
- `fileMaxWidth`
|
||||
- `mode`
|
||||
|
||||
Explicit tool parameters override these defaults.
|
||||
|
||||
Persistent viewer URL config:
|
||||
|
||||
- `viewerBaseUrl` (`string`, optional)
|
||||
- Plugin-owned fallback for returned viewer links when a tool call does not pass `baseUrl`.
|
||||
- Must be `http` or `https`, no query/hash.
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
enabled: true,
|
||||
config: {
|
||||
viewerBaseUrl: "https://gateway.example.com/openclaw",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Security config
|
||||
|
||||
- `security.allowRemoteViewer` (`boolean`, default `false`)
|
||||
- `false`: non-loopback requests to viewer routes are denied.
|
||||
- `true`: remote viewers are allowed if tokenized path is valid.
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
diffs: {
|
||||
enabled: true,
|
||||
config: {
|
||||
security: {
|
||||
allowRemoteViewer: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Artifact lifecycle and storage
|
||||
|
||||
- Artifacts are stored under the temp subfolder: `$TMPDIR/openclaw-diffs`.
|
||||
- Viewer artifact metadata contains:
|
||||
- random artifact ID (20 hex chars)
|
||||
- random token (48 hex chars)
|
||||
- `createdAt` and `expiresAt`
|
||||
- stored `viewer.html` path
|
||||
- Default artifact TTL is 30 minutes when not specified.
|
||||
- Maximum accepted viewer TTL is 6 hours.
|
||||
- Cleanup runs opportunistically after artifact creation.
|
||||
- Expired artifacts are deleted.
|
||||
- Fallback cleanup removes stale folders older than 24 hours when metadata is missing.
|
||||
|
||||
## Viewer URL and network behavior
|
||||
|
||||
Viewer route:
|
||||
|
||||
- `/plugins/diffs/view/{artifactId}/{token}`
|
||||
|
||||
Viewer assets:
|
||||
|
||||
- `/plugins/diffs/assets/viewer.js`
|
||||
- `/plugins/diffs/assets/viewer-runtime.js`
|
||||
|
||||
The viewer document resolves those assets relative to the viewer URL, so an optional `baseUrl` path prefix is preserved for both asset requests too.
|
||||
|
||||
URL construction behavior:
|
||||
|
||||
- If tool-call `baseUrl` is provided, it is used after strict validation.
|
||||
- Else if plugin `viewerBaseUrl` is configured, it is used.
|
||||
- Without either override, viewer URL defaults to loopback `127.0.0.1`.
|
||||
- If gateway bind mode is `custom` and `gateway.customBindHost` is set, that host is used.
|
||||
|
||||
`baseUrl` rules:
|
||||
|
||||
- Must be `http://` or `https://`.
|
||||
- Query and hash are rejected.
|
||||
- Origin plus optional base path is allowed.
|
||||
|
||||
## Security model
|
||||
|
||||
Viewer hardening:
|
||||
|
||||
- Loopback-only by default.
|
||||
- Tokenized viewer paths with strict ID and token validation.
|
||||
- Viewer response CSP:
|
||||
- `default-src 'none'`
|
||||
- scripts and assets only from self
|
||||
- no outbound `connect-src`
|
||||
- Remote miss throttling when remote access is enabled:
|
||||
- 40 failures per 60 seconds
|
||||
- 60 second lockout (`429 Too Many Requests`)
|
||||
|
||||
File rendering hardening:
|
||||
|
||||
- Screenshot browser request routing is deny-by-default.
|
||||
- Only local viewer assets from `http://127.0.0.1/plugins/diffs/assets/*` are allowed.
|
||||
- External network requests are blocked.
|
||||
|
||||
## Browser requirements for file mode
|
||||
|
||||
`mode: "file"` and `mode: "both"` need a Chromium-compatible browser.
|
||||
|
||||
Resolution order:
|
||||
|
||||
1. `browser.executablePath` in OpenClaw config.
|
||||
2. Environment variables:
|
||||
- `OPENCLAW_BROWSER_EXECUTABLE_PATH`
|
||||
- `BROWSER_EXECUTABLE_PATH`
|
||||
- `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH`
|
||||
3. Platform command/path discovery fallback.
|
||||
|
||||
Common failure text:
|
||||
|
||||
- `Diff PNG/PDF rendering requires a Chromium-compatible browser...`
|
||||
|
||||
Fix by installing Chrome, Chromium, Edge, or Brave, or setting one of the executable path options above.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Input validation errors:
|
||||
|
||||
- `Provide patch or both before and after text.`
|
||||
- Include both `before` and `after`, or provide `patch`.
|
||||
- `Provide either patch or before/after input, not both.`
|
||||
- Do not mix input modes.
|
||||
- `Invalid baseUrl: ...`
|
||||
- Use `http(s)` origin with optional path, no query/hash.
|
||||
- `{field} exceeds maximum size (...)`
|
||||
- Reduce payload size.
|
||||
- Large patch rejection
|
||||
- Reduce patch file count or total lines.
|
||||
|
||||
Viewer accessibility issues:
|
||||
|
||||
- Viewer URL resolves to `127.0.0.1` by default.
|
||||
- For remote access scenarios, either:
|
||||
- set plugin `viewerBaseUrl`, or
|
||||
- pass `baseUrl` per tool call, or
|
||||
- use `gateway.bind=custom` and `gateway.customBindHost`
|
||||
- If `gateway.trustedProxies` includes loopback for a same-host proxy (for example Tailscale Serve), raw loopback viewer requests without forwarded client-IP headers fail closed by design.
|
||||
- For that proxy topology:
|
||||
- prefer `mode: "file"` or `mode: "both"` when you only need an attachment, or
|
||||
- intentionally enable `security.allowRemoteViewer` and set plugin `viewerBaseUrl` or pass a proxy/public `baseUrl` when you need a shareable viewer URL
|
||||
- Enable `security.allowRemoteViewer` only when you intend external viewer access.
|
||||
|
||||
Unmodified-lines row has no expand button:
|
||||
|
||||
- This can happen for patch input when the patch does not carry expandable context.
|
||||
- This is expected and does not indicate a viewer failure.
|
||||
|
||||
Artifact not found:
|
||||
|
||||
- Artifact expired due TTL.
|
||||
- Token or path changed.
|
||||
- Cleanup removed stale data.
|
||||
|
||||
## Operational guidance
|
||||
|
||||
- Prefer `mode: "view"` for local interactive reviews in canvas.
|
||||
- Prefer `mode: "file"` for outbound chat channels that need an attachment.
|
||||
- Keep `allowRemoteViewer` disabled unless your deployment requires remote viewer URLs.
|
||||
- Set explicit short `ttlSeconds` for sensitive diffs.
|
||||
- Avoid sending secrets in diff input when not required.
|
||||
- If your channel compresses images aggressively (for example Telegram or WhatsApp), prefer PDF output (`fileFormat: "pdf"`).
|
||||
|
||||
Diff rendering engine:
|
||||
|
||||
- Powered by [Diffs](https://diffs.com).
|
||||
|
||||
## Related docs
|
||||
|
||||
- [Tools overview](/tools)
|
||||
- [Plugins](/tools/plugin)
|
||||
- [Browser](/tools/browser)
|
||||
102
openclaw/docs/tools/duckduckgo-search.md
Normal file
102
openclaw/docs/tools/duckduckgo-search.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
summary: "DuckDuckGo web search -- key-free fallback provider (experimental, HTML-based)"
|
||||
read_when:
|
||||
- You want a web search provider that requires no API key
|
||||
- You want to use DuckDuckGo for web_search
|
||||
- You need a zero-config search fallback
|
||||
title: "DuckDuckGo Search"
|
||||
---
|
||||
|
||||
# DuckDuckGo Search
|
||||
|
||||
OpenClaw supports DuckDuckGo as a **key-free** `web_search` provider. No API
|
||||
key or account is required.
|
||||
|
||||
<Warning>
|
||||
DuckDuckGo is an **experimental, unofficial** integration that pulls results
|
||||
from DuckDuckGo's non-JavaScript search pages — not an official API. Expect
|
||||
occasional breakage from bot-challenge pages or HTML changes.
|
||||
</Warning>
|
||||
|
||||
## Setup
|
||||
|
||||
No API key needed — just set DuckDuckGo as your provider:
|
||||
|
||||
<Steps>
|
||||
<Step title="Configure">
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
# Select "duckduckgo" as the provider
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "duckduckgo",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Optional plugin-level settings for region and SafeSearch:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
duckduckgo: {
|
||||
config: {
|
||||
webSearch: {
|
||||
region: "us-en", // DuckDuckGo region code
|
||||
safeSearch: "moderate", // "strict", "moderate", or "off"
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Tool parameters
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------ | ---------------------------------------------------------- |
|
||||
| `query` | Search query (required) |
|
||||
| `count` | Results to return (1-10, default: 5) |
|
||||
| `region` | DuckDuckGo region code (e.g. `us-en`, `uk-en`, `de-de`) |
|
||||
| `safeSearch` | SafeSearch level: `strict`, `moderate` (default), or `off` |
|
||||
|
||||
Region and SafeSearch can also be set in plugin config (see above) — tool
|
||||
parameters override config values per-query.
|
||||
|
||||
## Notes
|
||||
|
||||
- **No API key** — works out of the box, zero configuration
|
||||
- **Experimental** — gathers results from DuckDuckGo's non-JavaScript HTML
|
||||
search pages, not an official API or SDK
|
||||
- **Bot-challenge risk** — DuckDuckGo may serve CAPTCHAs or block requests
|
||||
under heavy or automated use
|
||||
- **HTML parsing** — results depend on page structure, which can change without
|
||||
notice
|
||||
- **Auto-detection order** — DuckDuckGo is the first key-free fallback
|
||||
(order 100) in auto-detection. API-backed providers with configured keys run
|
||||
first, then Ollama Web Search (order 110), then SearXNG (order 200)
|
||||
- **SafeSearch defaults to moderate** when not configured
|
||||
|
||||
<Tip>
|
||||
For production use, consider [Brave Search](/tools/brave-search) (free tier
|
||||
available) or another API-backed provider.
|
||||
</Tip>
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Brave Search](/tools/brave-search) -- structured results with free tier
|
||||
- [Exa Search](/tools/exa-search) -- neural search with content extraction
|
||||
116
openclaw/docs/tools/elevated.md
Normal file
116
openclaw/docs/tools/elevated.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
---
|
||||
summary: "Elevated exec mode: run commands outside the sandbox from a sandboxed agent"
|
||||
read_when:
|
||||
- Adjusting elevated mode defaults, allowlists, or slash command behavior
|
||||
- Understanding how sandboxed agents can access the host
|
||||
title: "Elevated Mode"
|
||||
---
|
||||
|
||||
# Elevated Mode
|
||||
|
||||
When an agent runs inside a sandbox, its `exec` commands are confined to the
|
||||
sandbox environment. **Elevated mode** lets the agent break out and run commands
|
||||
outside the sandbox instead, with configurable approval gates.
|
||||
|
||||
<Info>
|
||||
Elevated mode only changes behavior when the agent is **sandboxed**. For
|
||||
unsandboxed agents, exec already runs on the host.
|
||||
</Info>
|
||||
|
||||
## Directives
|
||||
|
||||
Control elevated mode per-session with slash commands:
|
||||
|
||||
| Directive | What it does |
|
||||
| ---------------- | ---------------------------------------------------------------------- |
|
||||
| `/elevated on` | Run outside the sandbox on the configured host path, keep approvals |
|
||||
| `/elevated ask` | Same as `on` (alias) |
|
||||
| `/elevated full` | Run outside the sandbox on the configured host path and skip approvals |
|
||||
| `/elevated off` | Return to sandbox-confined execution |
|
||||
|
||||
Also available as `/elev on|off|ask|full`.
|
||||
|
||||
Send `/elevated` with no argument to see the current level.
|
||||
|
||||
## How it works
|
||||
|
||||
<Steps>
|
||||
<Step title="Check availability">
|
||||
Elevated must be enabled in config and the sender must be on the allowlist:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
elevated: {
|
||||
enabled: true,
|
||||
allowFrom: {
|
||||
discord: ["user-id-123"],
|
||||
whatsapp: ["+15555550123"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Set the level">
|
||||
Send a directive-only message to set the session default:
|
||||
|
||||
```
|
||||
/elevated full
|
||||
```
|
||||
|
||||
Or use it inline (applies to that message only):
|
||||
|
||||
```
|
||||
/elevated on run the deployment script
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Commands run outside the sandbox">
|
||||
With elevated active, `exec` calls leave the sandbox. The effective host is
|
||||
`gateway` by default, or `node` when the configured/session exec target is
|
||||
`node`. In `full` mode, exec approvals are skipped. In `on`/`ask` mode,
|
||||
configured approval rules still apply.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Resolution order
|
||||
|
||||
1. **Inline directive** on the message (applies only to that message)
|
||||
2. **Session override** (set by sending a directive-only message)
|
||||
3. **Global default** (`agents.defaults.elevatedDefault` in config)
|
||||
|
||||
## Availability and allowlists
|
||||
|
||||
- **Global gate**: `tools.elevated.enabled` (must be `true`)
|
||||
- **Sender allowlist**: `tools.elevated.allowFrom` with per-channel lists
|
||||
- **Per-agent gate**: `agents.list[].tools.elevated.enabled` (can only further restrict)
|
||||
- **Per-agent allowlist**: `agents.list[].tools.elevated.allowFrom` (sender must match both global + per-agent)
|
||||
- **Discord fallback**: if `tools.elevated.allowFrom.discord` is omitted, `channels.discord.allowFrom` is used as fallback
|
||||
- **All gates must pass**; otherwise elevated is treated as unavailable
|
||||
|
||||
Allowlist entry formats:
|
||||
|
||||
| Prefix | Matches |
|
||||
| ----------------------- | ------------------------------- |
|
||||
| (none) | Sender ID, E.164, or From field |
|
||||
| `name:` | Sender display name |
|
||||
| `username:` | Sender username |
|
||||
| `tag:` | Sender tag |
|
||||
| `id:`, `from:`, `e164:` | Explicit identity targeting |
|
||||
|
||||
## What elevated does not control
|
||||
|
||||
- **Tool policy**: if `exec` is denied by tool policy, elevated cannot override it
|
||||
- **Host selection policy**: elevated does not turn `auto` into a free cross-host override. It uses the configured/session exec target rules, choosing `node` only when the target is already `node`.
|
||||
- **Separate from `/exec`**: the `/exec` directive adjusts per-session exec defaults for authorized senders and does not require elevated mode
|
||||
|
||||
## Related
|
||||
|
||||
- [Exec tool](/tools/exec) — shell command execution
|
||||
- [Exec approvals](/tools/exec-approvals) — approval and allowlist system
|
||||
- [Sandboxing](/gateway/sandboxing) — sandbox configuration
|
||||
- [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated)
|
||||
127
openclaw/docs/tools/exa-search.md
Normal file
127
openclaw/docs/tools/exa-search.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
---
|
||||
summary: "Exa AI search -- neural and keyword search with content extraction"
|
||||
read_when:
|
||||
- You want to use Exa for web_search
|
||||
- You need an EXA_API_KEY
|
||||
- You want neural search or content extraction
|
||||
title: "Exa Search"
|
||||
---
|
||||
|
||||
# Exa Search
|
||||
|
||||
OpenClaw supports [Exa AI](https://exa.ai/) as a `web_search` provider. Exa
|
||||
offers neural, keyword, and hybrid search modes with built-in content
|
||||
extraction (highlights, text, summaries).
|
||||
|
||||
## Get an API key
|
||||
|
||||
<Steps>
|
||||
<Step title="Create an account">
|
||||
Sign up at [exa.ai](https://exa.ai/) and generate an API key from your
|
||||
dashboard.
|
||||
</Step>
|
||||
<Step title="Store the key">
|
||||
Set `EXA_API_KEY` in the Gateway environment, or configure via:
|
||||
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
exa: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "exa-...", // optional if EXA_API_KEY is set
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "exa",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Environment alternative:** set `EXA_API_KEY` in the Gateway environment.
|
||||
For a gateway install, put it in `~/.openclaw/.env`.
|
||||
|
||||
## Tool parameters
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------- | ----------------------------------------------------------------------------- |
|
||||
| `query` | Search query (required) |
|
||||
| `count` | Results to return (1-100) |
|
||||
| `type` | Search mode: `auto`, `neural`, `fast`, `deep`, `deep-reasoning`, or `instant` |
|
||||
| `freshness` | Time filter: `day`, `week`, `month`, or `year` |
|
||||
| `date_after` | Results after this date (YYYY-MM-DD) |
|
||||
| `date_before` | Results before this date (YYYY-MM-DD) |
|
||||
| `contents` | Content extraction options (see below) |
|
||||
|
||||
### Content extraction
|
||||
|
||||
Exa can return extracted content alongside search results. Pass a `contents`
|
||||
object to enable:
|
||||
|
||||
```javascript
|
||||
await web_search({
|
||||
query: "transformer architecture explained",
|
||||
type: "neural",
|
||||
contents: {
|
||||
text: true, // full page text
|
||||
highlights: { numSentences: 3 }, // key sentences
|
||||
summary: true, // AI summary
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
| Contents option | Type | Description |
|
||||
| --------------- | --------------------------------------------------------------------- | ---------------------- |
|
||||
| `text` | `boolean \| { maxCharacters }` | Extract full page text |
|
||||
| `highlights` | `boolean \| { maxCharacters, query, numSentences, highlightsPerUrl }` | Extract key sentences |
|
||||
| `summary` | `boolean \| { query }` | AI-generated summary |
|
||||
|
||||
### Search modes
|
||||
|
||||
| Mode | Description |
|
||||
| ---------------- | --------------------------------- |
|
||||
| `auto` | Exa picks the best mode (default) |
|
||||
| `neural` | Semantic/meaning-based search |
|
||||
| `fast` | Quick keyword search |
|
||||
| `deep` | Thorough deep search |
|
||||
| `deep-reasoning` | Deep search with reasoning |
|
||||
| `instant` | Fastest results |
|
||||
|
||||
## Notes
|
||||
|
||||
- If no `contents` option is provided, Exa defaults to `{ highlights: true }`
|
||||
so results include key sentence excerpts
|
||||
- Results preserve `highlightScores` and `summary` fields from the Exa API
|
||||
response when available
|
||||
- Result descriptions are resolved from highlights first, then summary, then
|
||||
full text — whichever is available
|
||||
- `freshness` and `date_after`/`date_before` cannot be combined — use one
|
||||
time-filter mode
|
||||
- Up to 100 results can be returned per query (subject to Exa search-type
|
||||
limits)
|
||||
- Results are cached for 15 minutes by default (configurable via
|
||||
`cacheTtlMinutes`)
|
||||
- Exa is an official API integration with structured JSON responses
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Brave Search](/tools/brave-search) -- structured results with country/language filters
|
||||
- [Perplexity Search](/tools/perplexity-search) -- structured results with domain filtering
|
||||
661
openclaw/docs/tools/exec-approvals.md
Normal file
661
openclaw/docs/tools/exec-approvals.md
Normal file
|
|
@ -0,0 +1,661 @@
|
|||
---
|
||||
summary: "Exec approvals, allowlists, and sandbox escape prompts"
|
||||
read_when:
|
||||
- Configuring exec approvals or allowlists
|
||||
- Implementing exec approval UX in the macOS app
|
||||
- Reviewing sandbox escape prompts and implications
|
||||
title: "Exec Approvals"
|
||||
---
|
||||
|
||||
# Exec approvals
|
||||
|
||||
Exec approvals are the **companion app / node host guardrail** for letting a sandboxed agent run
|
||||
commands on a real host (`gateway` or `node`). Think of it like a safety interlock:
|
||||
commands are allowed only when policy + allowlist + (optional) user approval all agree.
|
||||
Exec approvals are **in addition** to tool policy and elevated gating (unless elevated is set to `full`, which skips approvals).
|
||||
Effective policy is the **stricter** of `tools.exec.*` and approvals defaults; if an approvals field is omitted, the `tools.exec` value is used.
|
||||
Host exec also uses the local approvals state on that machine. A host-local
|
||||
`ask: "always"` in `~/.openclaw/exec-approvals.json` keeps prompting even if
|
||||
session or config defaults request `ask: "on-miss"`.
|
||||
Use `openclaw approvals get`, `openclaw approvals get --gateway`, or
|
||||
`openclaw approvals get --node <id|name|ip>` to inspect the requested policy,
|
||||
host policy sources, and the effective result.
|
||||
For the local machine, `openclaw exec-policy show` exposes the same merged view and
|
||||
`openclaw exec-policy set|preset` can synchronize the local requested policy with the
|
||||
local host approvals file in one step. When a local scope requests `host=node`,
|
||||
`openclaw exec-policy show` reports that scope as node-managed at runtime instead of
|
||||
pretending the local approvals file is the effective source of truth.
|
||||
|
||||
If the companion app UI is **not available**, any request that requires a prompt is
|
||||
resolved by the **ask fallback** (default: deny).
|
||||
|
||||
Native chat approval clients can also expose channel-specific affordances on the
|
||||
pending approval message. For example, Matrix can seed reaction shortcuts on the
|
||||
approval prompt (`✅` allow once, `❌` deny, and `♾️` allow always when available)
|
||||
while still leaving the `/approve ...` commands in the message as a fallback.
|
||||
|
||||
## Where it applies
|
||||
|
||||
Exec approvals are enforced locally on the execution host:
|
||||
|
||||
- **gateway host** → `openclaw` process on the gateway machine
|
||||
- **node host** → node runner (macOS companion app or headless node host)
|
||||
|
||||
Trust model note:
|
||||
|
||||
- Gateway-authenticated callers are trusted operators for that Gateway.
|
||||
- Paired nodes extend that trusted operator capability onto the node host.
|
||||
- Exec approvals reduce accidental execution risk, but are not a per-user auth boundary.
|
||||
- Approved node-host runs bind canonical execution context: canonical cwd, exact argv, env
|
||||
binding when present, and pinned executable path when applicable.
|
||||
- For shell scripts and direct interpreter/runtime file invocations, OpenClaw also tries to bind
|
||||
one concrete local file operand. If that bound file changes after approval but before execution,
|
||||
the run is denied instead of executing drifted content.
|
||||
- This file binding is intentionally best-effort, not a complete semantic model of every
|
||||
interpreter/runtime loader path. If approval mode cannot identify exactly one concrete local
|
||||
file to bind, it refuses to mint an approval-backed run instead of pretending full coverage.
|
||||
|
||||
macOS split:
|
||||
|
||||
- **node host service** forwards `system.run` to the **macOS app** over local IPC.
|
||||
- **macOS app** enforces approvals + executes the command in UI context.
|
||||
|
||||
## Settings and storage
|
||||
|
||||
Approvals live in a local JSON file on the execution host:
|
||||
|
||||
`~/.openclaw/exec-approvals.json`
|
||||
|
||||
Example schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"socket": {
|
||||
"path": "~/.openclaw/exec-approvals.sock",
|
||||
"token": "base64url-token"
|
||||
},
|
||||
"defaults": {
|
||||
"security": "deny",
|
||||
"ask": "on-miss",
|
||||
"askFallback": "deny",
|
||||
"autoAllowSkills": false
|
||||
},
|
||||
"agents": {
|
||||
"main": {
|
||||
"security": "allowlist",
|
||||
"ask": "on-miss",
|
||||
"askFallback": "deny",
|
||||
"autoAllowSkills": true,
|
||||
"allowlist": [
|
||||
{
|
||||
"id": "B0C8C0B3-2C2D-4F8A-9A3C-5A4B3C2D1E0F",
|
||||
"pattern": "~/Projects/**/bin/rg",
|
||||
"lastUsedAt": 1737150000000,
|
||||
"lastUsedCommand": "rg -n TODO",
|
||||
"lastResolvedPath": "/Users/user/Projects/.../bin/rg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## No-approval "YOLO" mode
|
||||
|
||||
If you want host exec to run without approval prompts, you must open **both** policy layers:
|
||||
|
||||
- requested exec policy in OpenClaw config (`tools.exec.*`)
|
||||
- host-local approvals policy in `~/.openclaw/exec-approvals.json`
|
||||
|
||||
This is now the default host behavior unless you tighten it explicitly:
|
||||
|
||||
- `tools.exec.security`: `full` on `gateway`/`node`
|
||||
- `tools.exec.ask`: `off`
|
||||
- host `askFallback`: `full`
|
||||
|
||||
Important distinction:
|
||||
|
||||
- `tools.exec.host=auto` chooses where exec runs: sandbox when available, otherwise gateway.
|
||||
- YOLO chooses how host exec is approved: `security=full` plus `ask=off`.
|
||||
- In YOLO mode, OpenClaw does not add a separate heuristic command-obfuscation approval gate on top of the configured host exec policy.
|
||||
- `auto` does not make gateway routing a free override from a sandboxed session. A per-call `host=node` request is allowed from `auto`, and `host=gateway` is only allowed from `auto` when no sandbox runtime is active. If you want a stable non-auto default, set `tools.exec.host` or use `/exec host=...` explicitly.
|
||||
|
||||
If you want a more conservative setup, tighten either layer back to `allowlist` / `on-miss`
|
||||
or `deny`.
|
||||
|
||||
Persistent gateway-host "never prompt" setup:
|
||||
|
||||
```bash
|
||||
openclaw config set tools.exec.host gateway
|
||||
openclaw config set tools.exec.security full
|
||||
openclaw config set tools.exec.ask off
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
Then set the host approvals file to match:
|
||||
|
||||
```bash
|
||||
openclaw approvals set --stdin <<'EOF'
|
||||
{
|
||||
version: 1,
|
||||
defaults: {
|
||||
security: "full",
|
||||
ask: "off",
|
||||
askFallback: "full"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Local shortcut for the same gateway-host policy on the current machine:
|
||||
|
||||
```bash
|
||||
openclaw exec-policy preset yolo
|
||||
```
|
||||
|
||||
That local shortcut updates both:
|
||||
|
||||
- local `tools.exec.host/security/ask`
|
||||
- local `~/.openclaw/exec-approvals.json` defaults
|
||||
|
||||
It is intentionally local-only. If you need to change gateway-host or node-host approvals
|
||||
remotely, continue using `openclaw approvals set --gateway` or
|
||||
`openclaw approvals set --node <id|name|ip>`.
|
||||
|
||||
For a node host, apply the same approvals file on that node instead:
|
||||
|
||||
```bash
|
||||
openclaw approvals set --node <id|name|ip> --stdin <<'EOF'
|
||||
{
|
||||
version: 1,
|
||||
defaults: {
|
||||
security: "full",
|
||||
ask: "off",
|
||||
askFallback: "full"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
```
|
||||
|
||||
Important local-only limitation:
|
||||
|
||||
- `openclaw exec-policy` does not synchronize node approvals
|
||||
- `openclaw exec-policy set --host node` is rejected
|
||||
- node exec approvals are fetched from the node at runtime, so node-targeted updates must use `openclaw approvals --node ...`
|
||||
|
||||
Session-only shortcut:
|
||||
|
||||
- `/exec security=full ask=off` changes only the current session.
|
||||
- `/elevated full` is a break-glass shortcut that also skips exec approvals for that session.
|
||||
|
||||
If the host approvals file stays stricter than config, the stricter host policy still wins.
|
||||
|
||||
## Policy knobs
|
||||
|
||||
### Security (`exec.security`)
|
||||
|
||||
- **deny**: block all host exec requests.
|
||||
- **allowlist**: allow only allowlisted commands.
|
||||
- **full**: allow everything (equivalent to elevated).
|
||||
|
||||
### Ask (`exec.ask`)
|
||||
|
||||
- **off**: never prompt.
|
||||
- **on-miss**: prompt only when allowlist does not match.
|
||||
- **always**: prompt on every command.
|
||||
- `allow-always` durable trust does not suppress prompts when effective ask mode is `always`
|
||||
|
||||
### Ask fallback (`askFallback`)
|
||||
|
||||
If a prompt is required but no UI is reachable, fallback decides:
|
||||
|
||||
- **deny**: block.
|
||||
- **allowlist**: allow only if allowlist matches.
|
||||
- **full**: allow.
|
||||
|
||||
### Inline interpreter eval hardening (`tools.exec.strictInlineEval`)
|
||||
|
||||
When `tools.exec.strictInlineEval=true`, OpenClaw treats inline code-eval forms as approval-only even if the interpreter binary itself is allowlisted.
|
||||
|
||||
Examples:
|
||||
|
||||
- `python -c`
|
||||
- `node -e`, `node --eval`, `node -p`
|
||||
- `ruby -e`
|
||||
- `perl -e`, `perl -E`
|
||||
- `php -r`
|
||||
- `lua -e`
|
||||
- `osascript -e`
|
||||
|
||||
This is defense-in-depth for interpreter loaders that do not map cleanly to one stable file operand. In strict mode:
|
||||
|
||||
- these commands still need explicit approval;
|
||||
- `allow-always` does not persist new allowlist entries for them automatically.
|
||||
|
||||
## Allowlist (per agent)
|
||||
|
||||
Allowlists are **per agent**. If multiple agents exist, switch which agent you’re
|
||||
editing in the macOS app. Patterns are **case-insensitive glob matches**.
|
||||
Patterns should resolve to **binary paths** (basename-only entries are ignored).
|
||||
Legacy `agents.default` entries are migrated to `agents.main` on load.
|
||||
Shell chains such as `echo ok && pwd` still need every top-level segment to satisfy allowlist rules.
|
||||
|
||||
Examples:
|
||||
|
||||
- `~/Projects/**/bin/peekaboo`
|
||||
- `~/.local/bin/*`
|
||||
- `/opt/homebrew/bin/rg`
|
||||
|
||||
Each allowlist entry tracks:
|
||||
|
||||
- **id** stable UUID used for UI identity (optional)
|
||||
- **last used** timestamp
|
||||
- **last used command**
|
||||
- **last resolved path**
|
||||
|
||||
## Auto-allow skill CLIs
|
||||
|
||||
When **Auto-allow skill CLIs** is enabled, executables referenced by known skills
|
||||
are treated as allowlisted on nodes (macOS node or headless node host). This uses
|
||||
`skills.bins` over the Gateway RPC to fetch the skill bin list. Disable this if you want strict manual allowlists.
|
||||
|
||||
Important trust notes:
|
||||
|
||||
- This is an **implicit convenience allowlist**, separate from manual path allowlist entries.
|
||||
- It is intended for trusted operator environments where Gateway and node are in the same trust boundary.
|
||||
- If you require strict explicit trust, keep `autoAllowSkills: false` and use manual path allowlist entries only.
|
||||
|
||||
## Safe bins (stdin-only)
|
||||
|
||||
`tools.exec.safeBins` defines a small list of **stdin-only** binaries (for example `cut`)
|
||||
that can run in allowlist mode **without** explicit allowlist entries. Safe bins reject
|
||||
positional file args and path-like tokens, so they can only operate on the incoming stream.
|
||||
Treat this as a narrow fast-path for stream filters, not a general trust list.
|
||||
Do **not** add interpreter or runtime binaries (for example `python3`, `node`, `ruby`, `bash`, `sh`, `zsh`) to `safeBins`.
|
||||
If a command can evaluate code, execute subcommands, or read files by design, prefer explicit allowlist entries and keep approval prompts enabled.
|
||||
Custom safe bins must define an explicit profile in `tools.exec.safeBinProfiles.<bin>`.
|
||||
Validation is deterministic from argv shape only (no host filesystem existence checks), which
|
||||
prevents file-existence oracle behavior from allow/deny differences.
|
||||
File-oriented options are denied for default safe bins (for example `sort -o`, `sort --output`,
|
||||
`sort --files0-from`, `sort --compress-program`, `sort --random-source`,
|
||||
`sort --temporary-directory`/`-T`, `wc --files0-from`, `jq -f/--from-file`,
|
||||
`grep -f/--file`).
|
||||
Safe bins also enforce explicit per-binary flag policy for options that break stdin-only
|
||||
behavior (for example `sort -o/--output/--compress-program` and grep recursive flags).
|
||||
Long options are validated fail-closed in safe-bin mode: unknown flags and ambiguous
|
||||
abbreviations are rejected.
|
||||
Denied flags by safe-bin profile:
|
||||
|
||||
[//]: # "SAFE_BIN_DENIED_FLAGS:START"
|
||||
|
||||
- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r`
|
||||
- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f`
|
||||
- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o`
|
||||
- `wc`: `--files0-from`
|
||||
|
||||
[//]: # "SAFE_BIN_DENIED_FLAGS:END"
|
||||
|
||||
Safe bins also force argv tokens to be treated as **literal text** at execution time (no globbing
|
||||
and no `$VARS` expansion) for stdin-only segments, so patterns like `*` or `$HOME/...` cannot be
|
||||
used to smuggle file reads.
|
||||
Safe bins must also resolve from trusted binary directories (system defaults plus optional
|
||||
`tools.exec.safeBinTrustedDirs`). `PATH` entries are never auto-trusted.
|
||||
Default trusted safe-bin directories are intentionally minimal: `/bin`, `/usr/bin`.
|
||||
If your safe-bin executable lives in package-manager/user paths (for example
|
||||
`/opt/homebrew/bin`, `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them explicitly
|
||||
to `tools.exec.safeBinTrustedDirs`.
|
||||
Shell chaining and redirections are not auto-allowed in allowlist mode.
|
||||
|
||||
Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment satisfies the allowlist
|
||||
(including safe bins or skill auto-allow). Redirections remain unsupported in allowlist mode.
|
||||
Command substitution (`$()` / backticks) is rejected during allowlist parsing, including inside
|
||||
double quotes; use single quotes if you need literal `$()` text.
|
||||
On macOS companion-app approvals, raw shell text containing shell control or expansion syntax
|
||||
(`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is treated as an allowlist miss unless
|
||||
the shell binary itself is allowlisted.
|
||||
For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env overrides are reduced to a
|
||||
small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`).
|
||||
For allow-always decisions in allowlist mode, known dispatch wrappers
|
||||
(`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist inner executable paths instead of wrapper
|
||||
paths. Shell multiplexers (`busybox`, `toybox`) are also unwrapped for shell applets (`sh`, `ash`,
|
||||
etc.) so inner executables are persisted instead of multiplexer binaries. If a wrapper or
|
||||
multiplexer cannot be safely unwrapped, no allowlist entry is persisted automatically.
|
||||
If you allowlist interpreters like `python3` or `node`, prefer `tools.exec.strictInlineEval=true` so inline eval still requires an explicit approval. In strict mode, `allow-always` can still persist benign interpreter/script invocations, but inline-eval carriers are not persisted automatically.
|
||||
|
||||
Default safe bins:
|
||||
|
||||
[//]: # "SAFE_BIN_DEFAULTS:START"
|
||||
|
||||
`cut`, `uniq`, `head`, `tail`, `tr`, `wc`
|
||||
|
||||
[//]: # "SAFE_BIN_DEFAULTS:END"
|
||||
|
||||
`grep` and `sort` are not in the default list. If you opt in, keep explicit allowlist entries for
|
||||
their non-stdin workflows.
|
||||
For `grep` in safe-bin mode, provide the pattern with `-e`/`--regexp`; positional pattern form is
|
||||
rejected so file operands cannot be smuggled as ambiguous positionals.
|
||||
|
||||
### Safe bins versus allowlist
|
||||
|
||||
| Topic | `tools.exec.safeBins` | Allowlist (`exec-approvals.json`) |
|
||||
| ---------------- | ------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| Goal | Auto-allow narrow stdin filters | Explicitly trust specific executables |
|
||||
| Match type | Executable name + safe-bin argv policy | Resolved executable path glob pattern |
|
||||
| Argument scope | Restricted by safe-bin profile and literal-token rules | Path match only; arguments are otherwise your responsibility |
|
||||
| Typical examples | `head`, `tail`, `tr`, `wc` | `jq`, `python3`, `node`, `ffmpeg`, custom CLIs |
|
||||
| Best use | Low-risk text transforms in pipelines | Any tool with broader behavior or side effects |
|
||||
|
||||
Configuration location:
|
||||
|
||||
- `safeBins` comes from config (`tools.exec.safeBins` or per-agent `agents.list[].tools.exec.safeBins`).
|
||||
- `safeBinTrustedDirs` comes from config (`tools.exec.safeBinTrustedDirs` or per-agent `agents.list[].tools.exec.safeBinTrustedDirs`).
|
||||
- `safeBinProfiles` comes from config (`tools.exec.safeBinProfiles` or per-agent `agents.list[].tools.exec.safeBinProfiles`). Per-agent profile keys override global keys.
|
||||
- allowlist entries live in host-local `~/.openclaw/exec-approvals.json` under `agents.<id>.allowlist` (or via Control UI / `openclaw approvals allowlist ...`).
|
||||
- `openclaw security audit` warns with `tools.exec.safe_bins_interpreter_unprofiled` when interpreter/runtime bins appear in `safeBins` without explicit profiles.
|
||||
- `openclaw doctor --fix` can scaffold missing custom `safeBinProfiles.<bin>` entries as `{}` (review and tighten afterward). Interpreter/runtime bins are not auto-scaffolded.
|
||||
|
||||
Custom profile example:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
exec: {
|
||||
safeBins: ["jq", "myfilter"],
|
||||
safeBinProfiles: {
|
||||
myfilter: {
|
||||
minPositional: 0,
|
||||
maxPositional: 0,
|
||||
allowedValueFlags: ["-n", "--limit"],
|
||||
deniedFlags: ["-f", "--file", "-c", "--command"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If you explicitly opt `jq` into `safeBins`, OpenClaw still rejects the `env` builtin in safe-bin
|
||||
mode so `jq -n env` cannot dump the host process environment without an explicit allowlist path
|
||||
or approval prompt.
|
||||
|
||||
## Control UI editing
|
||||
|
||||
Use the **Control UI → Nodes → Exec approvals** card to edit defaults, per‑agent
|
||||
overrides, and allowlists. Pick a scope (Defaults or an agent), tweak the policy,
|
||||
add/remove allowlist patterns, then **Save**. The UI shows **last used** metadata
|
||||
per pattern so you can keep the list tidy.
|
||||
|
||||
The target selector chooses **Gateway** (local approvals) or a **Node**. Nodes
|
||||
must advertise `system.execApprovals.get/set` (macOS app or headless node host).
|
||||
If a node does not advertise exec approvals yet, edit its local
|
||||
`~/.openclaw/exec-approvals.json` directly.
|
||||
|
||||
CLI: `openclaw approvals` supports gateway or node editing (see [Approvals CLI](/cli/approvals)).
|
||||
|
||||
## Approval flow
|
||||
|
||||
When a prompt is required, the gateway broadcasts `exec.approval.requested` to operator clients.
|
||||
The Control UI and macOS app resolve it via `exec.approval.resolve`, then the gateway forwards the
|
||||
approved request to the node host.
|
||||
|
||||
For `host=node`, approval requests include a canonical `systemRunPlan` payload. The gateway uses
|
||||
that plan as the authoritative command/cwd/session context when forwarding approved `system.run`
|
||||
requests.
|
||||
|
||||
That matters for async approval latency:
|
||||
|
||||
- the node exec path prepares one canonical plan up front
|
||||
- the approval record stores that plan and its binding metadata
|
||||
- once approved, the final forwarded `system.run` call reuses the stored plan
|
||||
instead of trusting later caller edits
|
||||
- if the caller changes `command`, `rawCommand`, `cwd`, `agentId`, or
|
||||
`sessionKey` after the approval request was created, the gateway rejects the
|
||||
forwarded run as an approval mismatch
|
||||
|
||||
## Interpreter/runtime commands
|
||||
|
||||
Approval-backed interpreter/runtime runs are intentionally conservative:
|
||||
|
||||
- Exact argv/cwd/env context is always bound.
|
||||
- Direct shell script and direct runtime file forms are best-effort bound to one concrete local
|
||||
file snapshot.
|
||||
- Common package-manager wrapper forms that still resolve to one direct local file (for example
|
||||
`pnpm exec`, `pnpm node`, `npm exec`, `npx`) are unwrapped before binding.
|
||||
- If OpenClaw cannot identify exactly one concrete local file for an interpreter/runtime command
|
||||
(for example package scripts, eval forms, runtime-specific loader chains, or ambiguous multi-file
|
||||
forms), approval-backed execution is denied instead of claiming semantic coverage it does not
|
||||
have.
|
||||
- For those workflows, prefer sandboxing, a separate host boundary, or an explicit trusted
|
||||
allowlist/full workflow where the operator accepts the broader runtime semantics.
|
||||
|
||||
When approvals are required, the exec tool returns immediately with an approval id. Use that id to
|
||||
correlate later system events (`Exec finished` / `Exec denied`). If no decision arrives before the
|
||||
timeout, the request is treated as an approval timeout and surfaced as a denial reason.
|
||||
|
||||
### Followup delivery behavior
|
||||
|
||||
After an approved async exec finishes, OpenClaw sends a followup `agent` turn to the same session.
|
||||
|
||||
- If a valid external delivery target exists (deliverable channel plus target `to`), followup delivery uses that channel.
|
||||
- In webchat-only or internal-session flows with no external target, followup delivery stays session-only (`deliver: false`).
|
||||
- If a caller explicitly requests strict external delivery with no resolvable external channel, the request fails with `INVALID_REQUEST`.
|
||||
- If `bestEffortDeliver` is enabled and no external channel can be resolved, delivery is downgraded to session-only instead of failing.
|
||||
|
||||
The confirmation dialog includes:
|
||||
|
||||
- command + args
|
||||
- cwd
|
||||
- agent id
|
||||
- resolved executable path
|
||||
- host + policy metadata
|
||||
|
||||
Actions:
|
||||
|
||||
- **Allow once** → run now
|
||||
- **Always allow** → add to allowlist + run
|
||||
- **Deny** → block
|
||||
|
||||
## Approval forwarding to chat channels
|
||||
|
||||
You can forward exec approval prompts to any chat channel (including plugin channels) and approve
|
||||
them with `/approve`. This uses the normal outbound delivery pipeline.
|
||||
|
||||
Config:
|
||||
|
||||
```json5
|
||||
{
|
||||
approvals: {
|
||||
exec: {
|
||||
enabled: true,
|
||||
mode: "session", // "session" | "targets" | "both"
|
||||
agentFilter: ["main"],
|
||||
sessionFilter: ["discord"], // substring or regex
|
||||
targets: [
|
||||
{ channel: "slack", to: "U12345678" },
|
||||
{ channel: "telegram", to: "123456789" },
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Reply in chat:
|
||||
|
||||
```
|
||||
/approve <id> allow-once
|
||||
/approve <id> allow-always
|
||||
/approve <id> deny
|
||||
```
|
||||
|
||||
The `/approve` command handles both exec approvals and plugin approvals. If the ID does not match a pending exec approval, it automatically checks plugin approvals instead.
|
||||
|
||||
### Plugin approval forwarding
|
||||
|
||||
Plugin approval forwarding uses the same delivery pipeline as exec approvals but has its own
|
||||
independent config under `approvals.plugin`. Enabling or disabling one does not affect the other.
|
||||
|
||||
```json5
|
||||
{
|
||||
approvals: {
|
||||
plugin: {
|
||||
enabled: true,
|
||||
mode: "targets",
|
||||
agentFilter: ["main"],
|
||||
targets: [
|
||||
{ channel: "slack", to: "U12345678" },
|
||||
{ channel: "telegram", to: "123456789" },
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The config shape is identical to `approvals.exec`: `enabled`, `mode`, `agentFilter`,
|
||||
`sessionFilter`, and `targets` work the same way.
|
||||
|
||||
Channels that support shared interactive replies render the same approval buttons for both exec and
|
||||
plugin approvals. Channels without shared interactive UI fall back to plain text with `/approve`
|
||||
instructions.
|
||||
|
||||
### Same-chat approvals on any channel
|
||||
|
||||
When an exec or plugin approval request originates from a deliverable chat surface, the same chat
|
||||
can now approve it with `/approve` by default. This applies to channels such as Slack, Matrix, and
|
||||
Microsoft Teams in addition to the existing Web UI and terminal UI flows.
|
||||
|
||||
This shared text-command path uses the normal channel auth model for that conversation. If the
|
||||
originating chat can already send commands and receive replies, approval requests no longer need a
|
||||
separate native delivery adapter just to stay pending.
|
||||
|
||||
Discord and Telegram also support same-chat `/approve`, but those channels still use their
|
||||
resolved approver list for authorization even when native approval delivery is disabled.
|
||||
|
||||
For Telegram and other native approval clients that call the Gateway directly,
|
||||
this fallback is intentionally bounded to "approval not found" failures. A real
|
||||
exec approval denial/error does not silently retry as a plugin approval.
|
||||
|
||||
### Native approval delivery
|
||||
|
||||
Some channels can also act as native approval clients. Native clients add approver DMs, origin-chat
|
||||
fanout, and channel-specific interactive approval UX on top of the shared same-chat `/approve`
|
||||
flow.
|
||||
|
||||
When native approval cards/buttons are available, that native UI is the primary
|
||||
agent-facing path. The agent should not also echo a duplicate plain chat
|
||||
`/approve` command unless the tool result says chat approvals are unavailable or
|
||||
manual approval is the only remaining path.
|
||||
|
||||
Generic model:
|
||||
|
||||
- host exec policy still decides whether exec approval is required
|
||||
- `approvals.exec` controls forwarding approval prompts to other chat destinations
|
||||
- `channels.<channel>.execApprovals` controls whether that channel acts as a native approval client
|
||||
|
||||
Native approval clients auto-enable DM-first delivery when all of these are true:
|
||||
|
||||
- the channel supports native approval delivery
|
||||
- approvers can be resolved from explicit `execApprovals.approvers` or that
|
||||
channel's documented fallback sources
|
||||
- `channels.<channel>.execApprovals.enabled` is unset or `"auto"`
|
||||
|
||||
Set `enabled: false` to disable a native approval client explicitly. Set `enabled: true` to force
|
||||
it on when approvers resolve. Public origin-chat delivery stays explicit through
|
||||
`channels.<channel>.execApprovals.target`.
|
||||
|
||||
FAQ: [Why are there two exec approval configs for chat approvals?](/help/faq#why-are-there-two-exec-approval-configs-for-chat-approvals)
|
||||
|
||||
- Discord: `channels.discord.execApprovals.*`
|
||||
- Slack: `channels.slack.execApprovals.*`
|
||||
- Telegram: `channels.telegram.execApprovals.*`
|
||||
|
||||
These native approval clients add DM routing and optional channel fanout on top of the shared
|
||||
same-chat `/approve` flow and shared approval buttons.
|
||||
|
||||
Shared behavior:
|
||||
|
||||
- Slack, Matrix, Microsoft Teams, and similar deliverable chats use the normal channel auth model
|
||||
for same-chat `/approve`
|
||||
- when a native approval client auto-enables, the default native delivery target is approver DMs
|
||||
- for Discord and Telegram, only resolved approvers can approve or deny
|
||||
- Discord approvers can be explicit (`execApprovals.approvers`) or inferred from `commands.ownerAllowFrom`
|
||||
- Telegram approvers can be explicit (`execApprovals.approvers`) or inferred from existing owner config (`allowFrom`, plus direct-message `defaultTo` where supported)
|
||||
- Slack approvers can be explicit (`execApprovals.approvers`) or inferred from `commands.ownerAllowFrom`
|
||||
- Slack native buttons preserve approval id kind, so `plugin:` ids can resolve plugin approvals
|
||||
without a second Slack-local fallback layer
|
||||
- Matrix native DM/channel routing and reaction shortcuts handle both exec and plugin approvals;
|
||||
plugin authorization still comes from `channels.matrix.dm.allowFrom`
|
||||
- the requester does not need to be an approver
|
||||
- the originating chat can approve directly with `/approve` when that chat already supports commands and replies
|
||||
- native Discord approval buttons route by approval id kind: `plugin:` ids go
|
||||
straight to plugin approvals, everything else goes to exec approvals
|
||||
- native Telegram approval buttons follow the same bounded exec-to-plugin fallback as `/approve`
|
||||
- when native `target` enables origin-chat delivery, approval prompts include the command text
|
||||
- pending exec approvals expire after 30 minutes by default
|
||||
- if no operator UI or configured approval client can accept the request, the prompt falls back to `askFallback`
|
||||
|
||||
Telegram defaults to approver DMs (`target: "dm"`). You can switch to `channel` or `both` when you
|
||||
want approval prompts to appear in the originating Telegram chat/topic as well. For Telegram forum
|
||||
topics, OpenClaw preserves the topic for the approval prompt and the post-approval follow-up.
|
||||
|
||||
See:
|
||||
|
||||
- [Discord](/channels/discord)
|
||||
- [Telegram](/channels/telegram)
|
||||
|
||||
### macOS IPC flow
|
||||
|
||||
```
|
||||
Gateway -> Node Service (WS)
|
||||
| IPC (UDS + token + HMAC + TTL)
|
||||
v
|
||||
Mac App (UI + approvals + system.run)
|
||||
```
|
||||
|
||||
Security notes:
|
||||
|
||||
- Unix socket mode `0600`, token stored in `exec-approvals.json`.
|
||||
- Same-UID peer check.
|
||||
- Challenge/response (nonce + HMAC token + request hash) + short TTL.
|
||||
|
||||
## System events
|
||||
|
||||
Exec lifecycle is surfaced as system messages:
|
||||
|
||||
- `Exec running` (only if the command exceeds the running notice threshold)
|
||||
- `Exec finished`
|
||||
- `Exec denied`
|
||||
|
||||
These are posted to the agent’s session after the node reports the event.
|
||||
Gateway-host exec approvals emit the same lifecycle events when the command finishes (and optionally when running longer than the threshold).
|
||||
Approval-gated execs reuse the approval id as the `runId` in these messages for easy correlation.
|
||||
|
||||
## Denied approval behavior
|
||||
|
||||
When an async exec approval is denied, OpenClaw prevents the agent from reusing
|
||||
output from any earlier run of the same command in the session. The denial reason
|
||||
is passed with explicit guidance that no command output is available, which stops
|
||||
the agent from claiming there is new output or repeating the denied command with
|
||||
stale results from a prior successful run.
|
||||
|
||||
## Implications
|
||||
|
||||
- **full** is powerful; prefer allowlists when possible.
|
||||
- **ask** keeps you in the loop while still allowing fast approvals.
|
||||
- Per-agent allowlists prevent one agent’s approvals from leaking into others.
|
||||
- Approvals only apply to host exec requests from **authorized senders**. Unauthorized senders cannot issue `/exec`.
|
||||
- `/exec security=full` is a session-level convenience for authorized operators and skips approvals by design.
|
||||
To hard-block host exec, set approvals security to `deny` or deny the `exec` tool via tool policy.
|
||||
|
||||
Related:
|
||||
|
||||
- [Exec tool](/tools/exec)
|
||||
- [Elevated mode](/tools/elevated)
|
||||
- [Skills](/tools/skills)
|
||||
|
||||
## Related
|
||||
|
||||
- [Exec](/tools/exec) — shell command execution tool
|
||||
- [Sandboxing](/gateway/sandboxing) — sandbox modes and workspace access
|
||||
- [Security](/gateway/security) — security model and hardening
|
||||
- [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) — when to use each
|
||||
237
openclaw/docs/tools/exec.md
Normal file
237
openclaw/docs/tools/exec.md
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
---
|
||||
summary: "Exec tool usage, stdin modes, and TTY support"
|
||||
read_when:
|
||||
- Using or modifying the exec tool
|
||||
- Debugging stdin or TTY behavior
|
||||
title: "Exec Tool"
|
||||
---
|
||||
|
||||
# Exec tool
|
||||
|
||||
Run shell commands in the workspace. Supports foreground + background execution via `process`.
|
||||
If `process` is disallowed, `exec` runs synchronously and ignores `yieldMs`/`background`.
|
||||
Background sessions are scoped per agent; `process` only sees sessions from the same agent.
|
||||
|
||||
## Parameters
|
||||
|
||||
- `command` (required)
|
||||
- `workdir` (defaults to cwd)
|
||||
- `env` (key/value overrides)
|
||||
- `yieldMs` (default 10000): auto-background after delay
|
||||
- `background` (bool): background immediately
|
||||
- `timeout` (seconds, default 1800): kill on expiry
|
||||
- `pty` (bool): run in a pseudo-terminal when available (TTY-only CLIs, coding agents, terminal UIs)
|
||||
- `host` (`auto | sandbox | gateway | node`): where to execute
|
||||
- `security` (`deny | allowlist | full`): enforcement mode for `gateway`/`node`
|
||||
- `ask` (`off | on-miss | always`): approval prompts for `gateway`/`node`
|
||||
- `node` (string): node id/name for `host=node`
|
||||
- `elevated` (bool): request elevated mode (escape the sandbox onto the configured host path); `security=full` is only forced when elevated resolves to `full`
|
||||
|
||||
Notes:
|
||||
|
||||
- `host` defaults to `auto`: sandbox when sandbox runtime is active for the session, otherwise gateway.
|
||||
- `auto` is the default routing strategy, not a wildcard. Per-call `host=node` is allowed from `auto`; per-call `host=gateway` is only allowed when no sandbox runtime is active.
|
||||
- With no extra config, `host=auto` still "just works": no sandbox means it resolves to `gateway`; a live sandbox means it stays in the sandbox.
|
||||
- `elevated` escapes the sandbox onto the configured host path: `gateway` by default, or `node` when `tools.exec.host=node` (or the session default is `host=node`). It is only available when elevated access is enabled for the current session/provider.
|
||||
- `gateway`/`node` approvals are controlled by `~/.openclaw/exec-approvals.json`.
|
||||
- `node` requires a paired node (companion app or headless node host).
|
||||
- If multiple nodes are available, set `exec.node` or `tools.exec.node` to select one.
|
||||
- `exec host=node` is the only shell-execution path for nodes; the legacy `nodes.run` wrapper has been removed.
|
||||
- On non-Windows hosts, exec uses `SHELL` when set; if `SHELL` is `fish`, it prefers `bash` (or `sh`)
|
||||
from `PATH` to avoid fish-incompatible scripts, then falls back to `SHELL` if neither exists.
|
||||
- On Windows hosts, exec prefers PowerShell 7 (`pwsh`) discovery (Program Files, ProgramW6432, then PATH),
|
||||
then falls back to Windows PowerShell 5.1.
|
||||
- Host execution (`gateway`/`node`) rejects `env.PATH` and loader overrides (`LD_*`/`DYLD_*`) to
|
||||
prevent binary hijacking or injected code.
|
||||
- OpenClaw sets `OPENCLAW_SHELL=exec` in the spawned command environment (including PTY and sandbox execution) so shell/profile rules can detect exec-tool context.
|
||||
- Important: sandboxing is **off by default**. If sandboxing is off, implicit `host=auto`
|
||||
resolves to `gateway`. Explicit `host=sandbox` still fails closed instead of silently
|
||||
running on the gateway host. Enable sandboxing or use `host=gateway` with approvals.
|
||||
- Script preflight checks (for common Python/Node shell-syntax mistakes) only inspect files inside the
|
||||
effective `workdir` boundary. If a script path resolves outside `workdir`, preflight is skipped for
|
||||
that file.
|
||||
- For long-running work that starts now, start it once and rely on automatic
|
||||
completion wake when it is enabled and the command emits output or fails.
|
||||
Use `process` for logs, status, input, or intervention; do not emulate
|
||||
scheduling with sleep loops, timeout loops, or repeated polling.
|
||||
- For work that should happen later or on a schedule, use cron instead of
|
||||
`exec` sleep/delay patterns.
|
||||
|
||||
## Config
|
||||
|
||||
- `tools.exec.notifyOnExit` (default: true): when true, backgrounded exec sessions enqueue a system event and request a heartbeat on exit.
|
||||
- `tools.exec.approvalRunningNoticeMs` (default: 10000): emit a single “running” notice when an approval-gated exec runs longer than this (0 disables).
|
||||
- `tools.exec.host` (default: `auto`; resolves to `sandbox` when sandbox runtime is active, `gateway` otherwise)
|
||||
- `tools.exec.security` (default: `deny` for sandbox, `full` for gateway + node when unset)
|
||||
- `tools.exec.ask` (default: `off`)
|
||||
- No-approval host exec is the default for gateway + node. If you want approvals/allowlist behavior, tighten both `tools.exec.*` and the host `~/.openclaw/exec-approvals.json`; see [Exec approvals](/tools/exec-approvals#no-approval-yolo-mode).
|
||||
- YOLO comes from the host-policy defaults (`security=full`, `ask=off`), not from `host=auto`. If you want to force gateway or node routing, set `tools.exec.host` or use `/exec host=...`.
|
||||
- In `security=full` plus `ask=off` mode, host exec follows the configured policy directly; there is no extra heuristic command-obfuscation prefilter.
|
||||
- `tools.exec.node` (default: unset)
|
||||
- `tools.exec.strictInlineEval` (default: false): when true, inline interpreter eval forms such as `python -c`, `node -e`, `ruby -e`, `perl -e`, `php -r`, `lua -e`, and `osascript -e` always require explicit approval. `allow-always` can still persist benign interpreter/script invocations, but inline-eval forms still prompt each time.
|
||||
- `tools.exec.pathPrepend`: list of directories to prepend to `PATH` for exec runs (gateway + sandbox only).
|
||||
- `tools.exec.safeBins`: stdin-only safe binaries that can run without explicit allowlist entries. For behavior details, see [Safe bins](/tools/exec-approvals#safe-bins-stdin-only).
|
||||
- `tools.exec.safeBinTrustedDirs`: additional explicit directories trusted for `safeBins` path checks. `PATH` entries are never auto-trusted. Built-in defaults are `/bin` and `/usr/bin`.
|
||||
- `tools.exec.safeBinProfiles`: optional custom argv policy per safe bin (`minPositional`, `maxPositional`, `allowedValueFlags`, `deniedFlags`).
|
||||
|
||||
Example:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
exec: {
|
||||
pathPrepend: ["~/bin", "/opt/oss/bin"],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### PATH handling
|
||||
|
||||
- `host=gateway`: merges your login-shell `PATH` into the exec environment. `env.PATH` overrides are
|
||||
rejected for host execution. The daemon itself still runs with a minimal `PATH`:
|
||||
- macOS: `/opt/homebrew/bin`, `/usr/local/bin`, `/usr/bin`, `/bin`
|
||||
- Linux: `/usr/local/bin`, `/usr/bin`, `/bin`
|
||||
- `host=sandbox`: runs `sh -lc` (login shell) inside the container, so `/etc/profile` may reset `PATH`.
|
||||
OpenClaw prepends `env.PATH` after profile sourcing via an internal env var (no shell interpolation);
|
||||
`tools.exec.pathPrepend` applies here too.
|
||||
- `host=node`: only non-blocked env overrides you pass are sent to the node. `env.PATH` overrides are
|
||||
rejected for host execution and ignored by node hosts. If you need additional PATH entries on a node,
|
||||
configure the node host service environment (systemd/launchd) or install tools in standard locations.
|
||||
|
||||
Per-agent node binding (use the agent list index in config):
|
||||
|
||||
```bash
|
||||
openclaw config get agents.list
|
||||
openclaw config set agents.list[0].tools.exec.node "node-id-or-name"
|
||||
```
|
||||
|
||||
Control UI: the Nodes tab includes a small “Exec node binding” panel for the same settings.
|
||||
|
||||
## Session overrides (`/exec`)
|
||||
|
||||
Use `/exec` to set **per-session** defaults for `host`, `security`, `ask`, and `node`.
|
||||
Send `/exec` with no arguments to show the current values.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
/exec host=auto security=allowlist ask=on-miss node=mac-1
|
||||
```
|
||||
|
||||
## Authorization model
|
||||
|
||||
`/exec` is only honored for **authorized senders** (channel allowlists/pairing plus `commands.useAccessGroups`).
|
||||
It updates **session state only** and does not write config. To hard-disable exec, deny it via tool
|
||||
policy (`tools.deny: ["exec"]` or per-agent). Host approvals still apply unless you explicitly set
|
||||
`security=full` and `ask=off`.
|
||||
|
||||
## Exec approvals (companion app / node host)
|
||||
|
||||
Sandboxed agents can require per-request approval before `exec` runs on the gateway or node host.
|
||||
See [Exec approvals](/tools/exec-approvals) for the policy, allowlist, and UI flow.
|
||||
|
||||
When approvals are required, the exec tool returns immediately with
|
||||
`status: "approval-pending"` and an approval id. Once approved (or denied / timed out),
|
||||
the Gateway emits system events (`Exec finished` / `Exec denied`). If the command is still
|
||||
running after `tools.exec.approvalRunningNoticeMs`, a single `Exec running` notice is emitted.
|
||||
On channels with native approval cards/buttons, the agent should rely on that
|
||||
native UI first and only include a manual `/approve` command when the tool
|
||||
result explicitly says chat approvals are unavailable or manual approval is the
|
||||
only path.
|
||||
|
||||
## Allowlist + safe bins
|
||||
|
||||
Manual allowlist enforcement matches **resolved binary paths only** (no basename matches). When
|
||||
`security=allowlist`, shell commands are auto-allowed only if every pipeline segment is
|
||||
allowlisted or a safe bin. Chaining (`;`, `&&`, `||`) and redirections are rejected in
|
||||
allowlist mode unless every top-level segment satisfies the allowlist (including safe bins).
|
||||
Redirections remain unsupported.
|
||||
Durable `allow-always` trust does not bypass that rule: a chained command still requires every
|
||||
top-level segment to match.
|
||||
|
||||
`autoAllowSkills` is a separate convenience path in exec approvals. It is not the same as
|
||||
manual path allowlist entries. For strict explicit trust, keep `autoAllowSkills` disabled.
|
||||
|
||||
Use the two controls for different jobs:
|
||||
|
||||
- `tools.exec.safeBins`: small, stdin-only stream filters.
|
||||
- `tools.exec.safeBinTrustedDirs`: explicit extra trusted directories for safe-bin executable paths.
|
||||
- `tools.exec.safeBinProfiles`: explicit argv policy for custom safe bins.
|
||||
- allowlist: explicit trust for executable paths.
|
||||
|
||||
Do not treat `safeBins` as a generic allowlist, and do not add interpreter/runtime binaries (for example `python3`, `node`, `ruby`, `bash`). If you need those, use explicit allowlist entries and keep approval prompts enabled.
|
||||
`openclaw security audit` warns when interpreter/runtime `safeBins` entries are missing explicit profiles, and `openclaw doctor --fix` can scaffold missing custom `safeBinProfiles` entries.
|
||||
`openclaw security audit` and `openclaw doctor` also warn when you explicitly add broad-behavior bins such as `jq` back into `safeBins`.
|
||||
If you explicitly allowlist interpreters, enable `tools.exec.strictInlineEval` so inline code-eval forms still require a fresh approval.
|
||||
|
||||
For full policy details and examples, see [Exec approvals](/tools/exec-approvals#safe-bins-stdin-only) and [Safe bins versus allowlist](/tools/exec-approvals#safe-bins-versus-allowlist).
|
||||
|
||||
## Examples
|
||||
|
||||
Foreground:
|
||||
|
||||
```json
|
||||
{ "tool": "exec", "command": "ls -la" }
|
||||
```
|
||||
|
||||
Background + poll:
|
||||
|
||||
```json
|
||||
{"tool":"exec","command":"npm run build","yieldMs":1000}
|
||||
{"tool":"process","action":"poll","sessionId":"<id>"}
|
||||
```
|
||||
|
||||
Polling is for on-demand status, not waiting loops. If automatic completion wake
|
||||
is enabled, the command can wake the session when it emits output or fails.
|
||||
|
||||
Send keys (tmux-style):
|
||||
|
||||
```json
|
||||
{"tool":"process","action":"send-keys","sessionId":"<id>","keys":["Enter"]}
|
||||
{"tool":"process","action":"send-keys","sessionId":"<id>","keys":["C-c"]}
|
||||
{"tool":"process","action":"send-keys","sessionId":"<id>","keys":["Up","Up","Enter"]}
|
||||
```
|
||||
|
||||
Submit (send CR only):
|
||||
|
||||
```json
|
||||
{ "tool": "process", "action": "submit", "sessionId": "<id>" }
|
||||
```
|
||||
|
||||
Paste (bracketed by default):
|
||||
|
||||
```json
|
||||
{ "tool": "process", "action": "paste", "sessionId": "<id>", "text": "line1\nline2\n" }
|
||||
```
|
||||
|
||||
## apply_patch
|
||||
|
||||
`apply_patch` is a subtool of `exec` for structured multi-file edits.
|
||||
It is enabled by default for OpenAI and OpenAI Codex models. Use config only
|
||||
when you want to disable it or restrict it to specific models:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
exec: {
|
||||
applyPatch: { workspaceOnly: true, allowModels: ["gpt-5.4"] },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Only available for OpenAI/OpenAI Codex models.
|
||||
- Tool policy still applies; `allow: ["write"]` implicitly allows `apply_patch`.
|
||||
- Config lives under `tools.exec.applyPatch`.
|
||||
- `tools.exec.applyPatch.enabled` defaults to `true`; set it to `false` to disable the tool for OpenAI models.
|
||||
- `tools.exec.applyPatch.workspaceOnly` defaults to `true` (workspace-contained). Set it to `false` only if you intentionally want `apply_patch` to write/delete outside the workspace directory.
|
||||
|
||||
## Related
|
||||
|
||||
- [Exec Approvals](/tools/exec-approvals) — approval gates for shell commands
|
||||
- [Sandboxing](/gateway/sandboxing) — running commands in sandboxed environments
|
||||
- [Background Process](/gateway/background-process) — long-running exec and process tool
|
||||
- [Security](/gateway/security) — tool policy and elevated access
|
||||
147
openclaw/docs/tools/firecrawl.md
Normal file
147
openclaw/docs/tools/firecrawl.md
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
---
|
||||
summary: "Firecrawl search, scrape, and web_fetch fallback"
|
||||
read_when:
|
||||
- You want Firecrawl-backed web extraction
|
||||
- You need a Firecrawl API key
|
||||
- You want Firecrawl as a web_search provider
|
||||
- You want anti-bot extraction for web_fetch
|
||||
title: "Firecrawl"
|
||||
---
|
||||
|
||||
# Firecrawl
|
||||
|
||||
OpenClaw can use **Firecrawl** in three ways:
|
||||
|
||||
- as the `web_search` provider
|
||||
- as explicit plugin tools: `firecrawl_search` and `firecrawl_scrape`
|
||||
- as a fallback extractor for `web_fetch`
|
||||
|
||||
It is a hosted extraction/search service that supports bot circumvention and caching,
|
||||
which helps with JS-heavy sites or pages that block plain HTTP fetches.
|
||||
|
||||
## Get an API key
|
||||
|
||||
1. Create a Firecrawl account and generate an API key.
|
||||
2. Store it in config or set `FIRECRAWL_API_KEY` in the gateway environment.
|
||||
|
||||
## Configure Firecrawl search
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "firecrawl",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
entries: {
|
||||
firecrawl: {
|
||||
enabled: true,
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "FIRECRAWL_API_KEY_HERE",
|
||||
baseUrl: "https://api.firecrawl.dev",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Choosing Firecrawl in onboarding or `openclaw configure --section web` enables the bundled Firecrawl plugin automatically.
|
||||
- `web_search` with Firecrawl supports `query` and `count`.
|
||||
- For Firecrawl-specific controls like `sources`, `categories`, or result scraping, use `firecrawl_search`.
|
||||
- `baseUrl` overrides must stay on `https://api.firecrawl.dev`.
|
||||
- `FIRECRAWL_BASE_URL` is the shared env fallback for Firecrawl search and scrape base URLs.
|
||||
|
||||
## Configure Firecrawl scrape + web_fetch fallback
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
firecrawl: {
|
||||
enabled: true,
|
||||
config: {
|
||||
webFetch: {
|
||||
apiKey: "FIRECRAWL_API_KEY_HERE",
|
||||
baseUrl: "https://api.firecrawl.dev",
|
||||
onlyMainContent: true,
|
||||
maxAgeMs: 172800000,
|
||||
timeoutSeconds: 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Firecrawl fallback attempts run only when an API key is available (`plugins.entries.firecrawl.config.webFetch.apiKey` or `FIRECRAWL_API_KEY`).
|
||||
- `maxAgeMs` controls how old cached results can be (ms). Default is 2 days.
|
||||
- Legacy `tools.web.fetch.firecrawl.*` config is auto-migrated by `openclaw doctor --fix`.
|
||||
- Firecrawl scrape/base URL overrides are restricted to `https://api.firecrawl.dev`.
|
||||
|
||||
`firecrawl_scrape` reuses the same `plugins.entries.firecrawl.config.webFetch.*` settings and env vars.
|
||||
|
||||
## Firecrawl plugin tools
|
||||
|
||||
### `firecrawl_search`
|
||||
|
||||
Use this when you want Firecrawl-specific search controls instead of generic `web_search`.
|
||||
|
||||
Core parameters:
|
||||
|
||||
- `query`
|
||||
- `count`
|
||||
- `sources`
|
||||
- `categories`
|
||||
- `scrapeResults`
|
||||
- `timeoutSeconds`
|
||||
|
||||
### `firecrawl_scrape`
|
||||
|
||||
Use this for JS-heavy or bot-protected pages where plain `web_fetch` is weak.
|
||||
|
||||
Core parameters:
|
||||
|
||||
- `url`
|
||||
- `extractMode`
|
||||
- `maxChars`
|
||||
- `onlyMainContent`
|
||||
- `maxAgeMs`
|
||||
- `proxy`
|
||||
- `storeInCache`
|
||||
- `timeoutSeconds`
|
||||
|
||||
## Stealth / bot circumvention
|
||||
|
||||
Firecrawl exposes a **proxy mode** parameter for bot circumvention (`basic`, `stealth`, or `auto`).
|
||||
OpenClaw always uses `proxy: "auto"` plus `storeInCache: true` for Firecrawl requests.
|
||||
If proxy is omitted, Firecrawl defaults to `auto`. `auto` retries with stealth proxies if a basic attempt fails, which may use more credits
|
||||
than basic-only scraping.
|
||||
|
||||
## How `web_fetch` uses Firecrawl
|
||||
|
||||
`web_fetch` extraction order:
|
||||
|
||||
1. Readability (local)
|
||||
2. Firecrawl (if selected or auto-detected as the active web-fetch fallback)
|
||||
3. Basic HTML cleanup (last fallback)
|
||||
|
||||
The selection knob is `tools.web.fetch.provider`. If you omit it, OpenClaw
|
||||
auto-detects the first ready web-fetch provider from available credentials.
|
||||
Today the bundled provider is Firecrawl.
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Web Fetch](/tools/web-fetch) -- web_fetch tool with Firecrawl fallback
|
||||
- [Tavily](/tools/tavily) -- search + extract tools
|
||||
98
openclaw/docs/tools/gemini-search.md
Normal file
98
openclaw/docs/tools/gemini-search.md
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
summary: "Gemini web search with Google Search grounding"
|
||||
read_when:
|
||||
- You want to use Gemini for web_search
|
||||
- You need a GEMINI_API_KEY
|
||||
- You want Google Search grounding
|
||||
title: "Gemini Search"
|
||||
---
|
||||
|
||||
# Gemini Search
|
||||
|
||||
OpenClaw supports Gemini models with built-in
|
||||
[Google Search grounding](https://ai.google.dev/gemini-api/docs/grounding),
|
||||
which returns AI-synthesized answers backed by live Google Search results with
|
||||
citations.
|
||||
|
||||
## Get an API key
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a key">
|
||||
Go to [Google AI Studio](https://aistudio.google.com/apikey) and create an
|
||||
API key.
|
||||
</Step>
|
||||
<Step title="Store the key">
|
||||
Set `GEMINI_API_KEY` in the Gateway environment, or configure via:
|
||||
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
google: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "AIza...", // optional if GEMINI_API_KEY is set
|
||||
model: "gemini-2.5-flash", // default
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "gemini",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Environment alternative:** set `GEMINI_API_KEY` in the Gateway environment.
|
||||
For a gateway install, put it in `~/.openclaw/.env`.
|
||||
|
||||
## How it works
|
||||
|
||||
Unlike traditional search providers that return a list of links and snippets,
|
||||
Gemini uses Google Search grounding to produce AI-synthesized answers with
|
||||
inline citations. The results include both the synthesized answer and the source
|
||||
URLs.
|
||||
|
||||
- Citation URLs from Gemini grounding are automatically resolved from Google
|
||||
redirect URLs to direct URLs.
|
||||
- Redirect resolution uses the SSRF guard path (HEAD + redirect checks +
|
||||
http/https validation) before returning the final citation URL.
|
||||
- Redirect resolution uses strict SSRF defaults, so redirects to
|
||||
private/internal targets are blocked.
|
||||
|
||||
## Supported parameters
|
||||
|
||||
Gemini search supports `query`.
|
||||
|
||||
`count` is accepted for shared `web_search` compatibility, but Gemini grounding
|
||||
still returns one synthesized answer with citations rather than an N-result
|
||||
list.
|
||||
|
||||
Provider-specific filters like `country`, `language`, `freshness`, and
|
||||
`domain_filter` are not supported.
|
||||
|
||||
## Model selection
|
||||
|
||||
The default model is `gemini-2.5-flash` (fast and cost-effective). Any Gemini
|
||||
model that supports grounding can be used via
|
||||
`plugins.entries.google.config.webSearch.model`.
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Brave Search](/tools/brave-search) -- structured results with snippets
|
||||
- [Perplexity Search](/tools/perplexity-search) -- structured results + content extraction
|
||||
102
openclaw/docs/tools/grok-search.md
Normal file
102
openclaw/docs/tools/grok-search.md
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
summary: "Grok web search via xAI web-grounded responses"
|
||||
read_when:
|
||||
- You want to use Grok for web_search
|
||||
- You need an XAI_API_KEY for web search
|
||||
title: "Grok Search"
|
||||
---
|
||||
|
||||
# Grok Search
|
||||
|
||||
OpenClaw supports Grok as a `web_search` provider, using xAI web-grounded
|
||||
responses to produce AI-synthesized answers backed by live search results
|
||||
with citations.
|
||||
|
||||
The same `XAI_API_KEY` can also power the built-in `x_search` tool for X
|
||||
(formerly Twitter) post search. If you store the key under
|
||||
`plugins.entries.xai.config.webSearch.apiKey`, OpenClaw now reuses it as a
|
||||
fallback for the bundled xAI model provider too.
|
||||
|
||||
For post-level X metrics such as reposts, replies, bookmarks, or views, prefer
|
||||
`x_search` with the exact post URL or status ID instead of a broad search
|
||||
query.
|
||||
|
||||
## Onboarding and configure
|
||||
|
||||
If you choose **Grok** during:
|
||||
|
||||
- `openclaw onboard`
|
||||
- `openclaw configure --section web`
|
||||
|
||||
OpenClaw can show a separate follow-up step to enable `x_search` with the same
|
||||
`XAI_API_KEY`. That follow-up:
|
||||
|
||||
- only appears after you choose Grok for `web_search`
|
||||
- is not a separate top-level web-search provider choice
|
||||
- can optionally set the `x_search` model during the same flow
|
||||
|
||||
If you skip it, you can enable or change `x_search` later in config.
|
||||
|
||||
## Get an API key
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a key">
|
||||
Get an API key from [xAI](https://console.x.ai/).
|
||||
</Step>
|
||||
<Step title="Store the key">
|
||||
Set `XAI_API_KEY` in the Gateway environment, or configure via:
|
||||
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
xai: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "xai-...", // optional if XAI_API_KEY is set
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "grok",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Environment alternative:** set `XAI_API_KEY` in the Gateway environment.
|
||||
For a gateway install, put it in `~/.openclaw/.env`.
|
||||
|
||||
## How it works
|
||||
|
||||
Grok uses xAI web-grounded responses to synthesize answers with inline
|
||||
citations, similar to Gemini's Google Search grounding approach.
|
||||
|
||||
## Supported parameters
|
||||
|
||||
Grok search supports `query`.
|
||||
|
||||
`count` is accepted for shared `web_search` compatibility, but Grok still
|
||||
returns one synthesized answer with citations rather than an N-result list.
|
||||
|
||||
Provider-specific filters are not currently supported.
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [x_search in Web Search](/tools/web#x_search) -- first-class X search via xAI
|
||||
- [Gemini Search](/tools/gemini-search) -- AI-synthesized answers via Google grounding
|
||||
151
openclaw/docs/tools/image-generation.md
Normal file
151
openclaw/docs/tools/image-generation.md
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
summary: "Generate and edit images using configured providers (OpenAI, Google Gemini, fal, MiniMax, ComfyUI, Vydra)"
|
||||
read_when:
|
||||
- Generating images via the agent
|
||||
- Configuring image generation providers and models
|
||||
- Understanding the image_generate tool parameters
|
||||
title: "Image Generation"
|
||||
---
|
||||
|
||||
# Image Generation
|
||||
|
||||
The `image_generate` tool lets the agent create and edit images using your configured providers. Generated images are delivered automatically as media attachments in the agent's reply.
|
||||
|
||||
<Note>
|
||||
The tool only appears when at least one image generation provider is available. If you don't see `image_generate` in your agent's tools, configure `agents.defaults.imageGenerationModel` or set up a provider API key.
|
||||
</Note>
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Set an API key for at least one provider (for example `OPENAI_API_KEY` or `GEMINI_API_KEY`).
|
||||
2. Optionally set your preferred model:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
imageGenerationModel: {
|
||||
primary: "openai/gpt-image-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
3. Ask the agent: _"Generate an image of a friendly lobster mascot."_
|
||||
|
||||
The agent calls `image_generate` automatically. No tool allow-listing needed — it's enabled by default when a provider is available.
|
||||
|
||||
## Supported providers
|
||||
|
||||
| Provider | Default model | Edit support | API key |
|
||||
| -------- | -------------------------------- | ---------------------------------- | ----------------------------------------------------- |
|
||||
| OpenAI | `gpt-image-1` | Yes (up to 5 images) | `OPENAI_API_KEY` |
|
||||
| Google | `gemini-3.1-flash-image-preview` | Yes | `GEMINI_API_KEY` or `GOOGLE_API_KEY` |
|
||||
| fal | `fal-ai/flux/dev` | Yes | `FAL_KEY` |
|
||||
| MiniMax | `image-01` | Yes (subject reference) | `MINIMAX_API_KEY` or MiniMax OAuth (`minimax-portal`) |
|
||||
| ComfyUI | `workflow` | Yes (1 image, workflow-configured) | `COMFY_API_KEY` or `COMFY_CLOUD_API_KEY` for cloud |
|
||||
| Vydra | `grok-imagine` | No | `VYDRA_API_KEY` |
|
||||
|
||||
Use `action: "list"` to inspect available providers and models at runtime:
|
||||
|
||||
```
|
||||
/tool image_generate action=list
|
||||
```
|
||||
|
||||
## Tool parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ------------- | -------- | ------------------------------------------------------------------------------------- |
|
||||
| `prompt` | string | Image generation prompt (required for `action: "generate"`) |
|
||||
| `action` | string | `"generate"` (default) or `"list"` to inspect providers |
|
||||
| `model` | string | Provider/model override, e.g. `openai/gpt-image-1` |
|
||||
| `image` | string | Single reference image path or URL for edit mode |
|
||||
| `images` | string[] | Multiple reference images for edit mode (up to 5) |
|
||||
| `size` | string | Size hint: `1024x1024`, `1536x1024`, `1024x1536`, `1024x1792`, `1792x1024` |
|
||||
| `aspectRatio` | string | Aspect ratio: `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9` |
|
||||
| `resolution` | string | Resolution hint: `1K`, `2K`, or `4K` |
|
||||
| `count` | number | Number of images to generate (1–4) |
|
||||
| `filename` | string | Output filename hint |
|
||||
|
||||
Not all providers support all parameters. When a fallback provider supports a nearby geometry option instead of the exact requested one, OpenClaw remaps to the closest supported size, aspect ratio, or resolution before submission. Truly unsupported overrides are still reported in the tool result.
|
||||
|
||||
Tool results report the applied settings. When OpenClaw remaps geometry during provider fallback, the returned `size`, `aspectRatio`, and `resolution` values reflect what was actually sent, and `details.normalization` captures the requested-to-applied translation.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Model selection
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
imageGenerationModel: {
|
||||
primary: "openai/gpt-image-1",
|
||||
fallbacks: ["google/gemini-3.1-flash-image-preview", "fal/fal-ai/flux/dev"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Provider selection order
|
||||
|
||||
When generating an image, OpenClaw tries providers in this order:
|
||||
|
||||
1. **`model` parameter** from the tool call (if the agent specifies one)
|
||||
2. **`imageGenerationModel.primary`** from config
|
||||
3. **`imageGenerationModel.fallbacks`** in order
|
||||
4. **Auto-detection** — uses auth-backed provider defaults only:
|
||||
- current default provider first
|
||||
- remaining registered image-generation providers in provider-id order
|
||||
|
||||
If a provider fails (auth error, rate limit, etc.), the next candidate is tried automatically. If all fail, the error includes details from each attempt.
|
||||
|
||||
Notes:
|
||||
|
||||
- Auto-detection is auth-aware. A provider default only enters the candidate list
|
||||
when OpenClaw can actually authenticate that provider.
|
||||
- Auto-detection is enabled by default. Set
|
||||
`agents.defaults.mediaGenerationAutoProviderFallback: false` if you want image
|
||||
generation to use only the explicit `model`, `primary`, and `fallbacks`
|
||||
entries.
|
||||
- Use `action: "list"` to inspect the currently registered providers, their
|
||||
default models, and auth env-var hints.
|
||||
|
||||
### Image editing
|
||||
|
||||
OpenAI, Google, fal, MiniMax, and ComfyUI support editing reference images. Pass a reference image path or URL:
|
||||
|
||||
```
|
||||
"Generate a watercolor version of this photo" + image: "/path/to/photo.jpg"
|
||||
```
|
||||
|
||||
OpenAI and Google support up to 5 reference images via the `images` parameter. fal, MiniMax, and ComfyUI support 1.
|
||||
|
||||
MiniMax image generation is available through both bundled MiniMax auth paths:
|
||||
|
||||
- `minimax/image-01` for API-key setups
|
||||
- `minimax-portal/image-01` for OAuth setups
|
||||
|
||||
## Provider capabilities
|
||||
|
||||
| Capability | OpenAI | Google | fal | MiniMax | ComfyUI | Vydra |
|
||||
| --------------------- | -------------------- | -------------------- | ------------------- | -------------------------- | ---------------------------------- | ------- |
|
||||
| Generate | Yes (up to 4) | Yes (up to 4) | Yes (up to 4) | Yes (up to 9) | Yes (workflow-defined outputs) | Yes (1) |
|
||||
| Edit/reference | Yes (up to 5 images) | Yes (up to 5 images) | Yes (1 image) | Yes (1 image, subject ref) | Yes (1 image, workflow-configured) | No |
|
||||
| Size control | Yes | Yes | Yes | No | No | No |
|
||||
| Aspect ratio | No | Yes | Yes (generate only) | Yes | No | No |
|
||||
| Resolution (1K/2K/4K) | No | Yes | Yes | No | No | No |
|
||||
|
||||
## Related
|
||||
|
||||
- [Tools Overview](/tools) — all available agent tools
|
||||
- [fal](/providers/fal) — fal image and video provider setup
|
||||
- [ComfyUI](/providers/comfy) — local ComfyUI and Comfy Cloud workflow setup
|
||||
- [Google (Gemini)](/providers/google) — Gemini image provider setup
|
||||
- [MiniMax](/providers/minimax) — MiniMax image provider setup
|
||||
- [OpenAI](/providers/openai) — OpenAI Images provider setup
|
||||
- [Vydra](/providers/vydra) — Vydra image, video, and speech setup
|
||||
- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — `imageGenerationModel` config
|
||||
- [Models](/concepts/models) — model configuration and failover
|
||||
184
openclaw/docs/tools/index.md
Normal file
184
openclaw/docs/tools/index.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
---
|
||||
summary: "OpenClaw tools and plugins overview: what the agent can do and how to extend it"
|
||||
read_when:
|
||||
- You want to understand what tools OpenClaw provides
|
||||
- You need to configure, allow, or deny tools
|
||||
- You are deciding between built-in tools, skills, and plugins
|
||||
title: "Tools and Plugins"
|
||||
---
|
||||
|
||||
# Tools and Plugins
|
||||
|
||||
Everything the agent does beyond generating text happens through **tools**.
|
||||
Tools are how the agent reads files, runs commands, browses the web, sends
|
||||
messages, and interacts with devices.
|
||||
|
||||
## Tools, skills, and plugins
|
||||
|
||||
OpenClaw has three layers that work together:
|
||||
|
||||
<Steps>
|
||||
<Step title="Tools are what the agent calls">
|
||||
A tool is a typed function the agent can invoke (e.g. `exec`, `browser`,
|
||||
`web_search`, `message`). OpenClaw ships a set of **built-in tools** and
|
||||
plugins can register additional ones.
|
||||
|
||||
The agent sees tools as structured function definitions sent to the model API.
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Skills teach the agent when and how">
|
||||
A skill is a markdown file (`SKILL.md`) injected into the system prompt.
|
||||
Skills give the agent context, constraints, and step-by-step guidance for
|
||||
using tools effectively. Skills live in your workspace, in shared folders,
|
||||
or ship inside plugins.
|
||||
|
||||
[Skills reference](/tools/skills) | [Creating skills](/tools/creating-skills)
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Plugins package everything together">
|
||||
A plugin is a package that can register any combination of capabilities:
|
||||
channels, model providers, tools, skills, speech, realtime transcription,
|
||||
realtime voice, media understanding, image generation, video generation,
|
||||
web fetch, web search, and more. Some plugins are **core** (shipped with
|
||||
OpenClaw), others are **external** (published on npm by the community).
|
||||
|
||||
[Install and configure plugins](/tools/plugin) | [Build your own](/plugins/building-plugins)
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Built-in tools
|
||||
|
||||
These tools ship with OpenClaw and are available without installing any plugins:
|
||||
|
||||
| Tool | What it does | Page |
|
||||
| ------------------------------------------ | --------------------------------------------------------------------- | ------------------------------------------- |
|
||||
| `exec` / `process` | Run shell commands, manage background processes | [Exec](/tools/exec) |
|
||||
| `code_execution` | Run sandboxed remote Python analysis | [Code Execution](/tools/code-execution) |
|
||||
| `browser` | Control a Chromium browser (navigate, click, screenshot) | [Browser](/tools/browser) |
|
||||
| `web_search` / `x_search` / `web_fetch` | Search the web, search X posts, fetch page content | [Web](/tools/web) |
|
||||
| `read` / `write` / `edit` | File I/O in the workspace | |
|
||||
| `apply_patch` | Multi-hunk file patches | [Apply Patch](/tools/apply-patch) |
|
||||
| `message` | Send messages across all channels | [Agent Send](/tools/agent-send) |
|
||||
| `canvas` | Drive node Canvas (present, eval, snapshot) | |
|
||||
| `nodes` | Discover and target paired devices | |
|
||||
| `cron` / `gateway` | Manage scheduled jobs; inspect, patch, restart, or update the gateway | |
|
||||
| `image` / `image_generate` | Analyze or generate images | [Image Generation](/tools/image-generation) |
|
||||
| `music_generate` | Generate music tracks | [Music Generation](/tools/music-generation) |
|
||||
| `video_generate` | Generate videos | [Video Generation](/tools/video-generation) |
|
||||
| `tts` | One-shot text-to-speech conversion | [TTS](/tools/tts) |
|
||||
| `sessions_*` / `subagents` / `agents_list` | Session management, status, and sub-agent orchestration | [Sub-agents](/tools/subagents) |
|
||||
| `session_status` | Lightweight `/status`-style readback and session model override | [Session Tools](/concepts/session-tool) |
|
||||
|
||||
For image work, use `image` for analysis and `image_generate` for generation or editing. If you target `openai/*`, `google/*`, `fal/*`, or another non-default image provider, configure that provider's auth/API key first.
|
||||
|
||||
For music work, use `music_generate`. If you target `google/*`, `minimax/*`, or another non-default music provider, configure that provider's auth/API key first.
|
||||
|
||||
For video work, use `video_generate`. If you target `qwen/*` or another non-default video provider, configure that provider's auth/API key first.
|
||||
|
||||
For workflow-driven audio generation, use `music_generate` when a plugin such as
|
||||
ComfyUI registers it. This is separate from `tts`, which is text-to-speech.
|
||||
|
||||
`session_status` is the lightweight status/readback tool in the sessions group.
|
||||
It answers `/status`-style questions about the current session and can
|
||||
optionally set a per-session model override; `model=default` clears that
|
||||
override. Like `/status`, it can backfill sparse token/cache counters and the
|
||||
active runtime model label from the latest transcript usage entry.
|
||||
|
||||
`gateway` is the owner-only runtime tool for gateway operations:
|
||||
|
||||
- `config.schema.lookup` for one path-scoped config subtree before edits
|
||||
- `config.get` for the current config snapshot + hash
|
||||
- `config.patch` for partial config updates with restart
|
||||
- `config.apply` only for full-config replacement
|
||||
- `update.run` for explicit self-update + restart
|
||||
|
||||
For partial changes, prefer `config.schema.lookup` then `config.patch`. Use
|
||||
`config.apply` only when you intentionally replace the entire config.
|
||||
The tool also refuses to change `tools.exec.ask` or `tools.exec.security`;
|
||||
legacy `tools.bash.*` aliases normalize to the same protected exec paths.
|
||||
|
||||
### Plugin-provided tools
|
||||
|
||||
Plugins can register additional tools. Some examples:
|
||||
|
||||
- [Lobster](/tools/lobster) — typed workflow runtime with resumable approvals
|
||||
- [LLM Task](/tools/llm-task) — JSON-only LLM step for structured output
|
||||
- [Music Generation](/tools/music-generation) — shared `music_generate` tool with workflow-backed providers
|
||||
- [Diffs](/tools/diffs) — diff viewer and renderer
|
||||
- [OpenProse](/prose) — markdown-first workflow orchestration
|
||||
|
||||
## Tool configuration
|
||||
|
||||
### Allow and deny lists
|
||||
|
||||
Control which tools the agent can call via `tools.allow` / `tools.deny` in
|
||||
config. Deny always wins over allow.
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
allow: ["group:fs", "browser", "web_search"],
|
||||
deny: ["exec"],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Tool profiles
|
||||
|
||||
`tools.profile` sets a base allowlist before `allow`/`deny` is applied.
|
||||
Per-agent override: `agents.list[].tools.profile`.
|
||||
|
||||
| Profile | What it includes |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `full` | No restriction (same as unset) |
|
||||
| `coding` | `group:fs`, `group:runtime`, `group:web`, `group:sessions`, `group:memory`, `cron`, `image`, `image_generate`, `music_generate`, `video_generate` |
|
||||
| `messaging` | `group:messaging`, `sessions_list`, `sessions_history`, `sessions_send`, `session_status` |
|
||||
| `minimal` | `session_status` only |
|
||||
|
||||
### Tool groups
|
||||
|
||||
Use `group:*` shorthands in allow/deny lists:
|
||||
|
||||
| Group | Tools |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------- |
|
||||
| `group:runtime` | exec, process, code_execution (`bash` is accepted as an alias for `exec`) |
|
||||
| `group:fs` | read, write, edit, apply_patch |
|
||||
| `group:sessions` | sessions_list, sessions_history, sessions_send, sessions_spawn, sessions_yield, subagents, session_status |
|
||||
| `group:memory` | memory_search, memory_get |
|
||||
| `group:web` | web_search, x_search, web_fetch |
|
||||
| `group:ui` | browser, canvas |
|
||||
| `group:automation` | cron, gateway |
|
||||
| `group:messaging` | message |
|
||||
| `group:nodes` | nodes |
|
||||
| `group:agents` | agents_list |
|
||||
| `group:media` | image, image_generate, music_generate, video_generate, tts |
|
||||
| `group:openclaw` | All built-in OpenClaw tools (excludes plugin tools) |
|
||||
|
||||
`sessions_history` returns a bounded, safety-filtered recall view. It strips
|
||||
thinking tags, `<relevant-memories>` scaffolding, plain-text tool-call XML
|
||||
payloads (including `<tool_call>...</tool_call>`,
|
||||
`<function_call>...</function_call>`, `<tool_calls>...</tool_calls>`,
|
||||
`<function_calls>...</function_calls>`, and truncated tool-call blocks),
|
||||
downgraded tool-call scaffolding, leaked ASCII/full-width model control
|
||||
tokens, and malformed MiniMax tool-call XML from assistant text, then applies
|
||||
redaction/truncation and possible oversized-row placeholders instead of acting
|
||||
as a raw transcript dump.
|
||||
|
||||
### Provider-specific restrictions
|
||||
|
||||
Use `tools.byProvider` to restrict tools for specific providers without
|
||||
changing global defaults:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
profile: "coding",
|
||||
byProvider: {
|
||||
"google-antigravity": { profile: "minimal" },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
98
openclaw/docs/tools/kimi-search.md
Normal file
98
openclaw/docs/tools/kimi-search.md
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
summary: "Kimi web search via Moonshot web search"
|
||||
read_when:
|
||||
- You want to use Kimi for web_search
|
||||
- You need a KIMI_API_KEY or MOONSHOT_API_KEY
|
||||
title: "Kimi Search"
|
||||
---
|
||||
|
||||
# Kimi Search
|
||||
|
||||
OpenClaw supports Kimi as a `web_search` provider, using Moonshot web search
|
||||
to produce AI-synthesized answers with citations.
|
||||
|
||||
## Get an API key
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a key">
|
||||
Get an API key from [Moonshot AI](https://platform.moonshot.cn/).
|
||||
</Step>
|
||||
<Step title="Store the key">
|
||||
Set `KIMI_API_KEY` or `MOONSHOT_API_KEY` in the Gateway environment, or
|
||||
configure via:
|
||||
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
When you choose **Kimi** during `openclaw onboard` or
|
||||
`openclaw configure --section web`, OpenClaw can also ask for:
|
||||
|
||||
- the Moonshot API region:
|
||||
- `https://api.moonshot.ai/v1`
|
||||
- `https://api.moonshot.cn/v1`
|
||||
- the default Kimi web-search model (defaults to `kimi-k2.5`)
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
moonshot: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "sk-...", // optional if KIMI_API_KEY or MOONSHOT_API_KEY is set
|
||||
baseUrl: "https://api.moonshot.ai/v1",
|
||||
model: "kimi-k2.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "kimi",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If you use the China API host for chat (`models.providers.moonshot.baseUrl`:
|
||||
`https://api.moonshot.cn/v1`), OpenClaw reuses that same host for Kimi
|
||||
`web_search` when `tools.web.search.kimi.baseUrl` is omitted, so keys from
|
||||
[platform.moonshot.cn](https://platform.moonshot.cn/) do not hit the
|
||||
international endpoint by mistake (which often returns HTTP 401). Override
|
||||
with `tools.web.search.kimi.baseUrl` when you need a different search base URL.
|
||||
|
||||
**Environment alternative:** set `KIMI_API_KEY` or `MOONSHOT_API_KEY` in the
|
||||
Gateway environment. For a gateway install, put it in `~/.openclaw/.env`.
|
||||
|
||||
If you omit `baseUrl`, OpenClaw defaults to `https://api.moonshot.ai/v1`.
|
||||
If you omit `model`, OpenClaw defaults to `kimi-k2.5`.
|
||||
|
||||
## How it works
|
||||
|
||||
Kimi uses Moonshot web search to synthesize answers with inline citations,
|
||||
similar to Gemini and Grok's grounded response approach.
|
||||
|
||||
## Supported parameters
|
||||
|
||||
Kimi search supports `query`.
|
||||
|
||||
`count` is accepted for shared `web_search` compatibility, but Kimi still
|
||||
returns one synthesized answer with citations rather than an N-result list.
|
||||
|
||||
Provider-specific filters are not currently supported.
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Moonshot AI](/providers/moonshot) -- Moonshot model + Kimi Coding provider docs
|
||||
- [Gemini Search](/tools/gemini-search) -- AI-synthesized answers via Google grounding
|
||||
- [Grok Search](/tools/grok-search) -- AI-synthesized answers via xAI grounding
|
||||
119
openclaw/docs/tools/llm-task.md
Normal file
119
openclaw/docs/tools/llm-task.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
---
|
||||
summary: "JSON-only LLM tasks for workflows (optional plugin tool)"
|
||||
read_when:
|
||||
- You want a JSON-only LLM step inside workflows
|
||||
- You need schema-validated LLM output for automation
|
||||
title: "LLM Task"
|
||||
---
|
||||
|
||||
# LLM Task
|
||||
|
||||
`llm-task` is an **optional plugin tool** that runs a JSON-only LLM task and
|
||||
returns structured output (optionally validated against JSON Schema).
|
||||
|
||||
This is ideal for workflow engines like Lobster: you can add a single LLM step
|
||||
without writing custom OpenClaw code for each workflow.
|
||||
|
||||
## Enable the plugin
|
||||
|
||||
1. Enable the plugin:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"llm-task": { "enabled": true }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. Allowlist the tool (it is registered with `optional: true`):
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"tools": { "allow": ["llm-task"] }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Config (optional)
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"llm-task": {
|
||||
"enabled": true,
|
||||
"config": {
|
||||
"defaultProvider": "openai-codex",
|
||||
"defaultModel": "gpt-5.4",
|
||||
"defaultAuthProfileId": "main",
|
||||
"allowedModels": ["openai-codex/gpt-5.4"],
|
||||
"maxTokens": 800,
|
||||
"timeoutMs": 30000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`allowedModels` is an allowlist of `provider/model` strings. If set, any request
|
||||
outside the list is rejected.
|
||||
|
||||
## Tool parameters
|
||||
|
||||
- `prompt` (string, required)
|
||||
- `input` (any, optional)
|
||||
- `schema` (object, optional JSON Schema)
|
||||
- `provider` (string, optional)
|
||||
- `model` (string, optional)
|
||||
- `thinking` (string, optional)
|
||||
- `authProfileId` (string, optional)
|
||||
- `temperature` (number, optional)
|
||||
- `maxTokens` (number, optional)
|
||||
- `timeoutMs` (number, optional)
|
||||
|
||||
`thinking` accepts the standard OpenClaw reasoning presets, such as `low` or `medium`.
|
||||
|
||||
## Output
|
||||
|
||||
Returns `details.json` containing the parsed JSON (and validates against
|
||||
`schema` when provided).
|
||||
|
||||
## Example: Lobster workflow step
|
||||
|
||||
```lobster
|
||||
openclaw.invoke --tool llm-task --action json --args-json '{
|
||||
"prompt": "Given the input email, return intent and draft.",
|
||||
"thinking": "low",
|
||||
"input": {
|
||||
"subject": "Hello",
|
||||
"body": "Can you help?"
|
||||
},
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"intent": { "type": "string" },
|
||||
"draft": { "type": "string" }
|
||||
},
|
||||
"required": ["intent", "draft"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
## Safety notes
|
||||
|
||||
- The tool is **JSON-only** and instructs the model to output only JSON (no
|
||||
code fences, no commentary).
|
||||
- No tools are exposed to the model for this run.
|
||||
- Treat output as untrusted unless you validate with `schema`.
|
||||
- Put approvals before any side-effecting step (send, post, exec).
|
||||
350
openclaw/docs/tools/lobster.md
Normal file
350
openclaw/docs/tools/lobster.md
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
---
|
||||
title: Lobster
|
||||
summary: "Typed workflow runtime for OpenClaw with resumable approval gates."
|
||||
read_when:
|
||||
- You want deterministic multi-step workflows with explicit approvals
|
||||
- You need to resume a workflow without re-running earlier steps
|
||||
---
|
||||
|
||||
# Lobster
|
||||
|
||||
Lobster is a workflow shell that lets OpenClaw run multi-step tool sequences as a single, deterministic operation with explicit approval checkpoints.
|
||||
|
||||
Lobster is one authoring layer above detached background work. For flow orchestration above individual tasks, see [Task Flow](/automation/taskflow) (`openclaw tasks flow`). For the task activity ledger, see [`openclaw tasks`](/automation/tasks).
|
||||
|
||||
## Hook
|
||||
|
||||
Your assistant can build the tools that manage itself. Ask for a workflow, and 30 minutes later you have a CLI plus pipelines that run as one call. Lobster is the missing piece: deterministic pipelines, explicit approvals, and resumable state.
|
||||
|
||||
## Why
|
||||
|
||||
Today, complex workflows require many back-and-forth tool calls. Each call costs tokens, and the LLM has to orchestrate every step. Lobster moves that orchestration into a typed runtime:
|
||||
|
||||
- **One call instead of many**: OpenClaw runs one Lobster tool call and gets a structured result.
|
||||
- **Approvals built in**: Side effects (send email, post comment) halt the workflow until explicitly approved.
|
||||
- **Resumable**: Halted workflows return a token; approve and resume without re-running everything.
|
||||
|
||||
## Why a DSL instead of plain programs?
|
||||
|
||||
Lobster is intentionally small. The goal is not "a new language," it's a predictable, AI-friendly pipeline spec with first-class approvals and resume tokens.
|
||||
|
||||
- **Approve/resume is built in**: A normal program can prompt a human, but it can’t _pause and resume_ with a durable token without you inventing that runtime yourself.
|
||||
- **Determinism + auditability**: Pipelines are data, so they’re easy to log, diff, replay, and review.
|
||||
- **Constrained surface for AI**: A tiny grammar + JSON piping reduces “creative” code paths and makes validation realistic.
|
||||
- **Safety policy baked in**: Timeouts, output caps, sandbox checks, and allowlists are enforced by the runtime, not each script.
|
||||
- **Still programmable**: Each step can call any CLI or script. If you want JS/TS, generate `.lobster` files from code.
|
||||
|
||||
## How it works
|
||||
|
||||
OpenClaw runs Lobster workflows **in-process** using an embedded runner. No external CLI subprocess is spawned; the workflow engine executes inside the gateway process and returns a JSON envelope directly.
|
||||
If the pipeline pauses for approval, the tool returns a `resumeToken` so you can continue later.
|
||||
|
||||
## Pattern: small CLI + JSON pipes + approvals
|
||||
|
||||
Build tiny commands that speak JSON, then chain them into a single Lobster call. (Example command names below — swap in your own.)
|
||||
|
||||
```bash
|
||||
inbox list --json
|
||||
inbox categorize --json
|
||||
inbox apply --json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "run",
|
||||
"pipeline": "exec --json --shell 'inbox list --json' | exec --stdin json --shell 'inbox categorize --json' | exec --stdin json --shell 'inbox apply --json' | approve --preview-from-stdin --limit 5 --prompt 'Apply changes?'",
|
||||
"timeoutMs": 30000
|
||||
}
|
||||
```
|
||||
|
||||
If the pipeline requests approval, resume with the token:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "resume",
|
||||
"token": "<resumeToken>",
|
||||
"approve": true
|
||||
}
|
||||
```
|
||||
|
||||
AI triggers the workflow; Lobster executes the steps. Approval gates keep side effects explicit and auditable.
|
||||
|
||||
Example: map input items into tool calls:
|
||||
|
||||
```bash
|
||||
gog.gmail.search --query 'newer_than:1d' \
|
||||
| openclaw.invoke --tool message --action send --each --item-key message --args-json '{"provider":"telegram","to":"..."}'
|
||||
```
|
||||
|
||||
## JSON-only LLM steps (llm-task)
|
||||
|
||||
For workflows that need a **structured LLM step**, enable the optional
|
||||
`llm-task` plugin tool and call it from Lobster. This keeps the workflow
|
||||
deterministic while still letting you classify/summarize/draft with a model.
|
||||
|
||||
Enable the tool:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"llm-task": { "enabled": true }
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"tools": { "allow": ["llm-task"] }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use it in a pipeline:
|
||||
|
||||
```lobster
|
||||
openclaw.invoke --tool llm-task --action json --args-json '{
|
||||
"prompt": "Given the input email, return intent and draft.",
|
||||
"thinking": "low",
|
||||
"input": { "subject": "Hello", "body": "Can you help?" },
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"intent": { "type": "string" },
|
||||
"draft": { "type": "string" }
|
||||
},
|
||||
"required": ["intent", "draft"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
See [LLM Task](/tools/llm-task) for details and configuration options.
|
||||
|
||||
## Workflow files (.lobster)
|
||||
|
||||
Lobster can run YAML/JSON workflow files with `name`, `args`, `steps`, `env`, `condition`, and `approval` fields. In OpenClaw tool calls, set `pipeline` to the file path.
|
||||
|
||||
```yaml
|
||||
name: inbox-triage
|
||||
args:
|
||||
tag:
|
||||
default: "family"
|
||||
steps:
|
||||
- id: collect
|
||||
command: inbox list --json
|
||||
- id: categorize
|
||||
command: inbox categorize --json
|
||||
stdin: $collect.stdout
|
||||
- id: approve
|
||||
command: inbox apply --approve
|
||||
stdin: $categorize.stdout
|
||||
approval: required
|
||||
- id: execute
|
||||
command: inbox apply --execute
|
||||
stdin: $categorize.stdout
|
||||
condition: $approve.approved
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `stdin: $step.stdout` and `stdin: $step.json` pass a prior step’s output.
|
||||
- `condition` (or `when`) can gate steps on `$step.approved`.
|
||||
|
||||
## Install Lobster
|
||||
|
||||
Bundled Lobster workflows run in-process; no separate `lobster` binary is required. The embedded runner ships with the Lobster plugin.
|
||||
|
||||
If you need the standalone Lobster CLI for development or external pipelines, install it from the [Lobster repo](https://github.com/openclaw/lobster) and ensure `lobster` is on `PATH`.
|
||||
|
||||
## Enable the tool
|
||||
|
||||
Lobster is an **optional** plugin tool (not enabled by default).
|
||||
|
||||
Recommended (additive, safe):
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": {
|
||||
"alsoAllow": ["lobster"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Or per-agent:
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"tools": {
|
||||
"alsoAllow": ["lobster"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Avoid using `tools.allow: ["lobster"]` unless you intend to run in restrictive allowlist mode.
|
||||
|
||||
Note: allowlists are opt-in for optional plugins. If your allowlist only names
|
||||
plugin tools (like `lobster`), OpenClaw keeps core tools enabled. To restrict core
|
||||
tools, include the core tools or groups you want in the allowlist too.
|
||||
|
||||
## Example: Email triage
|
||||
|
||||
Without Lobster:
|
||||
|
||||
```
|
||||
User: "Check my email and draft replies"
|
||||
→ openclaw calls gmail.list
|
||||
→ LLM summarizes
|
||||
→ User: "draft replies to #2 and #5"
|
||||
→ LLM drafts
|
||||
→ User: "send #2"
|
||||
→ openclaw calls gmail.send
|
||||
(repeat daily, no memory of what was triaged)
|
||||
```
|
||||
|
||||
With Lobster:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "run",
|
||||
"pipeline": "email.triage --limit 20",
|
||||
"timeoutMs": 30000
|
||||
}
|
||||
```
|
||||
|
||||
Returns a JSON envelope (truncated):
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"status": "needs_approval",
|
||||
"output": [{ "summary": "5 need replies, 2 need action" }],
|
||||
"requiresApproval": {
|
||||
"type": "approval_request",
|
||||
"prompt": "Send 2 draft replies?",
|
||||
"items": [],
|
||||
"resumeToken": "..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
User approves → resume:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "resume",
|
||||
"token": "<resumeToken>",
|
||||
"approve": true
|
||||
}
|
||||
```
|
||||
|
||||
One workflow. Deterministic. Safe.
|
||||
|
||||
## Tool parameters
|
||||
|
||||
### `run`
|
||||
|
||||
Run a pipeline in tool mode.
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "run",
|
||||
"pipeline": "gog.gmail.search --query 'newer_than:1d' | email.triage",
|
||||
"cwd": "workspace",
|
||||
"timeoutMs": 30000,
|
||||
"maxStdoutBytes": 512000
|
||||
}
|
||||
```
|
||||
|
||||
Run a workflow file with args:
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "run",
|
||||
"pipeline": "/path/to/inbox-triage.lobster",
|
||||
"argsJson": "{\"tag\":\"family\"}"
|
||||
}
|
||||
```
|
||||
|
||||
### `resume`
|
||||
|
||||
Continue a halted workflow after approval.
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "resume",
|
||||
"token": "<resumeToken>",
|
||||
"approve": true
|
||||
}
|
||||
```
|
||||
|
||||
### Optional inputs
|
||||
|
||||
- `cwd`: Relative working directory for the pipeline (must stay within the gateway working directory).
|
||||
- `timeoutMs`: Abort the workflow if it exceeds this duration (default: 20000).
|
||||
- `maxStdoutBytes`: Abort the workflow if output exceeds this size (default: 512000).
|
||||
- `argsJson`: JSON string passed to `lobster run --args-json` (workflow files only).
|
||||
|
||||
## Output envelope
|
||||
|
||||
Lobster returns a JSON envelope with one of three statuses:
|
||||
|
||||
- `ok` → finished successfully
|
||||
- `needs_approval` → paused; `requiresApproval.resumeToken` is required to resume
|
||||
- `cancelled` → explicitly denied or cancelled
|
||||
|
||||
The tool surfaces the envelope in both `content` (pretty JSON) and `details` (raw object).
|
||||
|
||||
## Approvals
|
||||
|
||||
If `requiresApproval` is present, inspect the prompt and decide:
|
||||
|
||||
- `approve: true` → resume and continue side effects
|
||||
- `approve: false` → cancel and finalize the workflow
|
||||
|
||||
Use `approve --preview-from-stdin --limit N` to attach a JSON preview to approval requests without custom jq/heredoc glue. Resume tokens are now compact: Lobster stores workflow resume state under its state dir and hands back a small token key.
|
||||
|
||||
## OpenProse
|
||||
|
||||
OpenProse pairs well with Lobster: use `/prose` to orchestrate multi-agent prep, then run a Lobster pipeline for deterministic approvals. If a Prose program needs Lobster, allow the `lobster` tool for sub-agents via `tools.subagents.tools`. See [OpenProse](/prose).
|
||||
|
||||
## Safety
|
||||
|
||||
- **Local in-process only** — workflows execute inside the gateway process; no network calls from the plugin itself.
|
||||
- **No secrets** — Lobster doesn't manage OAuth; it calls OpenClaw tools that do.
|
||||
- **Sandbox-aware** — disabled when the tool context is sandboxed.
|
||||
- **Hardened** — timeouts and output caps enforced by the embedded runner.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`lobster timed out`** → increase `timeoutMs`, or split a long pipeline.
|
||||
- **`lobster output exceeded maxStdoutBytes`** → raise `maxStdoutBytes` or reduce output size.
|
||||
- **`lobster returned invalid JSON`** → ensure the pipeline runs in tool mode and prints only JSON.
|
||||
- **`lobster failed`** → check gateway logs for the embedded runner error details.
|
||||
|
||||
## Learn more
|
||||
|
||||
- [Plugins](/tools/plugin)
|
||||
- [Plugin tool authoring](/plugins/building-plugins#registering-agent-tools)
|
||||
|
||||
## Case study: community workflows
|
||||
|
||||
One public example: a “second brain” CLI + Lobster pipelines that manage three Markdown vaults (personal, partner, shared). The CLI emits JSON for stats, inbox listings, and stale scans; Lobster chains those commands into workflows like `weekly-review`, `inbox-triage`, `memory-consolidation`, and `shared-task-sync`, each with approval gates. AI handles judgment (categorization) when available and falls back to deterministic rules when not.
|
||||
|
||||
- Thread: [https://x.com/plattenschieber/status/2014508656335770033](https://x.com/plattenschieber/status/2014508656335770033)
|
||||
- Repo: [https://github.com/bloomedai/brain-cli](https://github.com/bloomedai/brain-cli)
|
||||
|
||||
## Related
|
||||
|
||||
- [Automation & Tasks](/automation) — scheduling Lobster workflows
|
||||
- [Automation Overview](/automation) — all automation mechanisms
|
||||
- [Tools Overview](/tools) — all available agent tools
|
||||
100
openclaw/docs/tools/loop-detection.md
Normal file
100
openclaw/docs/tools/loop-detection.md
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
title: "Tool-loop detection"
|
||||
summary: "How to enable and tune guardrails that detect repetitive tool-call loops"
|
||||
read_when:
|
||||
- A user reports agents getting stuck repeating tool calls
|
||||
- You need to tune repetitive-call protection
|
||||
- You are editing agent tool/runtime policies
|
||||
---
|
||||
|
||||
# Tool-loop detection
|
||||
|
||||
OpenClaw can keep agents from getting stuck in repeated tool-call patterns.
|
||||
The guard is **disabled by default**.
|
||||
|
||||
Enable it only where needed, because it can block legitimate repeated calls with strict settings.
|
||||
|
||||
## Why this exists
|
||||
|
||||
- Detect repetitive sequences that do not make progress.
|
||||
- Detect high-frequency no-result loops (same tool, same inputs, repeated errors).
|
||||
- Detect specific repeated-call patterns for known polling tools.
|
||||
|
||||
## Configuration block
|
||||
|
||||
Global defaults:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
loopDetection: {
|
||||
enabled: false,
|
||||
historySize: 30,
|
||||
warningThreshold: 10,
|
||||
criticalThreshold: 20,
|
||||
globalCircuitBreakerThreshold: 30,
|
||||
detectors: {
|
||||
genericRepeat: true,
|
||||
knownPollNoProgress: true,
|
||||
pingPong: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Per-agent override (optional):
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
list: [
|
||||
{
|
||||
id: "safe-runner",
|
||||
tools: {
|
||||
loopDetection: {
|
||||
enabled: true,
|
||||
warningThreshold: 8,
|
||||
criticalThreshold: 16,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Field behavior
|
||||
|
||||
- `enabled`: Master switch. `false` means no loop detection is performed.
|
||||
- `historySize`: number of recent tool calls kept for analysis.
|
||||
- `warningThreshold`: threshold before classifying a pattern as warning-only.
|
||||
- `criticalThreshold`: threshold for blocking repetitive loop patterns.
|
||||
- `globalCircuitBreakerThreshold`: global no-progress breaker threshold.
|
||||
- `detectors.genericRepeat`: detects repeated same-tool + same-params patterns.
|
||||
- `detectors.knownPollNoProgress`: detects known polling-like patterns with no state change.
|
||||
- `detectors.pingPong`: detects alternating ping-pong patterns.
|
||||
|
||||
## Recommended setup
|
||||
|
||||
- Start with `enabled: true`, defaults unchanged.
|
||||
- Keep thresholds ordered as `warningThreshold < criticalThreshold < globalCircuitBreakerThreshold`.
|
||||
- If false positives occur:
|
||||
- raise `warningThreshold` and/or `criticalThreshold`
|
||||
- (optionally) raise `globalCircuitBreakerThreshold`
|
||||
- disable only the detector causing issues
|
||||
- reduce `historySize` for less strict historical context
|
||||
|
||||
## Logs and expected behavior
|
||||
|
||||
When a loop is detected, OpenClaw reports a loop event and blocks or dampens the next tool-cycle depending on severity.
|
||||
This protects users from runaway token spend and lockups while preserving normal tool access.
|
||||
|
||||
- Prefer warning and temporary suppression first.
|
||||
- Escalate only when repeated evidence accumulates.
|
||||
|
||||
## Notes
|
||||
|
||||
- `tools.loopDetection` is merged with agent-level overrides.
|
||||
- Per-agent config fully overrides or extends global values.
|
||||
- If no config exists, guardrails stay off.
|
||||
60
openclaw/docs/tools/media-overview.md
Normal file
60
openclaw/docs/tools/media-overview.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
summary: "Unified landing page for media generation, understanding, and speech capabilities"
|
||||
read_when:
|
||||
- Looking for an overview of media capabilities
|
||||
- Deciding which media provider to configure
|
||||
- Understanding how async media generation works
|
||||
title: "Media Overview"
|
||||
---
|
||||
|
||||
# Media Generation and Understanding
|
||||
|
||||
OpenClaw generates images, videos, and music, understands inbound media (images, audio, video), and speaks replies aloud with text-to-speech. All media capabilities are tool-driven: the agent decides when to use them based on the conversation, and each tool only appears when at least one backing provider is configured.
|
||||
|
||||
## Capabilities at a glance
|
||||
|
||||
| Capability | Tool | Providers | What it does |
|
||||
| -------------------- | ---------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| Image generation | `image_generate` | ComfyUI, fal, Google, MiniMax, OpenAI, Vydra | Creates or edits images from text prompts or references |
|
||||
| Video generation | `video_generate` | Alibaba, BytePlus, ComfyUI, fal, Google, MiniMax, OpenAI, Qwen, Runway, Together, Vydra, xAI | Creates videos from text, images, or existing videos |
|
||||
| Music generation | `music_generate` | ComfyUI, Google, MiniMax | Creates music or audio tracks from text prompts |
|
||||
| Text-to-speech (TTS) | `tts` | ElevenLabs, Microsoft, MiniMax, OpenAI | Converts outbound replies to spoken audio |
|
||||
| Media understanding | (automatic) | Any vision/audio-capable model provider, plus CLI fallbacks | Summarizes inbound images, audio, and video |
|
||||
|
||||
## Provider capability matrix
|
||||
|
||||
This table shows which providers support which media capabilities across the platform.
|
||||
|
||||
| Provider | Image | Video | Music | TTS | STT / Transcription | Media Understanding |
|
||||
| ---------- | ----- | ----- | ----- | --- | ------------------- | ------------------- |
|
||||
| Alibaba | | Yes | | | | |
|
||||
| BytePlus | | Yes | | | | |
|
||||
| ComfyUI | Yes | Yes | Yes | | | |
|
||||
| Deepgram | | | | | Yes | |
|
||||
| ElevenLabs | | | | Yes | | |
|
||||
| fal | Yes | Yes | | | | |
|
||||
| Google | Yes | Yes | Yes | | | Yes |
|
||||
| Microsoft | | | | Yes | | |
|
||||
| MiniMax | Yes | Yes | Yes | Yes | | |
|
||||
| OpenAI | Yes | Yes | | Yes | Yes | Yes |
|
||||
| Qwen | | Yes | | | | |
|
||||
| Runway | | Yes | | | | |
|
||||
| Together | | Yes | | | | |
|
||||
| Vydra | Yes | Yes | | | | |
|
||||
| xAI | | Yes | | | | |
|
||||
|
||||
<Note>
|
||||
Media understanding uses any vision-capable or audio-capable model registered in your provider config. The table above highlights providers with dedicated media-understanding support; most LLM providers with multimodal models (Anthropic, Google, OpenAI, etc.) can also understand inbound media when configured as the active reply model.
|
||||
</Note>
|
||||
|
||||
## How async generation works
|
||||
|
||||
Video and music generation run as background tasks because provider processing typically takes 30 seconds to several minutes. When the agent calls `video_generate` or `music_generate`, OpenClaw submits the request to the provider, returns a task ID immediately, and tracks the job in the task ledger. The agent continues responding to other messages while the job runs. When the provider finishes, OpenClaw wakes the agent so it can post the finished media back into the original channel. Image generation and TTS are synchronous and complete inline with the reply.
|
||||
|
||||
## Quick links
|
||||
|
||||
- [Image Generation](/tools/image-generation) -- generating and editing images
|
||||
- [Video Generation](/tools/video-generation) -- text-to-video, image-to-video, and video-to-video
|
||||
- [Music Generation](/tools/music-generation) -- creating music and audio tracks
|
||||
- [Text-to-Speech](/tools/tts) -- converting replies to spoken audio
|
||||
- [Media Understanding](/nodes/media-understanding) -- understanding inbound images, audio, and video
|
||||
99
openclaw/docs/tools/minimax-search.md
Normal file
99
openclaw/docs/tools/minimax-search.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
summary: "MiniMax Search via the Coding Plan search API"
|
||||
read_when:
|
||||
- You want to use MiniMax for web_search
|
||||
- You need a MiniMax Coding Plan key
|
||||
- You want MiniMax CN/global search host guidance
|
||||
title: "MiniMax Search"
|
||||
---
|
||||
|
||||
# MiniMax Search
|
||||
|
||||
OpenClaw supports MiniMax as a `web_search` provider through the MiniMax
|
||||
Coding Plan search API. It returns structured search results with titles, URLs,
|
||||
snippets, and related queries.
|
||||
|
||||
## Get a Coding Plan key
|
||||
|
||||
<Steps>
|
||||
<Step title="Create a key">
|
||||
Create or copy a MiniMax Coding Plan key from
|
||||
[MiniMax Platform](https://platform.minimax.io/user-center/basic-information/interface-key).
|
||||
</Step>
|
||||
<Step title="Store the key">
|
||||
Set `MINIMAX_CODE_PLAN_KEY` in the Gateway environment, or configure via:
|
||||
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
OpenClaw also accepts `MINIMAX_CODING_API_KEY` as an env alias. `MINIMAX_API_KEY`
|
||||
is still read as a compatibility fallback when it already points at a coding-plan token.
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
minimax: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "sk-cp-...", // optional if MINIMAX_CODE_PLAN_KEY is set
|
||||
region: "global", // or "cn"
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "minimax",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**Environment alternative:** set `MINIMAX_CODE_PLAN_KEY` in the Gateway environment.
|
||||
For a gateway install, put it in `~/.openclaw/.env`.
|
||||
|
||||
## Region selection
|
||||
|
||||
MiniMax Search uses these endpoints:
|
||||
|
||||
- Global: `https://api.minimax.io/v1/coding_plan/search`
|
||||
- CN: `https://api.minimaxi.com/v1/coding_plan/search`
|
||||
|
||||
If `plugins.entries.minimax.config.webSearch.region` is unset, OpenClaw resolves
|
||||
the region in this order:
|
||||
|
||||
1. `tools.web.search.minimax.region` / plugin-owned `webSearch.region`
|
||||
2. `MINIMAX_API_HOST`
|
||||
3. `models.providers.minimax.baseUrl`
|
||||
4. `models.providers.minimax-portal.baseUrl`
|
||||
|
||||
That means CN onboarding or `MINIMAX_API_HOST=https://api.minimaxi.com/...`
|
||||
automatically keeps MiniMax Search on the CN host too.
|
||||
|
||||
Even when you authenticated MiniMax through the OAuth `minimax-portal` path,
|
||||
web search still registers as provider id `minimax`; the OAuth provider base URL
|
||||
is only used as a region hint for CN/global host selection.
|
||||
|
||||
## Supported parameters
|
||||
|
||||
MiniMax Search supports:
|
||||
|
||||
- `query`
|
||||
- `count` (OpenClaw trims the returned result list to the requested count)
|
||||
|
||||
Provider-specific filters are not currently supported.
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [MiniMax](/providers/minimax) -- model, image, speech, and auth setup
|
||||
373
openclaw/docs/tools/multi-agent-sandbox-tools.md
Normal file
373
openclaw/docs/tools/multi-agent-sandbox-tools.md
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
---
|
||||
summary: “Per-agent sandbox + tool restrictions, precedence, and examples”
|
||||
title: Multi-Agent Sandbox & Tools
|
||||
read_when: “You want per-agent sandboxing or per-agent tool allow/deny policies in a multi-agent gateway.”
|
||||
status: active
|
||||
---
|
||||
|
||||
# Multi-Agent Sandbox & Tools Configuration
|
||||
|
||||
Each agent in a multi-agent setup can override the global sandbox and tool
|
||||
policy. This page covers per-agent configuration, precedence rules, and
|
||||
examples.
|
||||
|
||||
- **Sandbox backends and modes**: see [Sandboxing](/gateway/sandboxing).
|
||||
- **Debugging blocked tools**: see [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) and `openclaw sandbox explain`.
|
||||
- **Elevated exec**: see [Elevated Mode](/tools/elevated).
|
||||
|
||||
Auth is per-agent: each agent reads from its own `agentDir` auth store at
|
||||
`~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
|
||||
Credentials are **not** shared between agents. Never reuse `agentDir` across agents.
|
||||
If you want to share creds, copy `auth-profiles.json` into the other agent's `agentDir`.
|
||||
|
||||
---
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Example 1: Personal + Restricted Family Agent
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"default": true,
|
||||
"name": "Personal Assistant",
|
||||
"workspace": "~/.openclaw/workspace",
|
||||
"sandbox": { "mode": "off" }
|
||||
},
|
||||
{
|
||||
"id": "family",
|
||||
"name": "Family Bot",
|
||||
"workspace": "~/.openclaw/workspace-family",
|
||||
"sandbox": {
|
||||
"mode": "all",
|
||||
"scope": "agent"
|
||||
},
|
||||
"tools": {
|
||||
"allow": ["read"],
|
||||
"deny": ["exec", "write", "edit", "apply_patch", "process", "browser"]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"bindings": [
|
||||
{
|
||||
"agentId": "family",
|
||||
"match": {
|
||||
"provider": "whatsapp",
|
||||
"accountId": "*",
|
||||
"peer": {
|
||||
"kind": "group",
|
||||
"id": "120363424282127706@g.us"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Result:**
|
||||
|
||||
- `main` agent: Runs on host, full tool access
|
||||
- `family` agent: Runs in Docker (one container per agent), only `read` tool
|
||||
|
||||
---
|
||||
|
||||
### Example 2: Work Agent with Shared Sandbox
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"list": [
|
||||
{
|
||||
"id": "personal",
|
||||
"workspace": "~/.openclaw/workspace-personal",
|
||||
"sandbox": { "mode": "off" }
|
||||
},
|
||||
{
|
||||
"id": "work",
|
||||
"workspace": "~/.openclaw/workspace-work",
|
||||
"sandbox": {
|
||||
"mode": "all",
|
||||
"scope": "shared",
|
||||
"workspaceRoot": "/tmp/work-sandboxes"
|
||||
},
|
||||
"tools": {
|
||||
"allow": ["read", "write", "apply_patch", "exec"],
|
||||
"deny": ["browser", "gateway", "discord"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Example 2b: Global coding profile + messaging-only agent
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": { "profile": "coding" },
|
||||
"agents": {
|
||||
"list": [
|
||||
{
|
||||
"id": "support",
|
||||
"tools": { "profile": "messaging", "allow": ["slack"] }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Result:**
|
||||
|
||||
- default agents get coding tools
|
||||
- `support` agent is messaging-only (+ Slack tool)
|
||||
|
||||
---
|
||||
|
||||
### Example 3: Different Sandbox Modes per Agent
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"sandbox": {
|
||||
"mode": "non-main", // Global default
|
||||
"scope": "session"
|
||||
}
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"workspace": "~/.openclaw/workspace",
|
||||
"sandbox": {
|
||||
"mode": "off" // Override: main never sandboxed
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "public",
|
||||
"workspace": "~/.openclaw/workspace-public",
|
||||
"sandbox": {
|
||||
"mode": "all", // Override: public always sandboxed
|
||||
"scope": "agent"
|
||||
},
|
||||
"tools": {
|
||||
"allow": ["read"],
|
||||
"deny": ["exec", "write", "edit", "apply_patch"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Precedence
|
||||
|
||||
When both global (`agents.defaults.*`) and agent-specific (`agents.list[].*`) configs exist:
|
||||
|
||||
### Sandbox Config
|
||||
|
||||
Agent-specific settings override global:
|
||||
|
||||
```
|
||||
agents.list[].sandbox.mode > agents.defaults.sandbox.mode
|
||||
agents.list[].sandbox.scope > agents.defaults.sandbox.scope
|
||||
agents.list[].sandbox.workspaceRoot > agents.defaults.sandbox.workspaceRoot
|
||||
agents.list[].sandbox.workspaceAccess > agents.defaults.sandbox.workspaceAccess
|
||||
agents.list[].sandbox.docker.* > agents.defaults.sandbox.docker.*
|
||||
agents.list[].sandbox.browser.* > agents.defaults.sandbox.browser.*
|
||||
agents.list[].sandbox.prune.* > agents.defaults.sandbox.prune.*
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
|
||||
- `agents.list[].sandbox.{docker,browser,prune}.*` overrides `agents.defaults.sandbox.{docker,browser,prune}.*` for that agent (ignored when sandbox scope resolves to `"shared"`).
|
||||
|
||||
### Tool Restrictions
|
||||
|
||||
The filtering order is:
|
||||
|
||||
1. **Tool profile** (`tools.profile` or `agents.list[].tools.profile`)
|
||||
2. **Provider tool profile** (`tools.byProvider[provider].profile` or `agents.list[].tools.byProvider[provider].profile`)
|
||||
3. **Global tool policy** (`tools.allow` / `tools.deny`)
|
||||
4. **Provider tool policy** (`tools.byProvider[provider].allow/deny`)
|
||||
5. **Agent-specific tool policy** (`agents.list[].tools.allow/deny`)
|
||||
6. **Agent provider policy** (`agents.list[].tools.byProvider[provider].allow/deny`)
|
||||
7. **Sandbox tool policy** (`tools.sandbox.tools` or `agents.list[].tools.sandbox.tools`)
|
||||
8. **Subagent tool policy** (`tools.subagents.tools`, if applicable)
|
||||
|
||||
Each level can further restrict tools, but cannot grant back denied tools from earlier levels.
|
||||
If `agents.list[].tools.sandbox.tools` is set, it replaces `tools.sandbox.tools` for that agent.
|
||||
If `agents.list[].tools.profile` is set, it overrides `tools.profile` for that agent.
|
||||
Provider tool keys accept either `provider` (e.g. `google-antigravity`) or `provider/model` (e.g. `openai/gpt-5.4`).
|
||||
|
||||
Tool policies support `group:*` shorthands that expand to multiple tools. See [Tool groups](/gateway/sandbox-vs-tool-policy-vs-elevated#tool-groups-shorthands) for the full list.
|
||||
|
||||
Per-agent elevated overrides (`agents.list[].tools.elevated`) can further restrict elevated exec for specific agents. See [Elevated Mode](/tools/elevated) for details.
|
||||
|
||||
---
|
||||
|
||||
## Migration from Single Agent
|
||||
|
||||
**Before (single agent):**
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"workspace": "~/.openclaw/workspace",
|
||||
"sandbox": {
|
||||
"mode": "non-main"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tools": {
|
||||
"sandbox": {
|
||||
"tools": {
|
||||
"allow": ["read", "write", "apply_patch", "exec"],
|
||||
"deny": []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**After (multi-agent with different profiles):**
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"default": true,
|
||||
"workspace": "~/.openclaw/workspace",
|
||||
"sandbox": { "mode": "off" }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Legacy `agent.*` configs are migrated by `openclaw doctor`; prefer `agents.defaults` + `agents.list` going forward.
|
||||
|
||||
---
|
||||
|
||||
## Tool Restriction Examples
|
||||
|
||||
### Read-only Agent
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": {
|
||||
"allow": ["read"],
|
||||
"deny": ["exec", "write", "edit", "apply_patch", "process"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Safe Execution Agent (no file modifications)
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": {
|
||||
"allow": ["read", "exec", "process"],
|
||||
"deny": ["write", "edit", "apply_patch", "browser", "gateway"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Communication-only Agent
|
||||
|
||||
```json
|
||||
{
|
||||
"tools": {
|
||||
"sessions": { "visibility": "tree" },
|
||||
"allow": ["sessions_list", "sessions_send", "sessions_history", "session_status"],
|
||||
"deny": ["exec", "write", "edit", "apply_patch", "read", "browser"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`sessions_history` in this profile still returns a bounded, sanitized recall
|
||||
view rather than a raw transcript dump. Assistant recall strips thinking tags,
|
||||
`<relevant-memories>` scaffolding, plain-text tool-call XML payloads
|
||||
(including `<tool_call>...</tool_call>`,
|
||||
`<function_call>...</function_call>`, `<tool_calls>...</tool_calls>`,
|
||||
`<function_calls>...</function_calls>`, and truncated tool-call blocks),
|
||||
downgraded tool-call scaffolding, leaked ASCII/full-width model control
|
||||
tokens, and malformed MiniMax tool-call XML before redaction/truncation.
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfall: "non-main"
|
||||
|
||||
`agents.defaults.sandbox.mode: "non-main"` is based on `session.mainKey` (default `"main"`),
|
||||
not the agent id. Group/channel sessions always get their own keys, so they
|
||||
are treated as non-main and will be sandboxed. If you want an agent to never
|
||||
sandbox, set `agents.list[].sandbox.mode: "off"`.
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
After configuring multi-agent sandbox and tools:
|
||||
|
||||
1. **Check agent resolution:**
|
||||
|
||||
```exec
|
||||
openclaw agents list --bindings
|
||||
```
|
||||
|
||||
2. **Verify sandbox containers:**
|
||||
|
||||
```exec
|
||||
docker ps --filter "name=openclaw-sbx-"
|
||||
```
|
||||
|
||||
3. **Test tool restrictions:**
|
||||
- Send a message requiring restricted tools
|
||||
- Verify the agent cannot use denied tools
|
||||
|
||||
4. **Monitor logs:**
|
||||
|
||||
```exec
|
||||
tail -f "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/logs/gateway.log" | grep -E "routing|sandbox|tools"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Agent not sandboxed despite `mode: "all"`
|
||||
|
||||
- Check if there's a global `agents.defaults.sandbox.mode` that overrides it
|
||||
- Agent-specific config takes precedence, so set `agents.list[].sandbox.mode: "all"`
|
||||
|
||||
### Tools still available despite deny list
|
||||
|
||||
- Check tool filtering order: global → agent → sandbox → subagent
|
||||
- Each level can only further restrict, not grant back
|
||||
- Verify with logs: `[tools] filtering tools for agent:${agentId}`
|
||||
|
||||
### Container not isolated per agent
|
||||
|
||||
- Set `scope: "agent"` in agent-specific sandbox config
|
||||
- Default is `"session"` which creates one container per session
|
||||
|
||||
---
|
||||
|
||||
## See also
|
||||
|
||||
- [Sandboxing](/gateway/sandboxing) -- full sandbox reference (modes, scopes, backends, images)
|
||||
- [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) -- debugging "why is this blocked?"
|
||||
- [Elevated Mode](/tools/elevated)
|
||||
- [Multi-Agent Routing](/concepts/multi-agent)
|
||||
- [Sandbox Configuration](/gateway/configuration-reference#agentsdefaultssandbox)
|
||||
- [Session Management](/concepts/session)
|
||||
292
openclaw/docs/tools/music-generation.md
Normal file
292
openclaw/docs/tools/music-generation.md
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
---
|
||||
summary: "Generate music with shared providers, including workflow-backed plugins"
|
||||
read_when:
|
||||
- Generating music or audio via the agent
|
||||
- Configuring music generation providers and models
|
||||
- Understanding the music_generate tool parameters
|
||||
title: "Music Generation"
|
||||
---
|
||||
|
||||
# Music Generation
|
||||
|
||||
The `music_generate` tool lets the agent create music or audio through the
|
||||
shared music-generation capability with configured providers such as Google,
|
||||
MiniMax, and workflow-configured ComfyUI.
|
||||
|
||||
For shared provider-backed agent sessions, OpenClaw starts music generation as a
|
||||
background task, tracks it in the task ledger, then wakes the agent again when
|
||||
the track is ready so the agent can post the finished audio back into the
|
||||
original channel.
|
||||
|
||||
<Note>
|
||||
The built-in shared tool only appears when at least one music-generation provider is available. If you don't see `music_generate` in your agent's tools, configure `agents.defaults.musicGenerationModel` or set up a provider API key.
|
||||
</Note>
|
||||
|
||||
## Quick start
|
||||
|
||||
### Shared provider-backed generation
|
||||
|
||||
1. Set an API key for at least one provider, for example `GEMINI_API_KEY` or
|
||||
`MINIMAX_API_KEY`.
|
||||
2. Optionally set your preferred model:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
musicGenerationModel: {
|
||||
primary: "google/lyria-3-clip-preview",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
3. Ask the agent: _"Generate an upbeat synthpop track about a night drive
|
||||
through a neon city."_
|
||||
|
||||
The agent calls `music_generate` automatically. No tool allow-listing needed.
|
||||
|
||||
For direct synchronous contexts without a session-backed agent run, the built-in
|
||||
tool still falls back to inline generation and returns the final media path in
|
||||
the tool result.
|
||||
|
||||
Example prompts:
|
||||
|
||||
```text
|
||||
Generate a cinematic piano track with soft strings and no vocals.
|
||||
```
|
||||
|
||||
```text
|
||||
Generate an energetic chiptune loop about launching a rocket at sunrise.
|
||||
```
|
||||
|
||||
### Workflow-driven Comfy generation
|
||||
|
||||
The bundled `comfy` plugin plugs into the shared `music_generate` tool through
|
||||
the music-generation provider registry.
|
||||
|
||||
1. Configure `models.providers.comfy.music` with a workflow JSON and
|
||||
prompt/output nodes.
|
||||
2. If you use Comfy Cloud, set `COMFY_API_KEY` or `COMFY_CLOUD_API_KEY`.
|
||||
3. Ask the agent for music or call the tool directly.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
/tool music_generate prompt="Warm ambient synth loop with soft tape texture"
|
||||
```
|
||||
|
||||
## Shared bundled provider support
|
||||
|
||||
| Provider | Default model | Reference inputs | Supported controls | API key |
|
||||
| -------- | ---------------------- | ---------------- | --------------------------------------------------------- | -------------------------------------- |
|
||||
| ComfyUI | `workflow` | Up to 1 image | Workflow-defined music or audio | `COMFY_API_KEY`, `COMFY_CLOUD_API_KEY` |
|
||||
| Google | `lyria-3-clip-preview` | Up to 10 images | `lyrics`, `instrumental`, `format` | `GEMINI_API_KEY`, `GOOGLE_API_KEY` |
|
||||
| MiniMax | `music-2.5+` | None | `lyrics`, `instrumental`, `durationSeconds`, `format=mp3` | `MINIMAX_API_KEY` |
|
||||
|
||||
### Declared capability matrix
|
||||
|
||||
This is the explicit mode contract used by `music_generate`, contract tests,
|
||||
and the shared live sweep.
|
||||
|
||||
| Provider | `generate` | `edit` | Edit limit | Shared live lanes |
|
||||
| -------- | ---------- | ------ | ---------- | ------------------------------------------------------------------------- |
|
||||
| ComfyUI | Yes | Yes | 1 image | Not in the shared sweep; covered by `extensions/comfy/comfy.live.test.ts` |
|
||||
| Google | Yes | Yes | 10 images | `generate`, `edit` |
|
||||
| MiniMax | Yes | No | None | `generate` |
|
||||
|
||||
Use `action: "list"` to inspect available shared providers and models at
|
||||
runtime:
|
||||
|
||||
```text
|
||||
/tool music_generate action=list
|
||||
```
|
||||
|
||||
Use `action: "status"` to inspect the active session-backed music task:
|
||||
|
||||
```text
|
||||
/tool music_generate action=status
|
||||
```
|
||||
|
||||
Direct generation example:
|
||||
|
||||
```text
|
||||
/tool music_generate prompt="Dreamy lo-fi hip hop with vinyl texture and gentle rain" instrumental=true
|
||||
```
|
||||
|
||||
## Built-in tool parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ----------------- | -------- | ------------------------------------------------------------------------------------------------- |
|
||||
| `prompt` | string | Music generation prompt (required for `action: "generate"`) |
|
||||
| `action` | string | `"generate"` (default), `"status"` for the current session task, or `"list"` to inspect providers |
|
||||
| `model` | string | Provider/model override, e.g. `google/lyria-3-pro-preview` or `comfy/workflow` |
|
||||
| `lyrics` | string | Optional lyrics when the provider supports explicit lyric input |
|
||||
| `instrumental` | boolean | Request instrumental-only output when the provider supports it |
|
||||
| `image` | string | Single reference image path or URL |
|
||||
| `images` | string[] | Multiple reference images (up to 10) |
|
||||
| `durationSeconds` | number | Target duration in seconds when the provider supports duration hints |
|
||||
| `format` | string | Output format hint (`mp3` or `wav`) when the provider supports it |
|
||||
| `filename` | string | Output filename hint |
|
||||
|
||||
Not all providers support all parameters. OpenClaw still validates hard limits
|
||||
such as input counts before submission. When a provider supports duration but
|
||||
uses a shorter maximum than the requested value, OpenClaw automatically clamps
|
||||
to the closest supported duration. Truly unsupported optional hints are ignored
|
||||
with a warning when the selected provider or model cannot honor them.
|
||||
|
||||
Tool results report the applied settings. When OpenClaw clamps duration during provider fallback, the returned `durationSeconds` reflects the submitted value and `details.normalization.durationSeconds` shows the requested-to-applied mapping.
|
||||
|
||||
## Async behavior for the shared provider-backed path
|
||||
|
||||
- Session-backed agent runs: `music_generate` creates a background task, returns a started/task response immediately, and posts the finished track later in a follow-up agent message.
|
||||
- Duplicate prevention: while that background task is still `queued` or `running`, later `music_generate` calls in the same session return task status instead of starting another generation.
|
||||
- Status lookup: use `action: "status"` to inspect the active session-backed music task without starting a new one.
|
||||
- Task tracking: use `openclaw tasks list` or `openclaw tasks show <taskId>` to inspect queued, running, and terminal status for the generation.
|
||||
- Completion wake: OpenClaw injects an internal completion event back into the same session so the model can write the user-facing follow-up itself.
|
||||
- Prompt hint: later user/manual turns in the same session get a small runtime hint when a music task is already in flight so the model does not blindly call `music_generate` again.
|
||||
- No-session fallback: direct/local contexts without a real agent session still run inline and return the final audio result in the same turn.
|
||||
|
||||
### Task lifecycle
|
||||
|
||||
Each `music_generate` request moves through four states:
|
||||
|
||||
1. **queued** -- task created, waiting for the provider to accept it.
|
||||
2. **running** -- provider is processing (typically 30 seconds to 3 minutes depending on provider and duration).
|
||||
3. **succeeded** -- track ready; the agent wakes and posts it to the conversation.
|
||||
4. **failed** -- provider error or timeout; the agent wakes with error details.
|
||||
|
||||
Check status from the CLI:
|
||||
|
||||
```bash
|
||||
openclaw tasks list
|
||||
openclaw tasks show <taskId>
|
||||
openclaw tasks cancel <taskId>
|
||||
```
|
||||
|
||||
Duplicate prevention: if a music task is already `queued` or `running` for the current session, `music_generate` returns the existing task status instead of starting a new one. Use `action: "status"` to check explicitly without triggering a new generation.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Model selection
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
musicGenerationModel: {
|
||||
primary: "google/lyria-3-clip-preview",
|
||||
fallbacks: ["minimax/music-2.5+"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Provider selection order
|
||||
|
||||
When generating music, OpenClaw tries providers in this order:
|
||||
|
||||
1. `model` parameter from the tool call, if the agent specifies one
|
||||
2. `musicGenerationModel.primary` from config
|
||||
3. `musicGenerationModel.fallbacks` in order
|
||||
4. Auto-detection using auth-backed provider defaults only:
|
||||
- current default provider first
|
||||
- remaining registered music-generation providers in provider-id order
|
||||
|
||||
If a provider fails, the next candidate is tried automatically. If all fail, the
|
||||
error includes details from each attempt.
|
||||
|
||||
Set `agents.defaults.mediaGenerationAutoProviderFallback: false` if you want
|
||||
music generation to use only the explicit `model`, `primary`, and `fallbacks`
|
||||
entries.
|
||||
|
||||
## Provider notes
|
||||
|
||||
- Google uses Lyria 3 batch generation. The current bundled flow supports
|
||||
prompt, optional lyrics text, and optional reference images.
|
||||
- MiniMax uses the batch `music_generation` endpoint. The current bundled flow
|
||||
supports prompt, optional lyrics, instrumental mode, duration steering, and
|
||||
mp3 output.
|
||||
- ComfyUI support is workflow-driven and depends on the configured graph plus
|
||||
node mapping for prompt/output fields.
|
||||
|
||||
## Provider capability modes
|
||||
|
||||
The shared music-generation contract now supports explicit mode declarations:
|
||||
|
||||
- `generate` for prompt-only generation
|
||||
- `edit` when the request includes one or more reference images
|
||||
|
||||
New provider implementations should prefer explicit mode blocks:
|
||||
|
||||
```typescript
|
||||
capabilities: {
|
||||
generate: {
|
||||
maxTracks: 1,
|
||||
supportsLyrics: true,
|
||||
supportsFormat: true,
|
||||
},
|
||||
edit: {
|
||||
enabled: true,
|
||||
maxTracks: 1,
|
||||
maxInputImages: 1,
|
||||
supportsFormat: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Legacy flat fields such as `maxInputImages`, `supportsLyrics`, and
|
||||
`supportsFormat` are not enough to advertise edit support. Providers should
|
||||
declare `generate` and `edit` explicitly so live tests, contract tests, and
|
||||
the shared `music_generate` tool can validate mode support deterministically.
|
||||
|
||||
## Choosing the right path
|
||||
|
||||
- Use the shared provider-backed path when you want model selection, provider failover, and the built-in async task/status flow.
|
||||
- Use a plugin path such as ComfyUI when you need a custom workflow graph or a provider that is not part of the shared bundled music capability.
|
||||
- If you are debugging ComfyUI-specific behavior, see [ComfyUI](/providers/comfy). If you are debugging shared provider behavior, start with [Google (Gemini)](/providers/google) or [MiniMax](/providers/minimax).
|
||||
|
||||
## Live tests
|
||||
|
||||
Opt-in live coverage for the shared bundled providers:
|
||||
|
||||
```bash
|
||||
OPENCLAW_LIVE_TEST=1 pnpm test:live -- extensions/music-generation-providers.live.test.ts
|
||||
```
|
||||
|
||||
Repo wrapper:
|
||||
|
||||
```bash
|
||||
pnpm test:live:media music
|
||||
```
|
||||
|
||||
This live file loads missing provider env vars from `~/.profile`, prefers
|
||||
live/env API keys ahead of stored auth profiles by default, and runs both
|
||||
`generate` and declared `edit` coverage when the provider enables edit mode.
|
||||
|
||||
Today that means:
|
||||
|
||||
- `google`: `generate` plus `edit`
|
||||
- `minimax`: `generate` only
|
||||
- `comfy`: separate Comfy live coverage, not the shared provider sweep
|
||||
|
||||
Opt-in live coverage for the bundled ComfyUI music path:
|
||||
|
||||
```bash
|
||||
OPENCLAW_LIVE_TEST=1 COMFY_LIVE_TEST=1 pnpm test:live -- extensions/comfy/comfy.live.test.ts
|
||||
```
|
||||
|
||||
The Comfy live file also covers comfy image and video workflows when those
|
||||
sections are configured.
|
||||
|
||||
## Related
|
||||
|
||||
- [Background Tasks](/automation/tasks) - task tracking for detached `music_generate` runs
|
||||
- [Configuration Reference](/gateway/configuration-reference#agent-defaults) - `musicGenerationModel` config
|
||||
- [ComfyUI](/providers/comfy)
|
||||
- [Google (Gemini)](/providers/google)
|
||||
- [MiniMax](/providers/minimax)
|
||||
- [Models](/concepts/models) - model configuration and failover
|
||||
- [Tools Overview](/tools)
|
||||
100
openclaw/docs/tools/ollama-search.md
Normal file
100
openclaw/docs/tools/ollama-search.md
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
summary: "Ollama Web Search via your configured Ollama host"
|
||||
read_when:
|
||||
- You want to use Ollama for web_search
|
||||
- You want a key-free web_search provider
|
||||
- You need Ollama Web Search setup guidance
|
||||
title: "Ollama Web Search"
|
||||
---
|
||||
|
||||
# Ollama Web Search
|
||||
|
||||
OpenClaw supports **Ollama Web Search** as a bundled `web_search` provider.
|
||||
It uses Ollama's experimental web-search API and returns structured results
|
||||
with titles, URLs, and snippets.
|
||||
|
||||
Unlike the Ollama model provider, this setup does not need an API key by
|
||||
default. It does require:
|
||||
|
||||
- an Ollama host that is reachable from OpenClaw
|
||||
- `ollama signin`
|
||||
|
||||
## Setup
|
||||
|
||||
<Steps>
|
||||
<Step title="Start Ollama">
|
||||
Make sure Ollama is installed and running.
|
||||
</Step>
|
||||
<Step title="Sign in">
|
||||
Run:
|
||||
|
||||
```bash
|
||||
ollama signin
|
||||
```
|
||||
|
||||
</Step>
|
||||
<Step title="Choose Ollama Web Search">
|
||||
Run:
|
||||
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
|
||||
Then select **Ollama Web Search** as the provider.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
If you already use Ollama for models, Ollama Web Search reuses the same
|
||||
configured host.
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "ollama",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Optional Ollama host override:
|
||||
|
||||
```json5
|
||||
{
|
||||
models: {
|
||||
providers: {
|
||||
ollama: {
|
||||
baseUrl: "http://ollama-host:11434",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If no explicit Ollama base URL is set, OpenClaw uses `http://127.0.0.1:11434`.
|
||||
|
||||
If your Ollama host expects bearer auth, OpenClaw reuses
|
||||
`models.providers.ollama.apiKey` (or the matching env-backed provider auth)
|
||||
for web-search requests too.
|
||||
|
||||
## Notes
|
||||
|
||||
- No web-search-specific API key field is required for this provider.
|
||||
- If the Ollama host is auth-protected, OpenClaw reuses the normal Ollama
|
||||
provider API key when present.
|
||||
- OpenClaw warns during setup if Ollama is unreachable or not signed in, but
|
||||
it does not block selection.
|
||||
- Runtime auto-detect can fall back to Ollama Web Search when no higher-priority
|
||||
credentialed provider is configured.
|
||||
- The provider uses Ollama's experimental `/api/experimental/web_search`
|
||||
endpoint.
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Ollama](/providers/ollama) -- Ollama model setup and cloud/local modes
|
||||
176
openclaw/docs/tools/pdf.md
Normal file
176
openclaw/docs/tools/pdf.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
---
|
||||
title: "PDF Tool"
|
||||
summary: "Analyze one or more PDF documents with native provider support and extraction fallback"
|
||||
read_when:
|
||||
- You want to analyze PDFs from agents
|
||||
- You need exact pdf tool parameters and limits
|
||||
- You are debugging native PDF mode vs extraction fallback
|
||||
---
|
||||
|
||||
# PDF tool
|
||||
|
||||
`pdf` analyzes one or more PDF documents and returns text.
|
||||
|
||||
Quick behavior:
|
||||
|
||||
- Native provider mode for Anthropic and Google model providers.
|
||||
- Extraction fallback mode for other providers (extract text first, then page images when needed).
|
||||
- Supports single (`pdf`) or multi (`pdfs`) input, max 10 PDFs per call.
|
||||
|
||||
## Availability
|
||||
|
||||
The tool is only registered when OpenClaw can resolve a PDF-capable model config for the agent:
|
||||
|
||||
1. `agents.defaults.pdfModel`
|
||||
2. fallback to `agents.defaults.imageModel`
|
||||
3. fallback to the agent's resolved session/default model
|
||||
4. if native-PDF providers are auth-backed, prefer them ahead of generic image fallback candidates
|
||||
|
||||
If no usable model can be resolved, the `pdf` tool is not exposed.
|
||||
|
||||
Availability notes:
|
||||
|
||||
- The fallback chain is auth-aware. A configured `provider/model` only counts if
|
||||
OpenClaw can actually authenticate that provider for the agent.
|
||||
- Native PDF providers are currently **Anthropic** and **Google**.
|
||||
- If the resolved session/default provider already has a configured vision/PDF
|
||||
model, the PDF tool reuses that before falling back to other auth-backed
|
||||
providers.
|
||||
|
||||
## Input reference
|
||||
|
||||
- `pdf` (`string`): one PDF path or URL
|
||||
- `pdfs` (`string[]`): multiple PDF paths or URLs, up to 10 total
|
||||
- `prompt` (`string`): analysis prompt, default `Analyze this PDF document.`
|
||||
- `pages` (`string`): page filter like `1-5` or `1,3,7-9`
|
||||
- `model` (`string`): optional model override (`provider/model`)
|
||||
- `maxBytesMb` (`number`): per-PDF size cap in MB
|
||||
|
||||
Input notes:
|
||||
|
||||
- `pdf` and `pdfs` are merged and deduplicated before loading.
|
||||
- If no PDF input is provided, the tool errors.
|
||||
- `pages` is parsed as 1-based page numbers, deduped, sorted, and clamped to the configured max pages.
|
||||
- `maxBytesMb` defaults to `agents.defaults.pdfMaxBytesMb` or `10`.
|
||||
|
||||
## Supported PDF references
|
||||
|
||||
- local file path (including `~` expansion)
|
||||
- `file://` URL
|
||||
- `http://` and `https://` URL
|
||||
|
||||
Reference notes:
|
||||
|
||||
- Other URI schemes (for example `ftp://`) are rejected with `unsupported_pdf_reference`.
|
||||
- In sandbox mode, remote `http(s)` URLs are rejected.
|
||||
- With workspace-only file policy enabled, local file paths outside allowed roots are rejected.
|
||||
|
||||
## Execution modes
|
||||
|
||||
### Native provider mode
|
||||
|
||||
Native mode is used for provider `anthropic` and `google`.
|
||||
The tool sends raw PDF bytes directly to provider APIs.
|
||||
|
||||
Native mode limits:
|
||||
|
||||
- `pages` is not supported. If set, the tool returns an error.
|
||||
- Multi-PDF input is supported; each PDF is sent as a native document block /
|
||||
inline PDF part before the prompt.
|
||||
|
||||
### Extraction fallback mode
|
||||
|
||||
Fallback mode is used for non-native providers.
|
||||
|
||||
Flow:
|
||||
|
||||
1. Extract text from selected pages (up to `agents.defaults.pdfMaxPages`, default `20`).
|
||||
2. If extracted text length is below `200` chars, render selected pages to PNG images and include them.
|
||||
3. Send extracted content plus prompt to the selected model.
|
||||
|
||||
Fallback details:
|
||||
|
||||
- Page image extraction uses a pixel budget of `4,000,000`.
|
||||
- If the target model does not support image input and there is no extractable text, the tool errors.
|
||||
- If text extraction succeeds but image extraction would require vision on a
|
||||
text-only model, OpenClaw drops the rendered images and continues with the
|
||||
extracted text.
|
||||
- Extraction fallback requires `pdfjs-dist` (and `@napi-rs/canvas` for image rendering).
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
pdfModel: {
|
||||
primary: "anthropic/claude-opus-4-6",
|
||||
fallbacks: ["openai/gpt-5.4-mini"],
|
||||
},
|
||||
pdfMaxBytesMb: 10,
|
||||
pdfMaxPages: 20,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
See [Configuration Reference](/gateway/configuration-reference) for full field details.
|
||||
|
||||
## Output details
|
||||
|
||||
The tool returns text in `content[0].text` and structured metadata in `details`.
|
||||
|
||||
Common `details` fields:
|
||||
|
||||
- `model`: resolved model ref (`provider/model`)
|
||||
- `native`: `true` for native provider mode, `false` for fallback
|
||||
- `attempts`: fallback attempts that failed before success
|
||||
|
||||
Path fields:
|
||||
|
||||
- single PDF input: `details.pdf`
|
||||
- multiple PDF inputs: `details.pdfs[]` with `pdf` entries
|
||||
- sandbox path rewrite metadata (when applicable): `rewrittenFrom`
|
||||
|
||||
## Error behavior
|
||||
|
||||
- Missing PDF input: throws `pdf required: provide a path or URL to a PDF document`
|
||||
- Too many PDFs: returns structured error in `details.error = "too_many_pdfs"`
|
||||
- Unsupported reference scheme: returns `details.error = "unsupported_pdf_reference"`
|
||||
- Native mode with `pages`: throws clear `pages is not supported with native PDF providers` error
|
||||
|
||||
## Examples
|
||||
|
||||
Single PDF:
|
||||
|
||||
```json
|
||||
{
|
||||
"pdf": "/tmp/report.pdf",
|
||||
"prompt": "Summarize this report in 5 bullets"
|
||||
}
|
||||
```
|
||||
|
||||
Multiple PDFs:
|
||||
|
||||
```json
|
||||
{
|
||||
"pdfs": ["/tmp/q1.pdf", "/tmp/q2.pdf"],
|
||||
"prompt": "Compare risks and timeline changes across both documents"
|
||||
}
|
||||
```
|
||||
|
||||
Page-filtered fallback model:
|
||||
|
||||
```json
|
||||
{
|
||||
"pdf": "https://example.com/report.pdf",
|
||||
"pages": "1-3,7",
|
||||
"model": "openai/gpt-5.4-mini",
|
||||
"prompt": "Extract only customer-impacting incidents"
|
||||
}
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Tools Overview](/tools) — all available agent tools
|
||||
- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — pdfMaxBytesMb and pdfMaxPages config
|
||||
185
openclaw/docs/tools/perplexity-search.md
Normal file
185
openclaw/docs/tools/perplexity-search.md
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
---
|
||||
summary: "Perplexity Search API and Sonar/OpenRouter compatibility for web_search"
|
||||
read_when:
|
||||
- You want to use Perplexity Search for web search
|
||||
- You need PERPLEXITY_API_KEY or OPENROUTER_API_KEY setup
|
||||
title: "Perplexity Search"
|
||||
---
|
||||
|
||||
# Perplexity Search API
|
||||
|
||||
OpenClaw supports Perplexity Search API as a `web_search` provider.
|
||||
It returns structured results with `title`, `url`, and `snippet` fields.
|
||||
|
||||
For compatibility, OpenClaw also supports legacy Perplexity Sonar/OpenRouter setups.
|
||||
If you use `OPENROUTER_API_KEY`, an `sk-or-...` key in `plugins.entries.perplexity.config.webSearch.apiKey`, or set `plugins.entries.perplexity.config.webSearch.baseUrl` / `model`, the provider switches to the chat-completions path and returns AI-synthesized answers with citations instead of structured Search API results.
|
||||
|
||||
## Getting a Perplexity API key
|
||||
|
||||
1. Create a Perplexity account at [perplexity.ai/settings/api](https://www.perplexity.ai/settings/api)
|
||||
2. Generate an API key in the dashboard
|
||||
3. Store the key in config or set `PERPLEXITY_API_KEY` in the Gateway environment.
|
||||
|
||||
## OpenRouter compatibility
|
||||
|
||||
If you were already using OpenRouter for Perplexity Sonar, keep `provider: "perplexity"` and set `OPENROUTER_API_KEY` in the Gateway environment, or store an `sk-or-...` key in `plugins.entries.perplexity.config.webSearch.apiKey`.
|
||||
|
||||
Optional compatibility controls:
|
||||
|
||||
- `plugins.entries.perplexity.config.webSearch.baseUrl`
|
||||
- `plugins.entries.perplexity.config.webSearch.model`
|
||||
|
||||
## Config examples
|
||||
|
||||
### Native Perplexity Search API
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
perplexity: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "pplx-...",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "perplexity",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### OpenRouter / Sonar compatibility
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
perplexity: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "<openrouter-api-key>",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
model: "perplexity/sonar-pro",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "perplexity",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Where to set the key
|
||||
|
||||
**Via config:** run `openclaw configure --section web`. It stores the key in
|
||||
`~/.openclaw/openclaw.json` under `plugins.entries.perplexity.config.webSearch.apiKey`.
|
||||
That field also accepts SecretRef objects.
|
||||
|
||||
**Via environment:** set `PERPLEXITY_API_KEY` or `OPENROUTER_API_KEY`
|
||||
in the Gateway process environment. For a gateway install, put it in
|
||||
`~/.openclaw/.env` (or your service environment). See [Env vars](/help/faq#env-vars-and-env-loading).
|
||||
|
||||
If `provider: "perplexity"` is configured and the Perplexity key SecretRef is unresolved with no env fallback, startup/reload fails fast.
|
||||
|
||||
## Tool parameters
|
||||
|
||||
These parameters apply to the native Perplexity Search API path.
|
||||
|
||||
| Parameter | Description |
|
||||
| --------------------- | ---------------------------------------------------- |
|
||||
| `query` | Search query (required) |
|
||||
| `count` | Number of results to return (1-10, default: 5) |
|
||||
| `country` | 2-letter ISO country code (e.g., "US", "DE") |
|
||||
| `language` | ISO 639-1 language code (e.g., "en", "de", "fr") |
|
||||
| `freshness` | Time filter: `day` (24h), `week`, `month`, or `year` |
|
||||
| `date_after` | Only results published after this date (YYYY-MM-DD) |
|
||||
| `date_before` | Only results published before this date (YYYY-MM-DD) |
|
||||
| `domain_filter` | Domain allowlist/denylist array (max 20) |
|
||||
| `max_tokens` | Total content budget (default: 25000, max: 1000000) |
|
||||
| `max_tokens_per_page` | Per-page token limit (default: 2048) |
|
||||
|
||||
For the legacy Sonar/OpenRouter compatibility path:
|
||||
|
||||
- `query`, `count`, and `freshness` are accepted
|
||||
- `count` is compatibility-only there; the response is still one synthesized
|
||||
answer with citations rather than an N-result list
|
||||
- Search API-only filters such as `country`, `language`, `date_after`,
|
||||
`date_before`, `domain_filter`, `max_tokens`, and `max_tokens_per_page`
|
||||
return explicit errors
|
||||
|
||||
**Examples:**
|
||||
|
||||
```javascript
|
||||
// Country and language-specific search
|
||||
await web_search({
|
||||
query: "renewable energy",
|
||||
country: "DE",
|
||||
language: "de",
|
||||
});
|
||||
|
||||
// Recent results (past week)
|
||||
await web_search({
|
||||
query: "AI news",
|
||||
freshness: "week",
|
||||
});
|
||||
|
||||
// Date range search
|
||||
await web_search({
|
||||
query: "AI developments",
|
||||
date_after: "2024-01-01",
|
||||
date_before: "2024-06-30",
|
||||
});
|
||||
|
||||
// Domain filtering (allowlist)
|
||||
await web_search({
|
||||
query: "climate research",
|
||||
domain_filter: ["nature.com", "science.org", ".edu"],
|
||||
});
|
||||
|
||||
// Domain filtering (denylist - prefix with -)
|
||||
await web_search({
|
||||
query: "product reviews",
|
||||
domain_filter: ["-reddit.com", "-pinterest.com"],
|
||||
});
|
||||
|
||||
// More content extraction
|
||||
await web_search({
|
||||
query: "detailed AI research",
|
||||
max_tokens: 50000,
|
||||
max_tokens_per_page: 4096,
|
||||
});
|
||||
```
|
||||
|
||||
### Domain filter rules
|
||||
|
||||
- Maximum 20 domains per filter
|
||||
- Cannot mix allowlist and denylist in the same request
|
||||
- Use `-` prefix for denylist entries (e.g., `["-reddit.com"]`)
|
||||
|
||||
## Notes
|
||||
|
||||
- Perplexity Search API returns structured web search results (`title`, `url`, `snippet`)
|
||||
- OpenRouter or explicit `plugins.entries.perplexity.config.webSearch.baseUrl` / `model` switches Perplexity back to Sonar chat completions for compatibility
|
||||
- Sonar/OpenRouter compatibility returns one synthesized answer with citations, not structured result rows
|
||||
- Results are cached for 15 minutes by default (configurable via `cacheTtlMinutes`)
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Perplexity Search API docs](https://docs.perplexity.ai/docs/search/quickstart) -- official Perplexity documentation
|
||||
- [Brave Search](/tools/brave-search) -- structured results with country/language filters
|
||||
- [Exa Search](/tools/exa-search) -- neural search with content extraction
|
||||
349
openclaw/docs/tools/plugin.md
Normal file
349
openclaw/docs/tools/plugin.md
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
---
|
||||
summary: "Install, configure, and manage OpenClaw plugins"
|
||||
read_when:
|
||||
- Installing or configuring plugins
|
||||
- Understanding plugin discovery and load rules
|
||||
- Working with Codex/Claude-compatible plugin bundles
|
||||
title: "Plugins"
|
||||
sidebarTitle: "Install and Configure"
|
||||
---
|
||||
|
||||
# Plugins
|
||||
|
||||
Plugins extend OpenClaw with new capabilities: channels, model providers,
|
||||
tools, skills, speech, realtime transcription, realtime voice,
|
||||
media-understanding, image generation, video generation, web fetch, web
|
||||
search, and more. Some plugins are **core** (shipped with OpenClaw), others
|
||||
are **external** (published on npm by the community).
|
||||
|
||||
## Quick start
|
||||
|
||||
<Steps>
|
||||
<Step title="See what is loaded">
|
||||
```bash
|
||||
openclaw plugins list
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="Install a plugin">
|
||||
```bash
|
||||
# From npm
|
||||
openclaw plugins install @openclaw/voice-call
|
||||
|
||||
# From a local directory or archive
|
||||
openclaw plugins install ./my-plugin
|
||||
openclaw plugins install ./my-plugin.tgz
|
||||
```
|
||||
|
||||
</Step>
|
||||
|
||||
<Step title="Restart the Gateway">
|
||||
```bash
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
Then configure under `plugins.entries.\<id\>.config` in your config file.
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
If you prefer chat-native control, enable `commands.plugins: true` and use:
|
||||
|
||||
```text
|
||||
/plugin install clawhub:@openclaw/voice-call
|
||||
/plugin show voice-call
|
||||
/plugin enable voice-call
|
||||
```
|
||||
|
||||
The install path uses the same resolver as the CLI: local path/archive, explicit
|
||||
`clawhub:<pkg>`, or bare package spec (ClawHub first, then npm fallback).
|
||||
|
||||
If config is invalid, install normally fails closed and points you at
|
||||
`openclaw doctor --fix`. The only recovery exception is a narrow bundled-plugin
|
||||
reinstall path for plugins that opt into
|
||||
`openclaw.install.allowInvalidConfigRecovery`.
|
||||
|
||||
## Plugin types
|
||||
|
||||
OpenClaw recognizes two plugin formats:
|
||||
|
||||
| Format | How it works | Examples |
|
||||
| ---------- | ------------------------------------------------------------------ | ------------------------------------------------------ |
|
||||
| **Native** | `openclaw.plugin.json` + runtime module; executes in-process | Official plugins, community npm packages |
|
||||
| **Bundle** | Codex/Claude/Cursor-compatible layout; mapped to OpenClaw features | `.codex-plugin/`, `.claude-plugin/`, `.cursor-plugin/` |
|
||||
|
||||
Both show up under `openclaw plugins list`. See [Plugin Bundles](/plugins/bundles) for bundle details.
|
||||
|
||||
If you are writing a native plugin, start with [Building Plugins](/plugins/building-plugins)
|
||||
and the [Plugin SDK Overview](/plugins/sdk-overview).
|
||||
|
||||
## Official plugins
|
||||
|
||||
### Installable (npm)
|
||||
|
||||
| Plugin | Package | Docs |
|
||||
| --------------- | ---------------------- | ------------------------------------ |
|
||||
| Matrix | `@openclaw/matrix` | [Matrix](/channels/matrix) |
|
||||
| Microsoft Teams | `@openclaw/msteams` | [Microsoft Teams](/channels/msteams) |
|
||||
| Nostr | `@openclaw/nostr` | [Nostr](/channels/nostr) |
|
||||
| Voice Call | `@openclaw/voice-call` | [Voice Call](/plugins/voice-call) |
|
||||
| Zalo | `@openclaw/zalo` | [Zalo](/channels/zalo) |
|
||||
| Zalo Personal | `@openclaw/zalouser` | [Zalo Personal](/plugins/zalouser) |
|
||||
|
||||
### Core (shipped with OpenClaw)
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Model providers (enabled by default)">
|
||||
`anthropic`, `byteplus`, `cloudflare-ai-gateway`, `github-copilot`, `google`,
|
||||
`huggingface`, `kilocode`, `kimi-coding`, `minimax`, `mistral`, `qwen`,
|
||||
`moonshot`, `nvidia`, `openai`, `opencode`, `opencode-go`, `openrouter`,
|
||||
`qianfan`, `synthetic`, `together`, `venice`,
|
||||
`vercel-ai-gateway`, `volcengine`, `xiaomi`, `zai`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Memory plugins">
|
||||
- `memory-core` — bundled memory search (default via `plugins.slots.memory`)
|
||||
- `memory-lancedb` — install-on-demand long-term memory with auto-recall/capture (set `plugins.slots.memory = "memory-lancedb"`)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Speech providers (enabled by default)">
|
||||
`elevenlabs`, `microsoft`
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Other">
|
||||
- `browser` — bundled browser plugin for the browser tool, `openclaw browser` CLI, `browser.request` gateway method, browser runtime, and default browser control service (enabled by default; disable before replacing it)
|
||||
- `copilot-proxy` — VS Code Copilot Proxy bridge (disabled by default)
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
Looking for third-party plugins? See [Community Plugins](/plugins/community).
|
||||
|
||||
## Configuration
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
enabled: true,
|
||||
allow: ["voice-call"],
|
||||
deny: ["untrusted-plugin"],
|
||||
load: { paths: ["~/Projects/oss/voice-call-extension"] },
|
||||
entries: {
|
||||
"voice-call": { enabled: true, config: { provider: "twilio" } },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Description |
|
||||
| ---------------- | --------------------------------------------------------- |
|
||||
| `enabled` | Master toggle (default: `true`) |
|
||||
| `allow` | Plugin allowlist (optional) |
|
||||
| `deny` | Plugin denylist (optional; deny wins) |
|
||||
| `load.paths` | Extra plugin files/directories |
|
||||
| `slots` | Exclusive slot selectors (e.g. `memory`, `contextEngine`) |
|
||||
| `entries.\<id\>` | Per-plugin toggles + config |
|
||||
|
||||
Config changes **require a gateway restart**. If the Gateway is running with config
|
||||
watch + in-process restart enabled (the default `openclaw gateway` path), that
|
||||
restart is usually performed automatically a moment after the config write lands.
|
||||
|
||||
<Accordion title="Plugin states: disabled vs missing vs invalid">
|
||||
- **Disabled**: plugin exists but enablement rules turned it off. Config is preserved.
|
||||
- **Missing**: config references a plugin id that discovery did not find.
|
||||
- **Invalid**: plugin exists but its config does not match the declared schema.
|
||||
</Accordion>
|
||||
|
||||
## Discovery and precedence
|
||||
|
||||
OpenClaw scans for plugins in this order (first match wins):
|
||||
|
||||
<Steps>
|
||||
<Step title="Config paths">
|
||||
`plugins.load.paths` — explicit file or directory paths.
|
||||
</Step>
|
||||
|
||||
<Step title="Workspace extensions">
|
||||
`\<workspace\>/.openclaw/<plugin-root>/*.ts` and `\<workspace\>/.openclaw/<plugin-root>/*/index.ts`.
|
||||
</Step>
|
||||
|
||||
<Step title="Global extensions">
|
||||
`~/.openclaw/<plugin-root>/*.ts` and `~/.openclaw/<plugin-root>/*/index.ts`.
|
||||
</Step>
|
||||
|
||||
<Step title="Bundled plugins">
|
||||
Shipped with OpenClaw. Many are enabled by default (model providers, speech).
|
||||
Others require explicit enablement.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### Enablement rules
|
||||
|
||||
- `plugins.enabled: false` disables all plugins
|
||||
- `plugins.deny` always wins over allow
|
||||
- `plugins.entries.\<id\>.enabled: false` disables that plugin
|
||||
- Workspace-origin plugins are **disabled by default** (must be explicitly enabled)
|
||||
- Bundled plugins follow the built-in default-on set unless overridden
|
||||
- Exclusive slots can force-enable the selected plugin for that slot
|
||||
|
||||
## Plugin slots (exclusive categories)
|
||||
|
||||
Some categories are exclusive (only one active at a time):
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
slots: {
|
||||
memory: "memory-core", // or "none" to disable
|
||||
contextEngine: "legacy", // or a plugin id
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
| Slot | What it controls | Default |
|
||||
| --------------- | --------------------- | ------------------- |
|
||||
| `memory` | Active memory plugin | `memory-core` |
|
||||
| `contextEngine` | Active context engine | `legacy` (built-in) |
|
||||
|
||||
## CLI reference
|
||||
|
||||
```bash
|
||||
openclaw plugins list # compact inventory
|
||||
openclaw plugins list --enabled # only loaded plugins
|
||||
openclaw plugins list --verbose # per-plugin detail lines
|
||||
openclaw plugins list --json # machine-readable inventory
|
||||
openclaw plugins inspect <id> # deep detail
|
||||
openclaw plugins inspect <id> --json # machine-readable
|
||||
openclaw plugins inspect --all # fleet-wide table
|
||||
openclaw plugins info <id> # inspect alias
|
||||
openclaw plugins doctor # diagnostics
|
||||
|
||||
openclaw plugins install <package> # install (ClawHub first, then npm)
|
||||
openclaw plugins install clawhub:<pkg> # install from ClawHub only
|
||||
openclaw plugins install <spec> --force # overwrite existing install
|
||||
openclaw plugins install <path> # install from local path
|
||||
openclaw plugins install -l <path> # link (no copy) for dev
|
||||
openclaw plugins install <plugin> --marketplace <source>
|
||||
openclaw plugins install <plugin> --marketplace https://github.com/<owner>/<repo>
|
||||
openclaw plugins install <spec> --pin # record exact resolved npm spec
|
||||
openclaw plugins install <spec> --dangerously-force-unsafe-install
|
||||
openclaw plugins update <id> # update one plugin
|
||||
openclaw plugins update <id> --dangerously-force-unsafe-install
|
||||
openclaw plugins update --all # update all
|
||||
openclaw plugins uninstall <id> # remove config/install records
|
||||
openclaw plugins uninstall <id> --keep-files
|
||||
openclaw plugins marketplace list <source>
|
||||
openclaw plugins marketplace list <source> --json
|
||||
|
||||
openclaw plugins enable <id>
|
||||
openclaw plugins disable <id>
|
||||
```
|
||||
|
||||
Bundled plugins ship with OpenClaw. Many are enabled by default (for example
|
||||
bundled model providers, bundled speech providers, and the bundled browser
|
||||
plugin). Other bundled plugins still need `openclaw plugins enable <id>`.
|
||||
|
||||
`--force` overwrites an existing installed plugin or hook pack in place.
|
||||
It is not supported with `--link`, which reuses the source path instead of
|
||||
copying over a managed install target.
|
||||
|
||||
`--pin` is npm-only. It is not supported with `--marketplace`, because
|
||||
marketplace installs persist marketplace source metadata instead of an npm spec.
|
||||
|
||||
`--dangerously-force-unsafe-install` is a break-glass override for false
|
||||
positives from the built-in dangerous-code scanner. It allows plugin installs
|
||||
and plugin updates to continue past built-in `critical` findings, but it still
|
||||
does not bypass plugin `before_install` policy blocks or scan-failure blocking.
|
||||
|
||||
This CLI flag applies to plugin install/update flows only. Gateway-backed skill
|
||||
dependency installs use the matching `dangerouslyForceUnsafeInstall` request
|
||||
override instead, while `openclaw skills install` remains the separate ClawHub
|
||||
skill download/install flow.
|
||||
|
||||
Compatible bundles participate in the same plugin list/inspect/enable/disable
|
||||
flow. Current runtime support includes bundle skills, Claude command-skills,
|
||||
Claude `settings.json` defaults, Claude `.lsp.json` and manifest-declared
|
||||
`lspServers` defaults, Cursor command-skills, and compatible Codex hook
|
||||
directories.
|
||||
|
||||
`openclaw plugins inspect <id>` also reports detected bundle capabilities plus
|
||||
supported or unsupported MCP and LSP server entries for bundle-backed plugins.
|
||||
|
||||
Marketplace sources can be a Claude known-marketplace name from
|
||||
`~/.claude/plugins/known_marketplaces.json`, a local marketplace root or
|
||||
`marketplace.json` path, a GitHub shorthand like `owner/repo`, a GitHub repo
|
||||
URL, or a git URL. For remote marketplaces, plugin entries must stay inside the
|
||||
cloned marketplace repo and use relative path sources only.
|
||||
|
||||
See [`openclaw plugins` CLI reference](/cli/plugins) for full details.
|
||||
|
||||
## Plugin API overview
|
||||
|
||||
Native plugins export an entry object that exposes `register(api)`. Older
|
||||
plugins may still use `activate(api)` as a legacy alias, but new plugins should
|
||||
use `register`.
|
||||
|
||||
```typescript
|
||||
export default definePluginEntry({
|
||||
id: "my-plugin",
|
||||
name: "My Plugin",
|
||||
register(api) {
|
||||
api.registerProvider({
|
||||
/* ... */
|
||||
});
|
||||
api.registerTool({
|
||||
/* ... */
|
||||
});
|
||||
api.registerChannel({
|
||||
/* ... */
|
||||
});
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
OpenClaw loads the entry object and calls `register(api)` during plugin
|
||||
activation. The loader still falls back to `activate(api)` for older plugins,
|
||||
but bundled plugins and new external plugins should treat `register` as the
|
||||
public contract.
|
||||
|
||||
Common registration methods:
|
||||
|
||||
| Method | What it registers |
|
||||
| --------------------------------------- | --------------------------- |
|
||||
| `registerProvider` | Model provider (LLM) |
|
||||
| `registerChannel` | Chat channel |
|
||||
| `registerTool` | Agent tool |
|
||||
| `registerHook` / `on(...)` | Lifecycle hooks |
|
||||
| `registerSpeechProvider` | Text-to-speech / STT |
|
||||
| `registerRealtimeTranscriptionProvider` | Streaming STT |
|
||||
| `registerRealtimeVoiceProvider` | Duplex realtime voice |
|
||||
| `registerMediaUnderstandingProvider` | Image/audio analysis |
|
||||
| `registerImageGenerationProvider` | Image generation |
|
||||
| `registerMusicGenerationProvider` | Music generation |
|
||||
| `registerVideoGenerationProvider` | Video generation |
|
||||
| `registerWebFetchProvider` | Web fetch / scrape provider |
|
||||
| `registerWebSearchProvider` | Web search |
|
||||
| `registerHttpRoute` | HTTP endpoint |
|
||||
| `registerCommand` / `registerCli` | CLI commands |
|
||||
| `registerContextEngine` | Context engine |
|
||||
| `registerService` | Background service |
|
||||
|
||||
Hook guard behavior for typed lifecycle hooks:
|
||||
|
||||
- `before_tool_call`: `{ block: true }` is terminal; lower-priority handlers are skipped.
|
||||
- `before_tool_call`: `{ block: false }` is a no-op and does not clear an earlier block.
|
||||
- `before_install`: `{ block: true }` is terminal; lower-priority handlers are skipped.
|
||||
- `before_install`: `{ block: false }` is a no-op and does not clear an earlier block.
|
||||
- `message_sending`: `{ cancel: true }` is terminal; lower-priority handlers are skipped.
|
||||
- `message_sending`: `{ cancel: false }` is a no-op and does not clear an earlier cancel.
|
||||
|
||||
For full typed hook behavior, see [SDK Overview](/plugins/sdk-overview#hook-decision-semantics).
|
||||
|
||||
## Related
|
||||
|
||||
- [Building Plugins](/plugins/building-plugins) — create your own plugin
|
||||
- [Plugin Bundles](/plugins/bundles) — Codex/Claude/Cursor bundle compatibility
|
||||
- [Plugin Manifest](/plugins/manifest) — manifest schema
|
||||
- [Registering Tools](/plugins/building-plugins#registering-agent-tools) — add agent tools in a plugin
|
||||
- [Plugin Internals](/plugins/architecture) — capability model and load pipeline
|
||||
- [Community Plugins](/plugins/community) — third-party listings
|
||||
78
openclaw/docs/tools/reactions.md
Normal file
78
openclaw/docs/tools/reactions.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
---
|
||||
summary: "Reaction tool semantics across all supported channels"
|
||||
read_when:
|
||||
- Working on reactions in any channel
|
||||
- Understanding how emoji reactions differ across platforms
|
||||
title: "Reactions"
|
||||
---
|
||||
|
||||
# Reactions
|
||||
|
||||
The agent can add and remove emoji reactions on messages using the `message`
|
||||
tool with the `react` action. Reaction behavior varies by channel.
|
||||
|
||||
## How it works
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "react",
|
||||
"messageId": "msg-123",
|
||||
"emoji": "thumbsup"
|
||||
}
|
||||
```
|
||||
|
||||
- `emoji` is required when adding a reaction.
|
||||
- Set `emoji` to an empty string (`""`) to remove the bot's reaction(s).
|
||||
- Set `remove: true` to remove a specific emoji (requires non-empty `emoji`).
|
||||
|
||||
## Channel behavior
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Discord and Slack">
|
||||
- Empty `emoji` removes all of the bot's reactions on the message.
|
||||
- `remove: true` removes just the specified emoji.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Google Chat">
|
||||
- Empty `emoji` removes the app's reactions on the message.
|
||||
- `remove: true` removes just the specified emoji.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Telegram">
|
||||
- Empty `emoji` removes the bot's reactions.
|
||||
- `remove: true` also removes reactions but still requires a non-empty `emoji` for tool validation.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="WhatsApp">
|
||||
- Empty `emoji` removes the bot reaction.
|
||||
- `remove: true` maps to empty emoji internally (still requires `emoji` in the tool call).
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Zalo Personal (zalouser)">
|
||||
- Requires non-empty `emoji`.
|
||||
- `remove: true` removes that specific emoji reaction.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Feishu/Lark">
|
||||
- Use the `feishu_reaction` tool with actions `add`, `remove`, and `list`.
|
||||
- Add/remove requires `emoji_type`; remove also requires `reaction_id`.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Signal">
|
||||
- Inbound reaction notifications are controlled by `channels.signal.reactionNotifications`: `"off"` disables them, `"own"` (default) emits events when users react to bot messages, and `"all"` emits events for all reactions.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Reaction level
|
||||
|
||||
Per-channel `reactionLevel` config controls how broadly the agent uses reactions. Values are typically `off`, `ack`, `minimal`, or `extensive`.
|
||||
|
||||
- [Telegram reactionLevel](/channels/telegram#reaction-notifications) — `channels.telegram.reactionLevel`
|
||||
- [WhatsApp reactionLevel](/channels/whatsapp#reaction-level) — `channels.whatsapp.reactionLevel`
|
||||
|
||||
Set `reactionLevel` on individual channels to tune how actively the agent reacts to messages on each platform.
|
||||
|
||||
## Related
|
||||
|
||||
- [Agent Send](/tools/agent-send) — the `message` tool that includes `react`
|
||||
- [Channels](/channels) — channel-specific configuration
|
||||
132
openclaw/docs/tools/searxng-search.md
Normal file
132
openclaw/docs/tools/searxng-search.md
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
---
|
||||
summary: "SearXNG web search -- self-hosted, key-free meta-search provider"
|
||||
read_when:
|
||||
- You want a self-hosted web search provider
|
||||
- You want to use SearXNG for web_search
|
||||
- You need a privacy-focused or air-gapped search option
|
||||
title: "SearXNG Search"
|
||||
---
|
||||
|
||||
# SearXNG Search
|
||||
|
||||
OpenClaw supports [SearXNG](https://docs.searxng.org/) as a **self-hosted,
|
||||
key-free** `web_search` provider. SearXNG is an open-source meta-search engine
|
||||
that aggregates results from Google, Bing, DuckDuckGo, and other sources.
|
||||
|
||||
Advantages:
|
||||
|
||||
- **Free and unlimited** -- no API key or commercial subscription required
|
||||
- **Privacy / air-gap** -- queries never leave your network
|
||||
- **Works anywhere** -- no region restrictions on commercial search APIs
|
||||
|
||||
## Setup
|
||||
|
||||
<Steps>
|
||||
<Step title="Run a SearXNG instance">
|
||||
```bash
|
||||
docker run -d -p 8888:8080 searxng/searxng
|
||||
```
|
||||
|
||||
Or use any existing SearXNG deployment you have access to. See the
|
||||
[SearXNG documentation](https://docs.searxng.org/) for production setup.
|
||||
|
||||
</Step>
|
||||
<Step title="Configure">
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
# Select "searxng" as the provider
|
||||
```
|
||||
|
||||
Or set the env var and let auto-detection find it:
|
||||
|
||||
```bash
|
||||
export SEARXNG_BASE_URL="http://localhost:8888"
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "searxng",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Plugin-level settings for the SearXNG instance:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
searxng: {
|
||||
config: {
|
||||
webSearch: {
|
||||
baseUrl: "http://localhost:8888",
|
||||
categories: "general,news", // optional
|
||||
language: "en", // optional
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The `baseUrl` field also accepts SecretRef objects.
|
||||
|
||||
Transport rules:
|
||||
|
||||
- `https://` works for public or private SearXNG hosts
|
||||
- `http://` is only accepted for trusted private-network or loopback hosts
|
||||
- public SearXNG hosts must use `https://`
|
||||
|
||||
## Environment variable
|
||||
|
||||
Set `SEARXNG_BASE_URL` as an alternative to config:
|
||||
|
||||
```bash
|
||||
export SEARXNG_BASE_URL="http://localhost:8888"
|
||||
```
|
||||
|
||||
When `SEARXNG_BASE_URL` is set and no explicit provider is configured, auto-detection
|
||||
picks SearXNG automatically (at the lowest priority -- any API-backed provider with a
|
||||
key wins first).
|
||||
|
||||
## Plugin config reference
|
||||
|
||||
| Field | Description |
|
||||
| ------------ | ------------------------------------------------------------------ |
|
||||
| `baseUrl` | Base URL of your SearXNG instance (required) |
|
||||
| `categories` | Comma-separated categories such as `general`, `news`, or `science` |
|
||||
| `language` | Language code for results such as `en`, `de`, or `fr` |
|
||||
|
||||
## Notes
|
||||
|
||||
- **JSON API** -- uses SearXNG's native `format=json` endpoint, not HTML scraping
|
||||
- **No API key** -- works with any SearXNG instance out of the box
|
||||
- **Base URL validation** -- `baseUrl` must be a valid `http://` or `https://`
|
||||
URL; public hosts must use `https://`
|
||||
- **Auto-detection order** -- SearXNG is checked last (order 200) in
|
||||
auto-detection. API-backed providers with configured keys run first, then
|
||||
DuckDuckGo (order 100), then Ollama Web Search (order 110)
|
||||
- **Self-hosted** -- you control the instance, queries, and upstream search engines
|
||||
- **Categories** default to `general` when not configured
|
||||
|
||||
<Tip>
|
||||
For SearXNG JSON API to work, make sure your SearXNG instance has the `json`
|
||||
format enabled in its `settings.yml` under `search.formats`.
|
||||
</Tip>
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [DuckDuckGo Search](/tools/duckduckgo-search) -- another key-free fallback
|
||||
- [Brave Search](/tools/brave-search) -- structured results with free tier
|
||||
133
openclaw/docs/tools/skills-config.md
Normal file
133
openclaw/docs/tools/skills-config.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
---
|
||||
summary: "Skills config schema and examples"
|
||||
read_when:
|
||||
- Adding or modifying skills config
|
||||
- Adjusting bundled allowlist or install behavior
|
||||
title: "Skills Config"
|
||||
---
|
||||
|
||||
# Skills Config
|
||||
|
||||
Most skills loader/install configuration lives under `skills` in
|
||||
`~/.openclaw/openclaw.json`. Agent-specific skill visibility lives under
|
||||
`agents.defaults.skills` and `agents.list[].skills`.
|
||||
|
||||
```json5
|
||||
{
|
||||
skills: {
|
||||
allowBundled: ["gemini", "peekaboo"],
|
||||
load: {
|
||||
extraDirs: ["~/Projects/agent-scripts/skills", "~/Projects/oss/some-skill-pack/skills"],
|
||||
watch: true,
|
||||
watchDebounceMs: 250,
|
||||
},
|
||||
install: {
|
||||
preferBrew: true,
|
||||
nodeManager: "npm", // npm | pnpm | yarn | bun (Gateway runtime still Node; bun not recommended)
|
||||
},
|
||||
entries: {
|
||||
"image-lab": {
|
||||
enabled: true,
|
||||
apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, // or plaintext string
|
||||
env: {
|
||||
GEMINI_API_KEY: "GEMINI_KEY_HERE",
|
||||
},
|
||||
},
|
||||
peekaboo: { enabled: true },
|
||||
sag: { enabled: false },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
For built-in image generation/editing, prefer `agents.defaults.imageGenerationModel`
|
||||
plus the core `image_generate` tool. `skills.entries.*` is only for custom or
|
||||
third-party skill workflows.
|
||||
|
||||
If you select a specific image provider/model, also configure that provider's
|
||||
auth/API key. Typical examples: `GEMINI_API_KEY` or `GOOGLE_API_KEY` for
|
||||
`google/*`, `OPENAI_API_KEY` for `openai/*`, and `FAL_KEY` for `fal/*`.
|
||||
|
||||
Examples:
|
||||
|
||||
- Native Nano Banana-style setup: `agents.defaults.imageGenerationModel.primary: "google/gemini-3.1-flash-image-preview"`
|
||||
- Native fal setup: `agents.defaults.imageGenerationModel.primary: "fal/fal-ai/flux/dev"`
|
||||
|
||||
## Agent skill allowlists
|
||||
|
||||
Use agent config when you want the same machine/workspace skill roots, but a
|
||||
different visible skill set per agent.
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
skills: ["github", "weather"],
|
||||
},
|
||||
list: [
|
||||
{ id: "writer" }, // inherits defaults -> github, weather
|
||||
{ id: "docs", skills: ["docs-search"] }, // replaces defaults
|
||||
{ id: "locked-down", skills: [] }, // no skills
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- `agents.defaults.skills`: shared baseline allowlist for agents that omit
|
||||
`agents.list[].skills`.
|
||||
- Omit `agents.defaults.skills` to leave skills unrestricted by default.
|
||||
- `agents.list[].skills`: explicit final skill set for that agent; it does not
|
||||
merge with defaults.
|
||||
- `agents.list[].skills: []`: expose no skills for that agent.
|
||||
|
||||
## Fields
|
||||
|
||||
- Built-in skill roots always include `~/.openclaw/skills`, `~/.agents/skills`,
|
||||
`<workspace>/.agents/skills`, and `<workspace>/skills`.
|
||||
- `allowBundled`: optional allowlist for **bundled** skills only. When set, only
|
||||
bundled skills in the list are eligible (managed, agent, and workspace skills unaffected).
|
||||
- `load.extraDirs`: additional skill directories to scan (lowest precedence).
|
||||
- `load.watch`: watch skill folders and refresh the skills snapshot (default: true).
|
||||
- `load.watchDebounceMs`: debounce for skill watcher events in milliseconds (default: 250).
|
||||
- `install.preferBrew`: prefer brew installers when available (default: true).
|
||||
- `install.nodeManager`: node installer preference (`npm` | `pnpm` | `yarn` | `bun`, default: npm).
|
||||
This only affects **skill installs**; the Gateway runtime should still be Node
|
||||
(Bun not recommended for WhatsApp/Telegram).
|
||||
- `openclaw setup --node-manager` is narrower and currently accepts `npm`,
|
||||
`pnpm`, or `bun`. Set `skills.install.nodeManager: "yarn"` manually if you
|
||||
want Yarn-backed skill installs.
|
||||
- `entries.<skillKey>`: per-skill overrides.
|
||||
- `agents.defaults.skills`: optional default skill allowlist inherited by agents
|
||||
that omit `agents.list[].skills`.
|
||||
- `agents.list[].skills`: optional per-agent final skill allowlist; explicit
|
||||
lists replace inherited defaults instead of merging.
|
||||
|
||||
Per-skill fields:
|
||||
|
||||
- `enabled`: set `false` to disable a skill even if it’s bundled/installed.
|
||||
- `env`: environment variables injected for the agent run (only if not already set).
|
||||
- `apiKey`: optional convenience for skills that declare a primary env var.
|
||||
Supports plaintext string or SecretRef object (`{ source, provider, id }`).
|
||||
|
||||
## Notes
|
||||
|
||||
- Keys under `entries` map to the skill name by default. If a skill defines
|
||||
`metadata.openclaw.skillKey`, use that key instead.
|
||||
- Load precedence is `<workspace>/skills` → `<workspace>/.agents/skills` →
|
||||
`~/.agents/skills` → `~/.openclaw/skills` → bundled skills →
|
||||
`skills.load.extraDirs`.
|
||||
- Changes to skills are picked up on the next agent turn when the watcher is enabled.
|
||||
|
||||
### Sandboxed skills + env vars
|
||||
|
||||
When a session is **sandboxed**, skill processes run inside Docker. The sandbox
|
||||
does **not** inherit the host `process.env`.
|
||||
|
||||
Use one of:
|
||||
|
||||
- `agents.defaults.sandbox.docker.env` (or per-agent `agents.list[].sandbox.docker.env`)
|
||||
- bake the env into your custom sandbox image
|
||||
|
||||
Global `env` and `skills.entries.<skill>.env/apiKey` apply to **host** runs only.
|
||||
384
openclaw/docs/tools/skills.md
Normal file
384
openclaw/docs/tools/skills.md
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
---
|
||||
summary: "Skills: managed vs workspace, gating rules, and config/env wiring"
|
||||
read_when:
|
||||
- Adding or modifying skills
|
||||
- Changing skill gating or load rules
|
||||
title: "Skills"
|
||||
---
|
||||
|
||||
# Skills (OpenClaw)
|
||||
|
||||
OpenClaw uses **[AgentSkills](https://agentskills.io)-compatible** skill folders to teach the agent how to use tools. Each skill is a directory containing a `SKILL.md` with YAML frontmatter and instructions. OpenClaw loads **bundled skills** plus optional local overrides, and filters them at load time based on environment, config, and binary presence.
|
||||
|
||||
## Locations and precedence
|
||||
|
||||
OpenClaw loads skills from these sources:
|
||||
|
||||
1. **Extra skill folders**: configured with `skills.load.extraDirs`
|
||||
2. **Bundled skills**: shipped with the install (npm package or OpenClaw.app)
|
||||
3. **Managed/local skills**: `~/.openclaw/skills`
|
||||
4. **Personal agent skills**: `~/.agents/skills`
|
||||
5. **Project agent skills**: `<workspace>/.agents/skills`
|
||||
6. **Workspace skills**: `<workspace>/skills`
|
||||
|
||||
If a skill name conflicts, precedence is:
|
||||
|
||||
`<workspace>/skills` (highest) → `<workspace>/.agents/skills` → `~/.agents/skills` → `~/.openclaw/skills` → bundled skills → `skills.load.extraDirs` (lowest)
|
||||
|
||||
## Per-agent vs shared skills
|
||||
|
||||
In **multi-agent** setups, each agent has its own workspace. That means:
|
||||
|
||||
- **Per-agent skills** live in `<workspace>/skills` for that agent only.
|
||||
- **Project agent skills** live in `<workspace>/.agents/skills` and apply to
|
||||
that workspace before the normal workspace `skills/` folder.
|
||||
- **Personal agent skills** live in `~/.agents/skills` and apply across
|
||||
workspaces on that machine.
|
||||
- **Shared skills** live in `~/.openclaw/skills` (managed/local) and are visible
|
||||
to **all agents** on the same machine.
|
||||
- **Shared folders** can also be added via `skills.load.extraDirs` (lowest
|
||||
precedence) if you want a common skills pack used by multiple agents.
|
||||
|
||||
If the same skill name exists in more than one place, the usual precedence
|
||||
applies: workspace wins, then project agent skills, then personal agent skills,
|
||||
then managed/local, then bundled, then extra dirs.
|
||||
|
||||
## Agent skill allowlists
|
||||
|
||||
Skill **location** and skill **visibility** are separate controls.
|
||||
|
||||
- Location/precedence decides which copy of a same-named skill wins.
|
||||
- Agent allowlists decide which visible skills an agent can actually use.
|
||||
|
||||
Use `agents.defaults.skills` for a shared baseline, then override per agent with
|
||||
`agents.list[].skills`:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
skills: ["github", "weather"],
|
||||
},
|
||||
list: [
|
||||
{ id: "writer" }, // inherits github, weather
|
||||
{ id: "docs", skills: ["docs-search"] }, // replaces defaults
|
||||
{ id: "locked-down", skills: [] }, // no skills
|
||||
],
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Omit `agents.defaults.skills` for unrestricted skills by default.
|
||||
- Omit `agents.list[].skills` to inherit `agents.defaults.skills`.
|
||||
- Set `agents.list[].skills: []` for no skills.
|
||||
- A non-empty `agents.list[].skills` list is the final set for that agent; it
|
||||
does not merge with defaults.
|
||||
|
||||
OpenClaw applies the effective agent skill set across prompt building, skill
|
||||
slash-command discovery, sandbox sync, and skill snapshots.
|
||||
|
||||
## Plugins + skills
|
||||
|
||||
Plugins can ship their own skills by listing `skills` directories in
|
||||
`openclaw.plugin.json` (paths relative to the plugin root). Plugin skills load
|
||||
when the plugin is enabled. Today those directories are merged into the same
|
||||
low-precedence path as `skills.load.extraDirs`, so a same-named bundled,
|
||||
managed, agent, or workspace skill overrides them.
|
||||
You can gate them via `metadata.openclaw.requires.config` on the plugin’s config
|
||||
entry. See [Plugins](/tools/plugin) for discovery/config and [Tools](/tools) for the
|
||||
tool surface those skills teach.
|
||||
|
||||
## ClawHub (install + sync)
|
||||
|
||||
ClawHub is the public skills registry for OpenClaw. Browse at
|
||||
[https://clawhub.ai](https://clawhub.ai). Use native `openclaw skills`
|
||||
commands to discover/install/update skills, or the separate `clawhub` CLI when
|
||||
you need publish/sync workflows.
|
||||
Full guide: [ClawHub](/tools/clawhub).
|
||||
|
||||
Common flows:
|
||||
|
||||
- Install a skill into your workspace:
|
||||
- `openclaw skills install <skill-slug>`
|
||||
- Update all installed skills:
|
||||
- `openclaw skills update --all`
|
||||
- Sync (scan + publish updates):
|
||||
- `clawhub sync --all`
|
||||
|
||||
Native `openclaw skills install` installs into the active workspace `skills/`
|
||||
directory. The separate `clawhub` CLI also installs into `./skills` under your
|
||||
current working directory (or falls back to the configured OpenClaw workspace).
|
||||
OpenClaw picks that up as `<workspace>/skills` on the next session.
|
||||
|
||||
## Security notes
|
||||
|
||||
- Treat third-party skills as **untrusted code**. Read them before enabling.
|
||||
- Prefer sandboxed runs for untrusted inputs and risky tools. See [Sandboxing](/gateway/sandboxing).
|
||||
- Workspace and extra-dir skill discovery only accepts skill roots and `SKILL.md` files whose resolved realpath stays inside the configured root.
|
||||
- Gateway-backed skill dependency installs (`skills.install`, onboarding, and the Skills settings UI) run the built-in dangerous-code scanner before executing installer metadata. `critical` findings block by default unless the caller explicitly sets the dangerous override; suspicious findings still warn only.
|
||||
- `openclaw skills install <slug>` is different: it downloads a ClawHub skill folder into the workspace and does not use the installer-metadata path above.
|
||||
- `skills.entries.*.env` and `skills.entries.*.apiKey` inject secrets into the **host** process
|
||||
for that agent turn (not the sandbox). Keep secrets out of prompts and logs.
|
||||
- For a broader threat model and checklists, see [Security](/gateway/security).
|
||||
|
||||
## Format (AgentSkills + Pi-compatible)
|
||||
|
||||
`SKILL.md` must include at least:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: image-lab
|
||||
description: Generate or edit images via a provider-backed image workflow
|
||||
---
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- We follow the AgentSkills spec for layout/intent.
|
||||
- The parser used by the embedded agent supports **single-line** frontmatter keys only.
|
||||
- `metadata` should be a **single-line JSON object**.
|
||||
- Use `{baseDir}` in instructions to reference the skill folder path.
|
||||
- Optional frontmatter keys:
|
||||
- `homepage` — URL surfaced as “Website” in the macOS Skills UI (also supported via `metadata.openclaw.homepage`).
|
||||
- `user-invocable` — `true|false` (default: `true`). When `true`, the skill is exposed as a user slash command.
|
||||
- `disable-model-invocation` — `true|false` (default: `false`). When `true`, the skill is excluded from the model prompt (still available via user invocation).
|
||||
- `command-dispatch` — `tool` (optional). When set to `tool`, the slash command bypasses the model and dispatches directly to a tool.
|
||||
- `command-tool` — tool name to invoke when `command-dispatch: tool` is set.
|
||||
- `command-arg-mode` — `raw` (default). For tool dispatch, forwards the raw args string to the tool (no core parsing).
|
||||
|
||||
The tool is invoked with params:
|
||||
`{ command: "<raw args>", commandName: "<slash command>", skillName: "<skill name>" }`.
|
||||
|
||||
## Gating (load-time filters)
|
||||
|
||||
OpenClaw **filters skills at load time** using `metadata` (single-line JSON):
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: image-lab
|
||||
description: Generate or edit images via a provider-backed image workflow
|
||||
metadata:
|
||||
{
|
||||
"openclaw":
|
||||
{
|
||||
"requires": { "bins": ["uv"], "env": ["GEMINI_API_KEY"], "config": ["browser.enabled"] },
|
||||
"primaryEnv": "GEMINI_API_KEY",
|
||||
},
|
||||
}
|
||||
---
|
||||
```
|
||||
|
||||
Fields under `metadata.openclaw`:
|
||||
|
||||
- `always: true` — always include the skill (skip other gates).
|
||||
- `emoji` — optional emoji used by the macOS Skills UI.
|
||||
- `homepage` — optional URL shown as “Website” in the macOS Skills UI.
|
||||
- `os` — optional list of platforms (`darwin`, `linux`, `win32`). If set, the skill is only eligible on those OSes.
|
||||
- `requires.bins` — list; each must exist on `PATH`.
|
||||
- `requires.anyBins` — list; at least one must exist on `PATH`.
|
||||
- `requires.env` — list; env var must exist **or** be provided in config.
|
||||
- `requires.config` — list of `openclaw.json` paths that must be truthy.
|
||||
- `primaryEnv` — env var name associated with `skills.entries.<name>.apiKey`.
|
||||
- `install` — optional array of installer specs used by the macOS Skills UI (brew/node/go/uv/download).
|
||||
|
||||
Note on sandboxing:
|
||||
|
||||
- `requires.bins` is checked on the **host** at skill load time.
|
||||
- If an agent is sandboxed, the binary must also exist **inside the container**.
|
||||
Install it via `agents.defaults.sandbox.docker.setupCommand` (or a custom image).
|
||||
`setupCommand` runs once after the container is created.
|
||||
Package installs also require network egress, a writable root FS, and a root user in the sandbox.
|
||||
Example: the `summarize` skill (`skills/summarize/SKILL.md`) needs the `summarize` CLI
|
||||
in the sandbox container to run there.
|
||||
|
||||
Installer example:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: gemini
|
||||
description: Use Gemini CLI for coding assistance and Google search lookups.
|
||||
metadata:
|
||||
{
|
||||
"openclaw":
|
||||
{
|
||||
"emoji": "♊️",
|
||||
"requires": { "bins": ["gemini"] },
|
||||
"install":
|
||||
[
|
||||
{
|
||||
"id": "brew",
|
||||
"kind": "brew",
|
||||
"formula": "gemini-cli",
|
||||
"bins": ["gemini"],
|
||||
"label": "Install Gemini CLI (brew)",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
---
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- If multiple installers are listed, the gateway picks a **single** preferred option (brew when available, otherwise node).
|
||||
- If all installers are `download`, OpenClaw lists each entry so you can see the available artifacts.
|
||||
- Installer specs can include `os: ["darwin"|"linux"|"win32"]` to filter options by platform.
|
||||
- Node installs honor `skills.install.nodeManager` in `openclaw.json` (default: npm; options: npm/pnpm/yarn/bun).
|
||||
This only affects **skill installs**; the Gateway runtime should still be Node
|
||||
(Bun is not recommended for WhatsApp/Telegram).
|
||||
- Gateway-backed installer selection is preference-driven, not node-only:
|
||||
when install specs mix kinds, OpenClaw prefers Homebrew when
|
||||
`skills.install.preferBrew` is enabled and `brew` exists, then `uv`, then the
|
||||
configured node manager, then other fallbacks like `go` or `download`.
|
||||
- If every install spec is `download`, OpenClaw surfaces all download options
|
||||
instead of collapsing to one preferred installer.
|
||||
- Go installs: if `go` is missing and `brew` is available, the gateway installs Go via Homebrew first and sets `GOBIN` to Homebrew’s `bin` when possible.
|
||||
- Download installs: `url` (required), `archive` (`tar.gz` | `tar.bz2` | `zip`), `extract` (default: auto when archive detected), `stripComponents`, `targetDir` (default: `~/.openclaw/tools/<skillKey>`).
|
||||
|
||||
If no `metadata.openclaw` is present, the skill is always eligible (unless
|
||||
disabled in config or blocked by `skills.allowBundled` for bundled skills).
|
||||
|
||||
## Config overrides (`~/.openclaw/openclaw.json`)
|
||||
|
||||
Bundled/managed skills can be toggled and supplied with env values:
|
||||
|
||||
```json5
|
||||
{
|
||||
skills: {
|
||||
entries: {
|
||||
"image-lab": {
|
||||
enabled: true,
|
||||
apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, // or plaintext string
|
||||
env: {
|
||||
GEMINI_API_KEY: "GEMINI_KEY_HERE",
|
||||
},
|
||||
config: {
|
||||
endpoint: "https://example.invalid",
|
||||
model: "nano-pro",
|
||||
},
|
||||
},
|
||||
peekaboo: { enabled: true },
|
||||
sag: { enabled: false },
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Note: if the skill name contains hyphens, quote the key (JSON5 allows quoted keys).
|
||||
|
||||
If you want stock image generation/editing inside OpenClaw itself, use the core
|
||||
`image_generate` tool with `agents.defaults.imageGenerationModel` instead of a
|
||||
bundled skill. Skill examples here are for custom or third-party workflows.
|
||||
|
||||
For native image analysis, use the `image` tool with `agents.defaults.imageModel`.
|
||||
For native image generation/editing, use `image_generate` with
|
||||
`agents.defaults.imageGenerationModel`. If you pick `openai/*`, `google/*`,
|
||||
`fal/*`, or another provider-specific image model, add that provider's auth/API
|
||||
key too.
|
||||
|
||||
Config keys match the **skill name** by default. If a skill defines
|
||||
`metadata.openclaw.skillKey`, use that key under `skills.entries`.
|
||||
|
||||
Rules:
|
||||
|
||||
- `enabled: false` disables the skill even if it’s bundled/installed.
|
||||
- `env`: injected **only if** the variable isn’t already set in the process.
|
||||
- `apiKey`: convenience for skills that declare `metadata.openclaw.primaryEnv`.
|
||||
Supports plaintext string or SecretRef object (`{ source, provider, id }`).
|
||||
- `config`: optional bag for custom per-skill fields; custom keys must live here.
|
||||
- `allowBundled`: optional allowlist for **bundled** skills only. If set, only
|
||||
bundled skills in the list are eligible (managed/workspace skills unaffected).
|
||||
|
||||
## Environment injection (per agent run)
|
||||
|
||||
When an agent run starts, OpenClaw:
|
||||
|
||||
1. Reads skill metadata.
|
||||
2. Applies any `skills.entries.<key>.env` or `skills.entries.<key>.apiKey` to
|
||||
`process.env`.
|
||||
3. Builds the system prompt with **eligible** skills.
|
||||
4. Restores the original environment after the run ends.
|
||||
|
||||
This is **scoped to the agent run**, not a global shell environment.
|
||||
|
||||
For the bundled `claude-cli` backend, OpenClaw also materializes the same
|
||||
eligible snapshot as a temporary Claude Code plugin and passes it with
|
||||
`--plugin-dir`. Claude Code can then use its native skill resolver while
|
||||
OpenClaw still owns precedence, per-agent allowlists, gating, and
|
||||
`skills.entries.*` env/API key injection. Other CLI backends use the prompt
|
||||
catalog only.
|
||||
|
||||
## Session snapshot (performance)
|
||||
|
||||
OpenClaw snapshots the eligible skills **when a session starts** and reuses that list for subsequent turns in the same session. Changes to skills or config take effect on the next new session.
|
||||
|
||||
Skills can also refresh mid-session when the skills watcher is enabled or when a new eligible remote node appears (see below). Think of this as a **hot reload**: the refreshed list is picked up on the next agent turn.
|
||||
|
||||
If the effective agent skill allowlist changes for that session, OpenClaw
|
||||
refreshes the snapshot so the visible skills stay aligned with the current
|
||||
agent.
|
||||
|
||||
## Remote macOS nodes (Linux gateway)
|
||||
|
||||
If the Gateway is running on Linux but a **macOS node** is connected **with `system.run` allowed** (Exec approvals security not set to `deny`), OpenClaw can treat macOS-only skills as eligible when the required binaries are present on that node. The agent should execute those skills via the `exec` tool with `host=node`.
|
||||
|
||||
This relies on the node reporting its command support and on a bin probe via `system.run`. If the macOS node goes offline later, the skills remain visible; invocations may fail until the node reconnects.
|
||||
|
||||
## Skills watcher (auto-refresh)
|
||||
|
||||
By default, OpenClaw watches skill folders and bumps the skills snapshot when `SKILL.md` files change. Configure this under `skills.load`:
|
||||
|
||||
```json5
|
||||
{
|
||||
skills: {
|
||||
load: {
|
||||
watch: true,
|
||||
watchDebounceMs: 250,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Token impact (skills list)
|
||||
|
||||
When skills are eligible, OpenClaw injects a compact XML list of available skills into the system prompt (via `formatSkillsForPrompt` in `pi-coding-agent`). The cost is deterministic:
|
||||
|
||||
- **Base overhead (only when ≥1 skill):** 195 characters.
|
||||
- **Per skill:** 97 characters + the length of the XML-escaped `<name>`, `<description>`, and `<location>` values.
|
||||
|
||||
Formula (characters):
|
||||
|
||||
```
|
||||
total = 195 + Σ (97 + len(name_escaped) + len(description_escaped) + len(location_escaped))
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- XML escaping expands `& < > " '` into entities (`&`, `<`, etc.), increasing length.
|
||||
- Token counts vary by model tokenizer. A rough OpenAI-style estimate is ~4 chars/token, so **97 chars ≈ 24 tokens** per skill plus your actual field lengths.
|
||||
|
||||
## Managed skills lifecycle
|
||||
|
||||
OpenClaw ships a baseline set of skills as **bundled skills** as part of the
|
||||
install (npm package or OpenClaw.app). `~/.openclaw/skills` exists for local
|
||||
overrides (for example, pinning/patching a skill without changing the bundled
|
||||
copy). Workspace skills are user-owned and override both on name conflicts.
|
||||
|
||||
## Config reference
|
||||
|
||||
See [Skills config](/tools/skills-config) for the full configuration schema.
|
||||
|
||||
## Looking for more skills?
|
||||
|
||||
Browse [https://clawhub.ai](https://clawhub.ai).
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- [Creating Skills](/tools/creating-skills) — building custom skills
|
||||
- [Skills Config](/tools/skills-config) — skill configuration reference
|
||||
- [Slash Commands](/tools/slash-commands) — all available slash commands
|
||||
- [Plugins](/tools/plugin) — plugin system overview
|
||||
384
openclaw/docs/tools/slash-commands.md
Normal file
384
openclaw/docs/tools/slash-commands.md
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
---
|
||||
summary: "Slash commands: text vs native, config, and supported commands"
|
||||
read_when:
|
||||
- Using or configuring chat commands
|
||||
- Debugging command routing or permissions
|
||||
title: "Slash Commands"
|
||||
---
|
||||
|
||||
# Slash commands
|
||||
|
||||
Commands are handled by the Gateway. Most commands must be sent as a **standalone** message that starts with `/`.
|
||||
The host-only bash chat command uses `! <cmd>` (with `/bash <cmd>` as an alias).
|
||||
|
||||
There are two related systems:
|
||||
|
||||
- **Commands**: standalone `/...` messages.
|
||||
- **Directives**: `/think`, `/fast`, `/verbose`, `/trace`, `/reasoning`, `/elevated`, `/exec`, `/model`, `/queue`.
|
||||
- Directives are stripped from the message before the model sees it.
|
||||
- In normal chat messages (not directive-only), they are treated as “inline hints” and do **not** persist session settings.
|
||||
- In directive-only messages (the message contains only directives), they persist to the session and reply with an acknowledgement.
|
||||
- Directives are only applied for **authorized senders**. If `commands.allowFrom` is set, it is the only
|
||||
allowlist used; otherwise authorization comes from channel allowlists/pairing plus `commands.useAccessGroups`.
|
||||
Unauthorized senders see directives treated as plain text.
|
||||
|
||||
There are also a few **inline shortcuts** (allowlisted/authorized senders only): `/help`, `/commands`, `/status`, `/whoami` (`/id`).
|
||||
They run immediately, are stripped before the model sees the message, and the remaining text continues through the normal flow.
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
commands: {
|
||||
native: "auto",
|
||||
nativeSkills: "auto",
|
||||
text: true,
|
||||
bash: false,
|
||||
bashForegroundMs: 2000,
|
||||
config: false,
|
||||
mcp: false,
|
||||
plugins: false,
|
||||
debug: false,
|
||||
restart: true,
|
||||
ownerAllowFrom: ["discord:123456789012345678"],
|
||||
ownerDisplay: "raw",
|
||||
ownerDisplaySecret: "${OWNER_ID_HASH_SECRET}",
|
||||
allowFrom: {
|
||||
"*": ["user1"],
|
||||
discord: ["user:123"],
|
||||
},
|
||||
useAccessGroups: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
- `commands.text` (default `true`) enables parsing `/...` in chat messages.
|
||||
- On surfaces without native commands (WhatsApp/WebChat/Signal/iMessage/Google Chat/Microsoft Teams), text commands still work even if you set this to `false`.
|
||||
- `commands.native` (default `"auto"`) registers native commands.
|
||||
- Auto: on for Discord/Telegram; off for Slack (until you add slash commands); ignored for providers without native support.
|
||||
- Set `channels.discord.commands.native`, `channels.telegram.commands.native`, or `channels.slack.commands.native` to override per provider (bool or `"auto"`).
|
||||
- `false` clears previously registered commands on Discord/Telegram at startup. Slack commands are managed in the Slack app and are not removed automatically.
|
||||
- `commands.nativeSkills` (default `"auto"`) registers **skill** commands natively when supported.
|
||||
- Auto: on for Discord/Telegram; off for Slack (Slack requires creating a slash command per skill).
|
||||
- Set `channels.discord.commands.nativeSkills`, `channels.telegram.commands.nativeSkills`, or `channels.slack.commands.nativeSkills` to override per provider (bool or `"auto"`).
|
||||
- `commands.bash` (default `false`) enables `! <cmd>` to run host shell commands (`/bash <cmd>` is an alias; requires `tools.elevated` allowlists).
|
||||
- `commands.bashForegroundMs` (default `2000`) controls how long bash waits before switching to background mode (`0` backgrounds immediately).
|
||||
- `commands.config` (default `false`) enables `/config` (reads/writes `openclaw.json`).
|
||||
- `commands.mcp` (default `false`) enables `/mcp` (reads/writes OpenClaw-managed MCP config under `mcp.servers`).
|
||||
- `commands.plugins` (default `false`) enables `/plugins` (plugin discovery/status plus install + enable/disable controls).
|
||||
- `commands.debug` (default `false`) enables `/debug` (runtime-only overrides).
|
||||
- `commands.restart` (default `true`) enables `/restart` plus gateway restart tool actions.
|
||||
- `commands.ownerAllowFrom` (optional) sets the explicit owner allowlist for owner-only command/tool surfaces. This is separate from `commands.allowFrom`.
|
||||
- `commands.ownerDisplay` controls how owner ids appear in the system prompt: `raw` or `hash`.
|
||||
- `commands.ownerDisplaySecret` optionally sets the HMAC secret used when `commands.ownerDisplay="hash"`.
|
||||
- `commands.allowFrom` (optional) sets a per-provider allowlist for command authorization. When configured, it is the
|
||||
only authorization source for commands and directives (channel allowlists/pairing and `commands.useAccessGroups`
|
||||
are ignored). Use `"*"` for a global default; provider-specific keys override it.
|
||||
- `commands.useAccessGroups` (default `true`) enforces allowlists/policies for commands when `commands.allowFrom` is not set.
|
||||
|
||||
## Command list
|
||||
|
||||
Current source-of-truth:
|
||||
|
||||
- core built-ins come from `src/auto-reply/commands-registry.shared.ts`
|
||||
- generated dock commands come from `src/auto-reply/commands-registry.data.ts`
|
||||
- plugin commands come from plugin `registerCommand()` calls
|
||||
- actual availability on your gateway still depends on config flags, channel surface, and installed/enabled plugins
|
||||
|
||||
### Core built-in commands
|
||||
|
||||
Built-in commands available today:
|
||||
|
||||
- `/new [model]` starts a new session; `/reset` is the reset alias.
|
||||
- `/compact [instructions]` compacts the session context. See [/concepts/compaction](/concepts/compaction).
|
||||
- `/stop` aborts the current run.
|
||||
- `/session idle <duration|off>` and `/session max-age <duration|off>` manage thread-binding expiry.
|
||||
- `/think <off|minimal|low|medium|high|xhigh>` sets the thinking level. Aliases: `/thinking`, `/t`.
|
||||
- `/verbose on|off|full` toggles verbose output. Alias: `/v`.
|
||||
- `/trace on|off` toggles plugin trace output for the current session.
|
||||
- `/fast [status|on|off]` shows or sets fast mode.
|
||||
- `/reasoning [on|off|stream]` toggles reasoning visibility. Alias: `/reason`.
|
||||
- `/elevated [on|off|ask|full]` toggles elevated mode. Alias: `/elev`.
|
||||
- `/exec host=<auto|sandbox|gateway|node> security=<deny|allowlist|full> ask=<off|on-miss|always> node=<id>` shows or sets exec defaults.
|
||||
- `/model [name|#|status]` shows or sets the model.
|
||||
- `/models [provider] [page] [limit=<n>|size=<n>|all]` lists providers or models for a provider.
|
||||
- `/queue <mode>` manages queue behavior (`steer`, `interrupt`, `followup`, `collect`, `steer-backlog`) plus options like `debounce:2s cap:25 drop:summarize`.
|
||||
- `/help` shows the short help summary.
|
||||
- `/commands` shows the generated command catalog.
|
||||
- `/tools [compact|verbose]` shows what the current agent can use right now.
|
||||
- `/status` shows runtime status, including provider usage/quota when available.
|
||||
- `/tasks` lists active/recent background tasks for the current session.
|
||||
- `/context [list|detail|json]` explains how context is assembled.
|
||||
- `/export-session [path]` exports the current session to HTML. Alias: `/export`.
|
||||
- `/whoami` shows your sender id. Alias: `/id`.
|
||||
- `/skill <name> [input]` runs a skill by name.
|
||||
- `/allowlist [list|add|remove] ...` manages allowlist entries. Text-only.
|
||||
- `/approve <id> <decision>` resolves exec approval prompts.
|
||||
- `/btw <question>` asks a side question without changing future session context. See [/tools/btw](/tools/btw).
|
||||
- `/subagents list|kill|log|info|send|steer|spawn` manages sub-agent runs for the current session.
|
||||
- `/acp spawn|cancel|steer|close|sessions|status|set-mode|set|cwd|permissions|timeout|model|reset-options|doctor|install|help` manages ACP sessions and runtime options.
|
||||
- `/focus <target>` binds the current Discord thread or Telegram topic/conversation to a session target.
|
||||
- `/unfocus` removes the current binding.
|
||||
- `/agents` lists thread-bound agents for the current session.
|
||||
- `/kill <id|#|all>` aborts one or all running sub-agents.
|
||||
- `/steer <id|#> <message>` sends steering to a running sub-agent. Alias: `/tell`.
|
||||
- `/config show|get|set|unset` reads or writes `openclaw.json`. Owner-only. Requires `commands.config: true`.
|
||||
- `/mcp show|get|set|unset` reads or writes OpenClaw-managed MCP server config under `mcp.servers`. Owner-only. Requires `commands.mcp: true`.
|
||||
- `/plugins list|inspect|show|get|install|enable|disable` inspects or mutates plugin state. `/plugin` is an alias. Owner-only for writes. Requires `commands.plugins: true`.
|
||||
- `/debug show|set|unset|reset` manages runtime-only config overrides. Owner-only. Requires `commands.debug: true`.
|
||||
- `/usage off|tokens|full|cost` controls the per-response usage footer or prints a local cost summary.
|
||||
- `/tts on|off|status|provider|limit|summary|audio|help` controls TTS. See [/tools/tts](/tools/tts).
|
||||
- `/restart` restarts OpenClaw when enabled. Default: enabled; set `commands.restart: false` to disable it.
|
||||
- `/activation mention|always` sets group activation mode.
|
||||
- `/send on|off|inherit` sets send policy. Owner-only.
|
||||
- `/bash <command>` runs a host shell command. Text-only. Alias: `! <command>`. Requires `commands.bash: true` plus `tools.elevated` allowlists.
|
||||
- `!poll [sessionId]` checks a background bash job.
|
||||
- `!stop [sessionId]` stops a background bash job.
|
||||
|
||||
### Generated dock commands
|
||||
|
||||
Dock commands are generated from channel plugins with native-command support. Current bundled set:
|
||||
|
||||
- `/dock-discord` (alias: `/dock_discord`)
|
||||
- `/dock-mattermost` (alias: `/dock_mattermost`)
|
||||
- `/dock-slack` (alias: `/dock_slack`)
|
||||
- `/dock-telegram` (alias: `/dock_telegram`)
|
||||
|
||||
### Bundled plugin commands
|
||||
|
||||
Bundled plugins can add more slash commands. Current bundled commands in this repo:
|
||||
|
||||
- `/dreaming [on|off|status|help]` toggles memory dreaming. See [Dreaming](/concepts/dreaming).
|
||||
- `/pair [qr|status|pending|approve|cleanup|notify]` manages device pairing/setup flow. See [Pairing](/channels/pairing).
|
||||
- `/phone status|arm <camera|screen|writes|all> [duration]|disarm` temporarily arms high-risk phone node commands.
|
||||
- `/voice status|list [limit]|set <voiceId|name>` manages Talk voice config. On Discord, the native command name is `/talkvoice`.
|
||||
- `/card ...` sends LINE rich card presets. See [LINE](/channels/line).
|
||||
- `/codex status|models|threads|resume|compact|review|account|mcp|skills` inspects and controls the bundled Codex app-server harness. See [Codex Harness](/plugins/codex-harness).
|
||||
- QQBot-only commands:
|
||||
- `/bot-ping`
|
||||
- `/bot-version`
|
||||
- `/bot-help`
|
||||
- `/bot-upgrade`
|
||||
- `/bot-logs`
|
||||
|
||||
### Dynamic skill commands
|
||||
|
||||
User-invocable skills are also exposed as slash commands:
|
||||
|
||||
- `/skill <name> [input]` always works as the generic entrypoint.
|
||||
- skills may also appear as direct commands like `/prose` when the skill/plugin registers them.
|
||||
- native skill-command registration is controlled by `commands.nativeSkills` and `channels.<provider>.commands.nativeSkills`.
|
||||
|
||||
Notes:
|
||||
|
||||
- Commands accept an optional `:` between the command and args (e.g. `/think: high`, `/send: on`, `/help:`).
|
||||
- `/new <model>` accepts a model alias, `provider/model`, or a provider name (fuzzy match); if no match, the text is treated as the message body.
|
||||
- For full provider usage breakdown, use `openclaw status --usage`.
|
||||
- `/allowlist add|remove` requires `commands.config=true` and honors channel `configWrites`.
|
||||
- In multi-account channels, config-targeted `/allowlist --account <id>` and `/config set channels.<provider>.accounts.<id>...` also honor the target account's `configWrites`.
|
||||
- `/usage` controls the per-response usage footer; `/usage cost` prints a local cost summary from OpenClaw session logs.
|
||||
- `/restart` is enabled by default; set `commands.restart: false` to disable it.
|
||||
- `/plugins install <spec>` accepts the same plugin specs as `openclaw plugins install`: local path/archive, npm package, or `clawhub:<pkg>`.
|
||||
- `/plugins enable|disable` updates plugin config and may prompt for a restart.
|
||||
- Discord-only native command: `/vc join|leave|status` controls voice channels (requires `channels.discord.voice` and native commands; not available as text).
|
||||
- Discord thread-binding commands (`/focus`, `/unfocus`, `/agents`, `/session idle`, `/session max-age`) require effective thread bindings to be enabled (`session.threadBindings.enabled` and/or `channels.discord.threadBindings.enabled`).
|
||||
- ACP command reference and runtime behavior: [ACP Agents](/tools/acp-agents).
|
||||
- `/verbose` is meant for debugging and extra visibility; keep it **off** in normal use.
|
||||
- `/trace` is narrower than `/verbose`: it only reveals plugin-owned trace/debug lines and keeps normal verbose tool chatter off.
|
||||
- `/fast on|off` persists a session override. Use the Sessions UI `inherit` option to clear it and fall back to config defaults.
|
||||
- `/fast` is provider-specific: OpenAI/OpenAI Codex map it to `service_tier=priority` on native Responses endpoints, while direct public Anthropic requests, including OAuth-authenticated traffic sent to `api.anthropic.com`, map it to `service_tier=auto` or `standard_only`. See [OpenAI](/providers/openai) and [Anthropic](/providers/anthropic).
|
||||
- Tool failure summaries are still shown when relevant, but detailed failure text is only included when `/verbose` is `on` or `full`.
|
||||
- `/reasoning`, `/verbose`, and `/trace` are risky in group settings: they may reveal internal reasoning, tool output, or plugin diagnostics you did not intend to expose. Prefer leaving them off, especially in group chats.
|
||||
- `/model` persists the new session model immediately.
|
||||
- If the agent is idle, the next run uses it right away.
|
||||
- If a run is already active, OpenClaw marks a live switch as pending and only restarts into the new model at a clean retry point.
|
||||
- If tool activity or reply output has already started, the pending switch can stay queued until a later retry opportunity or the next user turn.
|
||||
- **Fast path:** command-only messages from allowlisted senders are handled immediately (bypass queue + model).
|
||||
- **Group mention gating:** command-only messages from allowlisted senders bypass mention requirements.
|
||||
- **Inline shortcuts (allowlisted senders only):** certain commands also work when embedded in a normal message and are stripped before the model sees the remaining text.
|
||||
- Example: `hey /status` triggers a status reply, and the remaining text continues through the normal flow.
|
||||
- Currently: `/help`, `/commands`, `/status`, `/whoami` (`/id`).
|
||||
- Unauthorized command-only messages are silently ignored, and inline `/...` tokens are treated as plain text.
|
||||
- **Skill commands:** `user-invocable` skills are exposed as slash commands. Names are sanitized to `a-z0-9_` (max 32 chars); collisions get numeric suffixes (e.g. `_2`).
|
||||
- `/skill <name> [input]` runs a skill by name (useful when native command limits prevent per-skill commands).
|
||||
- By default, skill commands are forwarded to the model as a normal request.
|
||||
- Skills may optionally declare `command-dispatch: tool` to route the command directly to a tool (deterministic, no model).
|
||||
- Example: `/prose` (OpenProse plugin) — see [OpenProse](/prose).
|
||||
- **Native command arguments:** Discord uses autocomplete for dynamic options (and button menus when you omit required args). Telegram and Slack show a button menu when a command supports choices and you omit the arg.
|
||||
|
||||
## `/tools`
|
||||
|
||||
`/tools` answers a runtime question, not a config question: **what this agent can use right now in
|
||||
this conversation**.
|
||||
|
||||
- Default `/tools` is compact and optimized for quick scanning.
|
||||
- `/tools verbose` adds short descriptions.
|
||||
- Native-command surfaces that support arguments expose the same mode switch as `compact|verbose`.
|
||||
- Results are session-scoped, so changing agent, channel, thread, sender authorization, or model can
|
||||
change the output.
|
||||
- `/tools` includes tools that are actually reachable at runtime, including core tools, connected
|
||||
plugin tools, and channel-owned tools.
|
||||
|
||||
For profile and override editing, use the Control UI Tools panel or config/catalog surfaces instead
|
||||
of treating `/tools` as a static catalog.
|
||||
|
||||
## Usage surfaces (what shows where)
|
||||
|
||||
- **Provider usage/quota** (example: “Claude 80% left”) shows up in `/status` for the current model provider when usage tracking is enabled. OpenClaw normalizes provider windows to `% left`; for MiniMax, remaining-only percent fields are inverted before display, and `model_remains` responses prefer the chat-model entry plus a model-tagged plan label.
|
||||
- **Token/cache lines** in `/status` can fall back to the latest transcript usage entry when the live session snapshot is sparse. Existing nonzero live values still win, and transcript fallback can also recover the active runtime model label plus a larger prompt-oriented total when stored totals are missing or smaller.
|
||||
- **Per-response tokens/cost** is controlled by `/usage off|tokens|full` (appended to normal replies).
|
||||
- `/model status` is about **models/auth/endpoints**, not usage.
|
||||
|
||||
## Model selection (`/model`)
|
||||
|
||||
`/model` is implemented as a directive.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
/model
|
||||
/model list
|
||||
/model 3
|
||||
/model openai/gpt-5.4
|
||||
/model opus@anthropic:default
|
||||
/model status
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `/model` and `/model list` show a compact, numbered picker (model family + available providers).
|
||||
- On Discord, `/model` and `/models` open an interactive picker with provider and model dropdowns plus a Submit step.
|
||||
- `/model <#>` selects from that picker (and prefers the current provider when possible).
|
||||
- `/model status` shows the detailed view, including configured provider endpoint (`baseUrl`) and API mode (`api`) when available.
|
||||
|
||||
## Debug overrides
|
||||
|
||||
`/debug` lets you set **runtime-only** config overrides (memory, not disk). Owner-only. Disabled by default; enable with `commands.debug: true`.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
/debug show
|
||||
/debug set messages.responsePrefix="[openclaw]"
|
||||
/debug set channels.whatsapp.allowFrom=["+1555","+4477"]
|
||||
/debug unset messages.responsePrefix
|
||||
/debug reset
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Overrides apply immediately to new config reads, but do **not** write to `openclaw.json`.
|
||||
- Use `/debug reset` to clear all overrides and return to the on-disk config.
|
||||
|
||||
## Plugin trace output
|
||||
|
||||
`/trace` lets you toggle **session-scoped plugin trace/debug lines** without turning on full verbose mode.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/trace
|
||||
/trace on
|
||||
/trace off
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `/trace` with no argument shows the current session trace state.
|
||||
- `/trace on` enables plugin trace lines for the current session.
|
||||
- `/trace off` disables them again.
|
||||
- Plugin trace lines can appear in `/status` and as a follow-up diagnostic message after the normal assistant reply.
|
||||
- `/trace` does not replace `/debug`; `/debug` still manages runtime-only config overrides.
|
||||
- `/trace` does not replace `/verbose`; normal verbose tool/status output still belongs to `/verbose`.
|
||||
|
||||
## Config updates
|
||||
|
||||
`/config` writes to your on-disk config (`openclaw.json`). Owner-only. Disabled by default; enable with `commands.config: true`.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
/config show
|
||||
/config show messages.responsePrefix
|
||||
/config get messages.responsePrefix
|
||||
/config set messages.responsePrefix="[openclaw]"
|
||||
/config unset messages.responsePrefix
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Config is validated before write; invalid changes are rejected.
|
||||
- `/config` updates persist across restarts.
|
||||
|
||||
## MCP updates
|
||||
|
||||
`/mcp` writes OpenClaw-managed MCP server definitions under `mcp.servers`. Owner-only. Disabled by default; enable with `commands.mcp: true`.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/mcp show
|
||||
/mcp show context7
|
||||
/mcp set context7={"command":"uvx","args":["context7-mcp"]}
|
||||
/mcp unset context7
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `/mcp` stores config in OpenClaw config, not Pi-owned project settings.
|
||||
- Runtime adapters decide which transports are actually executable.
|
||||
|
||||
## Plugin updates
|
||||
|
||||
`/plugins` lets operators inspect discovered plugins and toggle enablement in config. Read-only flows can use `/plugin` as an alias. Disabled by default; enable with `commands.plugins: true`.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/plugins
|
||||
/plugins list
|
||||
/plugin show context7
|
||||
/plugins enable context7
|
||||
/plugins disable context7
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `/plugins list` and `/plugins show` use real plugin discovery against the current workspace plus on-disk config.
|
||||
- `/plugins enable|disable` updates plugin config only; it does not install or uninstall plugins.
|
||||
- After enable/disable changes, restart the gateway to apply them.
|
||||
|
||||
## Surface notes
|
||||
|
||||
- **Text commands** run in the normal chat session (DMs share `main`, groups have their own session).
|
||||
- **Native commands** use isolated sessions:
|
||||
- Discord: `agent:<agentId>:discord:slash:<userId>`
|
||||
- Slack: `agent:<agentId>:slack:slash:<userId>` (prefix configurable via `channels.slack.slashCommand.sessionPrefix`)
|
||||
- Telegram: `telegram:slash:<userId>` (targets the chat session via `CommandTargetSessionKey`)
|
||||
- **`/stop`** targets the active chat session so it can abort the current run.
|
||||
- **Slack:** `channels.slack.slashCommand` is still supported for a single `/openclaw`-style command. If you enable `commands.native`, you must create one Slack slash command per built-in command (same names as `/help`). Command argument menus for Slack are delivered as ephemeral Block Kit buttons.
|
||||
- Slack native exception: register `/agentstatus` (not `/status`) because Slack reserves `/status`. Text `/status` still works in Slack messages.
|
||||
|
||||
## BTW side questions
|
||||
|
||||
`/btw` is a quick **side question** about the current session.
|
||||
|
||||
Unlike normal chat:
|
||||
|
||||
- it uses the current session as background context,
|
||||
- it runs as a separate **tool-less** one-shot call,
|
||||
- it does not change future session context,
|
||||
- it is not written to transcript history,
|
||||
- it is delivered as a live side result instead of a normal assistant message.
|
||||
|
||||
That makes `/btw` useful when you want a temporary clarification while the main
|
||||
task keeps going.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
/btw what are we doing right now?
|
||||
```
|
||||
|
||||
See [BTW Side Questions](/tools/btw) for the full behavior and client UX
|
||||
details.
|
||||
341
openclaw/docs/tools/subagents.md
Normal file
341
openclaw/docs/tools/subagents.md
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
---
|
||||
summary: "Sub-agents: spawning isolated agent runs that announce results back to the requester chat"
|
||||
read_when:
|
||||
- You want background/parallel work via the agent
|
||||
- You are changing sessions_spawn or sub-agent tool policy
|
||||
- You are implementing or troubleshooting thread-bound subagent sessions
|
||||
title: "Sub-Agents"
|
||||
---
|
||||
|
||||
# Sub-agents
|
||||
|
||||
Sub-agents are background agent runs spawned from an existing agent run. They run in their own session (`agent:<agentId>:subagent:<uuid>`) and, when finished, **announce** their result back to the requester chat channel. Each sub-agent run is tracked as a [background task](/automation/tasks).
|
||||
|
||||
## Slash command
|
||||
|
||||
Use `/subagents` to inspect or control sub-agent runs for the **current session**:
|
||||
|
||||
- `/subagents list`
|
||||
- `/subagents kill <id|#|all>`
|
||||
- `/subagents log <id|#> [limit] [tools]`
|
||||
- `/subagents info <id|#>`
|
||||
- `/subagents send <id|#> <message>`
|
||||
- `/subagents steer <id|#> <message>`
|
||||
- `/subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]`
|
||||
|
||||
Thread binding controls:
|
||||
|
||||
These commands work on channels that support persistent thread bindings. See **Thread supporting channels** below.
|
||||
|
||||
- `/focus <subagent-label|session-key|session-id|session-label>`
|
||||
- `/unfocus`
|
||||
- `/agents`
|
||||
- `/session idle <duration|off>`
|
||||
- `/session max-age <duration|off>`
|
||||
|
||||
`/subagents info` shows run metadata (status, timestamps, session id, transcript path, cleanup).
|
||||
Use `sessions_history` for a bounded, safety-filtered recall view; inspect the
|
||||
transcript path on disk when you need the raw full transcript.
|
||||
|
||||
### Spawn behavior
|
||||
|
||||
`/subagents spawn` starts a background sub-agent as a user command, not an internal relay, and it sends one final completion update back to the requester chat when the run finishes.
|
||||
|
||||
- The spawn command is non-blocking; it returns a run id immediately.
|
||||
- On completion, the sub-agent announces a summary/result message back to the requester chat channel.
|
||||
- Completion is push-based. Once spawned, do not poll `/subagents list`,
|
||||
`sessions_list`, or `sessions_history` in a loop just to wait for it to
|
||||
finish; inspect status only on-demand for debugging or intervention.
|
||||
- On completion, OpenClaw best-effort closes tracked browser tabs/processes opened by that sub-agent session before the announce cleanup flow continues.
|
||||
- For manual spawns, delivery is resilient:
|
||||
- OpenClaw tries direct `agent` delivery first with a stable idempotency key.
|
||||
- If direct delivery fails, it falls back to queue routing.
|
||||
- If queue routing is still not available, the announce is retried with a short exponential backoff before final give-up.
|
||||
- Completion delivery keeps the resolved requester route:
|
||||
- thread-bound or conversation-bound completion routes win when available
|
||||
- if the completion origin only provides a channel, OpenClaw fills the missing target/account from the requester session's resolved route (`lastChannel` / `lastTo` / `lastAccountId`) so direct delivery still works
|
||||
- The completion handoff to the requester session is runtime-generated internal context (not user-authored text) and includes:
|
||||
- `Result` (latest visible `assistant` reply text, otherwise sanitized latest tool/toolResult text)
|
||||
- `Status` (`completed successfully` / `failed` / `timed out` / `unknown`)
|
||||
- compact runtime/token stats
|
||||
- a delivery instruction telling the requester agent to rewrite in normal assistant voice (not forward raw internal metadata)
|
||||
- `--model` and `--thinking` override defaults for that specific run.
|
||||
- Use `info`/`log` to inspect details and output after completion.
|
||||
- `/subagents spawn` is one-shot mode (`mode: "run"`). For persistent thread-bound sessions, use `sessions_spawn` with `thread: true` and `mode: "session"`.
|
||||
- For ACP harness sessions (Codex, Claude Code, Gemini CLI), use `sessions_spawn` with `runtime: "acp"` and see [ACP Agents](/tools/acp-agents).
|
||||
|
||||
Primary goals:
|
||||
|
||||
- Parallelize "research / long task / slow tool" work without blocking the main run.
|
||||
- Keep sub-agents isolated by default (session separation + optional sandboxing).
|
||||
- Keep the tool surface hard to misuse: sub-agents do **not** get session tools by default.
|
||||
- Support configurable nesting depth for orchestrator patterns.
|
||||
|
||||
Cost note: each sub-agent has its **own** context and token usage. For heavy or repetitive
|
||||
tasks, set a cheaper model for sub-agents and keep your main agent on a higher-quality model.
|
||||
You can configure this via `agents.defaults.subagents.model` or per-agent overrides.
|
||||
|
||||
## Tool
|
||||
|
||||
Use `sessions_spawn`:
|
||||
|
||||
- Starts a sub-agent run (`deliver: false`, global lane: `subagent`)
|
||||
- Then runs an announce step and posts the announce reply to the requester chat channel
|
||||
- Default model: inherits the caller unless you set `agents.defaults.subagents.model` (or per-agent `agents.list[].subagents.model`); an explicit `sessions_spawn.model` still wins.
|
||||
- Default thinking: inherits the caller unless you set `agents.defaults.subagents.thinking` (or per-agent `agents.list[].subagents.thinking`); an explicit `sessions_spawn.thinking` still wins.
|
||||
- Default run timeout: if `sessions_spawn.runTimeoutSeconds` is omitted, OpenClaw uses `agents.defaults.subagents.runTimeoutSeconds` when set; otherwise it falls back to `0` (no timeout).
|
||||
|
||||
Tool params:
|
||||
|
||||
- `task` (required)
|
||||
- `label?` (optional)
|
||||
- `agentId?` (optional; spawn under another agent id if allowed)
|
||||
- `model?` (optional; overrides the sub-agent model; invalid values are skipped and the sub-agent runs on the default model with a warning in the tool result)
|
||||
- `thinking?` (optional; overrides thinking level for the sub-agent run)
|
||||
- `runTimeoutSeconds?` (defaults to `agents.defaults.subagents.runTimeoutSeconds` when set, otherwise `0`; when set, the sub-agent run is aborted after N seconds)
|
||||
- `thread?` (default `false`; when `true`, requests channel thread binding for this sub-agent session)
|
||||
- `mode?` (`run|session`)
|
||||
- default is `run`
|
||||
- if `thread: true` and `mode` omitted, default becomes `session`
|
||||
- `mode: "session"` requires `thread: true`
|
||||
- `cleanup?` (`delete|keep`, default `keep`)
|
||||
- `sandbox?` (`inherit|require`, default `inherit`; `require` rejects spawn unless target child runtime is sandboxed)
|
||||
- `sessions_spawn` does **not** accept channel-delivery params (`target`, `channel`, `to`, `threadId`, `replyTo`, `transport`). For delivery, use `message`/`sessions_send` from the spawned run.
|
||||
|
||||
## Thread-bound sessions
|
||||
|
||||
When thread bindings are enabled for a channel, a sub-agent can stay bound to a thread so follow-up user messages in that thread keep routing to the same sub-agent session.
|
||||
|
||||
### Thread supporting channels
|
||||
|
||||
- Discord (currently the only supported channel): supports persistent thread-bound subagent sessions (`sessions_spawn` with `thread: true`), manual thread controls (`/focus`, `/unfocus`, `/agents`, `/session idle`, `/session max-age`), and adapter keys `channels.discord.threadBindings.enabled`, `channels.discord.threadBindings.idleHours`, `channels.discord.threadBindings.maxAgeHours`, and `channels.discord.threadBindings.spawnSubagentSessions`.
|
||||
|
||||
Quick flow:
|
||||
|
||||
1. Spawn with `sessions_spawn` using `thread: true` (and optionally `mode: "session"`).
|
||||
2. OpenClaw creates or binds a thread to that session target in the active channel.
|
||||
3. Replies and follow-up messages in that thread route to the bound session.
|
||||
4. Use `/session idle` to inspect/update inactivity auto-unfocus and `/session max-age` to control the hard cap.
|
||||
5. Use `/unfocus` to detach manually.
|
||||
|
||||
Manual controls:
|
||||
|
||||
- `/focus <target>` binds the current thread (or creates one) to a sub-agent/session target.
|
||||
- `/unfocus` removes the binding for the current bound thread.
|
||||
- `/agents` lists active runs and binding state (`thread:<id>` or `unbound`).
|
||||
- `/session idle` and `/session max-age` only work for focused bound threads.
|
||||
|
||||
Config switches:
|
||||
|
||||
- Global default: `session.threadBindings.enabled`, `session.threadBindings.idleHours`, `session.threadBindings.maxAgeHours`
|
||||
- Channel override and spawn auto-bind keys are adapter-specific. See **Thread supporting channels** above.
|
||||
|
||||
See [Configuration Reference](/gateway/configuration-reference) and [Slash commands](/tools/slash-commands) for current adapter details.
|
||||
|
||||
Allowlist:
|
||||
|
||||
- `agents.list[].subagents.allowAgents`: list of agent ids that can be targeted via `agentId` (`["*"]` to allow any). Default: only the requester agent.
|
||||
- `agents.defaults.subagents.allowAgents`: default target-agent allowlist used when the requester agent does not set its own `subagents.allowAgents`.
|
||||
- Sandbox inheritance guard: if the requester session is sandboxed, `sessions_spawn` rejects targets that would run unsandboxed.
|
||||
- `agents.defaults.subagents.requireAgentId` / `agents.list[].subagents.requireAgentId`: when true, block `sessions_spawn` calls that omit `agentId` (forces explicit profile selection). Default: false.
|
||||
|
||||
Discovery:
|
||||
|
||||
- Use `agents_list` to see which agent ids are currently allowed for `sessions_spawn`.
|
||||
|
||||
Auto-archive:
|
||||
|
||||
- Sub-agent sessions are automatically archived after `agents.defaults.subagents.archiveAfterMinutes` (default: 60).
|
||||
- Archive uses `sessions.delete` and renames the transcript to `*.deleted.<timestamp>` (same folder).
|
||||
- `cleanup: "delete"` archives immediately after announce (still keeps the transcript via rename).
|
||||
- Auto-archive is best-effort; pending timers are lost if the gateway restarts.
|
||||
- `runTimeoutSeconds` does **not** auto-archive; it only stops the run. The session remains until auto-archive.
|
||||
- Auto-archive applies equally to depth-1 and depth-2 sessions.
|
||||
- Browser cleanup is separate from archive cleanup: tracked browser tabs/processes are best-effort closed when the run finishes, even if the transcript/session record is kept.
|
||||
|
||||
## Nested Sub-Agents
|
||||
|
||||
By default, sub-agents cannot spawn their own sub-agents (`maxSpawnDepth: 1`). You can enable one level of nesting by setting `maxSpawnDepth: 2`, which allows the **orchestrator pattern**: main → orchestrator sub-agent → worker sub-sub-agents.
|
||||
|
||||
### How to enable
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
maxSpawnDepth: 2, // allow sub-agents to spawn children (default: 1)
|
||||
maxChildrenPerAgent: 5, // max active children per agent session (default: 5)
|
||||
maxConcurrent: 8, // global concurrency lane cap (default: 8)
|
||||
runTimeoutSeconds: 900, // default timeout for sessions_spawn when omitted (0 = no timeout)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Depth levels
|
||||
|
||||
| Depth | Session key shape | Role | Can spawn? |
|
||||
| ----- | -------------------------------------------- | --------------------------------------------- | ---------------------------- |
|
||||
| 0 | `agent:<id>:main` | Main agent | Always |
|
||||
| 1 | `agent:<id>:subagent:<uuid>` | Sub-agent (orchestrator when depth 2 allowed) | Only if `maxSpawnDepth >= 2` |
|
||||
| 2 | `agent:<id>:subagent:<uuid>:subagent:<uuid>` | Sub-sub-agent (leaf worker) | Never |
|
||||
|
||||
### Announce chain
|
||||
|
||||
Results flow back up the chain:
|
||||
|
||||
1. Depth-2 worker finishes → announces to its parent (depth-1 orchestrator)
|
||||
2. Depth-1 orchestrator receives the announce, synthesizes results, finishes → announces to main
|
||||
3. Main agent receives the announce and delivers to the user
|
||||
|
||||
Each level only sees announces from its direct children.
|
||||
|
||||
Operational guidance:
|
||||
|
||||
- Start child work once and wait for completion events instead of building poll
|
||||
loops around `sessions_list`, `sessions_history`, `/subagents list`, or
|
||||
`exec` sleep commands.
|
||||
- If a child completion event arrives after you already sent the final answer,
|
||||
the correct follow-up is the exact silent token `NO_REPLY` / `no_reply`.
|
||||
|
||||
### Tool policy by depth
|
||||
|
||||
- Role and control scope are written into session metadata at spawn time. That keeps flat or restored session keys from accidentally regaining orchestrator privileges.
|
||||
- **Depth 1 (orchestrator, when `maxSpawnDepth >= 2`)**: Gets `sessions_spawn`, `subagents`, `sessions_list`, `sessions_history` so it can manage its children. Other session/system tools remain denied.
|
||||
- **Depth 1 (leaf, when `maxSpawnDepth == 1`)**: No session tools (current default behavior).
|
||||
- **Depth 2 (leaf worker)**: No session tools — `sessions_spawn` is always denied at depth 2. Cannot spawn further children.
|
||||
|
||||
### Per-agent spawn limit
|
||||
|
||||
Each agent session (at any depth) can have at most `maxChildrenPerAgent` (default: 5) active children at a time. This prevents runaway fan-out from a single orchestrator.
|
||||
|
||||
### Cascade stop
|
||||
|
||||
Stopping a depth-1 orchestrator automatically stops all its depth-2 children:
|
||||
|
||||
- `/stop` in the main chat stops all depth-1 agents and cascades to their depth-2 children.
|
||||
- `/subagents kill <id>` stops a specific sub-agent and cascades to its children.
|
||||
- `/subagents kill all` stops all sub-agents for the requester and cascades.
|
||||
|
||||
## Authentication
|
||||
|
||||
Sub-agent auth is resolved by **agent id**, not by session type:
|
||||
|
||||
- The sub-agent session key is `agent:<agentId>:subagent:<uuid>`.
|
||||
- The auth store is loaded from that agent's `agentDir`.
|
||||
- The main agent's auth profiles are merged in as a **fallback**; agent profiles override main profiles on conflicts.
|
||||
|
||||
Note: the merge is additive, so main profiles are always available as fallbacks. Fully isolated auth per agent is not supported yet.
|
||||
|
||||
## Announce
|
||||
|
||||
Sub-agents report back via an announce step:
|
||||
|
||||
- The announce step runs inside the sub-agent session (not the requester session).
|
||||
- If the sub-agent replies exactly `ANNOUNCE_SKIP`, nothing is posted.
|
||||
- If the latest assistant text is the exact silent token `NO_REPLY` / `no_reply`,
|
||||
announce output is suppressed even if earlier visible progress existed.
|
||||
- Otherwise delivery depends on requester depth:
|
||||
- top-level requester sessions use a follow-up `agent` call with external delivery (`deliver=true`)
|
||||
- nested requester subagent sessions receive an internal follow-up injection (`deliver=false`) so the orchestrator can synthesize child results in-session
|
||||
- if a nested requester subagent session is gone, OpenClaw falls back to that session's requester when available
|
||||
- For top-level requester sessions, completion-mode direct delivery first resolves any bound conversation/thread route and hook override, then fills missing channel-target fields from the requester session's stored route. That keeps completions on the right chat/topic even when the completion origin only identifies the channel.
|
||||
- Child completion aggregation is scoped to the current requester run when building nested completion findings, preventing stale prior-run child outputs from leaking into the current announce.
|
||||
- Announce replies preserve thread/topic routing when available on channel adapters.
|
||||
- Announce context is normalized to a stable internal event block:
|
||||
- source (`subagent` or `cron`)
|
||||
- child session key/id
|
||||
- announce type + task label
|
||||
- status line derived from runtime outcome (`success`, `error`, `timeout`, or `unknown`)
|
||||
- result content selected from the latest visible assistant text, otherwise sanitized latest tool/toolResult text
|
||||
- a follow-up instruction describing when to reply vs. stay silent
|
||||
- `Status` is not inferred from model output; it comes from runtime outcome signals.
|
||||
- On timeout, if the child only got through tool calls, announce can collapse that history into a short partial-progress summary instead of replaying raw tool output.
|
||||
|
||||
Announce payloads include a stats line at the end (even when wrapped):
|
||||
|
||||
- Runtime (e.g., `runtime 5m12s`)
|
||||
- Token usage (input/output/total)
|
||||
- Estimated cost when model pricing is configured (`models.providers.*.models[].cost`)
|
||||
- `sessionKey`, `sessionId`, and transcript path (so the main agent can fetch history via `sessions_history` or inspect the file on disk)
|
||||
- Internal metadata is meant for orchestration only; user-facing replies should be rewritten in normal assistant voice.
|
||||
|
||||
`sessions_history` is the safer orchestration path:
|
||||
|
||||
- assistant recall is normalized first:
|
||||
- thinking tags are stripped
|
||||
- `<relevant-memories>` / `<relevant_memories>` scaffolding blocks are stripped
|
||||
- plain-text tool-call XML payload blocks such as `<tool_call>...</tool_call>`,
|
||||
`<function_call>...</function_call>`, `<tool_calls>...</tool_calls>`, and
|
||||
`<function_calls>...</function_calls>` are stripped, including truncated
|
||||
payloads that never close cleanly
|
||||
- downgraded tool-call/result scaffolding and historical-context markers are stripped
|
||||
- leaked model control tokens such as `<|assistant|>`, other ASCII
|
||||
`<|...|>` tokens, and full-width `<|...|>` variants are stripped
|
||||
- malformed MiniMax tool-call XML is stripped
|
||||
- credential/token-like text is redacted
|
||||
- long blocks can be truncated
|
||||
- very large histories can drop older rows or replace an oversized row with
|
||||
`[sessions_history omitted: message too large]`
|
||||
- raw on-disk transcript inspection is the fallback when you need the full byte-for-byte transcript
|
||||
|
||||
## Tool Policy (sub-agent tools)
|
||||
|
||||
By default, sub-agents get **all tools except session tools** and system tools:
|
||||
|
||||
- `sessions_list`
|
||||
- `sessions_history`
|
||||
- `sessions_send`
|
||||
- `sessions_spawn`
|
||||
|
||||
`sessions_history` remains a bounded, sanitized recall view here too; it is not
|
||||
a raw transcript dump.
|
||||
|
||||
When `maxSpawnDepth >= 2`, depth-1 orchestrator sub-agents additionally receive `sessions_spawn`, `subagents`, `sessions_list`, and `sessions_history` so they can manage their children.
|
||||
|
||||
Override via config:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
subagents: {
|
||||
maxConcurrent: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
subagents: {
|
||||
tools: {
|
||||
// deny wins
|
||||
deny: ["gateway", "cron"],
|
||||
// if allow is set, it becomes allow-only (deny still wins)
|
||||
// allow: ["read", "exec", "process"]
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Concurrency
|
||||
|
||||
Sub-agents use a dedicated in-process queue lane:
|
||||
|
||||
- Lane name: `subagent`
|
||||
- Concurrency: `agents.defaults.subagents.maxConcurrent` (default `8`)
|
||||
|
||||
## Stopping
|
||||
|
||||
- Sending `/stop` in the requester chat aborts the requester session and stops any active sub-agent runs spawned from it, cascading to nested children.
|
||||
- `/subagents kill <id>` stops a specific sub-agent and cascades to its children.
|
||||
|
||||
## Limitations
|
||||
|
||||
- Sub-agent announce is **best-effort**. If the gateway restarts, pending "announce back" work is lost.
|
||||
- Sub-agents still share the same gateway process resources; treat `maxConcurrent` as a safety valve.
|
||||
- `sessions_spawn` is always non-blocking: it returns `{ status: "accepted", runId, childSessionKey }` immediately.
|
||||
- Sub-agent context only injects `AGENTS.md` + `TOOLS.md` (no `SOUL.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, or `BOOTSTRAP.md`).
|
||||
- Maximum nesting depth is 5 (`maxSpawnDepth` range: 1–5). Depth 2 is recommended for most use cases.
|
||||
- `maxChildrenPerAgent` caps active children per session (default: 5, range: 1–20).
|
||||
129
openclaw/docs/tools/tavily.md
Normal file
129
openclaw/docs/tools/tavily.md
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
---
|
||||
summary: "Tavily search and extract tools"
|
||||
read_when:
|
||||
- You want Tavily-backed web search
|
||||
- You need a Tavily API key
|
||||
- You want Tavily as a web_search provider
|
||||
- You want content extraction from URLs
|
||||
title: "Tavily"
|
||||
---
|
||||
|
||||
# Tavily
|
||||
|
||||
OpenClaw can use **Tavily** in two ways:
|
||||
|
||||
- as the `web_search` provider
|
||||
- as explicit plugin tools: `tavily_search` and `tavily_extract`
|
||||
|
||||
Tavily is a search API designed for AI applications, returning structured results
|
||||
optimized for LLM consumption. It supports configurable search depth, topic
|
||||
filtering, domain filters, AI-generated answer summaries, and content extraction
|
||||
from URLs (including JavaScript-rendered pages).
|
||||
|
||||
## Get an API key
|
||||
|
||||
1. Create a Tavily account at [tavily.com](https://tavily.com/).
|
||||
2. Generate an API key in the dashboard.
|
||||
3. Store it in config or set `TAVILY_API_KEY` in the gateway environment.
|
||||
|
||||
## Configure Tavily search
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
tavily: {
|
||||
enabled: true,
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "tvly-...", // optional if TAVILY_API_KEY is set
|
||||
baseUrl: "https://api.tavily.com",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
provider: "tavily",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Choosing Tavily in onboarding or `openclaw configure --section web` enables
|
||||
the bundled Tavily plugin automatically.
|
||||
- Store Tavily config under `plugins.entries.tavily.config.webSearch.*`.
|
||||
- `web_search` with Tavily supports `query` and `count` (up to 20 results).
|
||||
- For Tavily-specific controls like `search_depth`, `topic`, `include_answer`,
|
||||
or domain filters, use `tavily_search`.
|
||||
|
||||
## Tavily plugin tools
|
||||
|
||||
### `tavily_search`
|
||||
|
||||
Use this when you want Tavily-specific search controls instead of generic
|
||||
`web_search`.
|
||||
|
||||
| Parameter | Description |
|
||||
| ----------------- | --------------------------------------------------------------------- |
|
||||
| `query` | Search query string (keep under 400 characters) |
|
||||
| `search_depth` | `basic` (default, balanced) or `advanced` (highest relevance, slower) |
|
||||
| `topic` | `general` (default), `news` (real-time updates), or `finance` |
|
||||
| `max_results` | Number of results, 1-20 (default: 5) |
|
||||
| `include_answer` | Include an AI-generated answer summary (default: false) |
|
||||
| `time_range` | Filter by recency: `day`, `week`, `month`, or `year` |
|
||||
| `include_domains` | Array of domains to restrict results to |
|
||||
| `exclude_domains` | Array of domains to exclude from results |
|
||||
|
||||
**Search depth:**
|
||||
|
||||
| Depth | Speed | Relevance | Best for |
|
||||
| ---------- | ------ | --------- | ----------------------------------- |
|
||||
| `basic` | Faster | High | General-purpose queries (default) |
|
||||
| `advanced` | Slower | Highest | Precision, specific facts, research |
|
||||
|
||||
### `tavily_extract`
|
||||
|
||||
Use this to extract clean content from one or more URLs. Handles
|
||||
JavaScript-rendered pages and supports query-focused chunking for targeted
|
||||
extraction.
|
||||
|
||||
| Parameter | Description |
|
||||
| ------------------- | ---------------------------------------------------------- |
|
||||
| `urls` | Array of URLs to extract (1-20 per request) |
|
||||
| `query` | Rerank extracted chunks by relevance to this query |
|
||||
| `extract_depth` | `basic` (default, fast) or `advanced` (for JS-heavy pages) |
|
||||
| `chunks_per_source` | Chunks per URL, 1-5 (requires `query`) |
|
||||
| `include_images` | Include image URLs in results (default: false) |
|
||||
|
||||
**Extract depth:**
|
||||
|
||||
| Depth | When to use |
|
||||
| ---------- | ----------------------------------------- |
|
||||
| `basic` | Simple pages - try this first |
|
||||
| `advanced` | JS-rendered SPAs, dynamic content, tables |
|
||||
|
||||
Tips:
|
||||
|
||||
- Max 20 URLs per request. Batch larger lists into multiple calls.
|
||||
- Use `query` + `chunks_per_source` to get only relevant content instead of full pages.
|
||||
- Try `basic` first; fall back to `advanced` if content is missing or incomplete.
|
||||
|
||||
## Choosing the right tool
|
||||
|
||||
| Need | Tool |
|
||||
| ------------------------------------ | ---------------- |
|
||||
| Quick web search, no special options | `web_search` |
|
||||
| Search with depth, topic, AI answers | `tavily_search` |
|
||||
| Extract content from specific URLs | `tavily_extract` |
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search overview](/tools/web) -- all providers and auto-detection
|
||||
- [Firecrawl](/tools/firecrawl) -- search + scraping with content extraction
|
||||
- [Exa Search](/tools/exa-search) -- neural search with content extraction
|
||||
114
openclaw/docs/tools/thinking.md
Normal file
114
openclaw/docs/tools/thinking.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
summary: "Directive syntax for /think, /fast, /verbose, /trace, and reasoning visibility"
|
||||
read_when:
|
||||
- Adjusting thinking, fast-mode, or verbose directive parsing or defaults
|
||||
title: "Thinking Levels"
|
||||
---
|
||||
|
||||
# Thinking Levels (/think directives)
|
||||
|
||||
## What it does
|
||||
|
||||
- Inline directive in any inbound body: `/t <level>`, `/think:<level>`, or `/thinking <level>`.
|
||||
- Levels (aliases): `off | minimal | low | medium | high | xhigh | adaptive`
|
||||
- minimal → “think”
|
||||
- low → “think hard”
|
||||
- medium → “think harder”
|
||||
- high → “ultrathink” (max budget)
|
||||
- xhigh → “ultrathink+” (GPT-5.2 + Codex models and Anthropic Claude Opus 4.7 effort)
|
||||
- adaptive → provider-managed adaptive thinking (supported for Anthropic Claude 4.6 and Opus 4.7)
|
||||
- `x-high`, `x_high`, `extra-high`, `extra high`, and `extra_high` map to `xhigh`.
|
||||
- `highest`, `max` map to `high`.
|
||||
- Provider notes:
|
||||
- Anthropic Claude 4.6 models default to `adaptive` when no explicit thinking level is set.
|
||||
- Anthropic Claude Opus 4.7 does not default to adaptive thinking. Its API effort default remains provider-owned unless you explicitly set a thinking level.
|
||||
- Anthropic Claude Opus 4.7 maps `/think xhigh` to adaptive thinking plus `output_config.effort: "xhigh"`, because `/think` is a thinking directive and `xhigh` is the Opus 4.7 effort setting.
|
||||
- MiniMax (`minimax/*`) on the Anthropic-compatible streaming path defaults to `thinking: { type: "disabled" }` unless you explicitly set thinking in model params or request params. This avoids leaked `reasoning_content` deltas from MiniMax's non-native Anthropic stream format.
|
||||
- Z.AI (`zai/*`) only supports binary thinking (`on`/`off`). Any non-`off` level is treated as `on` (mapped to `low`).
|
||||
- Moonshot (`moonshot/*`) maps `/think off` to `thinking: { type: "disabled" }` and any non-`off` level to `thinking: { type: "enabled" }`. When thinking is enabled, Moonshot only accepts `tool_choice` `auto|none`; OpenClaw normalizes incompatible values to `auto`.
|
||||
|
||||
## Resolution order
|
||||
|
||||
1. Inline directive on the message (applies only to that message).
|
||||
2. Session override (set by sending a directive-only message).
|
||||
3. Per-agent default (`agents.list[].thinkingDefault` in config).
|
||||
4. Global default (`agents.defaults.thinkingDefault` in config).
|
||||
5. Fallback: `adaptive` for Anthropic Claude 4.6 models, `off` for Anthropic Claude Opus 4.7 unless explicitly configured, `low` for other reasoning-capable models, `off` otherwise.
|
||||
|
||||
## Setting a session default
|
||||
|
||||
- Send a message that is **only** the directive (whitespace allowed), e.g. `/think:medium` or `/t high`.
|
||||
- That sticks for the current session (per-sender by default); cleared by `/think:off` or session idle reset.
|
||||
- Confirmation reply is sent (`Thinking level set to high.` / `Thinking disabled.`). If the level is invalid (e.g. `/thinking big`), the command is rejected with a hint and the session state is left unchanged.
|
||||
- Send `/think` (or `/think:`) with no argument to see the current thinking level.
|
||||
|
||||
## Application by agent
|
||||
|
||||
- **Embedded Pi**: the resolved level is passed to the in-process Pi agent runtime.
|
||||
|
||||
## Fast mode (/fast)
|
||||
|
||||
- Levels: `on|off`.
|
||||
- Directive-only message toggles a session fast-mode override and replies `Fast mode enabled.` / `Fast mode disabled.`.
|
||||
- Send `/fast` (or `/fast status`) with no mode to see the current effective fast-mode state.
|
||||
- OpenClaw resolves fast mode in this order:
|
||||
1. Inline/directive-only `/fast on|off`
|
||||
2. Session override
|
||||
3. Per-agent default (`agents.list[].fastModeDefault`)
|
||||
4. Per-model config: `agents.defaults.models["<provider>/<model>"].params.fastMode`
|
||||
5. Fallback: `off`
|
||||
- For `openai/*`, fast mode maps to OpenAI priority processing by sending `service_tier=priority` on supported Responses requests.
|
||||
- For `openai-codex/*`, fast mode sends the same `service_tier=priority` flag on Codex Responses. OpenClaw keeps one shared `/fast` toggle across both auth paths.
|
||||
- For direct public `anthropic/*` requests, including OAuth-authenticated traffic sent to `api.anthropic.com`, fast mode maps to Anthropic service tiers: `/fast on` sets `service_tier=auto`, `/fast off` sets `service_tier=standard_only`.
|
||||
- For `minimax/*` on the Anthropic-compatible path, `/fast on` (or `params.fastMode: true`) rewrites `MiniMax-M2.7` to `MiniMax-M2.7-highspeed`.
|
||||
- Explicit Anthropic `serviceTier` / `service_tier` model params override the fast-mode default when both are set. OpenClaw still skips Anthropic service-tier injection for non-Anthropic proxy base URLs.
|
||||
|
||||
## Verbose directives (/verbose or /v)
|
||||
|
||||
- Levels: `on` (minimal) | `full` | `off` (default).
|
||||
- Directive-only message toggles session verbose and replies `Verbose logging enabled.` / `Verbose logging disabled.`; invalid levels return a hint without changing state.
|
||||
- `/verbose off` stores an explicit session override; clear it via the Sessions UI by choosing `inherit`.
|
||||
- Inline directive affects only that message; session/global defaults apply otherwise.
|
||||
- Send `/verbose` (or `/verbose:`) with no argument to see the current verbose level.
|
||||
- When verbose is on, agents that emit structured tool results (Pi, other JSON agents) send each tool call back as its own metadata-only message, prefixed with `<emoji> <tool-name>: <arg>` when available (path/command). These tool summaries are sent as soon as each tool starts (separate bubbles), not as streaming deltas.
|
||||
- Tool failure summaries remain visible in normal mode, but raw error detail suffixes are hidden unless verbose is `on` or `full`.
|
||||
- When verbose is `full`, tool outputs are also forwarded after completion (separate bubble, truncated to a safe length). If you toggle `/verbose on|full|off` while a run is in-flight, subsequent tool bubbles honor the new setting.
|
||||
|
||||
## Plugin trace directives (/trace)
|
||||
|
||||
- Levels: `on` | `off` (default).
|
||||
- Directive-only message toggles session plugin trace output and replies `Plugin trace enabled.` / `Plugin trace disabled.`.
|
||||
- Inline directive affects only that message; session/global defaults apply otherwise.
|
||||
- Send `/trace` (or `/trace:`) with no argument to see the current trace level.
|
||||
- `/trace` is narrower than `/verbose`: it only exposes plugin-owned trace/debug lines such as Active Memory debug summaries.
|
||||
- Trace lines can appear in `/status` and as a follow-up diagnostic message after the normal assistant reply.
|
||||
|
||||
## Reasoning visibility (/reasoning)
|
||||
|
||||
- Levels: `on|off|stream`.
|
||||
- Directive-only message toggles whether thinking blocks are shown in replies.
|
||||
- When enabled, reasoning is sent as a **separate message** prefixed with `Reasoning:`.
|
||||
- `stream` (Telegram only): streams reasoning into the Telegram draft bubble while the reply is generating, then sends the final answer without reasoning.
|
||||
- Alias: `/reason`.
|
||||
- Send `/reasoning` (or `/reasoning:`) with no argument to see the current reasoning level.
|
||||
- Resolution order: inline directive, then session override, then per-agent default (`agents.list[].reasoningDefault`), then fallback (`off`).
|
||||
|
||||
## Related
|
||||
|
||||
- Elevated mode docs live in [Elevated mode](/tools/elevated).
|
||||
|
||||
## Heartbeats
|
||||
|
||||
- Heartbeat probe body is the configured heartbeat prompt (default: `Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.`). Inline directives in a heartbeat message apply as usual (but avoid changing session defaults from heartbeats).
|
||||
- Heartbeat delivery defaults to the final payload only. To also send the separate `Reasoning:` message (when available), set `agents.defaults.heartbeat.includeReasoning: true` or per-agent `agents.list[].heartbeat.includeReasoning: true`.
|
||||
|
||||
## Web chat UI
|
||||
|
||||
- The web chat thinking selector mirrors the session's stored level from the inbound session store/config when the page loads.
|
||||
- Picking another level writes the session override immediately via `sessions.patch`; it does not wait for the next send and it is not a one-shot `thinkingOnce` override.
|
||||
- The first option is always `Default (<resolved level>)`, where the resolved default comes from the active session model: `adaptive` for Claude 4.6 on Anthropic, `off` for Anthropic Claude Opus 4.7 unless configured, `low` for other reasoning-capable models, `off` otherwise.
|
||||
- The picker stays provider-aware:
|
||||
- most providers show `off | minimal | low | medium | high | adaptive`
|
||||
- Anthropic Claude Opus 4.7 shows `off | minimal | low | medium | high | xhigh | adaptive`
|
||||
- Z.AI shows binary `off | on`
|
||||
- `/think:<level>` still works and updates the same stored session level, so chat directives and the picker stay in sync.
|
||||
485
openclaw/docs/tools/tts.md
Normal file
485
openclaw/docs/tools/tts.md
Normal file
|
|
@ -0,0 +1,485 @@
|
|||
---
|
||||
summary: "Text-to-speech (TTS) for outbound replies"
|
||||
read_when:
|
||||
- Enabling text-to-speech for replies
|
||||
- Configuring TTS providers or limits
|
||||
- Using /tts commands
|
||||
title: "Text-to-Speech"
|
||||
---
|
||||
|
||||
# Text-to-speech (TTS)
|
||||
|
||||
OpenClaw can convert outbound replies into audio using ElevenLabs, Google Gemini, Microsoft, MiniMax, or OpenAI.
|
||||
It works anywhere OpenClaw can send audio.
|
||||
|
||||
## Supported services
|
||||
|
||||
- **ElevenLabs** (primary or fallback provider)
|
||||
- **Google Gemini** (primary or fallback provider; uses Gemini API TTS)
|
||||
- **Microsoft** (primary or fallback provider; current bundled implementation uses `node-edge-tts`)
|
||||
- **MiniMax** (primary or fallback provider; uses the T2A v2 API)
|
||||
- **OpenAI** (primary or fallback provider; also used for summaries)
|
||||
|
||||
### Microsoft speech notes
|
||||
|
||||
The bundled Microsoft speech provider currently uses Microsoft Edge's online
|
||||
neural TTS service via the `node-edge-tts` library. It's a hosted service (not
|
||||
local), uses Microsoft endpoints, and does not require an API key.
|
||||
`node-edge-tts` exposes speech configuration options and output formats, but
|
||||
not all options are supported by the service. Legacy config and directive input
|
||||
using `edge` still works and is normalized to `microsoft`.
|
||||
|
||||
Because this path is a public web service without a published SLA or quota,
|
||||
treat it as best-effort. If you need guaranteed limits and support, use OpenAI
|
||||
or ElevenLabs.
|
||||
|
||||
## Optional keys
|
||||
|
||||
If you want OpenAI, ElevenLabs, Google Gemini, or MiniMax:
|
||||
|
||||
- `ELEVENLABS_API_KEY` (or `XI_API_KEY`)
|
||||
- `GEMINI_API_KEY` (or `GOOGLE_API_KEY`)
|
||||
- `MINIMAX_API_KEY`
|
||||
- `OPENAI_API_KEY`
|
||||
|
||||
Microsoft speech does **not** require an API key.
|
||||
|
||||
If multiple providers are configured, the selected provider is used first and the others are fallback options.
|
||||
Auto-summary uses the configured `summaryModel` (or `agents.defaults.model.primary`),
|
||||
so that provider must also be authenticated if you enable summaries.
|
||||
|
||||
## Service links
|
||||
|
||||
- [OpenAI Text-to-Speech guide](https://platform.openai.com/docs/guides/text-to-speech)
|
||||
- [OpenAI Audio API reference](https://platform.openai.com/docs/api-reference/audio)
|
||||
- [ElevenLabs Text to Speech](https://elevenlabs.io/docs/api-reference/text-to-speech)
|
||||
- [ElevenLabs Authentication](https://elevenlabs.io/docs/api-reference/authentication)
|
||||
- [MiniMax T2A v2 API](https://platform.minimaxi.com/document/T2A%20V2)
|
||||
- [node-edge-tts](https://github.com/SchneeHertz/node-edge-tts)
|
||||
- [Microsoft Speech output formats](https://learn.microsoft.com/azure/ai-services/speech-service/rest-text-to-speech#audio-outputs)
|
||||
|
||||
## Is it enabled by default?
|
||||
|
||||
No. Auto‑TTS is **off** by default. Enable it in config with
|
||||
`messages.tts.auto` or locally with `/tts on`.
|
||||
|
||||
When `messages.tts.provider` is unset, OpenClaw picks the first configured
|
||||
speech provider in registry auto-select order.
|
||||
|
||||
## Config
|
||||
|
||||
TTS config lives under `messages.tts` in `openclaw.json`.
|
||||
Full schema is in [Gateway configuration](/gateway/configuration).
|
||||
|
||||
### Minimal config (enable + provider)
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "always",
|
||||
provider: "elevenlabs",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### OpenAI primary with ElevenLabs fallback
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "always",
|
||||
provider: "openai",
|
||||
summaryModel: "openai/gpt-4.1-mini",
|
||||
modelOverrides: {
|
||||
enabled: true,
|
||||
},
|
||||
providers: {
|
||||
openai: {
|
||||
apiKey: "openai_api_key",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
model: "gpt-4o-mini-tts",
|
||||
voice: "alloy",
|
||||
},
|
||||
elevenlabs: {
|
||||
apiKey: "elevenlabs_api_key",
|
||||
baseUrl: "https://api.elevenlabs.io",
|
||||
voiceId: "voice_id",
|
||||
modelId: "eleven_multilingual_v2",
|
||||
seed: 42,
|
||||
applyTextNormalization: "auto",
|
||||
languageCode: "en",
|
||||
voiceSettings: {
|
||||
stability: 0.5,
|
||||
similarityBoost: 0.75,
|
||||
style: 0.0,
|
||||
useSpeakerBoost: true,
|
||||
speed: 1.0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Microsoft primary (no API key)
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "always",
|
||||
provider: "microsoft",
|
||||
providers: {
|
||||
microsoft: {
|
||||
enabled: true,
|
||||
voice: "en-US-MichelleNeural",
|
||||
lang: "en-US",
|
||||
outputFormat: "audio-24khz-48kbitrate-mono-mp3",
|
||||
rate: "+10%",
|
||||
pitch: "-5%",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### MiniMax primary
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "always",
|
||||
provider: "minimax",
|
||||
providers: {
|
||||
minimax: {
|
||||
apiKey: "minimax_api_key",
|
||||
baseUrl: "https://api.minimax.io",
|
||||
model: "speech-2.8-hd",
|
||||
voiceId: "English_expressive_narrator",
|
||||
speed: 1.0,
|
||||
vol: 1.0,
|
||||
pitch: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Google Gemini primary
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "always",
|
||||
provider: "google",
|
||||
providers: {
|
||||
google: {
|
||||
apiKey: "gemini_api_key",
|
||||
model: "gemini-3.1-flash-tts-preview",
|
||||
voiceName: "Kore",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Google Gemini TTS uses the Gemini API key path. A Google Cloud Console API key
|
||||
restricted to the Gemini API is valid here, and it is the same style of key used
|
||||
by the bundled Google image-generation provider. Resolution order is
|
||||
`messages.tts.providers.google.apiKey` -> `models.providers.google.apiKey` ->
|
||||
`GEMINI_API_KEY` -> `GOOGLE_API_KEY`.
|
||||
|
||||
### Disable Microsoft speech
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
providers: {
|
||||
microsoft: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Custom limits + prefs path
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "always",
|
||||
maxTextLength: 4000,
|
||||
timeoutMs: 30000,
|
||||
prefsPath: "~/.openclaw/settings/tts.json",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Only reply with audio after an inbound voice message
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "inbound",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Disable auto-summary for long replies
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
auto: "always",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```
|
||||
/tts summary off
|
||||
```
|
||||
|
||||
### Notes on fields
|
||||
|
||||
- `auto`: auto‑TTS mode (`off`, `always`, `inbound`, `tagged`).
|
||||
- `inbound` only sends audio after an inbound voice message.
|
||||
- `tagged` only sends audio when the reply includes `[[tts:key=value]]` directives or a `[[tts:text]]...[[/tts:text]]` block.
|
||||
- `enabled`: legacy toggle (doctor migrates this to `auto`).
|
||||
- `mode`: `"final"` (default) or `"all"` (includes tool/block replies).
|
||||
- `provider`: speech provider id such as `"elevenlabs"`, `"google"`, `"microsoft"`, `"minimax"`, or `"openai"` (fallback is automatic).
|
||||
- If `provider` is **unset**, OpenClaw uses the first configured speech provider in registry auto-select order.
|
||||
- Legacy `provider: "edge"` still works and is normalized to `microsoft`.
|
||||
- `summaryModel`: optional cheap model for auto-summary; defaults to `agents.defaults.model.primary`.
|
||||
- Accepts `provider/model` or a configured model alias.
|
||||
- `modelOverrides`: allow the model to emit TTS directives (on by default).
|
||||
- `allowProvider` defaults to `false` (provider switching is opt-in).
|
||||
- `providers.<id>`: provider-owned settings keyed by speech provider id.
|
||||
- Legacy direct provider blocks (`messages.tts.openai`, `messages.tts.elevenlabs`, `messages.tts.microsoft`, `messages.tts.edge`) are auto-migrated to `messages.tts.providers.<id>` on load.
|
||||
- `maxTextLength`: hard cap for TTS input (chars). `/tts audio` fails if exceeded.
|
||||
- `timeoutMs`: request timeout (ms).
|
||||
- `prefsPath`: override the local prefs JSON path (provider/limit/summary).
|
||||
- `apiKey` values fall back to env vars (`ELEVENLABS_API_KEY`/`XI_API_KEY`, `GEMINI_API_KEY`/`GOOGLE_API_KEY`, `MINIMAX_API_KEY`, `OPENAI_API_KEY`).
|
||||
- `providers.elevenlabs.baseUrl`: override ElevenLabs API base URL.
|
||||
- `providers.openai.baseUrl`: override the OpenAI TTS endpoint.
|
||||
- Resolution order: `messages.tts.providers.openai.baseUrl` -> `OPENAI_TTS_BASE_URL` -> `https://api.openai.com/v1`
|
||||
- Non-default values are treated as OpenAI-compatible TTS endpoints, so custom model and voice names are accepted.
|
||||
- `providers.elevenlabs.voiceSettings`:
|
||||
- `stability`, `similarityBoost`, `style`: `0..1`
|
||||
- `useSpeakerBoost`: `true|false`
|
||||
- `speed`: `0.5..2.0` (1.0 = normal)
|
||||
- `providers.elevenlabs.applyTextNormalization`: `auto|on|off`
|
||||
- `providers.elevenlabs.languageCode`: 2-letter ISO 639-1 (e.g. `en`, `de`)
|
||||
- `providers.elevenlabs.seed`: integer `0..4294967295` (best-effort determinism)
|
||||
- `providers.minimax.baseUrl`: override MiniMax API base URL (default `https://api.minimax.io`, env: `MINIMAX_API_HOST`).
|
||||
- `providers.minimax.model`: TTS model (default `speech-2.8-hd`, env: `MINIMAX_TTS_MODEL`).
|
||||
- `providers.minimax.voiceId`: voice identifier (default `English_expressive_narrator`, env: `MINIMAX_TTS_VOICE_ID`).
|
||||
- `providers.minimax.speed`: playback speed `0.5..2.0` (default 1.0).
|
||||
- `providers.minimax.vol`: volume `(0, 10]` (default 1.0; must be greater than 0).
|
||||
- `providers.minimax.pitch`: pitch shift `-12..12` (default 0).
|
||||
- `providers.google.model`: Gemini TTS model (default `gemini-3.1-flash-tts-preview`).
|
||||
- `providers.google.voiceName`: Gemini prebuilt voice name (default `Kore`; `voice` is also accepted).
|
||||
- `providers.google.baseUrl`: override the Gemini API base URL. Only `https://generativelanguage.googleapis.com` is accepted.
|
||||
- If `messages.tts.providers.google.apiKey` is omitted, TTS can reuse `models.providers.google.apiKey` before env fallback.
|
||||
- `providers.microsoft.enabled`: allow Microsoft speech usage (default `true`; no API key).
|
||||
- `providers.microsoft.voice`: Microsoft neural voice name (e.g. `en-US-MichelleNeural`).
|
||||
- `providers.microsoft.lang`: language code (e.g. `en-US`).
|
||||
- `providers.microsoft.outputFormat`: Microsoft output format (e.g. `audio-24khz-48kbitrate-mono-mp3`).
|
||||
- See Microsoft Speech output formats for valid values; not all formats are supported by the bundled Edge-backed transport.
|
||||
- `providers.microsoft.rate` / `providers.microsoft.pitch` / `providers.microsoft.volume`: percent strings (e.g. `+10%`, `-5%`).
|
||||
- `providers.microsoft.saveSubtitles`: write JSON subtitles alongside the audio file.
|
||||
- `providers.microsoft.proxy`: proxy URL for Microsoft speech requests.
|
||||
- `providers.microsoft.timeoutMs`: request timeout override (ms).
|
||||
- `edge.*`: legacy alias for the same Microsoft settings.
|
||||
|
||||
## Model-driven overrides (default on)
|
||||
|
||||
By default, the model **can** emit TTS directives for a single reply.
|
||||
When `messages.tts.auto` is `tagged`, these directives are required to trigger audio.
|
||||
|
||||
When enabled, the model can emit `[[tts:...]]` directives to override the voice
|
||||
for a single reply, plus an optional `[[tts:text]]...[[/tts:text]]` block to
|
||||
provide expressive tags (laughter, singing cues, etc) that should only appear in
|
||||
the audio.
|
||||
|
||||
`provider=...` directives are ignored unless `modelOverrides.allowProvider: true`.
|
||||
|
||||
Example reply payload:
|
||||
|
||||
```
|
||||
Here you go.
|
||||
|
||||
[[tts:voiceId=pMsXgVXv3BLzUgSXRplE model=eleven_v3 speed=1.1]]
|
||||
[[tts:text]](laughs) Read the song once more.[[/tts:text]]
|
||||
```
|
||||
|
||||
Available directive keys (when enabled):
|
||||
|
||||
- `provider` (registered speech provider id, for example `openai`, `elevenlabs`, `google`, `minimax`, or `microsoft`; requires `allowProvider: true`)
|
||||
- `voice` (OpenAI voice), `voiceName` / `voice_name` / `google_voice` (Google voice), or `voiceId` (ElevenLabs / MiniMax)
|
||||
- `model` (OpenAI TTS model, ElevenLabs model id, or MiniMax model) or `google_model` (Google TTS model)
|
||||
- `stability`, `similarityBoost`, `style`, `speed`, `useSpeakerBoost`
|
||||
- `vol` / `volume` (MiniMax volume, 0-10)
|
||||
- `pitch` (MiniMax pitch, -12 to 12)
|
||||
- `applyTextNormalization` (`auto|on|off`)
|
||||
- `languageCode` (ISO 639-1)
|
||||
- `seed`
|
||||
|
||||
Disable all model overrides:
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
modelOverrides: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Optional allowlist (enable provider switching while keeping other knobs configurable):
|
||||
|
||||
```json5
|
||||
{
|
||||
messages: {
|
||||
tts: {
|
||||
modelOverrides: {
|
||||
enabled: true,
|
||||
allowProvider: true,
|
||||
allowSeed: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Per-user preferences
|
||||
|
||||
Slash commands write local overrides to `prefsPath` (default:
|
||||
`~/.openclaw/settings/tts.json`, override with `OPENCLAW_TTS_PREFS` or
|
||||
`messages.tts.prefsPath`).
|
||||
|
||||
Stored fields:
|
||||
|
||||
- `enabled`
|
||||
- `provider`
|
||||
- `maxLength` (summary threshold; default 1500 chars)
|
||||
- `summarize` (default `true`)
|
||||
|
||||
These override `messages.tts.*` for that host.
|
||||
|
||||
## Output formats (fixed)
|
||||
|
||||
- **Feishu / Matrix / Telegram / WhatsApp**: Opus voice message (`opus_48000_64` from ElevenLabs, `opus` from OpenAI).
|
||||
- 48kHz / 64kbps is a good voice message tradeoff.
|
||||
- **Other channels**: MP3 (`mp3_44100_128` from ElevenLabs, `mp3` from OpenAI).
|
||||
- 44.1kHz / 128kbps is the default balance for speech clarity.
|
||||
- **MiniMax**: MP3 (`speech-2.8-hd` model, 32kHz sample rate). Voice-note format not natively supported; use OpenAI or ElevenLabs for guaranteed Opus voice messages.
|
||||
- **Google Gemini**: Gemini API TTS returns raw 24kHz PCM. OpenClaw wraps it as WAV for audio attachments and returns PCM directly for Talk/telephony. Native Opus voice-note format is not supported by this path.
|
||||
- **Microsoft**: uses `microsoft.outputFormat` (default `audio-24khz-48kbitrate-mono-mp3`).
|
||||
- The bundled transport accepts an `outputFormat`, but not all formats are available from the service.
|
||||
- Output format values follow Microsoft Speech output formats (including Ogg/WebM Opus).
|
||||
- Telegram `sendVoice` accepts OGG/MP3/M4A; use OpenAI/ElevenLabs if you need
|
||||
guaranteed Opus voice messages.
|
||||
- If the configured Microsoft output format fails, OpenClaw retries with MP3.
|
||||
|
||||
OpenAI/ElevenLabs output formats are fixed per channel (see above).
|
||||
|
||||
## Auto-TTS behavior
|
||||
|
||||
When enabled, OpenClaw:
|
||||
|
||||
- skips TTS if the reply already contains media or a `MEDIA:` directive.
|
||||
- skips very short replies (< 10 chars).
|
||||
- summarizes long replies when enabled using `agents.defaults.model.primary` (or `summaryModel`).
|
||||
- attaches the generated audio to the reply.
|
||||
|
||||
If the reply exceeds `maxLength` and summary is off (or no API key for the
|
||||
summary model), audio
|
||||
is skipped and the normal text reply is sent.
|
||||
|
||||
## Flow diagram
|
||||
|
||||
```
|
||||
Reply -> TTS enabled?
|
||||
no -> send text
|
||||
yes -> has media / MEDIA: / short?
|
||||
yes -> send text
|
||||
no -> length > limit?
|
||||
no -> TTS -> attach audio
|
||||
yes -> summary enabled?
|
||||
no -> send text
|
||||
yes -> summarize (summaryModel or agents.defaults.model.primary)
|
||||
-> TTS -> attach audio
|
||||
```
|
||||
|
||||
## Slash command usage
|
||||
|
||||
There is a single command: `/tts`.
|
||||
See [Slash commands](/tools/slash-commands) for enablement details.
|
||||
|
||||
Discord note: `/tts` is a built-in Discord command, so OpenClaw registers
|
||||
`/voice` as the native command there. Text `/tts ...` still works.
|
||||
|
||||
```
|
||||
/tts off
|
||||
/tts on
|
||||
/tts status
|
||||
/tts provider openai
|
||||
/tts limit 2000
|
||||
/tts summary off
|
||||
/tts audio Hello from OpenClaw
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Commands require an authorized sender (allowlist/owner rules still apply).
|
||||
- `commands.text` or native command registration must be enabled.
|
||||
- Config `messages.tts.auto` accepts `off|always|inbound|tagged`.
|
||||
- `/tts on` writes the local TTS preference to `always`; `/tts off` writes it to `off`.
|
||||
- Use config when you want `inbound` or `tagged` defaults.
|
||||
- `limit` and `summary` are stored in local prefs, not the main config.
|
||||
- `/tts audio` generates a one-off audio reply (does not toggle TTS on).
|
||||
- `/tts status` includes fallback visibility for the latest attempt:
|
||||
- success fallback: `Fallback: <primary> -> <used>` plus `Attempts: ...`
|
||||
- failure: `Error: ...` plus `Attempts: ...`
|
||||
- detailed diagnostics: `Attempt details: provider:outcome(reasonCode) latency`
|
||||
- OpenAI and ElevenLabs API failures now include parsed provider error detail and request id (when returned by the provider), which is surfaced in TTS errors/logs.
|
||||
|
||||
## Agent tool
|
||||
|
||||
The `tts` tool converts text to speech and returns an audio attachment for
|
||||
reply delivery. When the channel is Feishu, Matrix, Telegram, or WhatsApp,
|
||||
the audio is delivered as a voice message rather than a file attachment.
|
||||
|
||||
## Gateway RPC
|
||||
|
||||
Gateway methods:
|
||||
|
||||
- `tts.status`
|
||||
- `tts.enable`
|
||||
- `tts.disable`
|
||||
- `tts.convert`
|
||||
- `tts.setProvider`
|
||||
- `tts.providers`
|
||||
384
openclaw/docs/tools/video-generation.md
Normal file
384
openclaw/docs/tools/video-generation.md
Normal file
|
|
@ -0,0 +1,384 @@
|
|||
---
|
||||
summary: "Generate videos from text, images, or existing videos using 14 provider backends"
|
||||
read_when:
|
||||
- Generating videos via the agent
|
||||
- Configuring video generation providers and models
|
||||
- Understanding the video_generate tool parameters
|
||||
title: "Video Generation"
|
||||
---
|
||||
|
||||
# Video Generation
|
||||
|
||||
OpenClaw agents can generate videos from text prompts, reference images, or existing videos. Fourteen provider backends are supported, each with different model options, input modes, and feature sets. The agent picks the right provider automatically based on your configuration and available API keys.
|
||||
|
||||
<Note>
|
||||
The `video_generate` tool only appears when at least one video-generation provider is available. If you do not see it in your agent tools, set a provider API key or configure `agents.defaults.videoGenerationModel`.
|
||||
</Note>
|
||||
|
||||
OpenClaw treats video generation as three runtime modes:
|
||||
|
||||
- `generate` for text-to-video requests with no reference media
|
||||
- `imageToVideo` when the request includes one or more reference images
|
||||
- `videoToVideo` when the request includes one or more reference videos
|
||||
|
||||
Providers can support any subset of those modes. The tool validates the active
|
||||
mode before submission and reports supported modes in `action=list`.
|
||||
|
||||
## Quick start
|
||||
|
||||
1. Set an API key for any supported provider:
|
||||
|
||||
```bash
|
||||
export GEMINI_API_KEY="your-key"
|
||||
```
|
||||
|
||||
2. Optionally pin a default model:
|
||||
|
||||
```bash
|
||||
openclaw config set agents.defaults.videoGenerationModel.primary "google/veo-3.1-fast-generate-preview"
|
||||
```
|
||||
|
||||
3. Ask the agent:
|
||||
|
||||
> Generate a 5-second cinematic video of a friendly lobster surfing at sunset.
|
||||
|
||||
The agent calls `video_generate` automatically. No tool allowlisting is needed.
|
||||
|
||||
## What happens when you generate a video
|
||||
|
||||
Video generation is asynchronous. When the agent calls `video_generate` in a session:
|
||||
|
||||
1. OpenClaw submits the request to the provider and immediately returns a task ID.
|
||||
2. The provider processes the job in the background (typically 30 seconds to 5 minutes depending on the provider and resolution).
|
||||
3. When the video is ready, OpenClaw wakes the same session with an internal completion event.
|
||||
4. The agent posts the finished video back into the original conversation.
|
||||
|
||||
While a job is in flight, duplicate `video_generate` calls in the same session return the current task status instead of starting another generation. Use `openclaw tasks list` or `openclaw tasks show <taskId>` to check progress from the CLI.
|
||||
|
||||
Outside of session-backed agent runs (for example, direct tool invocations), the tool falls back to inline generation and returns the final media path in the same turn.
|
||||
|
||||
### Task lifecycle
|
||||
|
||||
Each `video_generate` request moves through four states:
|
||||
|
||||
1. **queued** -- task created, waiting for the provider to accept it.
|
||||
2. **running** -- provider is processing (typically 30 seconds to 5 minutes depending on provider and resolution).
|
||||
3. **succeeded** -- video ready; the agent wakes and posts it to the conversation.
|
||||
4. **failed** -- provider error or timeout; the agent wakes with error details.
|
||||
|
||||
Check status from the CLI:
|
||||
|
||||
```bash
|
||||
openclaw tasks list
|
||||
openclaw tasks show <taskId>
|
||||
openclaw tasks cancel <taskId>
|
||||
```
|
||||
|
||||
Duplicate prevention: if a video task is already `queued` or `running` for the current session, `video_generate` returns the existing task status instead of starting a new one. Use `action: "status"` to check explicitly without triggering a new generation.
|
||||
|
||||
## Supported providers
|
||||
|
||||
| Provider | Default model | Text | Image ref | Video ref | API key |
|
||||
| --------------------- | ------------------------------- | ---- | ---------------------------------------------------- | ---------------- | ---------------------------------------- |
|
||||
| Alibaba | `wan2.6-t2v` | Yes | Yes (remote URL) | Yes (remote URL) | `MODELSTUDIO_API_KEY` |
|
||||
| BytePlus (1.0) | `seedance-1-0-pro-250528` | Yes | Up to 2 images (I2V models only; first + last frame) | No | `BYTEPLUS_API_KEY` |
|
||||
| BytePlus Seedance 1.5 | `seedance-1-5-pro-251215` | Yes | Up to 2 images (first + last frame via role) | No | `BYTEPLUS_API_KEY` |
|
||||
| BytePlus Seedance 2.0 | `dreamina-seedance-2-0-260128` | Yes | Up to 9 reference images | Up to 3 videos | `BYTEPLUS_API_KEY` |
|
||||
| ComfyUI | `workflow` | Yes | 1 image | No | `COMFY_API_KEY` or `COMFY_CLOUD_API_KEY` |
|
||||
| fal | `fal-ai/minimax/video-01-live` | Yes | 1 image | No | `FAL_KEY` |
|
||||
| Google | `veo-3.1-fast-generate-preview` | Yes | 1 image | 1 video | `GEMINI_API_KEY` |
|
||||
| MiniMax | `MiniMax-Hailuo-2.3` | Yes | 1 image | No | `MINIMAX_API_KEY` |
|
||||
| OpenAI | `sora-2` | Yes | 1 image | 1 video | `OPENAI_API_KEY` |
|
||||
| Qwen | `wan2.6-t2v` | Yes | Yes (remote URL) | Yes (remote URL) | `QWEN_API_KEY` |
|
||||
| Runway | `gen4.5` | Yes | 1 image | 1 video | `RUNWAYML_API_SECRET` |
|
||||
| Together | `Wan-AI/Wan2.2-T2V-A14B` | Yes | 1 image | No | `TOGETHER_API_KEY` |
|
||||
| Vydra | `veo3` | Yes | 1 image (`kling`) | No | `VYDRA_API_KEY` |
|
||||
| xAI | `grok-imagine-video` | Yes | 1 image | 1 video | `XAI_API_KEY` |
|
||||
|
||||
Some providers accept additional or alternate API key env vars. See individual [provider pages](#related) for details.
|
||||
|
||||
Run `video_generate action=list` to inspect available providers, models, and
|
||||
runtime modes at runtime.
|
||||
|
||||
### Declared capability matrix
|
||||
|
||||
This is the explicit mode contract used by `video_generate`, contract tests,
|
||||
and the shared live sweep.
|
||||
|
||||
| Provider | `generate` | `imageToVideo` | `videoToVideo` | Shared live lanes today |
|
||||
| -------- | ---------- | -------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Alibaba | Yes | Yes | Yes | `generate`, `imageToVideo`; `videoToVideo` skipped because this provider needs remote `http(s)` video URLs |
|
||||
| BytePlus | Yes | Yes | No | `generate`, `imageToVideo` |
|
||||
| ComfyUI | Yes | Yes | No | Not in the shared sweep; workflow-specific coverage lives with Comfy tests |
|
||||
| fal | Yes | Yes | No | `generate`, `imageToVideo` |
|
||||
| Google | Yes | Yes | Yes | `generate`, `imageToVideo`; shared `videoToVideo` skipped because the current buffer-backed Gemini/Veo sweep does not accept that input |
|
||||
| MiniMax | Yes | Yes | No | `generate`, `imageToVideo` |
|
||||
| OpenAI | Yes | Yes | Yes | `generate`, `imageToVideo`; shared `videoToVideo` skipped because this org/input path currently needs provider-side inpaint/remix access |
|
||||
| Qwen | Yes | Yes | Yes | `generate`, `imageToVideo`; `videoToVideo` skipped because this provider needs remote `http(s)` video URLs |
|
||||
| Runway | Yes | Yes | Yes | `generate`, `imageToVideo`; `videoToVideo` runs only when the selected model is `runway/gen4_aleph` |
|
||||
| Together | Yes | Yes | No | `generate`, `imageToVideo` |
|
||||
| Vydra | Yes | Yes | No | `generate`; shared `imageToVideo` skipped because bundled `veo3` is text-only and bundled `kling` requires a remote image URL |
|
||||
| xAI | Yes | Yes | Yes | `generate`, `imageToVideo`; `videoToVideo` skipped because this provider currently needs a remote MP4 URL |
|
||||
|
||||
## Tool parameters
|
||||
|
||||
### Required
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ------ | ----------------------------------------------------------------------------- |
|
||||
| `prompt` | string | Text description of the video to generate (required for `action: "generate"`) |
|
||||
|
||||
### Content inputs
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `image` | string | Single reference image (path or URL) |
|
||||
| `images` | string[] | Multiple reference images (up to 9) |
|
||||
| `imageRoles` | string[] | Optional per-position role hints parallel to the combined image list. Canonical values: `first_frame`, `last_frame`, `reference_image` |
|
||||
| `video` | string | Single reference video (path or URL) |
|
||||
| `videos` | string[] | Multiple reference videos (up to 4) |
|
||||
| `videoRoles` | string[] | Optional per-position role hints parallel to the combined video list. Canonical value: `reference_video` |
|
||||
| `audioRef` | string | Single reference audio (path or URL). Used for e.g. background music or voice reference when the provider supports audio inputs |
|
||||
| `audioRefs` | string[] | Multiple reference audios (up to 3) |
|
||||
| `audioRoles` | string[] | Optional per-position role hints parallel to the combined audio list. Canonical value: `reference_audio` |
|
||||
|
||||
Role hints are forwarded to the provider as-is. Canonical values come from
|
||||
the `VideoGenerationAssetRole` union but providers may accept additional
|
||||
role strings. `*Roles` arrays must not have more entries than the
|
||||
corresponding reference list; off-by-one mistakes fail with a clear error.
|
||||
Use an empty string to leave a slot unset.
|
||||
|
||||
### Style controls
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ----------------- | ------- | --------------------------------------------------------------------------------------- |
|
||||
| `aspectRatio` | string | `1:1`, `2:3`, `3:2`, `3:4`, `4:3`, `4:5`, `5:4`, `9:16`, `16:9`, `21:9`, or `adaptive` |
|
||||
| `resolution` | string | `480P`, `720P`, `768P`, or `1080P` |
|
||||
| `durationSeconds` | number | Target duration in seconds (rounded to nearest provider-supported value) |
|
||||
| `size` | string | Size hint when the provider supports it |
|
||||
| `audio` | boolean | Enable generated audio in the output when supported. Distinct from `audioRef*` (inputs) |
|
||||
| `watermark` | boolean | Toggle provider watermarking when supported |
|
||||
|
||||
`adaptive` is a provider-specific sentinel: it is forwarded as-is to
|
||||
providers that declare `adaptive` in their capabilities (e.g. BytePlus
|
||||
Seedance uses it to auto-detect the ratio from the input image
|
||||
dimensions). Providers that do not declare it surface the value via
|
||||
`details.ignoredOverrides` in the tool result so the drop is visible.
|
||||
|
||||
### Advanced
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ----------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `action` | string | `"generate"` (default), `"status"`, or `"list"` |
|
||||
| `model` | string | Provider/model override (e.g. `runway/gen4.5`) |
|
||||
| `filename` | string | Output filename hint |
|
||||
| `providerOptions` | object | Provider-specific options as a JSON object (e.g. `{"seed": 42, "draft": true}`). Providers that declare a typed schema validate the keys and types; unknown keys or mismatches skip the candidate during fallback. Providers without a declared schema receive the options as-is. Run `video_generate action=list` to see what each provider accepts |
|
||||
|
||||
Not all providers support all parameters. OpenClaw already normalizes duration to the closest provider-supported value, and it also remaps translated geometry hints such as size-to-aspect-ratio when a fallback provider exposes a different control surface. Truly unsupported overrides are ignored on a best-effort basis and reported as warnings in the tool result. Hard capability limits (such as too many reference inputs) fail before submission.
|
||||
|
||||
Tool results report the applied settings. When OpenClaw remaps duration or geometry during provider fallback, the returned `durationSeconds`, `size`, `aspectRatio`, and `resolution` values reflect what was submitted, and `details.normalization` captures the requested-to-applied translation.
|
||||
|
||||
Reference inputs also select the runtime mode:
|
||||
|
||||
- No reference media: `generate`
|
||||
- Any image reference: `imageToVideo`
|
||||
- Any video reference: `videoToVideo`
|
||||
- Reference audio inputs do not change the resolved mode; they apply on top of whatever mode the image/video references select, and only work with providers that declare `maxInputAudios`
|
||||
|
||||
Mixed image and video references are not a stable shared capability surface.
|
||||
Prefer one reference type per request.
|
||||
|
||||
#### Fallback and typed options
|
||||
|
||||
Some capability checks are applied at the fallback layer rather than the
|
||||
tool boundary so that a request that exceeds the primary provider's limits
|
||||
can still run on a capable fallback:
|
||||
|
||||
- If the active candidate declares no `maxInputAudios` (or declares it as
|
||||
`0`), it is skipped when the request contains audio references, and the
|
||||
next candidate is tried.
|
||||
- If the active candidate's `maxDurationSeconds` is below the requested
|
||||
`durationSeconds` and the candidate does not declare a
|
||||
`supportedDurationSeconds` list, it is skipped.
|
||||
- If the request contains `providerOptions` and the active candidate
|
||||
explicitly declares a typed `providerOptions` schema, the candidate is
|
||||
skipped when the supplied keys are not in the schema or the value types do
|
||||
not match. Providers that have not yet declared a schema receive the
|
||||
options as-is (backward-compatible pass-through). A provider can
|
||||
explicitly opt out of all provider options by declaring an empty schema
|
||||
(`capabilities.providerOptions: {}`), which causes the same skip as a
|
||||
type mismatch.
|
||||
|
||||
The first skip reason in a request is logged at `warn` so operators see
|
||||
when their primary provider was passed over; subsequent skips log at
|
||||
`debug` to keep long fallback chains quiet. If every candidate is skipped,
|
||||
the aggregated error includes the skip reason for each.
|
||||
|
||||
## Actions
|
||||
|
||||
- **generate** (default) -- create a video from the given prompt and optional reference inputs.
|
||||
- **status** -- check the state of the in-flight video task for the current session without starting another generation.
|
||||
- **list** -- show available providers, models, and their capabilities.
|
||||
|
||||
## Model selection
|
||||
|
||||
When generating a video, OpenClaw resolves the model in this order:
|
||||
|
||||
1. **`model` tool parameter** -- if the agent specifies one in the call.
|
||||
2. **`videoGenerationModel.primary`** -- from config.
|
||||
3. **`videoGenerationModel.fallbacks`** -- tried in order.
|
||||
4. **Auto-detection** -- uses providers that have valid auth, starting with the current default provider, then remaining providers in alphabetical order.
|
||||
|
||||
If a provider fails, the next candidate is tried automatically. If all candidates fail, the error includes details from each attempt.
|
||||
|
||||
Set `agents.defaults.mediaGenerationAutoProviderFallback: false` if you want
|
||||
video generation to use only the explicit `model`, `primary`, and `fallbacks`
|
||||
entries.
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
videoGenerationModel: {
|
||||
primary: "google/veo-3.1-fast-generate-preview",
|
||||
fallbacks: ["runway/gen4.5", "qwen/wan2.6-t2v"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Provider notes
|
||||
|
||||
| Provider | Notes |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| Alibaba | Uses DashScope/Model Studio async endpoint. Reference images and videos must be remote `http(s)` URLs. |
|
||||
| BytePlus (1.0) | Provider id `byteplus`. Models: `seedance-1-0-pro-250528` (default), `seedance-1-0-pro-t2v-250528`, `seedance-1-0-pro-fast-251015`, `seedance-1-0-lite-t2v-250428`, `seedance-1-0-lite-i2v-250428`. T2V models (`*-t2v-*`) do not accept image inputs; I2V models and general `*-pro-*` models support a single reference image (first frame). Pass the image positionally or set `role: "first_frame"`. T2V model IDs are automatically switched to the corresponding I2V variant when an image is provided. Supported `providerOptions` keys: `seed` (number), `draft` (boolean, forces 480p), `camera_fixed` (boolean). |
|
||||
| BytePlus Seedance 1.5 | Requires the [`@openclaw/byteplus-modelark`](https://www.npmjs.com/package/@openclaw/byteplus-modelark) plugin. Provider id `byteplus-seedance15`. Model: `seedance-1-5-pro-251215`. Uses the unified `content[]` API. Supports at most 2 input images (first_frame + last_frame). All inputs must be remote `https://` URLs. Set `role: "first_frame"` / `"last_frame"` on each image, or pass images positionally. `aspectRatio: "adaptive"` auto-detects ratio from the input image. `audio: true` maps to `generate_audio`. `providerOptions.seed` (number) is forwarded. |
|
||||
| BytePlus Seedance 2.0 | Requires the [`@openclaw/byteplus-modelark`](https://www.npmjs.com/package/@openclaw/byteplus-modelark) plugin. Provider id `byteplus-seedance2`. Models: `dreamina-seedance-2-0-260128`, `dreamina-seedance-2-0-fast-260128`. Uses the unified `content[]` API. Supports up to 9 reference images, 3 reference videos, and 3 reference audios. All inputs must be remote `https://` URLs. Set `role` on each asset — supported values: `"first_frame"`, `"last_frame"`, `"reference_image"`, `"reference_video"`, `"reference_audio"`. `aspectRatio: "adaptive"` auto-detects ratio from the input image. `audio: true` maps to `generate_audio`. `providerOptions.seed` (number) is forwarded. |
|
||||
| ComfyUI | Workflow-driven local or cloud execution. Supports text-to-video and image-to-video through the configured graph. |
|
||||
| fal | Uses queue-backed flow for long-running jobs. Single image reference only. |
|
||||
| Google | Uses Gemini/Veo. Supports one image or one video reference. |
|
||||
| MiniMax | Single image reference only. |
|
||||
| OpenAI | Only `size` override is forwarded. Other style overrides (`aspectRatio`, `resolution`, `audio`, `watermark`) are ignored with a warning. |
|
||||
| Qwen | Same DashScope backend as Alibaba. Reference inputs must be remote `http(s)` URLs; local files are rejected upfront. |
|
||||
| Runway | Supports local files via data URIs. Video-to-video requires `runway/gen4_aleph`. Text-only runs expose `16:9` and `9:16` aspect ratios. |
|
||||
| Together | Single image reference only. |
|
||||
| Vydra | Uses `https://www.vydra.ai/api/v1` directly to avoid auth-dropping redirects. `veo3` is bundled as text-to-video only; `kling` requires a remote image URL. |
|
||||
| xAI | Supports text-to-video, image-to-video, and remote video edit/extend flows. |
|
||||
|
||||
## Provider capability modes
|
||||
|
||||
The shared video-generation contract now lets providers declare mode-specific
|
||||
capabilities instead of only flat aggregate limits. New provider
|
||||
implementations should prefer explicit mode blocks:
|
||||
|
||||
```typescript
|
||||
capabilities: {
|
||||
generate: {
|
||||
maxVideos: 1,
|
||||
maxDurationSeconds: 10,
|
||||
supportsResolution: true,
|
||||
},
|
||||
imageToVideo: {
|
||||
enabled: true,
|
||||
maxVideos: 1,
|
||||
maxInputImages: 1,
|
||||
maxDurationSeconds: 5,
|
||||
},
|
||||
videoToVideo: {
|
||||
enabled: true,
|
||||
maxVideos: 1,
|
||||
maxInputVideos: 1,
|
||||
maxDurationSeconds: 5,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Flat aggregate fields such as `maxInputImages` and `maxInputVideos` are not
|
||||
enough to advertise transform-mode support. Providers should declare
|
||||
`generate`, `imageToVideo`, and `videoToVideo` explicitly so live tests,
|
||||
contract tests, and the shared `video_generate` tool can validate mode support
|
||||
deterministically.
|
||||
|
||||
## Live tests
|
||||
|
||||
Opt-in live coverage for the shared bundled providers:
|
||||
|
||||
```bash
|
||||
OPENCLAW_LIVE_TEST=1 pnpm test:live -- extensions/video-generation-providers.live.test.ts
|
||||
```
|
||||
|
||||
Repo wrapper:
|
||||
|
||||
```bash
|
||||
pnpm test:live:media video
|
||||
```
|
||||
|
||||
This live file loads missing provider env vars from `~/.profile`, prefers
|
||||
live/env API keys ahead of stored auth profiles by default, and runs a
|
||||
release-safe smoke by default:
|
||||
|
||||
- `generate` for every non-FAL provider in the sweep
|
||||
- one-second lobster prompt
|
||||
- per-provider operation cap from `OPENCLAW_LIVE_VIDEO_GENERATION_TIMEOUT_MS`
|
||||
(`180000` by default)
|
||||
|
||||
FAL is opt-in because provider-side queue latency can dominate release time:
|
||||
|
||||
```bash
|
||||
pnpm test:live:media video --video-providers fal
|
||||
```
|
||||
|
||||
Set `OPENCLAW_LIVE_VIDEO_GENERATION_FULL_MODES=1` to also run declared transform
|
||||
modes the shared sweep can exercise safely with local media:
|
||||
|
||||
- `imageToVideo` when `capabilities.imageToVideo.enabled`
|
||||
- `videoToVideo` when `capabilities.videoToVideo.enabled` and the provider/model
|
||||
accepts buffer-backed local video input in the shared sweep
|
||||
|
||||
Today the shared `videoToVideo` live lane covers:
|
||||
|
||||
- `runway` only when you select `runway/gen4_aleph`
|
||||
|
||||
## Configuration
|
||||
|
||||
Set the default video generation model in your OpenClaw config:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
videoGenerationModel: {
|
||||
primary: "qwen/wan2.6-t2v",
|
||||
fallbacks: ["qwen/wan2.6-r2v-flash"],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Or via the CLI:
|
||||
|
||||
```bash
|
||||
openclaw config set agents.defaults.videoGenerationModel.primary "qwen/wan2.6-t2v"
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Tools Overview](/tools)
|
||||
- [Background Tasks](/automation/tasks) -- task tracking for async video generation
|
||||
- [Alibaba Model Studio](/providers/alibaba)
|
||||
- [BytePlus](/concepts/model-providers#byteplus-international)
|
||||
- [ComfyUI](/providers/comfy)
|
||||
- [fal](/providers/fal)
|
||||
- [Google (Gemini)](/providers/google)
|
||||
- [MiniMax](/providers/minimax)
|
||||
- [OpenAI](/providers/openai)
|
||||
- [Qwen](/providers/qwen)
|
||||
- [Runway](/providers/runway)
|
||||
- [Together AI](/providers/together)
|
||||
- [Vydra](/providers/vydra)
|
||||
- [xAI](/providers/xai)
|
||||
- [Configuration Reference](/gateway/configuration-reference#agent-defaults)
|
||||
- [Models](/concepts/models)
|
||||
159
openclaw/docs/tools/web-fetch.md
Normal file
159
openclaw/docs/tools/web-fetch.md
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
---
|
||||
summary: "web_fetch tool -- HTTP fetch with readable content extraction"
|
||||
read_when:
|
||||
- You want to fetch a URL and extract readable content
|
||||
- You need to configure web_fetch or its Firecrawl fallback
|
||||
- You want to understand web_fetch limits and caching
|
||||
title: "Web Fetch"
|
||||
sidebarTitle: "Web Fetch"
|
||||
---
|
||||
|
||||
# Web Fetch
|
||||
|
||||
The `web_fetch` tool does a plain HTTP GET and extracts readable content
|
||||
(HTML to markdown or text). It does **not** execute JavaScript.
|
||||
|
||||
For JS-heavy sites or login-protected pages, use the
|
||||
[Web Browser](/tools/browser) instead.
|
||||
|
||||
## Quick start
|
||||
|
||||
`web_fetch` is **enabled by default** -- no configuration needed. The agent can
|
||||
call it immediately:
|
||||
|
||||
```javascript
|
||||
await web_fetch({ url: "https://example.com/article" });
|
||||
```
|
||||
|
||||
## Tool parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| ------------- | -------- | ---------------------------------------- |
|
||||
| `url` | `string` | URL to fetch (required, http/https only) |
|
||||
| `extractMode` | `string` | `"markdown"` (default) or `"text"` |
|
||||
| `maxChars` | `number` | Truncate output to this many chars |
|
||||
|
||||
## How it works
|
||||
|
||||
<Steps>
|
||||
<Step title="Fetch">
|
||||
Sends an HTTP GET with a Chrome-like User-Agent and `Accept-Language`
|
||||
header. Blocks private/internal hostnames and re-checks redirects.
|
||||
</Step>
|
||||
<Step title="Extract">
|
||||
Runs Readability (main-content extraction) on the HTML response.
|
||||
</Step>
|
||||
<Step title="Fallback (optional)">
|
||||
If Readability fails and Firecrawl is configured, retries through the
|
||||
Firecrawl API with bot-circumvention mode.
|
||||
</Step>
|
||||
<Step title="Cache">
|
||||
Results are cached for 15 minutes (configurable) to reduce repeated
|
||||
fetches of the same URL.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
fetch: {
|
||||
enabled: true, // default: true
|
||||
provider: "firecrawl", // optional; omit for auto-detect
|
||||
maxChars: 50000, // max output chars
|
||||
maxCharsCap: 50000, // hard cap for maxChars param
|
||||
maxResponseBytes: 2000000, // max download size before truncation
|
||||
timeoutSeconds: 30,
|
||||
cacheTtlMinutes: 15,
|
||||
maxRedirects: 3,
|
||||
readability: true, // use Readability extraction
|
||||
userAgent: "Mozilla/5.0 ...", // override User-Agent
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Firecrawl fallback
|
||||
|
||||
If Readability extraction fails, `web_fetch` can fall back to
|
||||
[Firecrawl](/tools/firecrawl) for bot-circumvention and better extraction:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
fetch: {
|
||||
provider: "firecrawl", // optional; omit for auto-detect from available credentials
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
entries: {
|
||||
firecrawl: {
|
||||
enabled: true,
|
||||
config: {
|
||||
webFetch: {
|
||||
apiKey: "fc-...", // optional if FIRECRAWL_API_KEY is set
|
||||
baseUrl: "https://api.firecrawl.dev",
|
||||
onlyMainContent: true,
|
||||
maxAgeMs: 86400000, // cache duration (1 day)
|
||||
timeoutSeconds: 60,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
`plugins.entries.firecrawl.config.webFetch.apiKey` supports SecretRef objects.
|
||||
Legacy `tools.web.fetch.firecrawl.*` config is auto-migrated by `openclaw doctor --fix`.
|
||||
|
||||
<Note>
|
||||
If Firecrawl is enabled and its SecretRef is unresolved with no
|
||||
`FIRECRAWL_API_KEY` env fallback, gateway startup fails fast.
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
Firecrawl `baseUrl` overrides are locked down: they must use `https://` and
|
||||
the official Firecrawl host (`api.firecrawl.dev`).
|
||||
</Note>
|
||||
|
||||
Current runtime behavior:
|
||||
|
||||
- `tools.web.fetch.provider` selects the fetch fallback provider explicitly.
|
||||
- If `provider` is omitted, OpenClaw auto-detects the first ready web-fetch
|
||||
provider from available credentials. Today the bundled provider is Firecrawl.
|
||||
- If Readability is disabled, `web_fetch` skips straight to the selected
|
||||
provider fallback. If no provider is available, it fails closed.
|
||||
|
||||
## Limits and safety
|
||||
|
||||
- `maxChars` is clamped to `tools.web.fetch.maxCharsCap`
|
||||
- Response body is capped at `maxResponseBytes` before parsing; oversized
|
||||
responses are truncated with a warning
|
||||
- Private/internal hostnames are blocked
|
||||
- Redirects are checked and limited by `maxRedirects`
|
||||
- `web_fetch` is best-effort -- some sites need the [Web Browser](/tools/browser)
|
||||
|
||||
## Tool profiles
|
||||
|
||||
If you use tool profiles or allowlists, add `web_fetch` or `group:web`:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
allow: ["web_fetch"],
|
||||
// or: allow: ["group:web"] (includes web_fetch, web_search, and x_search)
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Search](/tools/web) -- search the web with multiple providers
|
||||
- [Web Browser](/tools/browser) -- full browser automation for JS-heavy sites
|
||||
- [Firecrawl](/tools/firecrawl) -- Firecrawl search and scrape tools
|
||||
417
openclaw/docs/tools/web.md
Normal file
417
openclaw/docs/tools/web.md
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
---
|
||||
title: "Web Search"
|
||||
sidebarTitle: "Web Search"
|
||||
summary: "web_search, x_search, and web_fetch -- search the web, search X posts, or fetch page content"
|
||||
read_when:
|
||||
- You want to enable or configure web_search
|
||||
- You want to enable or configure x_search
|
||||
- You need to choose a search provider
|
||||
- You want to understand auto-detection and provider fallback
|
||||
---
|
||||
|
||||
# Web Search
|
||||
|
||||
The `web_search` tool searches the web using your configured provider and
|
||||
returns results. Results are cached by query for 15 minutes (configurable).
|
||||
|
||||
OpenClaw also includes `x_search` for X (formerly Twitter) posts and
|
||||
`web_fetch` for lightweight URL fetching. In this phase, `web_fetch` stays
|
||||
local while `web_search` and `x_search` can use xAI Responses under the hood.
|
||||
|
||||
<Info>
|
||||
`web_search` is a lightweight HTTP tool, not browser automation. For
|
||||
JS-heavy sites or logins, use the [Web Browser](/tools/browser). For
|
||||
fetching a specific URL, use [Web Fetch](/tools/web-fetch).
|
||||
</Info>
|
||||
|
||||
## Quick start
|
||||
|
||||
<Steps>
|
||||
<Step title="Choose a provider">
|
||||
Pick a provider and complete any required setup. Some providers are
|
||||
key-free, while others use API keys. See the provider pages below for
|
||||
details.
|
||||
</Step>
|
||||
<Step title="Configure">
|
||||
```bash
|
||||
openclaw configure --section web
|
||||
```
|
||||
This stores the provider and any needed credential. You can also set an env
|
||||
var (for example `BRAVE_API_KEY`) and skip this step for API-backed
|
||||
providers.
|
||||
</Step>
|
||||
<Step title="Use it">
|
||||
The agent can now call `web_search`:
|
||||
|
||||
```javascript
|
||||
await web_search({ query: "OpenClaw plugin SDK" });
|
||||
```
|
||||
|
||||
For X posts, use:
|
||||
|
||||
```javascript
|
||||
await x_search({ query: "dinner recipes" });
|
||||
```
|
||||
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Choosing a provider
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Brave Search" icon="shield" href="/tools/brave-search">
|
||||
Structured results with snippets. Supports `llm-context` mode, country/language filters. Free tier available.
|
||||
</Card>
|
||||
<Card title="DuckDuckGo" icon="bird" href="/tools/duckduckgo-search">
|
||||
Key-free fallback. No API key needed. Unofficial HTML-based integration.
|
||||
</Card>
|
||||
<Card title="Exa" icon="brain" href="/tools/exa-search">
|
||||
Neural + keyword search with content extraction (highlights, text, summaries).
|
||||
</Card>
|
||||
<Card title="Firecrawl" icon="flame" href="/tools/firecrawl">
|
||||
Structured results. Best paired with `firecrawl_search` and `firecrawl_scrape` for deep extraction.
|
||||
</Card>
|
||||
<Card title="Gemini" icon="sparkles" href="/tools/gemini-search">
|
||||
AI-synthesized answers with citations via Google Search grounding.
|
||||
</Card>
|
||||
<Card title="Grok" icon="zap" href="/tools/grok-search">
|
||||
AI-synthesized answers with citations via xAI web grounding.
|
||||
</Card>
|
||||
<Card title="Kimi" icon="moon" href="/tools/kimi-search">
|
||||
AI-synthesized answers with citations via Moonshot web search.
|
||||
</Card>
|
||||
<Card title="MiniMax Search" icon="globe" href="/tools/minimax-search">
|
||||
Structured results via the MiniMax Coding Plan search API.
|
||||
</Card>
|
||||
<Card title="Ollama Web Search" icon="globe" href="/tools/ollama-search">
|
||||
Key-free search via your configured Ollama host. Requires `ollama signin`.
|
||||
</Card>
|
||||
<Card title="Perplexity" icon="search" href="/tools/perplexity-search">
|
||||
Structured results with content extraction controls and domain filtering.
|
||||
</Card>
|
||||
<Card title="SearXNG" icon="server" href="/tools/searxng-search">
|
||||
Self-hosted meta-search. No API key needed. Aggregates Google, Bing, DuckDuckGo, and more.
|
||||
</Card>
|
||||
<Card title="Tavily" icon="globe" href="/tools/tavily">
|
||||
Structured results with search depth, topic filtering, and `tavily_extract` for URL extraction.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
### Provider comparison
|
||||
|
||||
| Provider | Result style | Filters | API key |
|
||||
| ----------------------------------------- | -------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- |
|
||||
| [Brave](/tools/brave-search) | Structured snippets | Country, language, time, `llm-context` mode | `BRAVE_API_KEY` |
|
||||
| [DuckDuckGo](/tools/duckduckgo-search) | Structured snippets | -- | None (key-free) |
|
||||
| [Exa](/tools/exa-search) | Structured + extracted | Neural/keyword mode, date, content extraction | `EXA_API_KEY` |
|
||||
| [Firecrawl](/tools/firecrawl) | Structured snippets | Via `firecrawl_search` tool | `FIRECRAWL_API_KEY` |
|
||||
| [Gemini](/tools/gemini-search) | AI-synthesized + citations | -- | `GEMINI_API_KEY` |
|
||||
| [Grok](/tools/grok-search) | AI-synthesized + citations | -- | `XAI_API_KEY` |
|
||||
| [Kimi](/tools/kimi-search) | AI-synthesized + citations | -- | `KIMI_API_KEY` / `MOONSHOT_API_KEY` |
|
||||
| [MiniMax Search](/tools/minimax-search) | Structured snippets | Region (`global` / `cn`) | `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` |
|
||||
| [Ollama Web Search](/tools/ollama-search) | Structured snippets | -- | None by default; `ollama signin` required, can reuse Ollama provider bearer auth |
|
||||
| [Perplexity](/tools/perplexity-search) | Structured snippets | Country, language, time, domains, content limits | `PERPLEXITY_API_KEY` / `OPENROUTER_API_KEY` |
|
||||
| [SearXNG](/tools/searxng-search) | Structured snippets | Categories, language | None (self-hosted) |
|
||||
| [Tavily](/tools/tavily) | Structured snippets | Via `tavily_search` tool | `TAVILY_API_KEY` |
|
||||
|
||||
## Auto-detection
|
||||
|
||||
## Native Codex web search
|
||||
|
||||
Codex-capable models can optionally use the provider-native Responses `web_search` tool instead of OpenClaw's managed `web_search` function.
|
||||
|
||||
- Configure it under `tools.web.search.openaiCodex`
|
||||
- It only activates for Codex-capable models (`openai-codex/*` or providers using `api: "openai-codex-responses"`)
|
||||
- Managed `web_search` still applies to non-Codex models
|
||||
- `mode: "cached"` is the default and recommended setting
|
||||
- `tools.web.search.enabled: false` disables both managed and native search
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
enabled: true,
|
||||
openaiCodex: {
|
||||
enabled: true,
|
||||
mode: "cached",
|
||||
allowedDomains: ["example.com"],
|
||||
contextSize: "high",
|
||||
userLocation: {
|
||||
country: "US",
|
||||
city: "New York",
|
||||
timezone: "America/New_York",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
If native Codex search is enabled but the current model is not Codex-capable, OpenClaw keeps the normal managed `web_search` behavior.
|
||||
|
||||
## Setting up web search
|
||||
|
||||
Provider lists in docs and setup flows are alphabetical. Auto-detection keeps a
|
||||
separate precedence order.
|
||||
|
||||
If no `provider` is set, OpenClaw checks providers in this order and uses the
|
||||
first one that is ready:
|
||||
|
||||
API-backed providers first:
|
||||
|
||||
1. **Brave** -- `BRAVE_API_KEY` or `plugins.entries.brave.config.webSearch.apiKey` (order 10)
|
||||
2. **MiniMax Search** -- `MINIMAX_CODE_PLAN_KEY` / `MINIMAX_CODING_API_KEY` or `plugins.entries.minimax.config.webSearch.apiKey` (order 15)
|
||||
3. **Gemini** -- `GEMINI_API_KEY` or `plugins.entries.google.config.webSearch.apiKey` (order 20)
|
||||
4. **Grok** -- `XAI_API_KEY` or `plugins.entries.xai.config.webSearch.apiKey` (order 30)
|
||||
5. **Kimi** -- `KIMI_API_KEY` / `MOONSHOT_API_KEY` or `plugins.entries.moonshot.config.webSearch.apiKey` (order 40)
|
||||
6. **Perplexity** -- `PERPLEXITY_API_KEY` / `OPENROUTER_API_KEY` or `plugins.entries.perplexity.config.webSearch.apiKey` (order 50)
|
||||
7. **Firecrawl** -- `FIRECRAWL_API_KEY` or `plugins.entries.firecrawl.config.webSearch.apiKey` (order 60)
|
||||
8. **Exa** -- `EXA_API_KEY` or `plugins.entries.exa.config.webSearch.apiKey` (order 65)
|
||||
9. **Tavily** -- `TAVILY_API_KEY` or `plugins.entries.tavily.config.webSearch.apiKey` (order 70)
|
||||
|
||||
Key-free fallbacks after that:
|
||||
|
||||
10. **DuckDuckGo** -- key-free HTML fallback with no account or API key (order 100)
|
||||
11. **Ollama Web Search** -- key-free fallback via your configured Ollama host; requires Ollama to be reachable and signed in with `ollama signin` and can reuse Ollama provider bearer auth if the host needs it (order 110)
|
||||
12. **SearXNG** -- `SEARXNG_BASE_URL` or `plugins.entries.searxng.config.webSearch.baseUrl` (order 200)
|
||||
|
||||
If no provider is detected, it falls back to Brave (you will get a missing-key
|
||||
error prompting you to configure one).
|
||||
|
||||
<Note>
|
||||
All provider key fields support SecretRef objects. In auto-detect mode,
|
||||
OpenClaw resolves only the selected provider key -- non-selected SecretRefs
|
||||
stay inactive.
|
||||
</Note>
|
||||
|
||||
## Config
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
web: {
|
||||
search: {
|
||||
enabled: true, // default: true
|
||||
provider: "brave", // or omit for auto-detection
|
||||
maxResults: 5,
|
||||
timeoutSeconds: 30,
|
||||
cacheTtlMinutes: 15,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Provider-specific config (API keys, base URLs, modes) lives under
|
||||
`plugins.entries.<plugin>.config.webSearch.*`. See the provider pages for
|
||||
examples.
|
||||
|
||||
`web_fetch` fallback provider selection is separate:
|
||||
|
||||
- choose it with `tools.web.fetch.provider`
|
||||
- or omit that field and let OpenClaw auto-detect the first ready web-fetch
|
||||
provider from available credentials
|
||||
- today the bundled web-fetch provider is Firecrawl, configured under
|
||||
`plugins.entries.firecrawl.config.webFetch.*`
|
||||
|
||||
When you choose **Kimi** during `openclaw onboard` or
|
||||
`openclaw configure --section web`, OpenClaw can also ask for:
|
||||
|
||||
- the Moonshot API region (`https://api.moonshot.ai/v1` or `https://api.moonshot.cn/v1`)
|
||||
- the default Kimi web-search model (defaults to `kimi-k2.5`)
|
||||
|
||||
For `x_search`, configure `plugins.entries.xai.config.xSearch.*`. It uses the
|
||||
same `XAI_API_KEY` fallback as Grok web search.
|
||||
Legacy `tools.web.x_search.*` config is auto-migrated by `openclaw doctor --fix`.
|
||||
When you choose Grok during `openclaw onboard` or `openclaw configure --section web`,
|
||||
OpenClaw can also offer optional `x_search` setup with the same key.
|
||||
This is a separate follow-up step inside the Grok path, not a separate top-level
|
||||
web-search provider choice. If you pick another provider, OpenClaw does not
|
||||
show the `x_search` prompt.
|
||||
|
||||
### Storing API keys
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Config file">
|
||||
Run `openclaw configure --section web` or set the key directly:
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
brave: {
|
||||
config: {
|
||||
webSearch: {
|
||||
apiKey: "YOUR_KEY", // pragma: allowlist secret
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab title="Environment variable">
|
||||
Set the provider env var in the Gateway process environment:
|
||||
|
||||
```bash
|
||||
export BRAVE_API_KEY="YOUR_KEY"
|
||||
```
|
||||
|
||||
For a gateway install, put it in `~/.openclaw/.env`.
|
||||
See [Env vars](/help/faq#env-vars-and-env-loading).
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Tool parameters
|
||||
|
||||
| Parameter | Description |
|
||||
| --------------------- | ----------------------------------------------------- |
|
||||
| `query` | Search query (required) |
|
||||
| `count` | Results to return (1-10, default: 5) |
|
||||
| `country` | 2-letter ISO country code (e.g. "US", "DE") |
|
||||
| `language` | ISO 639-1 language code (e.g. "en", "de") |
|
||||
| `search_lang` | Search-language code (Brave only) |
|
||||
| `freshness` | Time filter: `day`, `week`, `month`, or `year` |
|
||||
| `date_after` | Results after this date (YYYY-MM-DD) |
|
||||
| `date_before` | Results before this date (YYYY-MM-DD) |
|
||||
| `ui_lang` | UI language code (Brave only) |
|
||||
| `domain_filter` | Domain allowlist/denylist array (Perplexity only) |
|
||||
| `max_tokens` | Total content budget, default 25000 (Perplexity only) |
|
||||
| `max_tokens_per_page` | Per-page token limit, default 2048 (Perplexity only) |
|
||||
|
||||
<Warning>
|
||||
Not all parameters work with all providers. Brave `llm-context` mode
|
||||
rejects `ui_lang`, `freshness`, `date_after`, and `date_before`.
|
||||
Gemini, Grok, and Kimi return one synthesized answer with citations. They
|
||||
accept `count` for shared-tool compatibility, but it does not change the
|
||||
grounded answer shape.
|
||||
Perplexity behaves the same way when you use the Sonar/OpenRouter
|
||||
compatibility path (`plugins.entries.perplexity.config.webSearch.baseUrl` /
|
||||
`model` or `OPENROUTER_API_KEY`).
|
||||
SearXNG accepts `http://` only for trusted private-network or loopback hosts;
|
||||
public SearXNG endpoints must use `https://`.
|
||||
Firecrawl and Tavily only support `query` and `count` through `web_search`
|
||||
-- use their dedicated tools for advanced options.
|
||||
</Warning>
|
||||
|
||||
## x_search
|
||||
|
||||
`x_search` queries X (formerly Twitter) posts using xAI and returns
|
||||
AI-synthesized answers with citations. It accepts natural-language queries and
|
||||
optional structured filters. OpenClaw only enables the built-in xAI `x_search`
|
||||
tool on the request that serves this tool call.
|
||||
|
||||
<Note>
|
||||
xAI documents `x_search` as supporting keyword search, semantic search, user
|
||||
search, and thread fetch. For per-post engagement stats such as reposts,
|
||||
replies, bookmarks, or views, prefer a targeted lookup for the exact post URL
|
||||
or status ID. Broad keyword searches may find the right post but return less
|
||||
complete per-post metadata. A good pattern is: locate the post first, then
|
||||
run a second `x_search` query focused on that exact post.
|
||||
</Note>
|
||||
|
||||
### x_search config
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
entries: {
|
||||
xai: {
|
||||
config: {
|
||||
xSearch: {
|
||||
enabled: true,
|
||||
model: "grok-4-1-fast-non-reasoning",
|
||||
inlineCitations: false,
|
||||
maxTurns: 2,
|
||||
timeoutSeconds: 30,
|
||||
cacheTtlMinutes: 15,
|
||||
},
|
||||
webSearch: {
|
||||
apiKey: "xai-...", // optional if XAI_API_KEY is set
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### x_search parameters
|
||||
|
||||
| Parameter | Description |
|
||||
| ---------------------------- | ------------------------------------------------------ |
|
||||
| `query` | Search query (required) |
|
||||
| `allowed_x_handles` | Restrict results to specific X handles |
|
||||
| `excluded_x_handles` | Exclude specific X handles |
|
||||
| `from_date` | Only include posts on or after this date (YYYY-MM-DD) |
|
||||
| `to_date` | Only include posts on or before this date (YYYY-MM-DD) |
|
||||
| `enable_image_understanding` | Let xAI inspect images attached to matching posts |
|
||||
| `enable_video_understanding` | Let xAI inspect videos attached to matching posts |
|
||||
|
||||
### x_search example
|
||||
|
||||
```javascript
|
||||
await x_search({
|
||||
query: "dinner recipes",
|
||||
allowed_x_handles: ["nytfood"],
|
||||
from_date: "2026-03-01",
|
||||
});
|
||||
```
|
||||
|
||||
```javascript
|
||||
// Per-post stats: use the exact status URL or status ID when possible
|
||||
await x_search({
|
||||
query: "https://x.com/huntharo/status/1905678901234567890",
|
||||
});
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
```javascript
|
||||
// Basic search
|
||||
await web_search({ query: "OpenClaw plugin SDK" });
|
||||
|
||||
// German-specific search
|
||||
await web_search({ query: "TV online schauen", country: "DE", language: "de" });
|
||||
|
||||
// Recent results (past week)
|
||||
await web_search({ query: "AI developments", freshness: "week" });
|
||||
|
||||
// Date range
|
||||
await web_search({
|
||||
query: "climate research",
|
||||
date_after: "2024-01-01",
|
||||
date_before: "2024-06-30",
|
||||
});
|
||||
|
||||
// Domain filtering (Perplexity only)
|
||||
await web_search({
|
||||
query: "product reviews",
|
||||
domain_filter: ["-reddit.com", "-pinterest.com"],
|
||||
});
|
||||
```
|
||||
|
||||
## Tool profiles
|
||||
|
||||
If you use tool profiles or allowlists, add `web_search`, `x_search`, or `group:web`:
|
||||
|
||||
```json5
|
||||
{
|
||||
tools: {
|
||||
allow: ["web_search", "x_search"],
|
||||
// or: allow: ["group:web"] (includes web_search, x_search, and web_fetch)
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Fetch](/tools/web-fetch) -- fetch a URL and extract readable content
|
||||
- [Web Browser](/tools/browser) -- full browser automation for JS-heavy sites
|
||||
- [Grok Search](/tools/grok-search) -- Grok as the `web_search` provider
|
||||
- [Ollama Web Search](/tools/ollama-search) -- key-free web search through your Ollama host
|
||||
Loading…
Add table
Add a link
Reference in a new issue