1212 lines
33 KiB
Markdown
1212 lines
33 KiB
Markdown
# OpenClaw Integration With Agent Teams
|
|
|
|
- **Status:** local-first integration guide
|
|
- **Audience:** OpenClaw or any outside AI client that can run MCP tools or call a local REST API
|
|
- **Primary use case:** let an outside AI create, inspect, launch, and cross-check Agent Teams work
|
|
- **Recommended first implementation:** MCP-first, REST as a lifecycle/debug fallback
|
|
|
|
## 1. Executive Summary
|
|
|
|
Yes, this integration is feasible.
|
|
|
|
The clean local architecture is:
|
|
|
|
```text
|
|
OpenClaw
|
|
starts agent-teams-mcp over stdio
|
|
calls Agent Teams desktop HTTP control API
|
|
controls shared Agent Teams runtime and shared ~/.claude state
|
|
```
|
|
|
|
There are two integration surfaces:
|
|
|
|
1. **MCP surface**
|
|
- Best fit for an AI agent like OpenClaw.
|
|
- OpenClaw starts `agent-teams-mcp` as a child process.
|
|
- The MCP server exposes tools such as `team_list`, `team_create`, `team_get`, `team_launch`, `task_create`, `message_send`, `review_request`, and more.
|
|
|
|
2. **REST control API**
|
|
- Best fit for lifecycle automation, health checks, debugging, and simple wrappers.
|
|
- Runs inside the Agent Teams desktop app.
|
|
- Defaults to `http://127.0.0.1:3456`.
|
|
- Currently covers team lifecycle/runtime control. It does not replace the full board/message MCP tool surface.
|
|
|
|
For the original request - "can OpenClaw call Agent Teams for complex tasks and cross-checking?" - the answer is:
|
|
|
|
```text
|
|
Use MCP for normal AI-to-Agent-Teams interaction.
|
|
Use REST for lifecycle/debug or if OpenClaw cannot use MCP yet.
|
|
```
|
|
|
|
## 2. The Mental Model
|
|
|
|
### 2.1 What Runs Where
|
|
|
|
```text
|
|
Mac mini or local Mac
|
|
|
|
Agent Teams Desktop App
|
|
- owns Electron UI
|
|
- owns team runtime process management
|
|
- owns local HTTP control API
|
|
- writes current control API URL to ~/.claude/team-control-api.json
|
|
|
|
agent-teams-mcp
|
|
- stdio MCP server process
|
|
- started by each MCP client that needs it
|
|
- does not listen on a port
|
|
- forwards lifecycle operations to the desktop HTTP control API
|
|
- uses ~/.claude for team/task/message controller state
|
|
|
|
OpenClaw
|
|
- external AI client
|
|
- can start agent-teams-mcp as an MCP server
|
|
- can optionally call REST directly
|
|
```
|
|
|
|
### 2.2 One Control Plane, Many MCP Processes
|
|
|
|
Multiple MCP processes are expected and safe.
|
|
|
|
```text
|
|
Agent 1 MCP process \
|
|
Agent 2 MCP process -> one Agent Teams desktop HTTP API -> shared teams/tasks/runtime
|
|
OpenClaw MCP process/
|
|
```
|
|
|
|
This is safe because `agent-teams-mcp` is a stdio process:
|
|
|
|
- it does not bind a port;
|
|
- it does not own global runtime state;
|
|
- it does not create a second app server;
|
|
- it uses the shared desktop app control API for lifecycle operations;
|
|
- it uses the shared Claude data directory for team/task/message state.
|
|
|
|
The thing that must be singular is the **desktop control plane**, not the MCP process.
|
|
|
|
### 2.3 What Can Conflict
|
|
|
|
MCP processes themselves should not conflict.
|
|
|
|
Possible conflicts are logical, not port/process conflicts:
|
|
|
|
- two clients create the same `teamName`;
|
|
- two clients launch or stop the same team at the same time;
|
|
- two clients edit the same task concurrently;
|
|
- one client changes the board while another client is using stale state.
|
|
|
|
These are normal shared-state coordination issues. They are not caused by multiple MCP servers.
|
|
|
|
## 3. Recommended Integration Choice
|
|
|
|
### Option A: MCP-first integration
|
|
|
|
Scores: 🎯 9/10 🛡️ 8/10 🧠 4/10
|
|
|
|
Expected OpenClaw changes: roughly `20-80 LOC` plus configuration.
|
|
|
|
Use this if OpenClaw supports stdio MCP servers.
|
|
|
|
Why it is the recommended path:
|
|
|
|
- it matches how AI clients naturally call tools;
|
|
- it exposes the richer board/task/message/review surface;
|
|
- each OpenClaw run can start its own MCP process safely;
|
|
- it avoids writing a custom task/message client against internal files;
|
|
- it keeps OpenClaw integration close to the tools Agent Teams already gives team agents.
|
|
|
|
Use REST only for health checks and debugging in this option.
|
|
|
|
### Option B: REST-first lifecycle integration
|
|
|
|
Scores: 🎯 7/10 🛡️ 7/10 🧠 5/10
|
|
|
|
Expected OpenClaw changes: roughly `80-180 LOC`.
|
|
|
|
Use this if OpenClaw cannot run MCP yet.
|
|
|
|
Important limitation:
|
|
|
|
```text
|
|
REST currently covers team lifecycle/runtime control.
|
|
It is not the full board/task/message/review control surface.
|
|
```
|
|
|
|
REST can:
|
|
|
|
- list teams;
|
|
- create draft team configs;
|
|
- get team snapshots;
|
|
- launch teams;
|
|
- stop teams;
|
|
- poll runtime/provisioning state.
|
|
|
|
REST should not be treated as the full replacement for task/message MCP tools.
|
|
|
|
### Option C: Hybrid integration
|
|
|
|
Scores: 🎯 8/10 🛡️ 8/10 🧠 7/10
|
|
|
|
Expected OpenClaw changes: roughly `120-260 LOC`.
|
|
|
|
Use MCP for normal AI tool calls, and REST for operational checks.
|
|
|
|
Good split:
|
|
|
|
- MCP: team operations, task creation, messages, reviews, process registry.
|
|
- REST: "is the desktop app alive?", "what is the runtime state?", "what is the current run status?"
|
|
|
|
This is the best long-term shape if OpenClaw needs both agentic workflows and a supervisory dashboard.
|
|
|
|
## 4. Local Setup Checklist
|
|
|
|
### 4.1 Start Agent Teams Desktop App
|
|
|
|
The desktop app must be running. It owns the runtime and local HTTP API.
|
|
|
|
### 4.2 Enable Browser Access / Server Mode
|
|
|
|
In the desktop app:
|
|
|
|
```text
|
|
Settings -> Browser Access -> Enable server mode
|
|
```
|
|
|
|
When enabled, the app starts a local Fastify HTTP server.
|
|
|
|
Default:
|
|
|
|
```text
|
|
http://127.0.0.1:3456
|
|
```
|
|
|
|
If port `3456` is busy, the app tries the next ports.
|
|
|
|
### 4.3 Discover the Current Control API URL
|
|
|
|
The desktop app writes the active URL to:
|
|
|
|
```text
|
|
~/.claude/team-control-api.json
|
|
```
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"baseUrl": "http://127.0.0.1:3456",
|
|
"pid": 12345,
|
|
"updatedAt": "2026-04-29T10:00:00.000Z"
|
|
}
|
|
```
|
|
|
|
Check it:
|
|
|
|
```bash
|
|
cat ~/.claude/team-control-api.json
|
|
```
|
|
|
|
Then verify REST:
|
|
|
|
```bash
|
|
curl -s http://127.0.0.1:3456/api/teams
|
|
```
|
|
|
|
If the file shows a different port, use that `baseUrl`.
|
|
|
|
### 4.4 Local vs Remote OpenClaw
|
|
|
|
If OpenClaw runs on the same Mac:
|
|
|
|
```text
|
|
No tunnel needed.
|
|
Use http://127.0.0.1:<port>.
|
|
```
|
|
|
|
If OpenClaw runs on another machine:
|
|
|
|
```text
|
|
127.0.0.1 points to the OpenClaw machine, not to the Mac running Agent Teams.
|
|
Use an SSH tunnel, reverse tunnel, VPN, or another secure local-network setup.
|
|
```
|
|
|
|
Basic SSH tunnel example:
|
|
|
|
```bash
|
|
ssh -N -L 3456:127.0.0.1:3456 user@mac-mini-host
|
|
```
|
|
|
|
Then OpenClaw can use:
|
|
|
|
```text
|
|
http://127.0.0.1:3456
|
|
```
|
|
|
|
from the machine where the tunnel is open.
|
|
|
|
## 5. MCP Integration
|
|
|
|
### 5.1 What OpenClaw Needs To Do
|
|
|
|
OpenClaw should register `agent-teams-mcp` as a stdio MCP server.
|
|
|
|
That means OpenClaw starts a process and speaks MCP JSON-RPC over stdin/stdout.
|
|
|
|
OpenClaw does **not** connect to an MCP URL.
|
|
|
|
The URL belongs to the desktop HTTP control API and is passed to MCP through:
|
|
|
|
- `CLAUDE_TEAM_CONTROL_URL`, or
|
|
- `~/.claude/team-control-api.json`, or
|
|
- per-tool `controlUrl`.
|
|
|
|
### 5.2 Dev Checkout MCP Config
|
|
|
|
Use this while testing from the repository checkout:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"agent-teams": {
|
|
"command": "pnpm",
|
|
"args": ["--dir", "/Users/belief/dev/projects/claude/claude_team/mcp-server", "dev"],
|
|
"env": {
|
|
"AGENT_TEAMS_MCP_CLAUDE_DIR": "/Users/belief/.claude",
|
|
"CLAUDE_TEAM_CONTROL_URL": "http://127.0.0.1:3456"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Adjust:
|
|
|
|
- repo path;
|
|
- Claude data directory;
|
|
- control URL port.
|
|
|
|
### 5.3 Built MCP Config
|
|
|
|
Build:
|
|
|
|
```bash
|
|
pnpm --filter agent-teams-mcp build
|
|
```
|
|
|
|
Configure OpenClaw:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"agent-teams": {
|
|
"command": "node",
|
|
"args": ["/Users/belief/dev/projects/claude/claude_team/mcp-server/dist/index.js"],
|
|
"env": {
|
|
"AGENT_TEAMS_MCP_CLAUDE_DIR": "/Users/belief/.claude",
|
|
"CLAUDE_TEAM_CONTROL_URL": "http://127.0.0.1:3456"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5.4 If OpenClaw Supports `cwd`
|
|
|
|
Some MCP clients allow a `cwd` field. If OpenClaw supports it, this is cleaner:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"agent-teams": {
|
|
"command": "pnpm",
|
|
"args": ["dev"],
|
|
"cwd": "/Users/belief/dev/projects/claude/claude_team/mcp-server",
|
|
"env": {
|
|
"AGENT_TEAMS_MCP_CLAUDE_DIR": "/Users/belief/.claude",
|
|
"CLAUDE_TEAM_CONTROL_URL": "http://127.0.0.1:3456"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
If OpenClaw does not support `cwd`, use the `pnpm --dir ... dev` form.
|
|
|
|
### 5.5 MCP URL Discovery Order
|
|
|
|
For lifecycle tools such as `team_list`, `team_get`, `team_create`, and `team_launch`, the control URL is resolved in this order:
|
|
|
|
1. tool argument `controlUrl`;
|
|
2. `~/.claude/team-control-api.json`;
|
|
3. environment variable `CLAUDE_TEAM_CONTROL_URL`.
|
|
|
|
Passing `CLAUDE_TEAM_CONTROL_URL` is the most explicit OpenClaw setup.
|
|
|
|
Passing `controlUrl` per tool call is useful for debugging or tunnels.
|
|
|
|
### 5.6 MCP Tool Surface
|
|
|
|
Current tool groups:
|
|
|
|
| Group | Tools |
|
|
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| Team lifecycle | `team_list`, `team_get`, `team_create` |
|
|
| Runtime lifecycle | `team_launch`, `team_stop` |
|
|
| Task board | `task_create`, `task_create_from_message`, `task_get`, `task_get_comment`, `task_list`, `task_start`, `task_complete`, `task_set_owner`, `task_set_status`, `task_add_comment`, `task_link`, `task_unlink`, `task_set_clarification`, `task_restore`, `task_attach_file`, `task_attach_comment_file`, `task_briefing`, `member_briefing` |
|
|
| Lead briefing | `lead_briefing` |
|
|
| Review | `review_request`, `review_start`, `review_approve`, `review_request_changes` |
|
|
| Messages | `message_send` |
|
|
| Cross-team | `cross_team_send`, `cross_team_list_targets`, `cross_team_get_outbox` |
|
|
| Kanban | `kanban_get`, `kanban_set_column`, `kanban_clear`, `kanban_list_reviewers`, `kanban_add_reviewer`, `kanban_remove_reviewer` |
|
|
| Process registry | `process_register`, `process_list`, `process_stop`, `process_unregister` |
|
|
| Runtime bridge | `runtime_bootstrap_checkin`, `runtime_deliver_message`, `runtime_task_event`, `runtime_heartbeat` |
|
|
|
|
Most OpenClaw integrations need:
|
|
|
|
```text
|
|
team_list
|
|
team_get
|
|
team_create
|
|
team_launch
|
|
team_stop
|
|
task_create
|
|
task_list
|
|
task_get
|
|
message_send
|
|
review_request
|
|
review_request_changes
|
|
review_approve
|
|
```
|
|
|
|
The `runtime_*` tools are low-level OpenCode runtime bridge tools. Do not use them for ordinary user/team messaging.
|
|
|
|
## 6. MCP Workflow Examples
|
|
|
|
The exact call UI depends on OpenClaw. The examples below show the arguments conceptually.
|
|
|
|
### 6.1 List Teams
|
|
|
|
Tool:
|
|
|
|
```text
|
|
team_list
|
|
```
|
|
|
|
Arguments:
|
|
|
|
```json
|
|
{
|
|
"controlUrl": "http://127.0.0.1:3456"
|
|
}
|
|
```
|
|
|
|
`controlUrl` can be omitted if `~/.claude/team-control-api.json` exists and points to the running desktop app.
|
|
|
|
### 6.2 Get a Team
|
|
|
|
Tool:
|
|
|
|
```text
|
|
team_get
|
|
```
|
|
|
|
Arguments:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review"
|
|
}
|
|
```
|
|
|
|
For a draft team, the response includes `pendingCreate` and `savedRequest`.
|
|
|
|
For a configured team, the response is the normal team snapshot.
|
|
|
|
### 6.3 Create a Draft Review Team
|
|
|
|
Tool:
|
|
|
|
```text
|
|
team_create
|
|
```
|
|
|
|
Arguments:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review",
|
|
"displayName": "OpenClaw Review",
|
|
"description": "Team used by OpenClaw to cross-check complex work",
|
|
"cwd": "/Users/belief/dev/projects/example-project",
|
|
"providerId": "codex",
|
|
"providerBackendId": "codex-native",
|
|
"model": "gpt-5.4",
|
|
"effort": "high",
|
|
"fastMode": "inherit",
|
|
"limitContext": true,
|
|
"skipPermissions": false,
|
|
"members": [
|
|
{
|
|
"name": "reviewer",
|
|
"role": "Reviewer",
|
|
"workflow": "Review OpenClaw work for bugs, missing tests, incorrect assumptions, and integration risks.",
|
|
"providerId": "codex",
|
|
"providerBackendId": "codex-native",
|
|
"model": "gpt-5.4",
|
|
"effort": "high",
|
|
"fastMode": "inherit"
|
|
},
|
|
{
|
|
"name": "critic",
|
|
"role": "Critical reviewer",
|
|
"workflow": "Look for edge cases, concurrency issues, unsafe assumptions, and architectural regressions.",
|
|
"providerId": "anthropic",
|
|
"model": "claude-opus-4-6",
|
|
"effort": "high"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
This creates a draft team config. It does not start the runtime.
|
|
|
|
Important:
|
|
|
|
- Put provider/backend/model/fast-mode defaults into `team_create`.
|
|
- MCP `team_launch` currently accepts a smaller runtime override shape.
|
|
- When launching a draft through MCP, saved draft fields are reused.
|
|
|
|
### 6.4 Launch the Team
|
|
|
|
Tool:
|
|
|
|
```text
|
|
team_launch
|
|
```
|
|
|
|
Arguments:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review",
|
|
"cwd": "/Users/belief/dev/projects/example-project",
|
|
"prompt": "Cross-check OpenClaw latest work. Focus on bugs, missing tests, and architectural risks. Return concise actionable findings.",
|
|
"waitForReady": true,
|
|
"waitTimeoutMs": 180000
|
|
}
|
|
```
|
|
|
|
`team_launch` works for:
|
|
|
|
- a draft team created by `team_create`;
|
|
- an existing configured team.
|
|
|
|
Current MCP `team_launch` launch overrides are intentionally smaller than `team_create`:
|
|
|
|
```text
|
|
cwd
|
|
prompt
|
|
model
|
|
effort: low | medium | high
|
|
clearContext
|
|
skipPermissions
|
|
worktree
|
|
extraCliArgs
|
|
waitForReady
|
|
waitTimeoutMs
|
|
```
|
|
|
|
Do not pass `providerId`, `providerBackendId`, `fastMode`, or `limitContext` to MCP `team_launch`.
|
|
Put those into `team_create` so the saved draft can be reused at launch time.
|
|
|
|
If `waitForReady` is true, the tool waits for provisioning to reach `ready` or fail.
|
|
|
|
### 6.5 Create a Review Task After Launch
|
|
|
|
Use this if OpenClaw wants the team to track review work on the board.
|
|
|
|
Tool:
|
|
|
|
```text
|
|
task_create
|
|
```
|
|
|
|
Arguments:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review",
|
|
"subject": "Review OpenClaw latest patch",
|
|
"description": "Check correctness, tests, edge cases, and integration risks. Report concrete findings only.",
|
|
"owner": "reviewer",
|
|
"createdBy": "openclaw",
|
|
"startImmediately": true
|
|
}
|
|
```
|
|
|
|
`task_create` requires a configured team, so launch the team first.
|
|
|
|
### 6.6 Send a Message To the Team
|
|
|
|
Tool:
|
|
|
|
```text
|
|
message_send
|
|
```
|
|
|
|
Arguments:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review",
|
|
"to": "reviewer",
|
|
"from": "openclaw",
|
|
"text": "Please review the latest changes. Focus on regressions and missing tests.",
|
|
"summary": "Review request from OpenClaw"
|
|
}
|
|
```
|
|
|
|
Use `message_send` for normal visible messages.
|
|
|
|
Do not use `runtime_deliver_message` for ordinary OpenClaw-to-team communication.
|
|
|
|
### 6.7 Stop the Team
|
|
|
|
Tool:
|
|
|
|
```text
|
|
team_stop
|
|
```
|
|
|
|
Arguments:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review",
|
|
"waitForStop": true
|
|
}
|
|
```
|
|
|
|
## 7. Suggested OpenClaw Policy
|
|
|
|
OpenClaw should not call Agent Teams for every small task. Use it when parallel review or team behavior matters.
|
|
|
|
Suggested policy:
|
|
|
|
```text
|
|
Use the agent-teams MCP server when the task is complex, high-risk, user-visible, or needs independent cross-checking.
|
|
|
|
Prefer the existing team "openclaw-review".
|
|
Call team_get first.
|
|
If it does not exist, call team_create.
|
|
Call team_launch with a focused prompt.
|
|
If the review should be tracked, create a task with task_create.
|
|
Use message_send for visible follow-up messages.
|
|
Do not create duplicate teams with the same purpose.
|
|
Do not call runtime_* tools unless implementing an OpenCode runtime bridge.
|
|
Do not expose the local control API outside localhost without a secure tunnel.
|
|
```
|
|
|
|
Recommended task routing:
|
|
|
|
1. Small code change: OpenClaw handles it alone.
|
|
2. Medium risk: OpenClaw launches `openclaw-review` for cross-checking.
|
|
3. High risk: OpenClaw creates explicit review tasks for multiple reviewers.
|
|
4. Release/blocking work: OpenClaw uses task/review tools and waits for explicit review outcome.
|
|
|
|
## 8. Direct REST API Integration
|
|
|
|
REST is useful when:
|
|
|
|
- OpenClaw cannot run MCP yet;
|
|
- you need a simple health/lifecycle wrapper;
|
|
- you are debugging the desktop control API;
|
|
- you want a non-agent script to create or launch teams.
|
|
|
|
REST is **not** currently the full board/message/review surface.
|
|
|
|
Use MCP for task board and messaging operations.
|
|
|
|
### 8.1 Base URL
|
|
|
|
Default:
|
|
|
|
```text
|
|
http://127.0.0.1:3456
|
|
```
|
|
|
|
Discover current:
|
|
|
|
```bash
|
|
cat ~/.claude/team-control-api.json
|
|
```
|
|
|
|
Use:
|
|
|
|
```bash
|
|
BASE_URL="$(
|
|
node <<'NODE'
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const statePath = path.join(process.env.HOME, '.claude', 'team-control-api.json');
|
|
|
|
if (fs.existsSync(statePath)) {
|
|
const state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
console.log(state.baseUrl || 'http://127.0.0.1:3456');
|
|
} else {
|
|
console.log('http://127.0.0.1:3456');
|
|
}
|
|
NODE
|
|
)"
|
|
echo "$BASE_URL"
|
|
```
|
|
|
|
Or set manually:
|
|
|
|
```bash
|
|
BASE_URL="http://127.0.0.1:3456"
|
|
```
|
|
|
|
### 8.2 REST Endpoint Summary
|
|
|
|
| Method | Path | Purpose |
|
|
| ------ | -------------------------------- | --------------------------------- |
|
|
| `GET` | `/api/teams` | List teams |
|
|
| `POST` | `/api/teams` | Create a draft team configuration |
|
|
| `GET` | `/api/teams/:teamName` | Get a draft or configured team |
|
|
| `POST` | `/api/teams/:teamName/launch` | Launch a draft or configured team |
|
|
| `POST` | `/api/teams/:teamName/stop` | Stop a running team |
|
|
| `GET` | `/api/teams/:teamName/runtime` | Get runtime state for one team |
|
|
| `GET` | `/api/teams/provisioning/:runId` | Poll launch/provisioning status |
|
|
| `GET` | `/api/teams/runtime/alive` | List alive team runtime states |
|
|
|
|
Advanced OpenCode runtime bridge endpoints:
|
|
|
|
| Method | Path |
|
|
| ------ | --------------------------------------------------------- |
|
|
| `POST` | `/api/teams/:teamName/opencode/runtime/bootstrap-checkin` |
|
|
| `POST` | `/api/teams/:teamName/opencode/runtime/deliver-message` |
|
|
| `POST` | `/api/teams/:teamName/opencode/runtime/task-event` |
|
|
| `POST` | `/api/teams/:teamName/opencode/runtime/heartbeat` |
|
|
|
|
Do not use the OpenCode runtime bridge endpoints for normal OpenClaw user/team messages.
|
|
|
|
### 8.3 List Teams
|
|
|
|
```bash
|
|
curl -s "$BASE_URL/api/teams" | jq .
|
|
```
|
|
|
|
### 8.4 Create a Draft Team
|
|
|
|
```bash
|
|
curl -s \
|
|
-X POST "$BASE_URL/api/teams" \
|
|
-H 'content-type: application/json' \
|
|
-d '{
|
|
"teamName": "openclaw-review",
|
|
"displayName": "OpenClaw Review",
|
|
"description": "Team used by OpenClaw to cross-check complex work",
|
|
"cwd": "/Users/belief/dev/projects/example-project",
|
|
"providerId": "codex",
|
|
"providerBackendId": "codex-native",
|
|
"model": "gpt-5.4",
|
|
"effort": "high",
|
|
"fastMode": "inherit",
|
|
"limitContext": true,
|
|
"skipPermissions": false,
|
|
"members": [
|
|
{
|
|
"name": "reviewer",
|
|
"role": "Reviewer",
|
|
"workflow": "Review OpenClaw work for correctness, regressions, and missing tests.",
|
|
"providerId": "codex",
|
|
"providerBackendId": "codex-native",
|
|
"model": "gpt-5.4",
|
|
"effort": "high"
|
|
}
|
|
]
|
|
}' | jq .
|
|
```
|
|
|
|
Expected response:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review"
|
|
}
|
|
```
|
|
|
|
### 8.5 Get a Draft or Existing Team
|
|
|
|
```bash
|
|
curl -s "$BASE_URL/api/teams/openclaw-review" | jq .
|
|
```
|
|
|
|
Draft shape:
|
|
|
|
```json
|
|
{
|
|
"teamName": "openclaw-review",
|
|
"pendingCreate": true,
|
|
"savedRequest": {
|
|
"teamName": "openclaw-review",
|
|
"cwd": "/Users/belief/dev/projects/example-project",
|
|
"providerId": "codex",
|
|
"members": [
|
|
{
|
|
"name": "reviewer",
|
|
"role": "Reviewer"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
Configured teams return the normal Agent Teams team snapshot.
|
|
|
|
### 8.6 Launch a Team
|
|
|
|
```bash
|
|
curl -s \
|
|
-X POST "$BASE_URL/api/teams/openclaw-review/launch" \
|
|
-H 'content-type: application/json' \
|
|
-d '{
|
|
"cwd": "/Users/belief/dev/projects/example-project",
|
|
"prompt": "Cross-check OpenClaw latest work. Focus on bugs, missing tests, and architectural risks.",
|
|
"providerId": "codex",
|
|
"providerBackendId": "codex-native",
|
|
"model": "gpt-5.4",
|
|
"effort": "high",
|
|
"fastMode": "inherit",
|
|
"skipPermissions": false
|
|
}' | jq .
|
|
```
|
|
|
|
Expected response:
|
|
|
|
```json
|
|
{
|
|
"runId": "..."
|
|
}
|
|
```
|
|
|
|
For draft teams, missing launch fields fall back to the saved draft request where supported.
|
|
|
|
For existing configured teams, the launch payload is the runtime override for this launch.
|
|
|
|
⚠️ `limitContext` should be set during `team_create` for this integration path.
|
|
Do not depend on it as a configured-team REST launch override unless the route parser is extended.
|
|
|
|
### 8.7 Poll Launch Status
|
|
|
|
```bash
|
|
RUN_ID="paste-run-id-here"
|
|
curl -s "$BASE_URL/api/teams/provisioning/$RUN_ID" | jq .
|
|
```
|
|
|
|
Terminal states:
|
|
|
|
- `ready`
|
|
- `failed`
|
|
- `disconnected`
|
|
- `cancelled`
|
|
|
|
Successful launch:
|
|
|
|
```json
|
|
{
|
|
"state": "ready"
|
|
}
|
|
```
|
|
|
|
### 8.8 Get Runtime State
|
|
|
|
```bash
|
|
curl -s "$BASE_URL/api/teams/openclaw-review/runtime" | jq .
|
|
```
|
|
|
|
### 8.9 Stop a Team
|
|
|
|
```bash
|
|
curl -s \
|
|
-X POST "$BASE_URL/api/teams/openclaw-review/stop" \
|
|
-H 'content-type: application/json' \
|
|
-d '{}' | jq .
|
|
```
|
|
|
|
## 9. JavaScript REST Client Example
|
|
|
|
This is a minimal lifecycle-only helper for OpenClaw.
|
|
|
|
It does not implement task/message/review operations. Use MCP for those.
|
|
|
|
```js
|
|
import fs from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
|
|
async function getAgentTeamsBaseUrl() {
|
|
if (process.env.CLAUDE_TEAM_CONTROL_URL) {
|
|
return process.env.CLAUDE_TEAM_CONTROL_URL;
|
|
}
|
|
|
|
const statePath = path.join(os.homedir(), '.claude', 'team-control-api.json');
|
|
const raw = await fs.readFile(statePath, 'utf8');
|
|
const parsed = JSON.parse(raw);
|
|
if (!parsed.baseUrl) {
|
|
throw new Error('team-control-api.json does not contain baseUrl');
|
|
}
|
|
return parsed.baseUrl;
|
|
}
|
|
|
|
async function requestJson(pathname, options = {}) {
|
|
const baseUrl = await getAgentTeamsBaseUrl();
|
|
const response = await fetch(`${baseUrl}${pathname}`, {
|
|
method: options.method ?? 'GET',
|
|
headers: {
|
|
accept: 'application/json',
|
|
...(options.body ? { 'content-type': 'application/json' } : {}),
|
|
},
|
|
...(options.body ? { body: JSON.stringify(options.body) } : {}),
|
|
});
|
|
|
|
const payload = await response.json().catch(() => null);
|
|
if (!response.ok) {
|
|
throw new Error(payload?.error || `${response.status} ${response.statusText}`);
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
async function teamExists(teamName) {
|
|
try {
|
|
return await requestJson(`/api/teams/${encodeURIComponent(teamName)}`);
|
|
} catch (error) {
|
|
const message = String(error.message || '').toLowerCase();
|
|
if (message.includes('not found')) {
|
|
return null;
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function ensureReviewTeam({ cwd = process.cwd() } = {}) {
|
|
const teamName = 'openclaw-review';
|
|
const existing = await teamExists(teamName);
|
|
if (existing) {
|
|
return existing;
|
|
}
|
|
|
|
await requestJson('/api/teams', {
|
|
method: 'POST',
|
|
body: {
|
|
teamName,
|
|
displayName: 'OpenClaw Review',
|
|
description: 'Team used by OpenClaw to cross-check complex work',
|
|
cwd,
|
|
providerId: 'codex',
|
|
providerBackendId: 'codex-native',
|
|
model: 'gpt-5.4',
|
|
effort: 'high',
|
|
fastMode: 'inherit',
|
|
limitContext: true,
|
|
skipPermissions: false,
|
|
members: [
|
|
{
|
|
name: 'reviewer',
|
|
role: 'Reviewer',
|
|
workflow: 'Cross-check OpenClaw work for bugs, missing tests, and risky assumptions.',
|
|
providerId: 'codex',
|
|
providerBackendId: 'codex-native',
|
|
model: 'gpt-5.4',
|
|
effort: 'high',
|
|
fastMode: 'inherit',
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
return requestJson(`/api/teams/${encodeURIComponent(teamName)}`);
|
|
}
|
|
|
|
export async function launchReviewTeam({ cwd = process.cwd(), prompt }) {
|
|
const teamName = 'openclaw-review';
|
|
await ensureReviewTeam({ cwd });
|
|
|
|
const launch = await requestJson(`/api/teams/${encodeURIComponent(teamName)}/launch`, {
|
|
method: 'POST',
|
|
body: {
|
|
cwd,
|
|
prompt,
|
|
providerId: 'codex',
|
|
providerBackendId: 'codex-native',
|
|
model: 'gpt-5.4',
|
|
effort: 'high',
|
|
fastMode: 'inherit',
|
|
skipPermissions: false,
|
|
},
|
|
});
|
|
|
|
return launch;
|
|
}
|
|
|
|
export async function waitForReady(runId, { timeoutMs = 180000, pollMs = 1000 } = {}) {
|
|
const startedAt = Date.now();
|
|
|
|
while (Date.now() - startedAt < timeoutMs) {
|
|
const status = await requestJson(`/api/teams/provisioning/${encodeURIComponent(runId)}`);
|
|
if (status.state === 'ready') {
|
|
return status;
|
|
}
|
|
if (['failed', 'disconnected', 'cancelled'].includes(status.state)) {
|
|
throw new Error(`Team launch ended in ${status.state}: ${status.error || 'no details'}`);
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
}
|
|
|
|
throw new Error(`Timed out waiting for run ${runId}`);
|
|
}
|
|
```
|
|
|
|
Example use:
|
|
|
|
```js
|
|
const launch = await launchReviewTeam({
|
|
cwd: '/Users/belief/dev/projects/example-project',
|
|
prompt: 'Cross-check the latest OpenClaw changes. Return concrete bugs and missing tests.',
|
|
});
|
|
|
|
await waitForReady(launch.runId);
|
|
```
|
|
|
|
## 10. Validation Rules
|
|
|
|
### 10.1 Team Names
|
|
|
|
Team names must be kebab-case:
|
|
|
|
```text
|
|
lowercase alphanumeric segments separated by single hyphens, max 64 chars
|
|
```
|
|
|
|
Good:
|
|
|
|
```text
|
|
openclaw-review
|
|
repo-audit-1
|
|
security-check
|
|
```
|
|
|
|
Bad:
|
|
|
|
```text
|
|
OpenClaw Review
|
|
openclaw_review
|
|
review team
|
|
review--team
|
|
-review
|
|
review-
|
|
```
|
|
|
|
### 10.2 Member Names
|
|
|
|
Avoid reserved names:
|
|
|
|
- `user`
|
|
- `team-lead`
|
|
|
|
Good:
|
|
|
|
```text
|
|
reviewer
|
|
critic
|
|
tester
|
|
architect
|
|
```
|
|
|
|
### 10.3 Providers and Runtime Fields
|
|
|
|
Provider IDs:
|
|
|
|
```text
|
|
anthropic
|
|
codex
|
|
gemini
|
|
opencode
|
|
```
|
|
|
|
Provider backend IDs:
|
|
|
|
```text
|
|
auto
|
|
adapter
|
|
api
|
|
cli-sdk
|
|
codex-native
|
|
```
|
|
|
|
Fast mode:
|
|
|
|
```text
|
|
inherit
|
|
on
|
|
off
|
|
```
|
|
|
|
Effort values are provider-dependent. Common values include:
|
|
|
|
```text
|
|
low
|
|
medium
|
|
high
|
|
```
|
|
|
|
Codex-oriented create flows may also use values such as:
|
|
|
|
```text
|
|
none
|
|
minimal
|
|
xhigh
|
|
max
|
|
```
|
|
|
|
Use values supported by the selected provider/runtime.
|
|
|
|
## 11. Error Behavior
|
|
|
|
Common REST status codes:
|
|
|
|
| Status | Meaning |
|
|
| ------ | ------------------------------------------------------------------- |
|
|
| `400` | Invalid request payload |
|
|
| `404` | Team or run id not found |
|
|
| `409` | Conflict, for example team already exists or stale runtime evidence |
|
|
| `501` | Team control service is not available in this mode |
|
|
| `500` | Unexpected server/runtime error |
|
|
|
|
Common MCP failures:
|
|
|
|
| Symptom | Likely cause |
|
|
| ----------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
| Control API unavailable | Desktop app not running, server mode disabled, wrong `CLAUDE_TEAM_CONTROL_URL`, or wrong `~/.claude` |
|
|
| `team_create` conflict | Team already exists |
|
|
| `team_launch` timeout | Runtime auth/model/cwd/provisioning issue |
|
|
| Task tools fail after `team_create` | Team is still a draft. Launch it first |
|
|
| Remote OpenClaw cannot connect | Missing tunnel or wrong host mapping |
|
|
|
|
## 12. Troubleshooting
|
|
|
|
### 12.1 Confirm Desktop Control API
|
|
|
|
```bash
|
|
cat ~/.claude/team-control-api.json
|
|
curl -s http://127.0.0.1:3456/api/teams | jq .
|
|
```
|
|
|
|
If the file has another port, use that port.
|
|
|
|
### 12.2 Confirm MCP Starts
|
|
|
|
From the repo:
|
|
|
|
```bash
|
|
pnpm --dir /Users/belief/dev/projects/claude/claude_team/mcp-server dev
|
|
```
|
|
|
|
This starts the stdio server and waits for MCP JSON-RPC input. It will not print a normal HTTP URL.
|
|
|
|
In a real OpenClaw setup, OpenClaw starts this process itself.
|
|
|
|
### 12.3 MCP Starts But Tool Calls Fail
|
|
|
|
Check:
|
|
|
|
- `AGENT_TEAMS_MCP_CLAUDE_DIR` points to the same Claude root as the app;
|
|
- `CLAUDE_TEAM_CONTROL_URL` points to the app's current local HTTP URL;
|
|
- Agent Teams desktop app is running;
|
|
- Browser Access / server mode is enabled;
|
|
- OpenClaw is on the same machine or has a working tunnel.
|
|
|
|
### 12.4 `team_create` Says Team Already Exists
|
|
|
|
Use:
|
|
|
|
```text
|
|
team_get
|
|
```
|
|
|
|
Then reuse the existing team, or pick another `teamName`.
|
|
|
|
### 12.5 `team_launch` Hangs
|
|
|
|
With REST, poll:
|
|
|
|
```bash
|
|
curl -s "$BASE_URL/api/teams/provisioning/<runId>" | jq .
|
|
```
|
|
|
|
With MCP, use `waitForReady: true` and a larger `waitTimeoutMs`.
|
|
|
|
Possible causes:
|
|
|
|
- model unavailable;
|
|
- provider authentication missing;
|
|
- invalid working directory;
|
|
- provisioning failure;
|
|
- already-running/stale runtime state.
|
|
|
|
### 12.6 Remote OpenClaw Cannot Connect
|
|
|
|
This is expected without a tunnel.
|
|
|
|
The desktop API binds to `127.0.0.1`, so a remote process cannot see it directly.
|
|
|
|
Use SSH tunnel or VPN. Do not publish the control API to a public interface without authentication.
|
|
|
|
## 13. Security Notes
|
|
|
|
- Treat the control API as runtime control access.
|
|
- Keep it local by default.
|
|
- Prefer SSH tunnels for remote use.
|
|
- Do not expose it publicly without authentication and transport security.
|
|
- Do not share `~/.claude` with untrusted processes.
|
|
- Remember that an AI client with this MCP server can create, launch, stop, and coordinate teams.
|
|
|
|
## 14. What To Tell The User
|
|
|
|
Use this short explanation:
|
|
|
|
```text
|
|
Yes, this is feasible.
|
|
|
|
Agent Teams can expose a local control API from the desktop app, and an outside AI like OpenClaw can access it through the agent-teams MCP server.
|
|
|
|
OpenClaw would start agent-teams-mcp as a stdio MCP server. That MCP process does not listen on a port, so it is fine if multiple agents and OpenClaw each start their own copy. They all point back to the same local Agent Teams desktop control API and shared ~/.claude state.
|
|
|
|
For a local Mac mini setup, this is straightforward:
|
|
1. Run the Agent Teams desktop app.
|
|
2. Enable Browser Access / server mode.
|
|
3. Configure OpenClaw with the agent-teams MCP server.
|
|
4. Let OpenClaw call team_list, team_get, team_create, and team_launch.
|
|
5. Use task/message/review MCP tools for deeper coordination.
|
|
|
|
REST is also available for lifecycle calls like list/create/get/launch/stop, but MCP is the better integration surface for actual AI-to-team work.
|
|
```
|
|
|
|
## 15. Final Recommendation
|
|
|
|
Start with MCP-first local integration.
|
|
|
|
Use this minimum viable flow:
|
|
|
|
```text
|
|
1. OpenClaw starts agent-teams-mcp.
|
|
2. OpenClaw calls team_get("openclaw-review").
|
|
3. If missing, OpenClaw calls team_create(...).
|
|
4. OpenClaw calls team_launch(..., waitForReady: true).
|
|
5. OpenClaw creates a review task with task_create or sends a message with message_send.
|
|
6. OpenClaw reads results via task_get/task_list/message flow.
|
|
```
|
|
|
|
This gives OpenClaw the team coordination behavior without inventing a separate orchestration layer.
|