From 46b9a3e12d91882669c1eb916e806276c4457d19 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 19 Jul 2026 05:33:00 -0700 Subject: [PATCH] docs: Swarm user guide (#110325) (#111384) --- docs/.i18n/glossary.zh-CN.json | 4 + docs/docs.json | 1 + docs/docs_map.md | 17 ++ docs/plan/swarms.md | 6 +- docs/tools/code-mode.md | 9 + docs/tools/index.md | 30 +-- docs/tools/swarm.md | 385 +++++++++++++++++++++++++++++++++ 7 files changed, 434 insertions(+), 18 deletions(-) create mode 100644 docs/tools/swarm.md diff --git a/docs/.i18n/glossary.zh-CN.json b/docs/.i18n/glossary.zh-CN.json index b77178a1fb2..5252dadb3ff 100644 --- a/docs/.i18n/glossary.zh-CN.json +++ b/docs/.i18n/glossary.zh-CN.json @@ -155,6 +155,10 @@ "source": "Code mode", "target": "代码模式" }, + { + "source": "Swarm", + "target": "Swarm" + }, { "source": "Codex harness", "target": "Codex harness" diff --git a/docs/docs.json b/docs/docs.json index 4b60348984a..43d1203c906 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1427,6 +1427,7 @@ "tools/goal", "tools/steer", "tools/subagents", + "tools/swarm", "tools/acp-agents", "tools/acp-agents-setup", "tools/multi-agent-sandbox-tools" diff --git a/docs/docs_map.md b/docs/docs_map.md index 040568906e2..136d5594c8c 100644 --- a/docs/docs_map.md +++ b/docs/docs_map.md @@ -9770,6 +9770,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H3: Enable Code Mode - H3: What the model does - H3: Verify the active surface + - H2: Use Swarm for agent fan-out - H2: Technical tour - H2: Runtime status - H2: Scope @@ -10425,6 +10426,22 @@ Do not edit it by hand; run `pnpm docs:map:gen`. - H2: Limitations - H2: Related +## tools/swarm.md + +- Route: /tools/swarm +- Headings: + - H2: Enable Swarm + - H2: Requirements + - H2: Write a Swarm script + - H3: Fan out in parallel with structured results + - H3: Loop on a decision gate + - H3: Process the first child that finishes + - H2: How collector children behave + - H2: Observe a Swarm + - H2: Use Swarm from other harnesses + - H2: Limits and roadmap + - H2: Related + ## tools/tavily.md - Route: /tools/tavily diff --git a/docs/plan/swarms.md b/docs/plan/swarms.md index af3e14a5f28..6a50d439236 100644 --- a/docs/plan/swarms.md +++ b/docs/plan/swarms.md @@ -1,9 +1,7 @@ # Swarms — agent fan-out and orchestration in code mode -Status: implementation spec (v1 in progress). This document is the frozen build -spec. It will be rewritten as user-facing docs (`docs/tools/swarm.md`) once the -feature lands and is tested. Feature-gated behind `tools.swarm` (default off); -`main` remains shippable at every point. +Status: Shipped — superseded by `docs/tools/swarm.md`. This document remains as +the implementation design record. ## 1. What and why diff --git a/docs/tools/code-mode.md b/docs/tools/code-mode.md index acb42aead2c..84ed4cc3049 100644 --- a/docs/tools/code-mode.md +++ b/docs/tools/code-mode.md @@ -166,6 +166,14 @@ With code mode active, the logged model-facing tool names should be `exec` and `wait`. For the full redacted provider payload, add `OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted` for a short debugging session. +## Use Swarm for agent fan-out + +[Swarm](/tools/swarm) adds `agents.run()`, `phase()`, and `log()` guest globals +for orchestrating concurrent sub-agents from Code Mode scripts. Enable both +`tools.codeMode` and `tools.swarm`, then use normal JavaScript control flow for +fan-out, decision gates, and structured collection. Swarm is a separate opt-in +gate; enabling Code Mode alone does not expose the `agents.*` API. + ## Technical tour The rest of this page covers the runtime contract and implementation details, @@ -1153,6 +1161,7 @@ Docs-only changes to this page should still run `pnpm check:docs`. ## Related +- [Swarm](/tools/swarm) for fan-out agent orchestration from Code Mode scripts - [Tool Search](/tools/tool-search) - [Agent runtimes](/concepts/agent-runtimes) - [Exec tool](/tools/exec) diff --git a/docs/tools/index.md b/docs/tools/index.md index d9e85a70fc7..d2b42061919 100644 --- a/docs/tools/index.md +++ b/docs/tools/index.md @@ -30,6 +30,7 @@ only when the agent should see fewer tools or needs explicit host access. | Add a new integration or runtime surface | [Plugins](#extend-capabilities) | [Plugins](/tools/plugin) and [Build plugins](/plugins/building-plugins) | | Run work later or in the background | [Automation](/automation) | [Automation overview](/automation) | | Coordinate multiple agents or harnesses | [Sub-agents](/tools/subagents) | [ACP agents](/tools/acp-agents) and [Agent send](/tools/agent-send) | +| Orchestrate concurrent agents from code | [Swarm](/tools/swarm) | [Code Mode](/tools/code-mode) and [Sub-agents](/tools/subagents) | | Search a large OpenClaw tool catalog | [Tool Search](/tools/tool-search) | [Tool Search](/tools/tool-search) | | Combine several tools in one compact program | [Code Mode](/tools/code-mode) | [Code Mode](/tools/code-mode) | @@ -81,20 +82,20 @@ The table lists representative tools so you can recognize the surface. It is not the full policy reference. For exact groups, defaults, and allow/deny semantics, use [Tools and custom providers](/gateway/config-tools). -| Category | Use when the agent needs to... | Representative tools | Read next | -| ----------------------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | -| Runtime | Run commands, manage processes, or use provider-backed Python analysis | `exec`, `process`, `terminal`, `code_execution` | [Exec](/tools/exec), [Control UI terminal](/web/control-ui#operator-terminal), [Code execution](/tools/code-execution) | -| Files | Read and change workspace files | `read`, `write`, `edit`, `apply_patch` | [Apply patch](/tools/apply-patch) | -| Human input | Pause for a structured decision owned by the user | `ask_user` | [Ask user](/tools/ask-user) | -| Web | Search the web, search X posts, or fetch readable page content | `web_search`, `x_search`, `web_fetch` | [Web tools](/tools/web), [Web fetch](/tools/web-fetch) | -| Browser | Operate a browser session | `browser` | [Browser](/tools/browser) | -| Operator UI | Arrange connected Control UI panes, panels, and navigation | `screen` | [Screen](/tools/screen) | -| Messaging and channels | Send replies or channel actions | `message` | [Agent send](/tools/agent-send) | -| Sessions and agents | Inspect sessions, delegate work, steer another run, or report status | `sessions_*`, `subagents`, `agents_list`, `session_status`, `get_goal`, `create_goal`, `update_goal` | [Goal](/tools/goal), [Sub-agents](/tools/subagents), [Session tool](/concepts/session-tool) | -| Automation | Schedule work or respond to background events | `cron`, `heartbeat_respond` | [Automation](/automation) | -| Gateway and nodes | Inspect Gateway state or paired target devices | `gateway`, `nodes` | [Gateway configuration](/gateway/configuration), [Nodes](/nodes) | -| Media | Analyze, generate, or speak media | `image`, `image_generate`, `music_generate`, `video_generate`, `tts` | [Media overview](/tools/media-overview) | -| Large OpenClaw catalogs | Search, call, and combine many eligible tools without sending every schema to the model | `exec`, `wait`, `tool_search_code`, `tool_search`, `tool_describe` | [Code Mode](/tools/code-mode), [Tool Search](/tools/tool-search) | +| Category | Use when the agent needs to... | Representative tools | Read next | +| ----------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | +| Runtime | Run commands, manage processes, or use provider-backed Python analysis | `exec`, `process`, `terminal`, `code_execution` | [Exec](/tools/exec), [Control UI terminal](/web/control-ui#operator-terminal), [Code execution](/tools/code-execution) | +| Files | Read and change workspace files | `read`, `write`, `edit`, `apply_patch` | [Apply patch](/tools/apply-patch) | +| Human input | Pause for a structured decision owned by the user | `ask_user` | [Ask user](/tools/ask-user) | +| Web | Search the web, search X posts, or fetch readable page content | `web_search`, `x_search`, `web_fetch` | [Web tools](/tools/web), [Web fetch](/tools/web-fetch) | +| Browser | Operate a browser session | `browser` | [Browser](/tools/browser) | +| Operator UI | Arrange connected Control UI panes, panels, and navigation | `screen` | [Screen](/tools/screen) | +| Messaging and channels | Send replies or channel actions | `message` | [Agent send](/tools/agent-send) | +| Sessions and agents | Inspect sessions, delegate work, orchestrate collectors, steer another run, or report status | `sessions_*`, `agents_wait`, `subagents`, `agents_list`, `session_status`, `get_goal`, `create_goal`, `update_goal` | [Goal](/tools/goal), [Swarm](/tools/swarm), [Sub-agents](/tools/subagents), [Session tool](/concepts/session-tool) | +| Automation | Schedule work or respond to background events | `cron`, `heartbeat_respond` | [Automation](/automation) | +| Gateway and nodes | Inspect Gateway state or paired target devices | `gateway`, `nodes` | [Gateway configuration](/gateway/configuration), [Nodes](/nodes) | +| Media | Analyze, generate, or speak media | `image`, `image_generate`, `music_generate`, `video_generate`, `tts` | [Media overview](/tools/media-overview) | +| Large OpenClaw catalogs | Search, call, and combine many eligible tools without sending every schema to the model | `exec`, `wait`, `tool_search_code`, `tool_search`, `tool_describe` | [Code Mode](/tools/code-mode), [Tool Search](/tools/tool-search) | Code Mode and Tool Search are experimental OpenClaw agent surfaces. Codex @@ -193,3 +194,4 @@ the current turn: discovery - [Code Mode](/tools/code-mode) for compact JavaScript or TypeScript workflows over a hidden OpenClaw tool catalog +- [Swarm](/tools/swarm) for structured fan-out and collection from Code Mode diff --git a/docs/tools/swarm.md b/docs/tools/swarm.md new file mode 100644 index 00000000000..92c2265f247 --- /dev/null +++ b/docs/tools/swarm.md @@ -0,0 +1,385 @@ +--- +summary: "Orchestrate concurrent sub-agents from Code Mode scripts with structured results, bounded fan-out, and live progress" +title: "Swarm" +sidebarTitle: "Swarm" +read_when: + - You want a Code Mode script to fan out work across several agents + - You need structured child results, decision gates, or first-completion pipelines + - You are enabling or tuning tools.swarm limits + - You want to observe collector children in the session dashboard +--- + +Swarm is an experimental, opt-in way to orchestrate many sub-agents from a +[Code Mode](/tools/code-mode) script. Use normal JavaScript or TypeScript +control flow such as `Promise.all`, `while`, and `if` to fan out work, collect +results, and make decisions. + +There is no graph DSL and no separate workflow format. The program is the +orchestration. Swarm adds awaitable collector children, structured results, +bounded concurrency, and progress reporting to that program. + +## Enable Swarm + +The recommended path is **Settings → Labs → Swarm** in the Control UI. The +toggle takes effect immediately and writes `tools.swarm.enabled` to your +configuration. + +You can also enable Swarm directly in `openclaw.json`: + +```json5 +{ + tools: { + swarm: { + enabled: true, + maxConcurrent: 8, + maxChildrenPerGroup: 50, + maxTotalPerGroup: 200, + waitTimeoutSecondsMax: 600, + defaultAgentId: "", + }, + }, +} +``` + +Boolean shorthand enables or disables the feature with all other values at +their defaults: + +```json5 +{ + tools: { + swarm: true, + }, +} +``` + +| Field | Default | Description | +| ----------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `enabled` | `false` | Exposes collector-mode spawn options, `agents_wait`, and the Code Mode `agents.*` guest API. | +| `maxConcurrent` | `8` | Maximum collector children running concurrently in one swarm group. Additional accepted children queue in FIFO order. | +| `maxChildrenPerGroup` | `50` | Maximum live collector children in one group. | +| `maxTotalPerGroup` | `200` | Maximum collector children a group may spawn over its lifetime. This is the runaway-spawn backstop. | +| `waitTimeoutSecondsMax` | `600` | Maximum timeout accepted by one `agents_wait` call. The call default is 30 seconds. | +| `defaultAgentId` | `""` | Target agent used when a spawn omits `agentId`. An empty value uses the requesting agent. Existing sub-agent allowlists apply. | + +Numeric values must be positive integers. OpenClaw bounds +`maxConcurrent` to `1`–`1000`, `maxChildrenPerGroup` to `1`–`10000`, +`maxTotalPerGroup` to `1`–`100000`, and `waitTimeoutSecondsMax` to +`1`–`86400`. + +You can override Swarm for one configured agent with +`agents.list[].tools.swarm`. The per-agent object merges over the top-level +`tools.swarm` object. + +## Requirements + +The `agents.run`, `phase`, and `log` guest globals require both Swarm and +OpenClaw Code Mode: + +```json5 +{ + tools: { + codeMode: true, + swarm: true, + }, +} +``` + +Code Mode must also have effective access to `sessions_spawn`. Tool profiles, +allow/deny policy, provider rules, and sandbox policy can remove that tool. +See [Code Mode activation](/tools/code-mode#activation) and +[Sub-agents](/tools/subagents) if a script reports that `sessions_spawn` is +unavailable. + +`defaultAgentId` and per-run `agentId` values must name a configured target +permitted by the requester's `subagents.allowAgents` policy. OpenClaw rejects +an unknown or disallowed target instead of falling back to another agent. + +## Write a Swarm script + +When Swarm is enabled, Code Mode exposes this guest API: + +```typescript +type AgentRunOptions = { + label?: string; + model?: string; + thinking?: string; + fastMode?: boolean | "auto"; + agentId?: string; + schema?: Record; + phase?: string; +}; + +agents.run(prompt: string, options?: AgentRunOptions & { schema?: undefined }): Promise; +agents.run(prompt: string, options: AgentRunOptions & { schema: Record }): Promise; +phase(title: string): void; +log(message: string): void; +``` + +Without `schema`, `agents.run()` resolves to the child's final text. With a +JSON Schema, it resolves to the value submitted through the child's +`structured_output` tool. A failed, killed, timed-out, or schema-invalid child +rejects the promise with a `SwarmAgentError`. Read the exact generated +declarations and short orchestration idioms from `API.read("agents.d.ts")` +inside Code Mode. + +Use `label` for a recognizable child name in the dashboard and sidebar. Use +`phase` in the options to publish a phase immediately before that child +starts, or call `phase()` when several children belong to the same stage. +`log()` publishes a short progress note. Progress calls are fire-and-forget; +they do not delay the script if the UI is unavailable. + +### Fan out in parallel with structured results + +This example launches one researcher per topic, waits for all of them, then +asks a final child to synthesize their structured reports: + +```javascript +const reportSchema = { + type: "object", + properties: { + finding: { type: "string" }, + evidence: { type: "array", items: { type: "string" } }, + confidence: { type: "number" }, + }, + required: ["finding", "evidence", "confidence"], + additionalProperties: false, +}; + +const topics = ["authentication", "storage", "recovery"]; +phase("Independent review"); + +const reports = await Promise.all( + topics.map((topic) => + agents.run(`Review the ${topic} path. Return one finding with evidence.`, { + label: `review-${topic}`, + thinking: "high", + fastMode: "auto", + schema: reportSchema, + }), + ), +); + +phase("Synthesis"); +log(`Collected ${reports.length} independent reports.`); + +return await agents.run( + `Reconcile these reports and explain disagreements:\n${JSON.stringify(reports)}`, + { label: "synthesis" }, +); +``` + +`Promise.all` is the fan-out and fan-in boundary. OpenClaw starts up to +`maxConcurrent` children for the group and queues the rest in submission +order. + +### Loop on a decision gate + +Use a bounded `while` loop when each pass decides whether another pass is +needed: + +```javascript +const gateSchema = { + type: "object", + properties: { + ready: { type: "boolean" }, + reason: { type: "string" }, + nextAction: { type: "string" }, + }, + required: ["ready", "reason", "nextAction"], + additionalProperties: false, +}; + +let pass = 0; +let decision = { ready: false, reason: "Not checked", nextAction: "Review" }; + +while (!decision.ready && pass < 4) { + pass += 1; + phase(`Decision pass ${pass}`); + decision = await agents.run( + `Check whether the release evidence is complete. Previous decision: ${JSON.stringify(decision)}`, + { + label: `release-gate-${pass}`, + schema: gateSchema, + }, + ); + log(decision.reason); +} + +if (!decision.ready) { + throw new Error(`Gate still closed after ${pass} passes: ${decision.nextAction}`); +} + +return decision; +``` + +Always bound decision loops. `maxTotalPerGroup` is the final safety backstop, +not a substitute for a clear stopping condition. + +### Process the first child that finishes + +`agents.run()` returns an ordinary promise, so `Promise.race` can react to the +first Code Mode child. For harnesses that call the lower-level tools, +`agents_wait` provides the same first-completion boundary: it returns as soon +as at least one requested run completes, or when the bounded timeout expires. +See [Use Swarm from other harnesses](#use-swarm-from-other-harnesses) for the +complete drain loop. + +## How collector children behave + +Collector children are ordinary isolated sub-agent sessions with a different +completion path. They write a durable collector result for the parent to +await instead of announcing or steering a reply back into the parent session. + +The target agent resolves in this order: + +1. `agentId` on the spawn or `agents.run()` call. +2. `tools.swarm.defaultAgentId`. +3. The requesting agent. + +A dedicated, lean worker agent is useful when swarm children need a smaller +tool surface, cheaper model, or tighter sandbox policy. OpenClaw does not ship +a built-in `worker` agent id; configure one before naming it as the default. + +Collector approvals fail closed. A child never opens an operator approval +prompt. A tool action that would require approval is denied, and the child can +report that denial in its result so the script can decide what to do next. + +For structured output, OpenClaw adds a synthetic `structured_output` tool to +the child and validates its payload against the supplied JSON Schema. An +invalid or missing payload gets one corrective nudge. If the retry still does +not validate, the collector completion keeps the child's raw text, leaves +`structured` unset, and includes `schemaError`. The low-level `agents_wait` +result exposes those fields for explicit recovery logic. + +Swarm enforces all three group caps before starting more work. Children above +`maxConcurrent` queue FIFO. A spawn that exceeds `maxChildrenPerGroup` or +`maxTotalPerGroup` is rejected with the relevant config key in the error. + +## Observe a Swarm + +Open the parent session's dashboard in the Control UI while a swarm is active. +The Swarm widget renders each active collector group as one dot per child with +queued, running, done, or failed state. Labels appear in dot tooltips, so short +stable labels make larger swarms easier to read. + +The session sidebar keeps the normal parent/child tree. Expand the parent row +to inspect a collector child or open its transcript without losing the swarm +hierarchy. + +Collector results remain waitable until their group is archived. After every +member reaches its retention deadline, OpenClaw archives the group's children +as a batch so completed swarms do not remain in the live session tree. + +## Use Swarm from other harnesses + +You can use Swarm without OpenClaw Code Mode. Its core tools are +harness-independent: start collector children with +`sessions_spawn({ collect: true })` and drain them with bounded `agents_wait` +calls. + +Codex Code Mode automatically exposes eligible dynamic OpenClaw tools under +`tools.*`. It does not use OpenClaw's QuickJS guest API or require +`tools.codeMode`, but `tools.swarm` must still be enabled. Use this pattern: + +```javascript +const tasks = [ + "Check the authentication path.", + "Check the storage path.", + "Check the recovery path.", +]; + +const launches = await Promise.all( + tasks.map((task, index) => + tools.sessions_spawn({ + task, + collect: true, + label: `review-${index + 1}`, + }), + ), +); + +for (const launch of launches) { + if (launch.status !== "accepted") { + throw new Error(launch.error ?? "Collector spawn was not accepted."); + } +} + +const pending = new Set(launches.map((launch) => launch.runId)); +const completed = []; + +while (pending.size > 0) { + const ids = [...pending].slice(0, 1000); + const batch = await tools.agents_wait({ + ids, + timeoutSeconds: 30, + }); + + // Rotate this bounded window behind ids that have not been checked yet. + for (const runId of ids) { + if (pending.delete(runId)) pending.add(runId); + } + + for (const item of batch.completed) { + pending.delete(item.runId); + if (item.status !== "done") { + throw new Error(item.schemaError ?? item.result ?? `${item.runId}: ${item.status}`); + } + completed.push(item); // Process each result as soon as it finishes. + } + + for (const failure of batch.errors ?? []) { + pending.delete(failure.runId); + throw new Error(`${failure.runId}: ${failure.error}`); + } +} + +return completed; +``` + +Each `agents_wait` call accepts 1–1000 run ids. It returns: + +```typescript +type AgentsWaitResult = { + completed: Array<{ + runId: string; + status: "done" | "failed" | "killed" | "timeout"; + result: string; + structured?: unknown; + schemaError?: string; + sessionKey: string; + label?: string; + usage?: { inputTokens: number; outputTokens: number }; + }>; + pending: string[]; + errors?: Array<{ + runId: string; + error: "not_found" | "not_owner"; + }>; +}; +``` + +The call returns immediately when any requested child is already complete, +when at least one pending child completes, when no valid pending ids remain, +or when its timeout expires. Completed records are idempotent, so passing an +already-completed run id returns its result again. Only the spawning session +or its authorized parent chain can wait on a collector. + +This is bounded long polling, not a busy status loop. Keep passing only the +remaining run ids until `pending` is empty. Collector mode supports native +OpenClaw sub-agents; it does not support ACP runtime, thread binding, visible +sessions, or persistent session mode. + +## Limits and roadmap + +Swarm v1 runs one-shot collector children; the planned `agents.session()` API +will add stateful multi-turn workers. Children currently run on the local +Gateway's sub-agent lane; cloud placement is planned as an explicit spawn +option. Saved workflow definitions and a graph DSL are not part of Swarm's +current direction. + +## Related + +- [Code Mode](/tools/code-mode) for the QuickJS guest runtime and activation rules +- [Sub-agents](/tools/subagents) for child policy, isolation, and session behavior +- [Multi-agent sandbox tools](/tools/multi-agent-sandbox-tools) for per-agent restrictions +- [Tools overview](/tools) for tool profiles and policy routing