External Agent Orchestration
Claude Deck exposes a local Agent Mail API for tools such as OpenClaw to coordinate installed agents without pretending to be a repo agent or a UI user.
This API is for same-machine automation. It does not replace Agent Teams preset launch APIs, and it does not add a new wake path for non-tmux agent sessions.
Setup
Create or rotate a local external actor token:
curl -s http://127.0.0.1:8000/api/v1/external/agent-mail/actors \
-H 'Content-Type: application/json' \
-d '{
"actor_key": "openclaw",
"display_name": "OpenClaw",
"kind": "external_tool",
"description": "Local validation and orchestration agent"
}'Store the returned token locally and send it as a bearer token:
export DECK_EXTERNAL_AGENT_TOKEN='returned-token'
export DECK_API='http://127.0.0.1:8000/api/v1'Actor registration is loopback-only. External Agent Mail endpoints require Authorization: Bearer ....
Discover Participants
curl -s "$DECK_API/external/agent-mail/members" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN"The response includes each Agent Mail participant's repo, role, charter, connection status, inbox load, wake_state, wake_methods, and current Agent Team preset/slot context when present. A repository can have multiple participants when Agent Team slots represent distinct same-repo roles.
Wake states mean:
wakeable: Claude Deck has a visible wake path, currently tmux-observed Claude Code or Codex through Agent Bridge.delivered_waiting: the message can be stored and read through Agent Mail, but Claude Deck cannot wake the visible session.offline: no live session is available.
Send A Direct Message
curl -s "$DECK_API/external/agent-mail/messages" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"recipient_member_id": 2,
"subject": "Validation note",
"body_markdown": "Please check your local test result when you are next active."
}'The response includes the stored message, receipt recipients, aggregate delivery_state, and per-recipient wake results.
Request Context And Poll
curl -s "$DECK_API/external/agent-mail/context-requests" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"recipient_member_id": 2,
"subject": "Need API ownership context",
"body_markdown": "Which module owns the Agent Mail delivery path?",
"why_needed": "OpenClaw is validating a cross-repo change.",
"files_or_symbols": ["backend/app/services/agent_mail_service.py"]
}'Poll the request:
curl -s "$DECK_API/external/agent-mail/requests/17/status" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN"Or wait briefly with bounded local long-polling:
curl -s "$DECK_API/external/agent-mail/requests/17/wait?timeout_seconds=20" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN"After consuming an answer, an external actor can acknowledge its own request:
curl -s -X POST "$DECK_API/external/agent-mail/requests/17/ack" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN"Handoffs And Broadcasts
Create a handoff:
curl -s "$DECK_API/external/agent-mail/handoffs" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"recipient_member_id": 2,
"subject": "Take over deploy check",
"body_markdown": "Please continue from the failed deploy step.",
"files": ["infra/deploy.yaml"],
"next_steps": ["Inspect the failing job", "Reply with the owner and likely fix"]
}'Broadcast to one repository's members by its repo_id from the members response:
curl -s "$DECK_API/external/agent-mail/broadcasts" \
-H "Authorization: Bearer $DECK_EXTERNAL_AGENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"audience_type": "repository",
"audience_id": "repo-id-from-members-response",
"subject": "Validation run started",
"body_markdown": "OpenClaw has started a local validation pass."
}'The broadcast endpoint also accepts team_preset or work_item with the corresponding ID. It does not accept operator_global; all-member maintenance notices require operator authorization. Requests without an explicit audience are rejected.
Agent Teams Integration
External tools should use the existing Agent Teams API to launch or reuse a saved roster. Listing presets needs no credential. Planning and launching need the operator token (X-Deck-Operator-Token) or an authenticated Mail session token (X-Deck-Session-Token). A Mail session qualifies only when the backend enforces Agent Mail capability tokens (mail_capability_tokens_required=true), the session comes from MCP, and its mailbox is connected; otherwise the route returns 403 authenticated_mcp_session_required. The route authenticates a non-empty session header first, also when both headers are sent. With no session header, or an empty one, it requires the operator token. The external Agent Mail bearer token above does not authorize team planning or launch. Use the operator token only from an operator-controlled tool; do not export it into an agent environment.
curl -s "$DECK_API/agent-teams/presets"
curl -s -X POST "$DECK_API/agent-teams/presets/3/plan-launch" \
-H "X-Deck-Operator-Token: $DECK_OPERATOR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"requested_by": "OpenClaw"}'After reviewing the plan, launch with the returned plan hash:
curl -s -X POST "$DECK_API/agent-teams/presets/3/launch" \
-H "X-Deck-Operator-Token: $DECK_OPERATOR_TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"requested_by": "OpenClaw",
"confirm_plan_hash": "returned-plan-hash"
}'A stale plan returns 409 with the current plan. A Mail session cannot skip plan confirmation or use launch overrides; those need the operator token.
Once agents register through Agent Mail, use /external/agent-mail/members to discover their participant/member ids, then send context requests or handoffs through the external Agent Mail endpoints.
Same-Repo Role Routing
External orchestrators should launch same-repo multi-agent workflows through Agent Teams before sending Agent Mail requests. For example, a planner/reviewer workflow should use two slots that point at the same repository:
Planner: creates or revises the planReviewer: reviews the plan and replies with feedback
After launch, discover participants with /external/agent-mail/members and route by the returned slot participant ids. Do not rely on manually started same-repo sessions for role-based routing; without Agent Team slot context they can appear as a single repo-level participant.
If wake_state is wakeable, Deck can nudge the visible tmux session when mail arrives. If it is delivered_waiting, the message is stored but the recipient must poll or reach a hook boundary.
Safeguards
- External actor tokens are distinct from Agent Mail members and are shown by name in the Agent Mail UI.
- Non-tmux Claude Code, Codex, and Copilot sessions return
delivered_waiting; they are not falsely reported as woken. - Per-actor message rate limits return
429with aRetry-Afterheader. - This is a local trust boundary, not a general network authentication system.
