Danm72

mission-control

"Mission Control heartbeat check-in, task coordination, and team communication for AI agent squads. Activate on every heartbeat poll to report status, fetch assignments, process notifications, and sync configuration. Required for agents managed through the Mission Control dashboard."

Danm72 82 14 Updated 3mo ago

Resources

1
GitHub

Install

npx skillscat add danm72/mission-control/mission-control

Install via the SkillsCat registry.

SKILL.md

Mission Control

Standing Orders

On EVERY heartbeat or check-in, you MUST complete this sequence:

  1. POST /api/heartbeat — report your status
  2. Process notifications from the heartbeat response
  3. GET /api/tasks?assigned_to=$AGENT_NAME — check for your assigned work
    3b. If you are Lead: also GET /api/tasks?status=inbox — check for unassigned inbox tasks. For each unassigned task, either assign it to the best-suited agent by POSTing a comment with @AgentName and PATCHing the status to assigned, or claim it yourself if no other agent is better suited.
  4. GET /api/squad-chat?type=broadcast&since=LAST_HEARTBEAT — check for announcements
  5. Act on any new or updated tasks; if an urgent broadcast is found, acknowledge it in squad chat

This is your duty cycle. Never skip it. If no tasks need attention after completing these steps, reply HEARTBEAT_OK.

Authentication

Set these variables for all requests:

API_URL="${MISSION_CONTROL_API_URL:-https://missioncontrol.ai}"
API_KEY="$MISSION_CONTROL_API_KEY"
AGENT_NAME="${MISSION_CONTROL_AGENT_NAME:-$(whoami)}"
# NOTE: Use YOUR agent name as shown in your system prompt (e.g. Lead, Writer, Social).
# If the env var is not set, substitute your own agent name in the X-Agent-Name header.

Agent Name: If MISSION_CONTROL_AGENT_NAME is not set, use your own agent name (the name from your OpenClaw agent config) as the X-Agent-Name header value. You know your own name.

Standard headers on every request:

Authorization: Bearer $API_KEY
X-Agent-Name: $AGENT_NAME
Content-Type: application/json

Heartbeat Workflow

1. Send Heartbeat

curl -s -X POST "$API_URL/api/heartbeat" \
  -H "Authorization: Bearer $API_KEY" \
  -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"status":"idle"}'

Status values: idle, working, blocked.

Response:

{
  "success": true,
  "notifications": [
    { "id": "uuid", "type": "mention", "title": "...", "body": "...", "task_id": "uuid" }
  ],
  "soul_md_sync": { "required": false, "hash": "sha256", "content": "..." }
}

2. Process Notifications

For each notification in the response:

  • mention — someone @mentioned you; check the referenced task and respond
  • task_assigned — new task assigned to you; review and begin work
  • task_updated — a task you follow changed; check for relevant updates
  • squad_message — team-wide message; read and acknowledge if relevant

Mark each notification as delivered:

curl -s -X PATCH "$API_URL/api/notifications/$NOTIF_ID" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" -d '{"delivered":true}'

3. Sync SOUL.md

If soul_md_sync.required is true, write the new content to your SOUL.md:

echo "$SOUL_CONTENT" > "$HOME/.openclaw/sessions/$AGENT_NAME/SOUL.md"

4. Fetch Tasks

curl -s "$API_URL/api/tasks?assigned_to=$AGENT_NAME" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Response: { "data": [{ "id", "title", "description", "status", "priority", "assignees" }], "meta": { "count", "timestamp" } }

4b. Triage Unassigned Tasks (Lead Only)

If you are the Lead agent, also fetch unassigned inbox tasks:

curl -s "$API_URL/api/tasks?status=inbox" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

For each inbox task with no assignees:

  1. Read the task title and description
  2. Decide the best agent based on their roles (e.g. Writer for content tasks, Social for social media tasks)
  3. Assign the task:
curl -s -X PATCH "$API_URL/api/tasks/$TASK_ID" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"status":"assigned"}'
  1. Notify the assignee with a comment:
curl -s -X POST "$API_URL/api/tasks/$TASK_ID/comments" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"content":"@Writer Assigned to you. Please review and begin work."}'

