AI Agent Orchestration Dashboard for OpenClaw.
- Agent Management: Create, configure, and monitor AI agents with custom personalities (SOUL.md, USER.md, AGENTS.md)
- Mission Queue: Kanban-style task board with drag-and-drop (INBOX → ASSIGNED → IN PROGRESS → REVIEW → DONE)
- Automated Task Dispatch: Tasks automatically route to agents' OpenClaw sessions when assigned
- Completion Detection: Agents report completion via TASK_COMPLETE message, auto-moves to review
- Quality Control: Only master agent (Charlie) can approve tasks from review to done
- Agent Chat: Real-time agent-to-agent conversations - watch your team collaborate
- Live Feed: Real-time event stream showing all activity
- OpenClaw Integration: Connects to your local OpenClaw Gateway
- You assign a task → Drag task to agent in ASSIGNED column
- System auto-dispatches → Task details sent to agent's OpenClaw session
- Agent works → Task moves to IN PROGRESS, agent status becomes "working"
- Agent completes → Agent replies
TASK_COMPLETE: [summary] - Auto-review → Task moves to REVIEW, agent returns to "standby"
- Charlie approves → Master agent reviews work, moves to DONE
Agents receive tasks like this:
🔵 **NEW TASK ASSIGNED**
**Title:** Build authentication system
**Priority:** HIGH
**Task ID:** abc-123
Please work on this task. When complete, reply with:
`TASK_COMPLETE: [brief summary of what you did]`
See Agent Protocol Documentation for full details.
- Node.js 20+
- OpenClaw running locally (
openclaw gateway start) - npm or pnpm
# Clone the repository
git clone https://github.com/yourusername/mission-control.git
cd mission-control
# Install dependencies
npm install
# Configure environment
cp .env.example .env.local
# Edit .env.local with your paths and settings
# Initialize database
npm run db:seed
# Start development server
npm run devOpen http://localhost:3000 to see Mission Control.
Mission Control supports two configuration methods:
- Environment Variables (
.env.local) - Server-side config, best for deployments - Settings UI - User preferences via web interface (Settings → gear icon)
📖 For complete setup instructions, see Production Setup Guide
| Variable | Default | Description |
|---|---|---|
WORKSPACE_BASE_PATH |
~/Documents/Shared |
Base directory for workspace |
PROJECTS_PATH |
~/Documents/Shared/projects |
Project folders location |
MISSION_CONTROL_URL |
Auto-detected | API URL for orchestration |
OPENCLAW_GATEWAY_URL |
ws://127.0.0.1:18789 |
Gateway WebSocket URL |
OPENCLAW_GATEWAY_TOKEN |
(empty) | Auth token (required for remote) |
DATABASE_PATH |
./mission-control.db |
SQLite database path |
.env.local! It's gitignored by default.
mission-control/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── api/ # API routes
│ │ │ ├── agents/ # Agent CRUD
│ │ │ ├── tasks/ # Task CRUD
│ │ │ ├── conversations/ # Chat/conversations
│ │ │ ├── events/ # Live feed events
│ │ │ └── openclaw/ # OpenClaw integration
│ │ ├── layout.tsx
│ │ └── page.tsx # Main dashboard
│ ├── components/ # React components
│ │ ├── Header.tsx
│ │ ├── AgentsSidebar.tsx
│ │ ├── AgentModal.tsx
│ │ ├── MissionQueue.tsx
│ │ ├── TaskModal.tsx
│ │ ├── ChatPanel.tsx
│ │ └── LiveFeed.tsx
│ └── lib/
│ ├── db/ # SQLite database
│ ├── openclaw/ # OpenClaw client
│ ├── store.ts # Zustand state
│ └── types.ts # TypeScript types
├── mission-control.db # SQLite database (created on seed)
└── package.json
Each agent can have three markdown files defining their personality:
Defines the agent's core identity, personality traits, and communication style.
Context about the human(s) the agent works with - preferences, communication style, goals.
Awareness of other agents in the system - who they are, how to collaborate.
GET /api/agents- List all agentsPOST /api/agents- Create agentGET /api/agents/[id]- Get agentPATCH /api/agents/[id]- Update agentDELETE /api/agents/[id]- Delete agent
GET /api/tasks- List tasks (with filters)POST /api/tasks- Create taskGET /api/tasks/[id]- Get taskPATCH /api/tasks/[id]- Update taskDELETE /api/tasks/[id]- Delete task
GET /api/conversations- List conversationsPOST /api/conversations- Create conversationGET /api/conversations/[id]/messages- Get messagesPOST /api/conversations/[id]/messages- Send message
GET /api/events- List events (live feed)POST /api/events- Create event
GET /api/openclaw/status- Check Gateway connection statusGET /api/openclaw/sessions- List OpenClaw sessionsPOST /api/openclaw/sessions- Create sessionGET /api/openclaw/sessions/[id]- Get session detailsPOST /api/openclaw/sessions/[id]- Send message to sessionGET /api/openclaw/sessions/[id]/history- Get session historyPATCH /api/openclaw/sessions/[id]- Update session (mark complete)DELETE /api/openclaw/sessions/[id]- Delete a session
GET /api/agents/[id]/openclaw- Get agent's OpenClaw sessionPOST /api/agents/[id]/openclaw- Link agent to OpenClawDELETE /api/agents/[id]/openclaw- Unlink agent from OpenClaw
GET /api/tasks/[id]/activities- List task activitiesPOST /api/tasks/[id]/activities- Log activityGET /api/tasks/[id]/deliverables- List deliverablesPOST /api/tasks/[id]/deliverables- Add deliverableGET /api/tasks/[id]/subagent- List sub-agentsPOST /api/tasks/[id]/subagent- Register sub-agent
POST /api/files/upload- Upload file from remote agentGET /api/files/upload- Get upload endpoint infoPOST /api/files/reveal- Open file in FinderGET /api/files/preview- Preview HTML file
POST /api/webhooks/agent-completion- Agent completion notification
Mission Control connects to OpenClaw Gateway via WebSocket. The protocol uses RequestFrame format (not JSON-RPC).
- OpenClaw Gateway running on your local machine or accessible via network
- Authentication token - Generate one with:
openssl rand -hex 32
- Configure your Gateway to accept the token (see OpenClaw docs)
To connect from another machine:
- Install Tailscale on both machines
- On the Gateway machine, expose the port:
tailscale serve --bg 18789
- Use the Tailscale URL in your
.env.local:OPENCLAW_GATEWAY_URL=wss://your-machine.tail12345.ts.net OPENCLAW_GATEWAY_TOKEN=your-64-char-hex-token
1. WebSocket Connect
Client → Gateway: wss://gateway?token=xxx
2. Challenge (Gateway initiates)
Gateway → Client: {
"type": "event",
"event": "connect.challenge",
"payload": { "nonce": "uuid", "ts": 1234567890 }
}
3. Connect Response (Client authenticates)
Client → Gateway: {
"type": "req",
"id": "uuid",
"method": "connect",
"params": {
"minProtocol": 3,
"maxProtocol": 3,
"client": { "id": "gateway-client", "version": "1.0.0", "platform": "web", "mode": "ui" },
"auth": { "token": "xxx" }
}
}
4. Hello OK (Connection established)
Gateway → Client: {
"type": "res",
"id": "uuid",
"ok": true,
"payload": { "type": "hello-ok", "protocol": 3, ... }
}
All requests after connection use this format:
// Request
{
type: "req",
id: crypto.randomUUID(), // Unique ID for matching responses
method: "sessions.list", // Method name
params: { ... } // Method-specific parameters
}
// Success Response
{
type: "res",
id: "matching-request-id",
ok: true,
payload: { ... }
}
// Error Response
{
type: "res",
id: "matching-request-id",
ok: false,
error: { code: "ERROR_CODE", message: "Description" }
}| Method | Description |
|---|---|
sessions.list |
List all sessions |
sessions.preview |
Preview session content |
sessions.patch |
Update session |
sessions.reset |
Reset session state |
sessions.delete |
Delete session |
sessions.compact |
Compact session history |
Note: There is no
sessions.createmethod. Sessions are created automatically when you send messages.
| Error | Cause | Fix |
|---|---|---|
invalid request frame |
Wrong message format | Use type: "req" not jsonrpc: "2.0" |
invalid request frame |
Sent message before challenge | Wait for connect.challenge event first |
protocol version mismatch |
Wrong protocol version | Use minProtocol: 3, maxProtocol: 3 |
device identity required |
Missing auth token | Include token in both URL query AND params.auth |
invalid mode |
Wrong client mode | Use mode: "ui" (not dashboard) |
WebSocket error (no connect) |
Gateway not running | Start OpenClaw Gateway first |
WebSocket error (remote) |
Tailscale not connected | Check tailscale status on both machines |
These approaches were tried and do not work:
- ❌ JSON-RPC format (
jsonrpc: "2.0") - Gateway expects RequestFrame - ❌
auth.loginmethod - Useconnectmethod instead - ❌ Sending
connectimmediately on open - Must wait for challenge first - ❌ Token only in URL - Must also include in
params.auth - ❌ Token only in params - Must also include in URL query string
- ❌
mode: "dashboard"- Usemode: "ui"instead - ❌ Protocol version 1 - Use version 3
| client.id | client.mode |
|---|---|
gateway-client |
ui |
webchat-ui |
webchat |
cli |
cli |
clawdbot-control-ui |
ui |
Mission Control supports orchestration across multiple machines. For example:
- Mission Control runs on your M4 Mac (server)
- Charlie (orchestrating LLM) runs on an M1 Mac (client)
Since Charlie can't directly write to the M4's filesystem, use the File Upload API:
# 1. Charlie uploads file content via HTTP
curl -X POST http://192.168.0.216:3000/api/files/upload \
-H "Content-Type: application/json" \
-d '{
"relativePath": "project-name/index.html",
"content": "<!DOCTYPE html>..."
}'
# Response: {"path": "/Users/chris/mission-control-projects/project-name/index.html", ...}
# 2. Register the deliverable using the returned path
curl -X POST http://192.168.0.216:3000/api/tasks/{TASK_ID}/deliverables \
-H "Content-Type: application/json" \
-d '{
"deliverable_type": "file",
"title": "Homepage",
"path": "/Users/chris/mission-control-projects/project-name/index.html"
}'See HEARTBEAT.md for full orchestration instructions that can be injected into your LLM's context.
Charlie is the default master agent who coordinates all other agents. Charlie:
- Receives and triages incoming tasks
- Assigns work to appropriate agents
- Facilitates team collaboration
- Monitors progress and quality
- Reports to the human
# Run development server with hot reload
npm run dev
# Build for production
npm run build
# Start production server
npm start
# Run database migrations
npm run db:migrate
# Seed database with sample data
npm run db:seed
# Backup current database state
npm run db:backup
# Restore database from backup
npm run db:restore
# Full reset (delete + reseed)
npm run db:reset
# Lint code
npm run lint- Framework: Next.js 14 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS
- Database: SQLite (better-sqlite3)
- State: Zustand
- Drag & Drop: @hello-pangea/dnd
- Icons: Lucide React
MIT
