|
| 1 | +# openclaw-orchestrator |
| 2 | + |
| 3 | +Adaptive multi-agent orchestration for [OpenClaw](https://openclaw.app) gateways. |
| 4 | + |
| 5 | +Break down complex goals into tasks, route them to specialized agents, and iterate until done — all driven by an LLM planner with a real-time web dashboard. |
| 6 | + |
| 7 | +``` |
| 8 | + +-----------+ |
| 9 | + | Goal | |
| 10 | + +-----+-----+ |
| 11 | + | |
| 12 | + +-----v-----+ |
| 13 | + +--->| Think |---+ |
| 14 | + | +-----+-----+ | |
| 15 | + | | | "finish" |
| 16 | + | +-----v-----+ +---------> Result |
| 17 | + | | Execute | |
| 18 | + | +-----+-----+ |
| 19 | + | | |
| 20 | + +----------+ |
| 21 | + results fed back |
| 22 | +``` |
| 23 | + |
| 24 | +## Features |
| 25 | + |
| 26 | +- **Adaptive loop** — LLM decides what to do next based on accumulated results, not a rigid pre-planned DAG |
| 27 | +- **Multi-agent routing** — tasks are assigned to the best agent by name or capability (researcher, coder, analyst, or any custom agent) |
| 28 | +- **Dynamic agent discovery** — agent metadata (description, capabilities, role prompt) loaded from each agent's SOUL.md on the gateway |
| 29 | +- **Real-time dashboard** — browser-based UI with SSE streaming, step visualization, and run history |
| 30 | +- **3 adapter types** — OpenClaw gateway agents, HTTP endpoints, or plain async functions |
| 31 | +- **Robust LLM parsing** — handles markdown-wrapped JSON, prose prefixes, and truncated gateway responses |
| 32 | +- **Zero frontend dependencies** — dashboard is a single HTML file with inline CSS/JS |
| 33 | + |
| 34 | +## Quick Start |
| 35 | + |
| 36 | +```bash |
| 37 | +# Install |
| 38 | +npm install openclaw-orchestrator |
| 39 | + |
| 40 | +# Start the dashboard (connects to your OpenClaw gateway) |
| 41 | +openclaw-orchestrator serve -g ws://your-gateway:port/ -t YOUR_TOKEN |
| 42 | + |
| 43 | +# Or run a goal directly from the CLI |
| 44 | +openclaw-orchestrator run "Compare React and Svelte for dashboards" \ |
| 45 | + -g ws://your-gateway:port/ -t YOUR_TOKEN |
| 46 | +``` |
| 47 | + |
| 48 | +Open `http://localhost:3000` to see the dashboard. |
| 49 | + |
| 50 | +<!-- TODO: Add screenshot of dashboard here --> |
| 51 | + |
| 52 | +## Prerequisites |
| 53 | + |
| 54 | +- **Node.js 22+** |
| 55 | +- An [OpenClaw](https://openclaw.app) gateway with at least one agent configured |
| 56 | + |
| 57 | +## CLI Reference |
| 58 | + |
| 59 | +### `serve` — Start the web dashboard |
| 60 | + |
| 61 | +```bash |
| 62 | +openclaw-orchestrator serve \ |
| 63 | + -g ws://host:port/ # Gateway URL (required, repeatable) |
| 64 | + -n my-gateway # Gateway name (optional, paired with -g) |
| 65 | + -t TOKEN # Auth token (paired with -g) |
| 66 | + -p 3000 # Dashboard port (default: 3000) |
| 67 | + --host 127.0.0.1 # Dashboard host (default: 127.0.0.1) |
| 68 | +``` |
| 69 | + |
| 70 | +### `run` — Execute a goal |
| 71 | + |
| 72 | +```bash |
| 73 | +openclaw-orchestrator run "Your goal here" \ |
| 74 | + -g ws://host:port/ -t TOKEN \ |
| 75 | + -c 8 # Max parallel tasks (default: 8) |
| 76 | + -s 10 # Max orchestrator steps (default: 10) |
| 77 | +``` |
| 78 | + |
| 79 | +If a dashboard is running, `run` delegates to it automatically. Use `--no-dashboard` to connect directly to the gateway. |
| 80 | + |
| 81 | +### `plan` — Dry-run the first step |
| 82 | + |
| 83 | +```bash |
| 84 | +openclaw-orchestrator plan "Your goal here" -g ws://host:port/ -t TOKEN |
| 85 | +``` |
| 86 | + |
| 87 | +### `agents` — List discovered agents |
| 88 | + |
| 89 | +```bash |
| 90 | +openclaw-orchestrator agents -g ws://host:port/ -t TOKEN |
| 91 | +``` |
| 92 | + |
| 93 | +### `gateways health` — Check gateway connectivity |
| 94 | + |
| 95 | +```bash |
| 96 | +openclaw-orchestrator gateways health -g ws://host:port/ -t TOKEN |
| 97 | +``` |
| 98 | + |
| 99 | +All commands accept `--debug` for verbose logging. |
| 100 | + |
| 101 | +## Programmatic API |
| 102 | + |
| 103 | +```typescript |
| 104 | +import { Orchestrator, FunctionAdapter } from "openclaw-orchestrator"; |
| 105 | + |
| 106 | +const orch = new Orchestrator(); |
| 107 | + |
| 108 | +// Register agents — can be functions, HTTP endpoints, or OpenClaw gateways |
| 109 | +orch.addAgent(new FunctionAdapter({ |
| 110 | + name: "researcher", |
| 111 | + description: "Finds information on the web", |
| 112 | + capabilities: ["research", "web-search"], |
| 113 | + fn: async (task) => { |
| 114 | + // Your research logic here |
| 115 | + return `Results for: ${task}`; |
| 116 | + }, |
| 117 | +})); |
| 118 | + |
| 119 | +orch.addAgent(new FunctionAdapter({ |
| 120 | + name: "coder", |
| 121 | + description: "Writes code", |
| 122 | + capabilities: ["coding", "programming"], |
| 123 | + fn: async (task) => { |
| 124 | + // Your coding logic here |
| 125 | + return `// Code for: ${task}`; |
| 126 | + }, |
| 127 | +})); |
| 128 | + |
| 129 | +// Run with callbacks for real-time updates |
| 130 | +const result = await orch.run("Build a URL shortener", { |
| 131 | + maxConcurrency: 4, |
| 132 | + maxSteps: 5, |
| 133 | +}, { |
| 134 | + onStepStart: (step, taskIds) => console.log(`Step ${step}: ${taskIds.join(", ")}`), |
| 135 | + onTaskEnd: (step, taskId, result) => console.log(` ${taskId}: ${result.status}`), |
| 136 | + onFinish: (answer) => console.log("\nDone:", answer), |
| 137 | +}); |
| 138 | +``` |
| 139 | + |
| 140 | +## How It Works |
| 141 | + |
| 142 | +1. **Think** — The orchestrator sends the goal and all accumulated results to an LLM, which responds with either: |
| 143 | + - `{ "action": "execute", "tasks": [...] }` — a batch of tasks to run in parallel |
| 144 | + - `{ "action": "finish", "answer": "..." }` — the final synthesized answer |
| 145 | + |
| 146 | +2. **Execute** — Tasks are dispatched to agents based on the `"agent"` field. The orchestrator matches by agent name first, then by capability. Tasks in the same step run concurrently. |
| 147 | + |
| 148 | +3. **Repeat** — Results feed back into the next think step. The LLM sees what succeeded, what failed, and decides what to do next. This continues until the LLM finishes or the step limit is reached. |
| 149 | + |
| 150 | +``` |
| 151 | +Goal: "Compare React vs Svelte for dashboards" |
| 152 | +
|
| 153 | +Step 1 (think): |
| 154 | + → researcher: "Find 2025 benchmarks for React vs Svelte" |
| 155 | +
|
| 156 | +Step 2 (think, after research results): |
| 157 | + → coder: "Write a React dashboard component" |
| 158 | + → coder: "Write a Svelte dashboard component" |
| 159 | + → analyst: "Compare frameworks based on research data" |
| 160 | +
|
| 161 | +Step 3 (think, after code + analysis): |
| 162 | + → finish: "Here's the comprehensive comparison..." |
| 163 | +``` |
| 164 | + |
| 165 | +## Agent Adapters |
| 166 | + |
| 167 | +### OpenClaw (gateway agents) |
| 168 | + |
| 169 | +```typescript |
| 170 | +import { Orchestrator, GatewayClient, OpenClawAdapter } from "openclaw-orchestrator"; |
| 171 | + |
| 172 | +const orch = new Orchestrator(); |
| 173 | +orch.addGateway({ name: "main", url: "ws://host:port/", token: "..." }); |
| 174 | + |
| 175 | +// The CLI does this automatically — agents are discovered from the gateway |
| 176 | +// and enriched with metadata from their SOUL.md files |
| 177 | +``` |
| 178 | + |
| 179 | +### HTTP (remote endpoints) |
| 180 | + |
| 181 | +```typescript |
| 182 | +import { HttpAdapter } from "openclaw-orchestrator"; |
| 183 | + |
| 184 | +orch.addAgent(new HttpAdapter({ |
| 185 | + name: "summarizer", |
| 186 | + url: "https://my-api.com/summarize", |
| 187 | + capabilities: ["summarization"], |
| 188 | + // POST { task, id, config } → { output, status? } |
| 189 | +})); |
| 190 | +``` |
| 191 | + |
| 192 | +### Function (in-process) |
| 193 | + |
| 194 | +```typescript |
| 195 | +import { FunctionAdapter } from "openclaw-orchestrator"; |
| 196 | + |
| 197 | +orch.addAgent(new FunctionAdapter({ |
| 198 | + name: "calculator", |
| 199 | + capabilities: ["math", "computation"], |
| 200 | + timeout: 10_000, // ms, default: 60s |
| 201 | + fn: async (task, ctx) => { |
| 202 | + return String(eval(task)); // your logic here |
| 203 | + }, |
| 204 | +})); |
| 205 | +``` |
| 206 | + |
| 207 | +## Dashboard |
| 208 | + |
| 209 | +The web dashboard provides real-time visibility into orchestrator runs: |
| 210 | + |
| 211 | +- Submit goals and configure concurrency/max steps |
| 212 | +- Watch tasks execute with live status updates via SSE |
| 213 | +- Expand task outputs to inspect results |
| 214 | +- Browse run history |
| 215 | + |
| 216 | +Start it with `openclaw-orchestrator serve` or programmatically: |
| 217 | + |
| 218 | +```typescript |
| 219 | +import { Orchestrator, DashboardServer } from "openclaw-orchestrator"; |
| 220 | + |
| 221 | +const orch = new Orchestrator(); |
| 222 | +// ... add gateways and agents ... |
| 223 | + |
| 224 | +const dashboard = new DashboardServer({ |
| 225 | + orchestrator: orch, |
| 226 | + port: 3000, |
| 227 | + host: "127.0.0.1", |
| 228 | +}); |
| 229 | + |
| 230 | +await dashboard.start(); |
| 231 | +``` |
| 232 | + |
| 233 | +## Contributing |
| 234 | + |
| 235 | +See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and guidelines. |
| 236 | + |
| 237 | +## License |
| 238 | + |
| 239 | +[MIT](LICENSE) |
0 commit comments