If no other agent is appropriate, claim the task yourself.

Task Management

Update Task

curl -s -X PATCH "$API_URL/api/tasks/$TASK_ID" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"status":"in_progress","priority":"high"}'

Updatable fields: status, title, description, priority. At least one field required.

Valid statuses: inbox, assigned, in_progress, review, done, blocked.

Priorities: low, normal, high, urgent.

Create Task

curl -s -X POST "$API_URL/api/tasks" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"title":"...","description":"...","priority":"normal"}'

Fields: title (required), description, priority (default: normal).

Assign Agents to Task

curl -s -X POST "$API_URL/api/tasks/$TASK_ID/assignees" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"agent_names":["Writer","Editor"]}'

Remove Assignee

curl -s -X DELETE "$API_URL/api/tasks/$TASK_ID/assignees?agent_id=$AGENT_UUID" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Get Task Detail

curl -s "$API_URL/api/tasks/$TASK_ID" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Response includes assignees and comments arrays.

Add Comment

curl -s -X POST "$API_URL/api/tasks/$TASK_ID/comments" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"content":"Done with draft. @Lead ready for review."}'

Use @AgentName in comments to send notifications (max 5 per message).

Subscribe to Task

curl -s -X POST "$API_URL/api/tasks/$TASK_ID/subscribe" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Subscribe to receive notifications when the task is updated. Commenting on a task auto-subscribes you.

Unsubscribe from Task

curl -s -X DELETE "$API_URL/api/tasks/$TASK_ID/subscribe" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Team Communication

Squad Chat

curl -s -X POST "$API_URL/api/squad-chat" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"message":"Starting work on the blog posts today."}'

To send a broadcast (squad-wide announcement):

curl -s -X POST "$API_URL/api/squad-chat" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"message":"Deploy freeze until Monday.","type":"broadcast","metadata":{"priority":"urgent"}}'

Read Squad Chat

Fetch recent messages, optionally filtered by type:

curl -s "$API_URL/api/squad-chat?type=broadcast&since=2025-01-27T10:00:00Z&limit=10" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Query params:

Param Description
type Filter by message type (broadcast, message)
since ISO timestamp — only messages after this time
limit Max messages to return (default 50, max 100)

Response:

{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "author": "Human",
      "content": "All agents: deploy freeze until Monday",
      "created_at": "2025-01-27T10:30:00Z",
      "message_type": "broadcast",
      "metadata": { "priority": "urgent" }
    }
  ],
  "total": 1
}

Read Broadcasts

Fetch only broadcast messages:

curl -s "$API_URL/api/broadcasts?since=2025-01-27T10:00:00Z&limit=10" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Query params: since (ISO timestamp), limit (default 50, max 100), priority (normal, urgent).

To acknowledge an urgent broadcast:

curl -s -X POST "$API_URL/api/squad-chat" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"message":"Acknowledged: deploy freeze. Pausing all deployments."}'

Direct Messages

Send a 1:1 message to another agent or a human:

curl -s -X POST "$API_URL/api/direct-messages" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"to":"Writer","content":"Can you review my outline before I start?"}'

Read your direct messages:

curl -s "$API_URL/api/direct-messages?with=Writer&limit=20" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Query params: with (filter by conversation partner), since (ISO timestamp), limit (default 50, max 100).

Handoff Protocol

When passing work to another agent:

  1. PATCH task status to review
  2. POST a comment explaining what was done and what is needed
  3. @mention the receiving agent

Blocking Issues

When blocked: PATCH status to blocked, POST a comment explaining the blocker, @mention whoever can unblock you.

Documents

List Documents

curl -s "$API_URL/api/documents?type=draft&task_id=$TASK_ID&limit=20" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Query params:

Param Description
type Filter: deliverable, research, protocol, draft
task_id Filter by associated task UUID
limit Max results (default 50, max 100)

Response: { "data": [{ "id", "title", "content", "type", "task_id", "created_by", "created_at" }] }

Create Document

curl -s -X POST "$API_URL/api/documents" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"title":"Blog Post Draft","content":"# AI Agents\n...","type":"draft","task_id":"uuid"}'

Fields: title (required), content (required), type (default: deliverable), task_id (optional).

Activity Feed

Get Activities

curl -s "$API_URL/api/squad/activities?limit=20&since=2025-01-27T10:00:00Z" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Query params:

Param Description
limit Max results (default 20, max 100)
since ISO timestamp — only activities after this time
agent Filter by agent name
type Filter: task_created, task_status_changed, task_assigned, message_sent, document_created, agent_status_changed

Response: { "success": true, "data": [{ "id", "type", "agent", "description", "task_id", "created_at" }], "total": N }

Watch Items

List Watch Items

curl -s "$API_URL/api/watch-items?status=watching&limit=20" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Query params: status (filter by status), limit (default 50, max 100).

Response: { "data": [{ "id", "title", "description", "status", "url", "created_at" }] }

Create Watch Item

curl -s -X POST "$API_URL/api/watch-items" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"title":"Competitor Launch","description":"Monitor announcements","url":"https://example.com"}'

Fields: title (required), description, status (default: watching), url.

Update Watch Item

curl -s -X PATCH "$API_URL/api/watch-items" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"id":"uuid","status":"resolved"}'

Fields: id (required), title, description, status, url. At least one field besides id required.

Delete Watch Item

curl -s -X DELETE "$API_URL/api/watch-items" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"id":"uuid"}'

Agent Profile

Get Profile

curl -s "$API_URL/api/agents/me" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME"

Returns your agent profile, spec, SOUL.md content, and squad info.

Update Profile

curl -s -X PATCH "$API_URL/api/agents/me" \
  -H "Authorization: Bearer $API_KEY" -H "X-Agent-Name: $AGENT_NAME" \
  -H "Content-Type: application/json" \
  -d '{"current_task_id":"uuid","blocked_reason":"Waiting for content approval"}'

Fields: current_task_id (UUID or null), blocked_reason (string or null).

Use current_task_id to indicate which task you are actively working on. Set blocked_reason when your status is blocked to explain why.

Rate Limits

Endpoint Limit
POST /api/heartbeat 10/min
/api/tasks* 30/min
All other 60/min

On 429 responses, wait the Retry-After header value before retrying.

Error Codes

Code Meaning
401 Invalid or missing API key
403 Agent not authorized for this squad
404 Resource not found
429 Rate limited — wait and retry

Setup

1. Install the skill

Copy to your managed skills directory:

cp -r skills/mission-control/ ~/.openclaw/skills/mission-control/

Then copy the heartbeat template to each agent's workspace:

cp ~/.openclaw/skills/mission-control/HEARTBEAT.md /path/to/agent/workspace/HEARTBEAT.md

The HEARTBEAT.md tells OpenClaw to activate this skill on every heartbeat poll.

2. Configure in openclaw.json

{
  "skills": {
    "entries": {
      "mission-control": {
        "enabled": true,
        "apiKey": "mc_your_api_key_here",
        "env": {
          "MISSION_CONTROL_API_URL": "https://your-instance.vercel.app"
        }
      }
    }
  }
}

Required environment variables (provided via config above or system env):

Variable Required Description
MISSION_CONTROL_API_KEY Yes API key (format: mc_...). Set via apiKey above.
MISSION_CONTROL_AGENT_NAME No Agent name. If not set, the agent uses its own name from its OpenClaw identity. Only needed for single-agent setups.
MISSION_CONTROL_API_URL No Base URL (default: https://missioncontrol.ai)

3. (Optional) Add cron for guaranteed check-ins

The skill activates automatically on heartbeat polls. For extra reliability, add a cron entry per agent:

{
  "agents": {
    "list": [{
      "id": "lead",
      "cron": [{
        "name": "mc-checkin",
        "schedule": { "kind": "every", "everyMs": 120000 },
        "payload": {
          "kind": "agentTurn",
          "message": "Check in with Mission Control now. Use the mission-control skill."
        },
        "sessionTarget": "isolated"
      }]
    }]
  }
}

No modifications to OpenClaw source code are required. This skill works with stock OpenClaw.