# Technical Documentation: builderz-labs/mission-control

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/builderz-labs/mission-control)

### Overview (`README.md`)

<div align="center">

# Mission Control

Self-hosted control plane for operating AI agents.

Dispatch tasks, inspect runs, review failures, track spend, and coordinate agent runtimes
from one local dashboard backed by SQLite.

An open-source project by [Builderz Labs](https://builderz.dev), created and maintained by [nyk](https://nyk.dev).
It works with OpenClaw, Claude Code, Codex, and other runtimes - it is not part of any one of them.

[](https://github.com/builderz-labs/mission-control/actions/workflows/quality-gate.yml)
[](https://github.com/builderz-labs/mission-control/releases)
[](LICENSE)
[](https://github.com/sponsors/builderz-labs)

<img src="docs/mission-control-overview.png" alt="Mission Control overview dashboard with active sessions, live activity, fleet status per runtime, and the task pipeline" width="900">

</div>

> [!WARNING]
> Mission Control is alpha software. APIs, schemas, and configuration may change between
> releases. Read the [security guidance](#security-boundary) before exposing it to a network.

## Start locally

Node.js 22 or newer and pnpm are required for a source install.

```bash
git clone https://github.com/builderz-labs/mission-control.git
cd mission-control
bash install.sh --local
```

Open `http://localhost:3000/setup`, create the first admin account, then copy the API key
from Settings if an agent or script needs headless access.

The manual path is useful when you already manage Node and pnpm:

```bash
nvm use 22
pnpm install
pnpm dev
```

Windows users can run `./install.ps1 -Mode local` in PowerShell.

### Start with Docker

```bash
docker compose up
```

Or run the published multi-architecture image:

```bash
docker pull ghcr.io/builderz-labs/mission-control:latest
docker run --rm -p 3000:3000 ghcr.io/builderz-labs/mission-control:latest
```

Use the hardened Compose overlay for a network-accessible deployment:

```bash
docker compose -f docker-compose.yml -f docker-compose.hardened.yml up -d
```

The [deployment guide](docs/deployment.md) covers persistent data, TLS termination,
gateway connectivity, and standalone builds.

## What Mission Control governs

The control plane sits above agent runtimes. It does not replace their reasoning or tool
loops. It gives operators one place to see and govern the work around those loops.

| Area | Shipped surface |
|---|---|
| Tasks | Inbox, assignment, execution, review, Aegis quality gate, and completion receipts |
| Agents | Registration, presence, sessions, runtime adapters, configuration, and workspace sync |
| Operations | Activity stream, schedules, alerts, webhooks, logs, token use, and cost views |
| Knowledge | Memory browser, relationship graph, skills registry, and local skill synchronization |
| Governance | Roles, API keys, security events, trust signals, approvals, audits, and evals |
| Interfaces | Web UI, CLI, MCP server, OpenAPI-described REST API, WebSocket, and SSE |

The runtime is self-hosted and workspace-aware. SQLite stores local control-plane state.
Shared workspaces can use deployment-level runtime integrations. Strict workspaces block
those integrations until the underlying resources carry workspace ownership. A gateway is
optional for task, project, agent, scheduler, webhook, alert, and cost work; live session
messaging needs a connected runtime gateway.

## Operator field notes

Dashboards compress a sequence into current state. When a run needs review, record the
identity, task, tool call, approval, result, and verification evidence before changing it.
Keep unresolved items distinct from accepted risk.



Logs show what ran. A completion receipt or inspected artifact shows what finished.

## Pick the right fit

Use Mission Control when multiple agents or runtimes make it hard to answer who owns a
task, what executed, which result passed review, or where spend and failures accumulated.

It is probably the wrong tool when:

- one agent on one machine already stays understandable from its native CLI;
- you need a managed multi-tenant SaaS rather than a self-hosted control plane;
- you want an agent framework to define planning and tool use;
- your deployment cannot tolerate alpha schema or API changes.

Adapters and observation surfaces cover OpenClaw, Claude Code, Codex,
CrewAI, LangGraph, AutoGen, and Claude SDK workflows. Adapter depth varies by runtime; see
[agent setup](docs/agent-setup.md) and [CLI integration](docs/cli-integration.md) before
assuming feature parity.

## Connect an agent

The shortest gateway-free loop uses the REST API. Export the URL and API key shown in
Settings:

```bash
export MC_URL=http://localhost:3000
export MC_API_KEY=replace-with-your-api-key
```

Register an agent and create work:

```bash
curl -s -X POST "$MC_URL/api/agents/register" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"scout","role":"researcher"}'

curl -s -X POST "$MC_URL/api/tasks" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Review open incidents","assigned_to":"scout","priority":"medium"}'
```

The agent can then claim its queue:

```bash
curl -s "$MC_URL/api/tasks/queue?agent=scout" \
  -H "Authorization: Bearer $MC_API_KEY"
```

Continue with the [first-agent quickstart](docs/quickstart.md) for heartbeats, task results,
queue behavior, CLI equivalents, and MCP setup.

### CLI

```bash
pnpm mc agents list --json
pnpm mc tasks queue --agent scout --json
pnpm mc events watch --types agent,task
```

### MCP server

```bash
claude mcp add mission-control -- \
  env MC_URL=http://127.0.0.1:3000 MC_API_KEY=replace-with-your-api-key \
  node /absolute/path/to/mission-control/scripts/mc-mcp-server.cjs
```

Use the [CLI and MCP reference](docs/cli-agent-control.md) for the current command and tool
surface. The REST contract lives in [`openapi.json`](openapi.json). A running instance serves
the interactive reference at `/docs` and the OpenAPI JSON at `/api/docs`.

## Product surfaces

### Tasks and quality review

The task board tracks work through inbox, assignment, execution, review, quality review,
and completion. Aegis review requires an approval record before a task reaches done.



### Agents and runtimes

Agent views combine registration state, heartbeats, sessions, configuration, local runtime
discovery, and workspace files.



### Memory and skills

The memory browser and relationship graph inspect filesystem-backed memory and linked
session knowledge. The Skills Hub discovers local skill roots and scans registry content
before installation.



### Schedules and activity

Recurring task templates create dated work on a cron schedule. The activity stream combines
agent, task, and system events for operator review.





## Documentation

| Guide | Use it for |
|---|---|
| [Quickstart](docs/quickstart.md) | Register an agent and run the first task loop |
| [Agent setup](docs/agent-setup.md) | Sources, identities, SOUL files, and heartbeats |
| [Orchestration](docs/orchestration.md) | Dispatch, handoffs, workflows, and review gates |
| [CLI and MCP](docs/cli-agent-control.md) | Headless commands and agent tools |
| [CLI integration](docs/cli-integration.md) | Claude Code, Codex, and gateway-free connections |
| [Deployment](docs/deployment.md) | Local, Docker, standalone, reverse proxy, and VPS setup |
| [Security hardening](docs/SECURITY-HARDENING.md) | Network, container, CSP, and secret controls |
| [Support](SUPPORT.md) | Questions, bugs, feature proposals, and security-report routing |
| [OpenClaw compatibility](docs/openclaw-config-compatibility.md) | Config and state-directory behavior |
| [Release process](RELEASE.md) | Versioning, tags, images, and release checks |

## Architecture

```text
Web UI ─┐
CLI ────┼── auth ─ dispatch ─ events ─ policy ─ receipts
MCP ────┤                                      │
REST ───┘                         SQLite + agent runtimes
```

| Layer | Technology |
|---|---|
| Application | Next.js 16 App Router, React 19, TypeScript 5 |
| Interface | Tailwind CSS 4, Zustand, Recharts, xterm.js |
| State | SQLite through better-sqlite3, with WAL mode |
| Boundaries | REST/OpenAPI, MCP, CLI, WebSocket, and SSE |
| Access | Session cookies, API keys, Google sign-in, and role checks |
| Validation | Zod at input boundaries |
| Verification | Vitest, Playwright, ESLint, TypeScript, build, and API parity checks |

Runtime data defaults to `.data/`. Set `MISSION_CONTROL_DATA_DIR` to an absolute persistent
path for standalone deployments. The complete environment contract is in
[`.env.example`](.env.example).

## Security boundary

- Keep Mission Control on a trusted network unless a TLS reverse proxy and
  `MC_ALLOWED_HOSTS` are configured.
- Replace or securely store generated credentials before broader access.
- Use the hardened Compose overlay for production-like container deployments.
- Treat agent messages, skill packages, webhooks, and MCP content as untrusted input.
- Report vulnerabilities through [SECURITY.md](SECURITY.md), not a public issue.

Access controls and security inspection surfaces are included, but alpha status
still applies. Read [SECURITY-HARDENING.md](docs/SECURITY-HARDENING.md) before relying on a
network-accessible deployment.

## Develop

```bash
pnpm install --frozen-lockfile
pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm test:e2e
```

`pnpm quality:gate` runs the full repository gate. Useful diagnostics:

```bash
bash scripts/station-doctor.sh
bash scripts/security-audit.sh
pnpm api:parity
```

Common local failures:

| Symptom | Check |
|---|---|
| Login returns an internal error after changing Node versions | Run `pnpm rebuild better-sqlite3` |
| Docker cannot reach the gateway | Set `OPENCLAW_GATEWAY_HOST=host.docker.internal` |
| Browser WebSocket cannot connect | Leave `NEXT_PUBLIC_GATEWAY_HOST` empty or set a browser-reachable host |
| Password text after `#` disappears | Quote `AUTH_PASS` or use `AUTH_PASS_B64` |

See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution scope, coding standards, and review
expectations. Community conduct is defined in [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).

## Project status and support

Release notes live in [CHANGELOG.md](CHANGELOG.md). Open issues are the current roadmap;
the project does not promise dates for unassigned work.

- Bugs and feature proposals: [GitHub Issues](https://github.com/builderz-labs/mission-control/issues)
- Vulnerabilities: [private reporting instructions](SECURITY.md)
- Builderz Labs: [builderz.dev](https://builderz.dev)
- Maintained by [Nyk](https://nyk.dev). Sponsor [Nyk](https://github.com/sponsors/0xNyk) or [Builderz Labs](https://github.com/sponsors/builderz-labs). Follow [@nykdotdev](https://x.com/nykdotdev).

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="docs/star-history-dark.svg">
    <img src="docs/star-history-light.svg" alt="Mission Control star history" width="600">
  </picture>
</p>

## License

[MIT](LICENSE) © 2026 [Builderz Labs](https://github.com/builderz-labs)

---

### Overview (`tests/README.md`)

# E2E Tests

Playwright end-to-end specs for Mission Control API and UI.

## Running

```bash
# Start the dev server first (or let Playwright auto-start via reuseExistingServer)
pnpm dev --hostname 127.0.0.1 --port 3005

# Run all tests
pnpm test:e2e

# Run offline OpenClaw harness (no OpenClaw install required)
pnpm test:e2e:openclaw

# Run a specific spec
pnpm exec playwright test tests/tasks-crud.spec.ts
```

## Test Environment

Tests require `.env.local` with:
- `API_KEY=test-api-key-e2e-12345`
- `MC_DISABLE_RATE_LIMIT=1` (bypasses mutation/read rate limits, keeps login rate limit active)

## OpenClaw Offline Harness

The harness runs Mission Control against fixture data and mock binaries/gateway:
- fixtures: `tests/fixtures/openclaw/`
- mock CLI: `scripts/e2e-openclaw/bin/{openclaw,clawdbot}`
- mock gateway: `scripts/e2e-openclaw/mock-gateway.mjs`

Profiles:
- `pnpm test:e2e:openclaw:local` - local mode (gateway not running)
- `pnpm test:e2e:openclaw:gateway` - gateway mode (mock gateway running)

## Spec Files

### Security & Auth
- `auth-guards.spec.ts` — All API routes return 401 without auth
- `csrf-validation.spec.ts` — CSRF origin header validation
- `legacy-cookie-removed.spec.ts` — Old cookie format rejected
- `login-flow.spec.ts` — Login, session, redirect lifecycle
- `rate-limiting.spec.ts` — Login brute-force protection
- `timing-safe-auth.spec.ts` — Constant-time API key comparison
- `workspace-isolation.spec.ts` — Real HTTP denial of cross-workspace list, search, read, update, and delete attempts

### CRUD Lifecycle
- `tasks-crud.spec.ts` — Tasks POST/GET/PUT/DELETE with filters, Aegis gate
- `agents-crud.spec.ts` — Agents CRUD, lookup by name/id, admin-only delete
- `task-comments.spec.ts` — Threaded comments on tasks
- `workflows-crud.spec.ts` — Workflow template CRUD
- `webhooks-crud.spec.ts` — Webhooks with secret masking and regeneration
- `alerts-crud.spec.ts` — Alert rule CRUD with full lifecycle
- `user-management.spec.ts` — User admin CRUD

### Features
- `notifications.spec.ts` — Notification delivery and read tracking
- `quality-review.spec.ts` — Quality reviews with batch lookup
- `search-and-export.spec.ts` — Global search, data export, activity feed

### Infrastructure
- `limit-caps.spec.ts` — Endpoint limit caps enforced
- `delete-body.spec.ts` — DELETE body standardization

### Shared
- `helpers.ts` — Factory functions (`createTestTask`, `createTestAgent`, etc.) and cleanup helpers

---

### Overview (`skills/mission-control-installer/README.md`)

# Mission Control Installer Skill

Install and configure Mission Control on any Linux or macOS system.

## What This Skill Does

1. Detects the target OS and available runtimes (Docker or Node.js 20+)
2. Clones or updates the Mission Control repository
3. Generates a secure `.env` with random credentials
4. Starts the dashboard via Docker Compose or local Node.js
5. Runs an OpenClaw fleet health check (cleans stale PIDs, old logs, validates gateway)
6. Prints the access URL and admin credentials

## Usage

Run the installer script:

```bash
# Auto-detect deployment mode (prefers Docker)
bash install.sh

# Force Docker deployment
bash install.sh --docker

# Force local deployment (Node.js + pnpm)
bash install.sh --local

# Custom port
bash install.sh --port 8080

# Skip OpenClaw fleet check
bash install.sh --skip-openclaw
```

Or as a one-liner:

```bash
curl -fsSL https://raw.githubusercontent.com/builderz-labs/mission-control/main/install.sh | bash
```

## Prerequisites

- **Docker mode**: Docker Engine with Docker Compose v2
- **Local mode**: Node.js 20+, pnpm (auto-installed via corepack if missing)
- **Both**: git (to clone the repository)

## Post-Install

After installation:

1. Open `http://localhost:3000` (or your configured port)
2. Log in with the credentials printed by the installer (also in `.env`)
3. Configure your OpenClaw gateway connection in Settings
4. Register agents via the Agents panel

## Environment Configuration

The installer generates a `.env` from `.env.example` with secure random values for:

- `AUTH_PASS` — 24-character random password
- `API_KEY` — 32-character hex API key
- `AUTH_SECRET` — 32-character session secret

To regenerate credentials independently:

```bash
bash scripts/generate-env.sh --force
```

---

### Overview (`skills/mission-control-manage/README.md`)

# Mission Control Management Skill

Manage a running Mission Control instance programmatically.

## API Endpoints

All endpoints require authentication via `x-api-key` header or session cookie.

### Health Check

```bash
# Quick health status
curl -H "x-api-key: $API_KEY" http://localhost:3000/api/status?action=health

# Response: { "status": "healthy", "version": "1.3.0", "checks": [...] }
```

Possible statuses: `healthy`, `degraded`, `unhealthy`

### System Overview

```bash
# Full system status (memory, disk, sessions, processes)
curl -H "x-api-key: $API_KEY" http://localhost:3000/api/status?action=overview
```

### Diagnostics (Admin Only)

```bash
# Comprehensive diagnostics including security posture
curl -H "x-api-key: $API_KEY" http://localhost:3000/api/diagnostics

# Response includes:
# - system: node version, platform, memory, docker detection
# - security: score (0-100) with individual checks
# - database: size, WAL mode, migration version
# - gateway: configured, reachable, host/port
# - agents: total count, by status
# - retention: configured retention policies
```

### Check for Updates

```bash
curl -H "x-api-key: $API_KEY" http://localhost:3000/api/releases/check

# Response: { "updateAvailable": true, "currentVersion": "1.3.0", "latestVersion": "1.4.0", ... }
```

### Trigger Update

```bash
# Apply available update (bare-metal only; Docker returns instructions)
curl -X POST -H "x-api-key: $API_KEY" http://localhost:3000/api/releases/update
```

### Database Backup

```bash
curl -X POST -H "x-api-key: $API_KEY" http://localhost:3000/api/backup
```

### Agent Management

```bash
# List agents
curl -H "x-api-key: $API_KEY" http://localhost:3000/api/agents

# Register an agent
curl -X POST -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-agent", "type": "openclaw"}' \
  http://localhost:3000/api/agents
```

## Station Doctor

For local diagnostics without API access:

```bash
bash scripts/station-doctor.sh
```

Checks: Docker health, port availability, disk space, DB integrity, backup age.

## Common Workflows

### Automated Health Monitoring

```bash
# Check health and alert if unhealthy
STATUS=$(curl -sf -H "x-api-key: $API_KEY" http://localhost:3000/api/status?action=health | jq -r '.status')
if [ "$STATUS" != "healthy" ]; then
  echo "ALERT: Mission Control is $STATUS"
fi
```

### Pre-Upgrade Checklist

1. Check for updates: `GET /api/releases/check`
2. Create backup: `POST /api/backup`
3. Run diagnostics: `GET /api/diagnostics` (verify no active tasks)
4. Apply update: `POST /api/releases/update` (or `docker pull` + recreate for Docker)
5. Verify health: `GET /api/status?action=health`

---

### Quickstart (`docs/quickstart.md`)

# Quickstart: Your First Agent in 5 Minutes

Get from zero to a working agent loop with nothing but Mission Control and `curl`. No gateway, no OpenClaw, no extra dependencies.

## Prerequisites

- Mission Control running (`pnpm dev` or Docker)
- An admin account (visit `/setup` on first run)
- Your API key (auto-generated on first run, shown in Settings)

## Step 1: Start Mission Control

```bash
pnpm dev
```

Open http://localhost:3000 and log in. If this is your first run, visit http://localhost:3000/setup to create your admin account.

Your API key is displayed in **Settings > API Key**. Export it for the commands below:

```bash
export MC_URL=http://localhost:3000
export MC_API_KEY=your-api-key
```

## Step 2: Register an Agent

Agents can self-register via the API. This is how autonomous agents announce themselves to Mission Control:

```bash
curl -s -X POST "$MC_URL/api/agents/register" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "scout", "role": "researcher"}' | jq
```

Expected response:

```json
{
  "agent": {
    "id": 1,
    "name": "scout",
    "role": "researcher",
    "status": "idle",
    "created_at": 1711234567
  },
  "registered": true,
  "message": "Agent registered successfully"
}
```

Note the `id` — you'll need it for heartbeats. The registration is idempotent: calling it again with the same name just updates the agent's status to `idle`.

**Valid roles**: `coder`, `reviewer`, `tester`, `devops`, `researcher`, `assistant`, `agent`

## Step 3: Create a Task

```bash
curl -s -X POST "$MC_URL/api/tasks" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Research competitor pricing",
    "description": "Find pricing pages for the top 3 competitors and summarize their tiers.",
    "priority": "medium",
    "assigned_to": "scout"
  }' | jq
```

Expected response:

```json
{
  "task": {
    "id": 1,
    "title": "Research competitor pricing",
    "status": "assigned",
    "priority": "medium",
    "assigned_to": "scout",
    "tags": [],
    "metadata": {}
  }
}
```

The task starts in `assigned` status because you specified `assigned_to`. If you omit it, the task goes to `inbox` for manual triage.

## Step 4: Poll the Task Queue

This is how your agent picks up work. The queue endpoint atomically claims the highest-priority available task:

```bash
curl -s "$MC_URL/api/tasks/queue?agent=scout" \
  -H "Authorization: Bearer $MC_API_KEY" | jq
```

Expected response:

```json
{
  "task": {
    "id": 1,
    "title": "Research competitor pricing",
    "status": "in_progress",
    "assigned_to": "scout"
  },
  "reason": "assigned",
  "agent": "scout",
  "timestamp": 1711234600
}
```

The task status automatically moved from `assigned` to `in_progress`. The `reason` field tells you why this task was returned:

| Reason | Meaning |
|--------|---------|
| `assigned` | Claimed a new task from the queue |
| `continue_current` | Agent already has a task in progress |
| `at_capacity` | Agent is at max concurrent tasks |
| `no_tasks_available` | Nothing in the queue for this agent |

## Step 5: Complete the Task

When your agent finishes work, update the task status and add a resolution:

```bash
curl -s -X PUT "$MC_URL/api/tasks/1" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "done",
    "resolution": "Found pricing for Acme ($29/49/99), Widget Corp ($19/39/79), and Gadget Inc ($25/50/100). All use 3-tier SaaS model. Summary doc attached."
  }' | jq
```

## Step 6: Send a Heartbeat

Heartbeats tell Mission Control your agent is alive. Without them, agents are marked offline after 10 minutes:

```bash
curl -s -X POST "$MC_URL/api/agents/1/heartbeat" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}' | jq
```

Expected response:

```json
{
  "success": true,
  "token_recorded": false,
  "work_items": [],
  "timestamp": 1711234700
}
```

In a real agent, you'd send heartbeats every 30 seconds in a background loop. The `work_items` array returns any pending tasks, mentions, or notifications.

## The Agent Loop

Here's the complete pattern your agent should follow:

```
┌─────────────────────────────────┐
│  1. Register with MC            │
│     POST /api/agents/register   │
└──────────────┬──────────────────┘
               │
               v
┌─────────────────────────────────┐
│  2. Poll for work               │◄──────┐
│     GET /api/tasks/queue        │       │
└──────────────┬──────────────────┘       │
               │                          │
               v                          │
┌─────────────────────────────────┐       │
│  3. Do the work                 │       │
│     (your agent logic here)     │       │
└──────────────┬──────────────────┘       │
               │                          │
               v                          │
┌─────────────────────────────────┐       │
│  4. Report result               │       │
│     PUT /api/tasks/{id}         │       │
└──────────────┬──────────────────┘       │
               │                          │
               v                          │
┌─────────────────────────────────┐       │
│  5. Heartbeat + repeat          │───────┘
│     POST /api/agents/{id}/hb    │
└─────────────────────────────────┘
```

## Using the CLI Instead

If you prefer the CLI over `curl`, the same flow works with `pnpm mc`:

```bash
# List agents
node scripts/mc-cli.cjs agents list --json

# Create an agent
node scripts/mc-cli.cjs agents create --name scout --role researcher --json

# Create a task
node scripts/mc-cli.cjs tasks create --title "Research competitors" --body '{"assigned_to":"scout","priority":"medium"}' --json

# Poll the queue
node scripts/mc-cli.cjs tasks queue --agent scout --json

# Watch events in real time
node scripts/mc-cli.cjs events watch --types task,agent
```

See [CLI Reference](cli-agent-control.md) for the full command list.

## Using the MCP Server (for Claude Code agents)

For agents built with Claude Code, the MCP server is the recommended integration:

```bash
claude mcp add mission-control -- node /path/to/mission-control/scripts/mc-mcp-server.cjs
```

Set `MC_URL` and `MC_API_KEY` in your environment. The MCP server exposes 35+ tools for agents, tasks, sessions, memory, and more. See [CLI Integration](cli-integration.md) for details.

## What's Next?

- **[Agent Setup Guide](agent-setup.md)** — Configure SOUL personalities, agent sources, and heartbeat settings
- **[Orchestration Patterns](orchestration.md)** — Multi-agent workflows, auto-dispatch, quality review gates
- **[CLI Reference](cli-agent-control.md)** — Full CLI command reference
- **[CLI Integration](cli-integration.md)** — Direct CLI and gateway-free connections
- **[Deployment Guide](deployment.md)** — Production deployment options

---

### SCREENSHOT GUIDE (`docs/SCREENSHOT-GUIDE.md`)

# Screenshot Guide

This document explains how to capture and review public screenshots without publishing
operator data. Treat every screenshot as a public release artifact.

## Screenshots in the README

The README uses conceptual artwork by default. Product screenshots may be added only when
they come from a disposable demo instance and pass the privacy review below.

## When to Refresh

Screenshots should be updated when:

- A new page, panel, or major UI component is added
- An existing page layout changes noticeably
- The color scheme or branding updates
- A GitHub Actions `screenshot-drift` label is applied to a PR (see [automation](#automation))

## How to Take New Screenshots

### Prerequisites

- Mission Control running against a new disposable database (`pnpm dev` or Docker)
- Browser with at least 1440×900 viewport recommended

### Steps

1. **Start a disposable demo instance.** Never capture an operator or production database.

   ```bash
   pnpm dev
   # or
   docker compose up
   ```

2. **Seed synthetic data only.** Use fictional names and values that cannot be mistaken for
   production claims.

   Populate the demo through the UI or a reviewed fixture script. Do not copy an existing
   database into the demo environment.

3. **Before capture, remove private state.** The frame must contain no real names, handles,
   email addresses, IDs, tokens, hostnames, paths, workspace names, sessions, logs, costs,
   alerts, timestamps, avatars, notifications, or browser profile chrome.

4. **Crop and optimise** to reduce file size:

   ```bash
   # macOS
   pngcrush -reduce -brute input.png output.png

   # Linux
   optipng -o5 input.png
   # or
   pngquant --quality=80-95 --output output.png input.png
   ```

5. **Review the final pixels at full resolution.** A second reviewer should inspect every
   visible label and value. Strip image metadata, then add the approved file under `docs/`.

   ```bash
   cp ~/Downloads/sanitized-demo.png docs/mission-control-demo.png
   git add docs/
   git commit -m "docs: refresh README screenshots"
   ```

## Automation

The repository has a GitHub Actions workflow (`.github/workflows/screenshot-drift.yml`) that:

- Detects changes to files under `src/app/`, `src/components/`, and `public/`
- Adds a `screenshot-drift` label to the PR as a reminder
- Posts a checklist comment listing which screenshots may need updating

This does **not** auto-capture screenshots — it just flags the PR so a human can decide whether the change is visually significant enough to warrant a refresh.

## Tips

- Use a consistent browser zoom level (100%) and window size
- Use a clean browser profile and hide bookmarks, extensions, account controls, and dev tools
- Light mode and dark mode screenshots can coexist — add a `*-dark.png` variant if useful
- Prefer PNG for UI screenshots (lossless); JPEG for photos/illustrations
- Do not blur or crop private data as the primary safeguard; regenerate the screenshot from
  synthetic state instead

---

### SECURITY HARDENING (`docs/SECURITY-HARDENING.md`)

# Security Hardening Guide

Comprehensive security hardening guide for Mission Control and OpenClaw Gateway deployments.

## Quick Assessment

Run the automated security audit:

```bash
bash scripts/security-audit.sh        # Check .env and configuration
bash scripts/station-doctor.sh         # Check runtime health
```

Or use the diagnostics API (admin only):

```bash
curl -H "x-api-key: $API_KEY" http://localhost:3000/api/diagnostics
curl -H "x-api-key: $API_KEY" http://localhost:3000/api/security-audit?timeframe=day
```

The `posture.score` field (0-100) gives a quick posture assessment. The **Security Audit Panel** (`/security` in the dashboard) provides a full real-time view with timeline charts, agent trust scores, and eval results.

---

## Mission Control Hardening

### 1. Credentials

**Generate strong credentials** using the included script:

```bash
bash scripts/generate-env.sh           # Generates .env with random secrets
chmod 600 .env                          # Lock down permissions
```

The installer (`install.sh`) does this automatically. If you set up manually, ensure:

- `AUTH_PASS` is 12+ characters, not a dictionary word
- `API_KEY` is 32+ hex characters
- `AUTH_SECRET` is a unique random string
- `.env` file permissions are `600`

### 2. Network Access Control

Mission Control uses a host allowlist in production:

```env
# Only allow connections from these hosts (comma-separated)
MC_ALLOWED_HOSTS=localhost,127.0.0.1

# For Tailscale: MC_ALLOWED_HOSTS=localhost,127.0.0.1,100.*
# For a domain: MC_ALLOWED_HOSTS=mc.example.com,localhost

# NEVER set this in production:
# MC_ALLOW_ANY_HOST=1
```

Deploy behind a reverse proxy with TLS (Caddy, nginx, Tailscale Funnel) for any network-accessible deployment.

### 3. HTTPS & Cookies

For HTTPS deployments:

```env
MC_COOKIE_SECURE=1           # Cookies only sent over HTTPS
MC_COOKIE_SAMESITE=strict    # CSRF protection
MC_ENABLE_HSTS=1             # HTTP Strict Transport Security
```

### 4. Rate Limiting

Rate limiting is enabled by default:

| Endpoint Type | Limit |
|--------------|-------|
| Login | 5 attempts/min (always active) |
| Mutations | 60 requests/min |
| Reads | 120 requests/min |
| Heavy operations | 10 requests/min |
| Agent heartbeat | 30/min per agent |
| Agent task polling | 20/min per agent |

Never set `MC_DISABLE_RATE_LIMIT=1` in production.

### 5. Docker Hardening

Use the production compose overlay:

```bash
docker compose -f docker-compose.yml -f docker-compose.hardened.yml up -d
```

This enables:
- **Read-only filesystem** with tmpfs for `/tmp` and `/app/.next/cache`
- **Capability dropping** — all Linux capabilities dropped, only `NET_BIND_SERVICE` retained
- **No new privileges** — prevents privilege escalation
- **PID limit** — prevents fork bombs
- **Memory/CPU limits** — prevents resource exhaustion
- **Log rotation** — prevents disk filling from verbose logging
- **HSTS, secure cookies** — forced via environment

### 6. Security Headers

Mission Control sets these headers automatically:

| Header | Value |
|--------|-------|
| `Content-Security-Policy` | `default-src 'self'; script-src 'self' 'nonce-<per-request>' 'strict-dynamic'; style-src 'self' 'nonce-<per-request>'` |
| `X-Frame-Options` | `DENY` |
| `X-Content-Type-Options` | `nosniff` |
| `Referrer-Policy` | `strict-origin-when-cross-origin` |
| `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` |
| `X-Request-Id` | Unique per-request UUID for log correlation |
| `Strict-Transport-Security` | Set when `MC_ENABLE_HSTS=1` |

### 7. Audit Logging

All security-relevant events are logged to the audit trail:

- Login attempts (success and failure)
- Task mutations
- User management actions
- Settings changes
- Update operations

Additionally, the **security event system** automatically logs:

- Auth failures (invalid passwords, expired tokens, access denials)
- Rate limit hits (429 responses with IP/agent correlation)
- Injection attempts (prompt injection, command injection, exfiltration)
- Secret exposures (AWS keys, GitHub tokens, Stripe keys, JWTs, private keys detected in agent messages)
- MCP tool calls (agent, tool, duration, success/failure)

These events feed into the **Security Audit Panel** (`/security`) which provides:

- **Posture score** (0-100) with level badges (hardened/secure/needs-attention/at-risk)
- **Agent trust scores** — weighted calculation based on auth failures, injection attempts, and task success rates
- **MCP call audit** — tool-use frequency, success/failure rates per agent
- **Timeline visualization** — event density over selected timeframe

Configure retention: `MC_RETAIN_AUDIT_DAYS=365` (default: 1 year).

### 8. Hook Profiles

Security strictness is tunable via hook profiles in Settings > Security Profiles:

| Profile | Secret Scanning | MCP Auditing | Block on Secrets | Rate Limit Multiplier |
|---------|----------------|--------------|------------------|----------------------|
| **minimal** | Off | Off | No | 2x (relaxed) |
| **standard** (default) | On | On | No | 1x |
| **strict** | On | On | Yes (blocks messages) | 0.5x (tighter) |

Set via the Settings panel or the `hook_profile` key in the settings API.

### 9. Agent Eval Framework

The four-layer eval stack helps detect degrading agent quality:

- **Output evals** — score task completion against golden datasets
- **Trace evals** — convergence scoring (>3.0 indicates looping behavior)
- **Component evals** — tool reliability from MCP call logs (p50/p95/p99 latency)
- **Drift detection** — 10% threshold vs 4-week rolling baseline triggers alerts

Access via `/api/agents/evals` or the Security Audit Panel's eval section.

### 10. Data Retention

```env
MC_RETAIN_ACTIVITIES_DAYS=90       # Activity feed
MC_RETAIN_AUDIT_DAYS=365           # Security audit trail
MC_RETAIN_LOGS_DAYS=30             # Application logs
MC_RETAIN_NOTIFICATIONS_DAYS=60    # Notifications
MC_RETAIN_PIPELINE_RUNS_DAYS=90    # Pipeline logs
MC_RETAIN_TOKEN_USAGE_DAYS=90      # Token/cost records
MC_RETAIN_GATEWAY_SESSIONS_DAYS=90 # Gateway session history
```

### 11. Runtime Installer Integrity

Dashboard-triggered OpenClaw and Hermes installations execute third-party
shell installers. Local runtime installation is disabled by default. Enable it
only after reviewing the source and rollback path. Mission Control also
requires an operator-approved SHA-256 digest before either remote script can
run:

```env
MC_ENABLE_RUNTIME_INSTALLS=1
MC_OPENCLAW_INSTALLER_SHA256=<64 lowercase hex characters>
MC_HERMES_INSTALLER_SHA256=<64 lowercase hex characters>
# Required only for per-user installs from the super-admin organization flow:
MC_OPENCLAW_GIT_COMMIT=<reviewed 40-character commit SHA>
MC_CLAUDE_CODE_VERSION=<exact semver>
MC_CODEX_VERSION=<exact semver>
```

Download the installer separately through a trusted channel, inspect it, and
calculate its digest with `sha256sum install.sh` (Linux) or
`shasum -a 256 install.sh` (macOS). If the publisher changes the installer,
the dashboard install fails closed until you review the new bytes and update
the configured digest. Regex and optional AI review remain defense-in-depth;
they do not replace provenance verification.

---

## OpenClaw Gateway Hardening

Mission Control acts as the mothership for your OpenClaw fleet. The installer automatically checks and repairs common OpenClaw configuration issues.

### 1. Network Security

- **Never expose the gateway publicly.** It runs on port 18789 by default.
- **Bind to localhost:** Set `gateway.bind: "loopback"` in `openclaw.json`.
- **Use SSH tunneling or Tailscale** for remote access.
- **Docker users:** Be aware that Docker can bypass UFW rules. Use `DOCKER-USER` chain rules.

### 2. Authentication

- **Always enable gateway auth** with a strong random token.
- Generate: `openclaw doctor --generate-gateway-token`
- Store in `OPENCLAW_GATEWAY_TOKEN` env var (never in `NEXT_PUBLIC_*` variables).
- Rotate regularly.

### 3. Hardened Gateway Configuration

```json
{
  "gateway": {
    "mode": "local",
    "bind": "loopback",
    "auth": {
      "mode": "token",
      "token": "replace-with-long-random-token"
    }
  },
  "session": {
    "dmScope": "per-channel-peer"
  },
  "tools": {
    "profile": "messaging",
    "deny": ["group:automation", "group:runtime", "group:fs", "sessions_spawn", "sessions_send"],
    "fs": { "workspaceOnly": true },
    "exec": { "security": "deny", "ask": "always" }
  },
  "elevated": { "enabled": false }
}
```

### 4. File Permissions

```bash
chmod 700 ~/.openclaw
chmod 600 ~/.openclaw/openclaw.json
chmod 600 ~/.openclaw/credentials/*
```

### 5. Tool Security

- Apply the principle of least privilege — only grant tools the agent needs.
- Audit third-party skills before installing (Mission Control's Skills Hub runs automatic security scans).
- Run agents processing untrusted content in a sandbox with a minimal toolset.

### 6. Monitoring

- Enable comprehensive logging: `logging.redactSensitive: "tools"`
- Store logs separately where agents cannot modify them.
- Use Mission Control's diagnostics API to monitor gateway health.
- Have an incident response plan: stop gateway, revoke API keys, review audit logs.

### 7. Known CVEs

Keep OpenClaw updated. Notable past vulnerabilities:

| CVE | Severity | Description | Fixed In |
|-----|----------|-------------|----------|
| CVE-2026-25253 | Critical | RCE via Control UI token hijack | v2026.1.29 |
| CVE-2026-26327 | High | Auth bypass via gateway spoofing | v2026.2.25 |
| CVE-2026-26322 | High | SSRF | v2026.2.25 |
| CVE-2026-26329 | High | Path traversal | v2026.2.25 |
| CVE-2026-26319 | Medium | Missing webhook auth | v2026.2.25 |

---

## Deployment Architecture

For production, the recommended architecture is:

```
Internet
  |
[Reverse Proxy (Caddy/nginx) + TLS]
  |
[Mission Control :3000] ---- [SQLite .data/]
  |
[OpenClaw Gateway :18789 (localhost only)]
  |
[Agent Workspaces]
```

- Reverse proxy handles TLS termination, rate limiting, and access control
- Mission Control listens on localhost or a private network
- OpenClaw Gateway is bound to loopback only
- Agent workspaces are isolated per-agent directories

---

## Agent Auth: Least-Privilege Key Guidance

### The Problem

The global API key (`API_KEY` env var) grants full `admin` access. When agents use it, they can:
- Create/delete other agents
- Modify any task or project
- Rotate the API key itself
- Access all workspaces

This violates least-privilege. A compromised agent session leaks admin access.

### Recommended: Agent-Scoped Keys

Create per-agent keys with limited scopes:

```bash
# Create a scoped key for agent "Aegis" (via CLI)
pnpm mc raw --method POST --path /api/agents/5/keys --body '{
  "name": "aegis-worker",
  "scopes": ["viewer", "agent:self", "agent:diagnostics", "tasks:write"],
  "expires_in_days": 30
}' --json
```

Scoped keys:
- Can only act as the agent they belong to (no cross-agent access)
- Have explicit scope lists (viewer, agent:self, tasks:write, etc.)
- Auto-expire after a set period
- Can be revoked without affecting other agents
- Are logged separately in the audit trail

### Auth Hierarchy

| Method | Role | Use Case |
|--------|------|----------|
| Agent-scoped key (`mca_...`) | Per-scope | Autonomous agents (recommended) |
| Global API key | admin | Admin scripts, CI/CD, initial setup |
| Session cookie | Per-user role | Human operators via web UI |
| Proxy header | Per-user role | SSO/gateway-authenticated users |

### Monitoring Global Key Usage

Mission Control logs a security event (`global_api_key_used`) every time the global API key is used. Monitor these in the audit log:

```bash
pnpm mc raw --method GET --path '/api/security-audit?event_type=global_api_key_used&timeframe=day' --json
```

Goal: drive global key usage to zero in production by replacing with scoped agent keys.

### Rate Limiting by Agent Identity

Agent-facing endpoints use per-agent rate limiters (keyed by `x-agent-name` header):
- Heartbeat: 30/min per agent
- Task polling: 20/min per agent
- Self-registration: 5/min per IP

This prevents a runaway agent from consuming the entire rate limit budget.

---

## Rate Limit Backend Strategy

Current: in-memory `Map` per process (suitable for single-instance deployments).

For multi-instance deployments, the rate limiter supports a pluggable backend via the `createRateLimiter` factory. Future options:
- **Redis**: shared state across instances (use Upstash or self-hosted)
- **SQLite WAL**: leverage the existing DB for cross-process coordination
- **Edge KV**: for edge-deployed instances

The current implementation includes:
- Periodic cleanup (60s interval)
- Capacity-bounded maps (default 10K entries, LRU eviction)
- Trusted proxy IP parsing (`MC_TRUSTED_PROXIES`)

No action needed for single-instance deployments. For multi-instance, implement a custom `RateLimitStore` interface when scaling beyond 1 node.

---

### Agent Setup (`docs/agent-setup.md`)

# Agent Setup Guide

This guide covers everything you need to configure agents in Mission Control: registration methods, SOUL personalities, working files, configuration, and liveness monitoring.

## Agent Registration

There are three ways to register agents with Mission Control.

### Method 1: API Self-Registration (Recommended for Autonomous Agents)

Agents register themselves at startup. This is the simplest path and requires no manual setup:

```bash
curl -X POST http://localhost:3000/api/agents/register \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "scout",
    "role": "researcher",
    "capabilities": ["web-search", "summarization"],
    "framework": "claude-sdk"
  }'
```

**Name rules**: 1-63 characters, alphanumeric plus `.`, `-`, `_`. Must start with a letter or digit.

**Valid roles**: `coder`, `reviewer`, `tester`, `devops`, `researcher`, `assistant`, `agent`

The endpoint is idempotent — registering the same name again updates the agent's status to `idle` and refreshes `last_seen`. Rate-limited to 5 registrations per minute per IP.

### Method 2: Manual Creation (UI or API)

Create agents through the dashboard UI or the API:

```bash
curl -X POST http://localhost:3000/api/agents \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "aegis",
    "role": "reviewer",
    "status": "offline",
    "soul_content": "You are Aegis, the quality reviewer...",
    "config": {
      "dispatchModel": "9router/cc/claude-opus-4-6",
      "openclawId": "aegis"
    }
  }'
```

This requires `operator` role and supports additional fields like `soul_content`, `config`, and `template`.

### Method 3: Config Sync (OpenClaw or Local Discovery)

Mission Control can auto-discover agents from:

**OpenClaw config sync** — Reads agents from your `openclaw.json` file:

```bash
curl -X POST http://localhost:3000/api/agents/sync \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source": "config"}'
```

Set `OPENCLAW_CONFIG_PATH` to point to your `openclaw.json`.

**Local agent discovery** — Scans standard directories for agent definitions:

```bash
curl -X POST http://localhost:3000/api/agents/sync \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"source": "local"}'
```

Scanned directories:
- `~/.agents/` — Top-level agent directories or `.md` files
- `~/.codex/agents/` — Codex agent definitions
- `~/.claude/agents/` — Claude Code agent definitions
- `~/.hermes/skills/` — Hermes skill definitions

Agent directories are detected by the presence of marker files: `soul.md`, `AGENT.md`, `identity.md`, `config.json`, or `agent.json`.

**Flat markdown files** (Claude Code format) are also supported:

```markdown
---
name: my-agent
description: A research assistant
model: claude-opus-4
tools: ["read", "write", "web-search"]
---
You are a research assistant specializing in competitive analysis...
```

## SOUL.md — Agent Personality

SOUL is the personality and capability definition for an agent. It's a markdown file that gets injected into dispatch prompts, shaping how the agent approaches tasks.

### What Goes in a SOUL

A SOUL defines:
- **Identity** — Who the agent is, its name, role
- **Expertise** — What domains it specializes in
- **Behavior** — How it approaches problems, communication style
- **Constraints** — What it should avoid, limitations

### Example: Developer Agent

```markdown
# Scout — Developer

You are Scout, a senior developer agent specializing in full-stack TypeScript development.

## Expertise
- Next.js, React, Node.js
- Database design (PostgreSQL, SQLite)
- API architecture and testing

## Approach
- Read existing code before proposing changes
- Write tests alongside implementation
- Keep changes minimal and focused

## Constraints
- Never commit secrets or credentials
- Ask for clarification on ambiguous requirements
- Flag security concerns immediately
```

### Example: Researcher Agent

```markdown
# Iris — Researcher

You are Iris, a research agent focused on gathering and synthesizing information.

## Expertise
- Web research and source verification
- Competitive analysis
- Data synthesis and report writing

## Approach
- Always cite sources with URLs
- Present findings in structured format
- Distinguish facts from inferences

## Output Format
- Use bullet points for key findings
- Include a "Sources" section at the end
- Highlight actionable insights
```

### Example: Reviewer Agent

```markdown
# Aegis — Quality Reviewer

You are Aegis, the quality gate for all agent work in Mission Control.

## Role
Review completed tasks for correctness, completeness, and quality.

## Review Criteria
- Does the output address all parts of the task?
- Are there factual errors or hallucinations?
- Is the work actionable and well-structured?

## Verdict Format
Respond with EXACTLY one of:

VERDICT: APPROVED
NOTES: <brief summary>

VERDICT: REJECTED
NOTES: <specific issues to fix>
```

### Managing SOUL Content

**Read** an agent's SOUL:

```bash
curl -s http://localhost:3000/api/agents/1/soul \
  -H "Authorization: Bearer $MC_API_KEY" | jq
```

Response:

```json
{
  "soul_content": "# Scout — Developer\n...",
  "source": "workspace",
  "available_templates": ["developer", "researcher", "reviewer"],
  "updated_at": 1711234567
}
```

The `source` field tells you where the SOUL was loaded from:
- `workspace` — Read from the agent's workspace `soul.md` file on disk
- `database` — Read from the MC database (no workspace file found)
- `none` — No SOUL content set

**Update** a SOUL:

```bash
curl -X PUT http://localhost:3000/api/agents/1/soul \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"soul_content": "# Scout — Developer\n\nYou are Scout..."}'
```

**Apply a template**:

```bash
curl -X PUT http://localhost:3000/api/agents/1/soul \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template_name": "developer"}'
```

Templates support substitution variables: `{{AGENT_NAME}}`, `{{AGENT_ROLE}}`, `{{TIMESTAMP}}`.

SOUL content syncs bidirectionally — edits in the UI write back to the workspace `soul.md` file, and changes on disk are picked up on the next sync.

## WORKING.md — Runtime Scratchpad

`WORKING.md` is an agent's runtime state file. It tracks:
- Current task context
- Intermediate results
- Session notes from the agent's perspective

**Do not hand-edit WORKING.md** — it's written and managed by the agent during task execution. If you need to give an agent persistent instructions, use SOUL.md instead.

## Agent Configuration

Each agent has a JSON `config` object stored in the database. Key fields:

| Field | Type | Description |
|-------|------|-------------|
| `openclawId` | string | Gateway agent identifier (falls back to agent name) |
| `dispatchModel` | string | Model override for auto-dispatch (e.g., `9router/cc/claude-opus-4-6`) |
| `capabilities` | string[] | List of agent capabilities |
| `framework` | string | Framework that created the agent (e.g., `claude-sdk`, `crewai`) |

Example config:

```json
{
  "openclawId": "scout",
  "dispatchModel": "9router/cc/claude-sonnet-4-6",
  "capabilities": ["code-review", "testing", "documentation"],
  "framework": "claude-sdk"
}
```

Update via API:

```bash
curl -X PUT http://localhost:3000/api/agents \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "id": 1,
    "config": {
      "dispatchModel": "9router/cc/claude-opus-4-6"
    }
  }'
```

## Heartbeat and Liveness

Mission Control tracks agent health through heartbeats.

### How It Works

1. Agent sends `POST /api/agents/{id}/heartbeat` every 30 seconds
2. MC updates `status` to `idle` and refreshes `last_seen`
3. If no heartbeat for 10 minutes (configurable), agent is marked `offline`
4. Stale tasks (in_progress for 10+ min with offline agent) are requeued

### Heartbeat Request

```bash
curl -X POST http://localhost:3000/api/agents/1/heartbeat \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "token_usage": {
      "model": "claude-sonnet-4-6",
      "inputTokens": 1500,
      "outputTokens": 300
    }
  }'
```

The heartbeat response includes pending work items (assigned tasks, mentions, notifications), so agents can use it as both a keepalive and a lightweight work check.

### Agent Status Values

| Status | Meaning |
|--------|---------|
| `offline` | No recent heartbeat, agent is unreachable |
| `idle` | Online and ready for work |
| `busy` | Currently executing a task |
| `sleeping` | Paused by user (wake with `POST /api/agents/{id}/wake`) |
| `error` | Agent reported an error state |

## Agent Sources

The `source` field on each agent indicates how it was registered:

| Source | Origin |
|--------|--------|
| `manual` | Created through UI or direct API call |
| `self` | Agent self-registered via `/api/agents/register` |
| `local` | Discovered from `~/.agents/`, `~/.claude/agents/`, etc. |
| `config` | Synced from `openclaw.json` |
| `gateway` | Registered by a gateway connection |

## Agent Templates

When creating agents via API, you can specify a `template` name to pre-populate the config:

```bash
curl -X POST http://localhost:3000/api/agents \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "scout", "role": "coder", "template": "developer"}'
```

Templates define model tier, tool permissions, and default configuration. Available templates include:
- `developer` — Full coding toolset (read, write, edit, exec, bash)
- `researcher` — Read-only tools plus web and memory access
- `reviewer` — Read-only tools for code review and quality checks

## What's Next

- **[Quickstart](quickstart.md)** — 5-minute first agent tutorial
- **[Orchestration Patterns](orchestration.md)** — Multi-agent workflows, auto-dispatch, quality review
- **[CLI Reference](cli-agent-control.md)** — Full CLI command reference

---

### Cli Agent Control (`docs/cli-agent-control.md`)

# Mission Control CLI for Agent-Complete Operations (v2)

This repository includes a first-party CLI at:

- scripts/mc-cli.cjs

Designed for autonomous/headless usage first:
- API key auth support
- Profile persistence (~/.mission-control/profiles/*.json)
- Stable JSON mode (`--json`) with NDJSON for streaming
- Deterministic exit code categories
- SSE streaming for real-time event watching
- Compound subcommands for memory, soul, comments

## Quick start

1) Ensure Mission Control API is running.
2) Set environment variables or use profile flags:

- MC_URL=http://127.0.0.1:3000
- MC_API_KEY=your-key

3) Run commands:

```bash
node scripts/mc-cli.cjs agents list --json
node scripts/mc-cli.cjs tasks queue --agent Aegis --max-capacity 2 --json
node scripts/mc-cli.cjs sessions control --id <session-id> --action terminate
```

## Command groups

### auth
- login --username --password
- logout
- whoami

### agents
- list
- get --id
- create --name --role [--body '{}']
- update --id [--body '{}']
- delete --id
- wake --id
- diagnostics --id
- heartbeat --id
- attribution --id [--hours 24] [--section identity,cost] [--privileged]
- memory get --id
- memory set --id --content "..." [--append]
- memory set --id --file ./memory.md
- memory clear --id
- soul get --id
- soul set --id --content "..."
- soul set --id --file ./soul.md
- soul set --id --template operator
- soul templates --id [--template name]

### tasks
- list
- get --id
- create --title [--body '{}']
- update --id [--body '{}']
- delete --id
- queue --agent <name> [--max-capacity 2]
- broadcast --id --message "..."
- comments list --id
- comments add --id --content "..." [--parent-id 5]

### sessions
- list
- control --id --action monitor|pause|terminate
- continue --kind claude-code|codex-cli --id --prompt "..."
- transcript --kind claude-code|codex-cli|hermes --id [--limit 40] [--source]

### connect
- register --tool-name --agent-name [--body '{}']
- list
- disconnect --connection-id

### tokens
- list [--timeframe hour|day|week|month|all]
- stats [--timeframe]
- by-agent [--days 30]
- agent-costs [--timeframe]
- task-costs [--timeframe]
- trends [--timeframe]
- export [--format json|csv] [--timeframe] [--limit]
- rotate (shows current key info)
- rotate --confirm (generates new key -- admin only)

### skills
- list
- content --source --name
- check --source --name
- upsert --source --name --file ./skill.md
- delete --source --name

### cron
- list
- create/update/pause/resume/remove/run [--body '{}']

### events
- watch [--types agent,task] [--timeout-ms 3600000]

  Streams SSE events to stdout. In `--json` mode, outputs NDJSON (one JSON object per line). Press Ctrl+C to stop.

### status
- health (no auth required)
- overview
- dashboard
- gateway
- models
- capabilities

### export (admin)
- audit [--format json|csv] [--since <unix>] [--until <unix>] [--limit]
- tasks [--format json|csv] [--since] [--until] [--limit]
- activities [--format json|csv] [--since] [--until] [--limit]
- pipelines [--format json|csv] [--since] [--until] [--limit]

### raw
- raw --method GET --path /api/... [--body '{}']

## Exit code contract

- 0 success
- 2 usage error
- 3 auth error (401)
- 4 permission error (403)
- 5 network/timeout
- 6 server error (5xx)

## API contract parity gate

To detect drift between Next.js route handlers and openapi.json, use:

```bash
node scripts/check-api-contract-parity.mjs \
  --root . \
  --openapi openapi.json \
  --ignore-file scripts/api-contract-parity.ignore
```

Machine output:

```bash
node scripts/check-api-contract-parity.mjs --json
```

The checker scans `src/app/api/**/route.ts(x)`, derives operations (METHOD + /api/path), compares against OpenAPI operations, and exits non-zero on mismatch.

Baseline policy in this repo:
- `scripts/api-contract-parity.ignore` currently stores a temporary baseline of known drift.
- CI enforces no regressions beyond baseline.
- When you fix a mismatch, remove its line from ignore file in the same PR.
- Goal is monotonic burn-down to an empty ignore file.

## Next steps

- Promote script to package.json bin entry (`mc`).
- Add retry/backoff for transient failures.
- Add integration tests that run the CLI against a test server fixture.
- Add richer pagination/filter flags for list commands.

---

### Cli Integration (`docs/cli-integration.md`)

# Direct CLI Integration

Connect CLI tools (Claude Code, Codex, custom agents) directly to Mission Control without a gateway.

## Quick Start

### 1. Register a connection

```bash
curl -X POST http://localhost:3000/api/connect \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "tool_name": "claude-code",
    "tool_version": "1.0.0",
    "agent_name": "my-agent",
    "agent_role": "developer"
  }'
```

Response:

```json
{
  "connection_id": "550e8400-e29b-41d4-a716-446655440000",
  "agent_id": 42,
  "agent_name": "my-agent",
  "status": "connected",
  "sse_url": "/api/events",
  "heartbeat_url": "/api/agents/42/heartbeat",
  "token_report_url": "/api/tokens"
}
```

- If `agent_name` doesn't exist, it's auto-created.
- Previous connections for the same agent are automatically deactivated.

### 2. Heartbeat loop

Send heartbeats to stay alive and optionally report token usage:

```bash
curl -X POST http://localhost:3000/api/agents/42/heartbeat \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "connection_id": "550e8400-e29b-41d4-a716-446655440000",
    "token_usage": {
      "model": "claude-sonnet-4",
      "inputTokens": 1500,
      "outputTokens": 800
    }
  }'
```

Response includes work items (mentions, assigned tasks, notifications) plus `"token_recorded": true` if usage was reported.

Recommended heartbeat interval: **30 seconds**.

### 3. Subscribe to events (SSE)

```bash
curl -N http://localhost:3000/api/events \
  -H "x-api-key: YOUR_API_KEY"
```

Receives real-time events: task assignments, mentions, agent status changes, etc.

### 4. Report token usage

For bulk token reporting (separate from heartbeat):

```bash
curl -X POST http://localhost:3000/api/tokens \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "model": "claude-sonnet-4",
    "sessionId": "my-agent:chat",
    "inputTokens": 5000,
    "outputTokens": 2000
  }'
```

### 5. Disconnect

```bash
curl -X DELETE http://localhost:3000/api/connect \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"connection_id": "550e8400-e29b-41d4-a716-446655440000"}'
```

Sets the agent offline if no other active connections exist.

## API Reference

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| POST | `/api/connect` | operator | Register CLI connection |
| GET | `/api/connect` | viewer | List all connections |
| DELETE | `/api/connect` | operator | Disconnect by connection_id |
| POST | `/api/agents/{id}/heartbeat` | operator | Heartbeat with optional token reporting |
| GET | `/api/events` | viewer | SSE event stream |
| POST | `/api/tokens` | operator | Report token usage |

## Connection Lifecycle

```
POST /api/connect  →  Agent set online
         ↓
  Heartbeat loop (30s)  →  Reports tokens, receives work items
         ↓
DELETE /api/connect  →  Agent set offline (if no other connections)
```

## Notes

- Each agent can only have one active connection at a time. A new `POST /api/connect` for the same agent deactivates the previous connection.
- The `sessionId` format for token reporting follows `{agentName}:{chatType}` convention (e.g., `my-agent:chat`, `my-agent:cli`).
- Heartbeat responses include pending work items (assigned tasks, mentions, notifications) so CLI tools can act on them.

---

### Deployment (`docs/deployment.md`)

# Deployment Guide

## Prerequisites

- **Node.js** >= 20 (LTS recommended)
- **pnpm** (installed via corepack: `corepack enable && corepack prepare pnpm@latest --activate`)

### Ubuntu / Debian

`better-sqlite3` requires native compilation tools:

```bash
sudo apt-get update
sudo apt-get install -y python3 make g++
```

### macOS

Xcode command line tools are required:

```bash
xcode-select --install
```

## Quick Start (Development)

```bash
cp .env.example .env.local
pnpm install
pnpm dev
```

Open http://localhost:3000. Login with `AUTH_USER` / `AUTH_PASS` from your `.env.local`.

## Production (Direct)

```bash
pnpm install --frozen-lockfile
pnpm build
pnpm start
```

The `pnpm start` script binds to `0.0.0.0:3005`. Override with:

```bash
PORT=3000 pnpm start
```

**Important:** The production build bundles platform-specific native binaries. You must run `pnpm install` and `pnpm build` on the same OS and architecture as the target server. A build created on macOS will not work on Linux.

## Production (Standalone)

Use this for bare-metal deployments that run Next's standalone server directly.
This path is preferred over ad hoc `node .next/standalone/server.js` because it
syncs `.next/static` and `public/` into the standalone bundle before launch.

```bash
pnpm install --frozen-lockfile
pnpm build
pnpm start:standalone
```

For a full in-place update on the target host:

```bash
BRANCH=fix/refactor PORT=3000 pnpm deploy:standalone
```

What `deploy:standalone` does:
- fetches and fast-forwards the requested branch
- reinstalls dependencies with the lockfile
- rebuilds from a clean `.next/`
- stops the old process bound to the target port
- starts the standalone server through `scripts/start-standalone.sh`
- verifies that the rendered login page references a CSS asset and that the CSS is served as `text/css`

## Production (Docker)

Preferred operator flow (Make controls docker compose):

```bash
# 1) choose mode in .env
#    MC_MODE=prod   # or dev
#    OPENCLAW_ENABLED=1   # set 0 to run MC without OpenClaw stack

# 2) run universal verbs
make up
make restart
make down
make status
```

### Mode-aware Make workflow (minimal commands)

For day-to-day operations, see the [Daily Ops Cheatsheet](./ops-cheatsheet.md).

Use `.env` + `.env.openclaw` as the single source of truth for mode/host/port/token values.

- `MC_MODE=prod` → `docker-compose.yml`
- `MC_MODE=dev` → `docker-compose-dev.yml`
- `OPENCLAW_ENABLED=1` → `make <verb> all` includes OpenClaw
- `OPENCLAW_ENABLED=0` → `make <verb> all` manages MC only

Command grammar:

```text
make <verb> [all|mc|openclaw] [dev|prod]
```

- `all` is default scope.
- `dev` / `prod` override `MC_MODE` for one command invocation.
- Why no `--dev` / `--prod`: GNU Make consumes unknown `--xxx` tokens as Make options before Makefile goals are parsed, so mode overrides use positional tokens for deterministic behavior.
- `make restart [scope]` is deterministic and always executes `make down [scope]` followed by `make up [scope]`.
- With default `all` scope, `OPENCLAW_ENABLED=1` includes OpenClaw in both the down and up phases; `OPENCLAW_ENABLED=0` skips OpenClaw in both phases.

Primary operator commands:

| Workflow | Command |
|---|---|
| Start selected component(s) | `make up [all|mc|openclaw]` |
| Restart selected component(s) | `make restart [all|mc|openclaw]` |
| Stop selected component(s) | `make down [all|mc|openclaw]` |
| Mode + endpoint health summary | `make status [all|mc|openclaw]` |
| Refresh source/state only | `make update [all|mc|openclaw]` |
| Force rebuild selected component(s) | `make rebuild [all|mc|openclaw]` |
| Full maintenance (`update` + `rebuild` + `restart`) | `make upgrade [all|mc|openclaw]` |

Mode override examples:

```bash
make restart dev
make restart mc dev
make status openclaw
make upgrade prod
```

### `update` vs `upgrade`

- `make update [scope]`
  - Fast-forwards the current Mission Control branch from origin.
  - For `scope=all`, if `OPENCLAW_ENABLED=1`, also refreshes OpenClaw source state.
  - For `scope=openclaw`, refreshes OpenClaw source state regardless of `OPENCLAW_ENABLED`.
  - Does **not** force an MC image rebuild and does **not** force restart.

- `make upgrade [scope]`
  - Runs update + rebuild + restart for selected scope.
  - `scope=mc`: MC-only flow.
  - `scope=openclaw`: OpenClaw update flow (`make openclaw-update`).
  - `scope=all`: both flows; OpenClaw path runs when `OPENCLAW_ENABLED=1`.

Minimum `.env` / `.env.openclaw` keys for this flow:

```env
# .env
MC_MODE=prod
OPENCLAW_ENABLED=1
MC_URL_SCHEME=http
MC_HOST=127.0.0.1
MC_PORT=7012
OPENCLAW_GATEWAY_TOKEN=...
TELEGRAM_BOT_TOKEN=...
TELEGRAM_NUMERIC_USER_ID=123456789
TELEGRAM_DM_POLICY=pairing
TELEGRAM_ALLOW_FROM=
TELEGRAM_OWNER_ALLOW_FROM=
# .env.openclaw (or keep in .env)
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_CONTROL_UI_PORT=18791
OPENCLAW_GATEWAY_INTERNAL_PORT=18789
OPENCLAW_STATUS_HOST=127.0.0.1
```

```bash
docker compose up          # with gateway connectivity
docker compose --profile standalone up   # without gateway (standalone mode)
```

Or build and run manually:

```bash
docker build -t mission-control .
docker run -p 3000:3000 \
  -v mission-control-data:/app/.data \
  -e AUTH_USER=admin \
  -e AUTH_PASS=your-secure-password \
  -e API_KEY=your-api-key \
  -e OPENCLAW_GATEWAY_HOST=host.docker.internal \
  --add-host=host.docker.internal:host-gateway \
  mission-control
```

The Docker image:
- Builds from `node:22-slim` with multi-stage build
- Compiles `better-sqlite3` natively inside the container (Linux x64)
- Uses Next.js standalone output for minimal image size
- Runs as non-root user `nextjs`
- Exposes port 3000 (override with `-e PORT=8080`)

### Gateway Connectivity from Docker

MC inside Docker needs to reach the gateway running on the host. There are **two** connections:

1. **Server-side** (MC backend → gateway): Set `OPENCLAW_GATEWAY_HOST=host.docker.internal`.
   Docker Desktop (macOS/Windows) resolves this automatically. On Linux, `docker-compose.yml`
   maps it via `extra_hosts`.

2. **Browser-side** (user's browser → gateway WebSocket): When the gateway host is a
   Docker-internal name (like `host.docker.internal`), MC automatically rewrites the WebSocket
   URL to the browser's own hostname. No extra config needed for local Docker usage.
   For remote access, set `NEXT_PUBLIC_GATEWAY_HOST` to the public hostname.

If your gateway runs in **another container**, put both on the same Docker network and set
`OPENCLAW_GATEWAY_HOST` to the gateway container name.

### Local Security Scan Expectations (HTTP dev vs HTTPS prod)

For local Docker development over plain `http://`, the following defaults are expected:

- Keep `MC_COOKIE_SECURE` unset
- Keep `MC_ENABLE_HSTS` unset
- Use `OPENCLAW_GATEWAY_HOST=host.docker.internal` when MC runs in Docker and gateway runs on host

`MC_COOKIE_SECURE=1` and `MC_ENABLE_HSTS=1` are HTTPS-only hardening flags. Enabling them on plain HTTP can break login/session behavior and create misleading local warnings.

Mission Control's security scan treats `host.docker.internal` as a valid local Docker topology (not a public exposure) and should not be interpreted as a production misconfiguration by itself.

### Persistent Data

SQLite database is stored in `/app/.data/` inside the container. Mount a volume to persist data across restarts:

```bash
docker run -v /path/to/data:/app/.data ...
```

### Automatic backups

- Set `MC_AUTO_BACKUP=1` (accepts `1`/`true`/`yes`/`on`) in your `.env` to enable automatic daily backups without toggling it in the UI.
- The backup directory is created automatically when scheduled backups run, so the backup warning clears once the task executes.

### Self-contained Operator Setup (Linux host with existing Claude Code / Codex CLIs)

For an operator running MC on a Linux/Docker host who already has authenticated
`claude` / `codex` / `opencode` CLIs in `~/.local/bin`, the default
`docker-compose.yml` projects the host configuration into the container so MC
can drive those same authenticated CLIs without re-login. This path runs MC
**without** OpenClaw gateway (which is macOS-only).

What the default compose does for this case:

- **Image bakes `claude` and `codex` as a fallback** — if the host doesn't
  have them in `~/.local/bin`, the container's installed copies are used.
  The host's `~/.local/bin` comes first in `PATH`, so an authenticated host
  install transparently shadows the baked one.
- **Host home is bind-mounted** — `${HOME}/.local/bin`, `${HOME}/.bun`,
  `${HOME}/.claude`, `${HOME}/.claude.json`, and `${HOME}/.local/share/claude`
  are mounted under `/home/nextjs/...` inside the container, plus `${HOME}`
  itself and `/mnt` are mounted at the same absolute paths so file paths the
  user sees on the host work identically inside the container.
- **Container runs as uid 1000** (the slim image's existing `node` user,
  renamed `nextjs`) so bind-mounted host files (typical Linux uid 1000) are
  read/written without `chown`.

**Ports.** `docker-compose.yml` maps `${MC_PORT}` on the host to `${PORT}` in
the container. The bundled `Makefile` computes its readiness/status URL from
`MC_URL_SCHEME`, `MC_HOST`, and `MC_PORT` loaded from `.env`.

**uid mismatch.** If your host user has uid ≠ 1000 (common on macOS, or
multi-user Linux), edit `docker-compose.yml`:

```yaml
user: "$(id -u):$(id -g)"   # or hard-code your uid:gid
```

Otherwise bind-mounted files in `${HOME}` will be read-only inside the
container and Claude Code will fail to write its config.

**Memory.** The compose file sets `memory: 2G` deploy limit. The upstream
default of 512M OOM-kills MC when `/chat` opens a `node-pty` terminal and the
task-dispatch loop is running concurrently. Do not lower this limit unless
you are sure neither feature is in use.

#### Direct API dispatch (gateway-free)

When OpenClaw is not present, MC dispatches tasks via direct provider APIs.
Provider is picked by the agent's `dispatchModel` prefix:

| `dispatchModel` pattern                                          | Provider           | Auth |
|------------------------------------------------------------------|--------------------|------|
| `claude-*`, `anthropic/*`                                        | Anthropic API      | `ANTHROPIC_API_KEY` |
| `gpt-*`, `o1-*`, `o3-*`, `openai/*`                              | OpenAI API         | `OPENAI_API_KEY` |
| `local/*`, `ollama/*`, `lmstudio/*`, `litellm/*`                 | OpenAI-compatible  | `LOCAL_LLM_ENDPOINT` (+ optional `LOCAL_LLM_API_KEY`) |

The "local" provider speaks the OpenAI `/v1/chat/completions` REST shape, so
LMStudio, Ollama, vLLM, and a [liteLLM](https://github.com/BerriAI/litellm)
proxy all work behind it. For multiple local backends behind one endpoint,
run liteLLM as a sidecar container and point `LOCAL_LLM_ENDPOINT` at it.

#### Shared host Claude Code session (`MC_HOST_SESSION_MODE`)

`/chat` can drive a Claude Code session that the operator has open in a host
terminal — both processes share the same `~/.claude/projects/<encoded>/<id>.jsonl`
transcript. Pick the policy via env:

| Mode | Behaviour |
|------|-----------|
| `coexist` (default) | Both MC and the host CLI append to the jsonl. Each side picks up the other's writes on its next prompt. Possible interleaving on simultaneous writes — fine for a single operator switching between the two surfaces. |
| `block-active` | Returns `409` from `/api/sessions/continue` if the jsonl was touched in the last 60s (heuristic: a live host CLI updates mtime frequently). Forces MC to act only on idle sessions. |
| `nudge` | Same as `coexist` plus a best-effort `utimes()` on the jsonl after the reply, so a tail-watching host CLI sees a fresh mtime. |

### Production Hardening

```bash
docker compose -f docker-compose.yml -f docker-compose.hardened.yml up -d
```

This adds: JSON logging, strict hostname allowlist, secure cookies, HSTS, internal-only network.

### Host hardening (Ubuntu quick actions)

- **Firewall (ufw)**: `sudo apt-get install -y ufw && sudo ufw allow OpenSSH && sudo ufw enable && sudo ufw status`
- **Time sync (NTP)**: `timedatectl set-ntp true && timedatectl status` (ensures systemd-timesyncd is active)
- **Automatic security updates**: `sudo apt-get install -y unattended-upgrades && sudo dpkg-reconfigure -plow unattended-upgrades && sudo unattended-upgrade -d`
- **Brute-force protection (fail2ban)**: `sudo apt-get install -y fail2ban && sudo systemctl enable --now fail2ban` (tune `/etc/fail2ban/jail.local` as needed)
- **/tmp noexec**: add `tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0` to `/etc/fstab`, then `sudo mount -o remount /tmp`
- **Encrypted data (LUKS)**: create/attach a LUKS volume for data (`sudo cryptsetup luksFormat /dev/sdX && sudo cryptsetup open /dev/sdX mc-data && sudo mkfs.ext4 /dev/mapper/mc-data`) and mount it for `.data/` or backups
- **MAC framework**: keep AppArmor enabled (`sudo systemctl enable --now apparmor && sudo aa-status`); 
  Ubuntu SELinux users can install `selinux-basics selinux-policy-default` and enable per Ubuntu guidance
  - sudo apt update
  - sudo apt install selinux-basics selinux-policy-default
  - sudo selinux-activate
  - sudo reboot
  - sudo apt install policycoreutils; sestatus # check status

## Environment Variables

See `.env.example` for the full list. Key variables:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `AUTH_USER` | Yes | `admin` | Admin username (seeded on first run) |
| `AUTH_PASS` | Yes | - | Admin password |
| `AUTH_PASS_B64` | No | - | Base64-encoded admin password (overrides `AUTH_PASS` if set) |
| `API_KEY` | Yes | - | API key for headless access |
| `PORT` | No | `3005` (direct) / `3000` (Docker) | Server port |
| `OPENCLAW_HOME` | No | - | Legacy: parent home directory containing `.openclaw/`. Use `OPENCLAW_STATE_DIR` instead (see note below) |
| `OPENCLAW_STATE_DIR` | No | `~/.openclaw` | Exact path to the OpenClaw state directory. Preferred over `OPENCLAW_HOME` — avoids double-nesting when the path already ends in `.openclaw` |
| `OPENCLAW_TOOLS_PROFILE` | No | `coding` | Tool profile projected into OpenClaw config when the env var is present (compose injects the default) |
| `OPENCLAW_SECURITY_WORKSPACE_ONLY` | No | `1` | Restrict filesystem tools to the workspace when set (env-driven) |
| `OPENCLAW_SECURITY_DENY_AUTOMATION` | No | `1` | Deny automation tool group via env-driven bootstrap |
| `OPENCLAW_SECURITY_DENY_RUNTIME` | No | `1` | Deny runtime tool group via env-driven bootstrap |
| `OPENCLAW_SECURITY_DENY_FS` | No | `0` | Deny filesystem tool group (opt-in; can block file workflows) |
| `OPENCLAW_SECURITY_SANDBOX_ALL` | No | `1` | Force `agents.defaults.sandbox.mode="all"` when set (env-driven) |
| `MISSION_CONTROL_DATA_DIR` | No | `.data/` | Directory for all Mission Control data files (DB, tokens, etc.). Use an absolute path with the standalone server to survive rebuilds. |
| `MC_ALLOWED_HOSTS` | No | `localhost,127.0.0.1` | Allowed hosts in production |
| `MC_PORT` | No | `3000` | Host-side port that the bundled `docker-compose.yml` publishes the container's `PORT` on. The bundled `Makefile` expects `7012`. |
| `ANTHROPIC_API_KEY` | No (Yes for direct dispatch) | - | Used when `dispatchModel` matches `claude-*` / `anthropic/*` and no gateway is available. |
| `OPENAI_API_KEY` | No | - | Used when `dispatchModel` matches `gpt-*` / `o1-*` / `o3-*` / `openai/*`. |
| `LOCAL_LLM_ENDPOINT` | No | `http://host.docker.internal:1234/v1` | OpenAI-compatible base URL (LMStudio default shown). Override for Ollama (`:11434/v1`) or a liteLLM proxy. |
| `LOCAL_LLM_API_KEY` | No | - | Bearer token sent to `LOCAL_LLM_ENDPOINT`. Only needed for proxies that require auth (e.g. liteLLM with master key). |
| `MC_HOST_SESSION_MODE` | No | `coexist` | Policy when MC `--resumes` a host Claude Code session that may have a live CLI attached. One of `coexist`, `block-active`, `nudge`. |
| `NEXT_PUBLIC_CHAT_POLL_INTERVAL_MS` | No | `1500` (code) / `1000` (docker-compose) | `/chat` transcript poll cadence (ms) when the SSE channel drops. **Baked at build time**, so changing it requires `make rebuild`. |

> **Sandbox runtime requirement**
> 
> Enabling sandbox mode via `OPENCLAW_SECURITY_SANDBOX_ALL=1` requires Docker access. Ensure the `mc-openclaw-gateway` service bind-mounts the host Docker socket (`/var/run/docker.sock`) as shown in `docker-compose-openclaw.yml`.

> **Note — `OPENCLAW_HOME` vs `OPENCLAW_STATE_DIR`**
>
> Mission Control supports two env vars for locating OpenClaw:
>
> - `OPENCLAW_HOME` — treated as the *parent* home directory; `.openclaw` is appended automatically.
>   Setting `OPENCLAW_HOME=/root/.openclaw` will resolve to `/root/.openclaw/.openclaw` (**double-nesting bug**).
> - `OPENCLAW_STATE_DIR` — treated as the *exact* state directory path. Always prefer this.
>
> **Recommended `.env` for a standard install:**
> ```env
> OPENCLAW_STATE_DIR=/root/.openclaw
> MISSION_CONTROL_DATA_DIR=/absolute/path/to/.data
> ```
> Using an absolute path for `MISSION_CONTROL_DATA_DIR` ensures your
> database and data survive `npm run build` / standalone server rebuilds.

## Kubernetes Sidecar Deployment

When running Mission Control alongside a gateway as containers in the same pod (sidecar pattern), agents are not discovered via the filesystem. Instead, use the gateway's agent registration API.

### Architecture

```
┌──────────────── Pod ────────────────┐
│  ┌─────────┐     ┌───────────────┐  │
│  │   MC    │◄───►│   Gateway     │  │
│  │ :3000   │     │   :18789      │  │
│  └─────────┘     └───────────────┘  │
│       ▲                  ▲          │
│       │ localhost        │          │
│       └──────────────────┘          │
└─────────────────────────────────────┘
```

### Required Configuration

**Environment variables** for the MC container:

```bash
AUTH_USER=admin
AUTH_PASS=<secure-password>
API_KEY=<your-api-key>
OPENCLAW_GATEWAY_HOST=127.0.0.1
NEXT_PUBLIC_GATEWAY_PORT=18789
```

### Agent Registration

The gateway must register its agents with MC on startup. Include the `agents` array in the gateway registration request:

```bash
curl -X POST http://localhost:3000/api/gateways \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "sidecar-gateway",
    "host": "127.0.0.1",
    "port": 18789,
    "is_primary": true,
    "agents": [
      { "name": "developer-1", "role": "developer" },
      { "name": "researcher-1", "role": "researcher" }
    ]
  }'
```

To update the agent list on reconnect, use `PUT /api/gateways` with the same `agents` field.

Alternatively, each agent can register itself via the direct connection endpoint:

```bash
curl -X POST http://localhost:3000/api/connect \
  -H "Authorization: Bearer <API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "tool_name": "openclaw-gateway",
    "agent_name": "developer-1",
    "agent_role": "developer"
  }'
```

### Health Checks

Agents must send heartbeats to stay visible:

```bash
curl http://localhost:3000/api/agents/<agent-id>/heartbeat \
  -H "Authorization: Bearer <API_KEY>"
```

Without heartbeats, agents will be marked offline after 10 minutes (configurable via `general.agent_timeout_minutes` setting).

## Troubleshooting

### "Internal server error" on login / NODE_MODULE_VERSION mismatch

`better-sqlite3` is a native addon compiled for a specific Node.js version.
If you switch Node versions (e.g. via nvm), the compiled binary won't load.

```bash
pnpm rebuild better-sqlite3
```

The health endpoint (`/api/status?action=health`) will report this error explicitly.

### "Module not found: better-sqlite3"

Native compilation failed. On Ubuntu/Debian:
```bash
sudo apt-get install -y python3 make g++
rm -rf node_modules
pnpm install
```

### Docker: gateway unreachable / WebSocket not connecting

**Checklist:**

1. Verify the gateway is reachable from inside the container:
   ```bash
   docker exec mission-control curl -s http://host.docker.internal:18789
   ```

2. Check env vars are set:
   ```bash
   docker exec mission-control env | grep -i gateway
   ```
   You should see `OPENCLAW_GATEWAY_HOST=host.docker.internal`.

3. If using a **mounted `~/.openclaw`** directory, the `openclaw.json` inside may have
   `gateway.host = "127.0.0.1"` — this is the host's loopback, not reachable from the
   container. Environment variables take precedence over `openclaw.json`, so set
   `OPENCLAW_GATEWAY_HOST=host.docker.internal` in your `.env` or docker-compose.

4. **Browser WebSocket**: MC automatically rewrites Docker-internal hostnames
   (`host.docker.internal`, `host-gateway`) to the browser's hostname. If the browser
   still can't connect, set `NEXT_PUBLIC_GATEWAY_HOST` to a hostname your browser can reach.

5. **Linux-specific**: `host.docker.internal` requires Docker 20.10+. The `extra_hosts`
   entry in `docker-compose.yml` handles this. If using `docker run` directly, add
   `--add-host=host.docker.internal:host-gateway`.

### AUTH_PASS with "#" is not working

In dotenv files, `#` starts a comment unless the value is quoted.

Use one of these:
- `AUTH_PASS="my#password"`
- `AUTH_PASS_B64=$(echo -n 'my#password' | base64)`

### "pnpm-lock.yaml not found" during Docker build

If your deployment context omits `pnpm-lock.yaml`, Docker build now falls back to
`pnpm install --no-frozen-lockfile`.

For reproducible builds, include `pnpm-lock.yaml` in the build context.

### "Invalid ELF header" or "Mach-O" errors

The native binary was compiled on a different platform. Rebuild:
```bash
rm -rf node_modules .next
pnpm install
pnpm build
```

### Database locked errors

Ensure only one instance is running against the same `.data/` directory. SQLite uses WAL mode but does not support multiple writers.

### "Gateway error: origin not allowed"

Your gateway is rejecting the Mission Control browser origin. Add the Control UI origin
to your gateway config allowlist, for example:

```json
{
  "gateway": {
    "controlUi": {
      "allowedOrigins": ["http://YOUR_HOST:3000"]
    }
  }
}
```

Then restart the gateway and reconnect from Mission Control.

### "Gateway error: device identity required"

Device identity signing uses WebCrypto and requires a secure browser context.
Open Mission Control over HTTPS (or localhost), then reconnect.

### "Gateway shows offline on VPS deployment"

Browser WebSocket connections to non-standard ports (like 18789/18790) are often blocked by VPS firewall/provider rules.

Quick option:

```bash
NEXT_PUBLIC_GATEWAY_OPTIONAL=true
```

This runs Mission Control in standalone mode (core features available, live gateway streams unavailable).

Production option: reverse-proxy gateway WebSocket over 443.

nginx example:

```nginx
location /gateway-ws {
  proxy_pass http://127.0.0.1:18789;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_set_header Host $host;
  proxy_read_timeout 86400;
}
```

Then point UI to:

```bash
NEXT_PUBLIC_GATEWAY_URL=wss://your-domain.com/gateway-ws
```

Mission Control now retries common reverse-proxy websocket paths (`/gateway-ws`, `/gw`) automatically when root-path handshake fails, but setting `NEXT_PUBLIC_GATEWAY_URL` is still recommended for deterministic production behavior.

## Next Steps

Once deployed, set up your agents and orchestration:

- **[Quickstart](quickstart.md)** — Register your first agent and complete a task in 5 minutes
- **[Agent Setup](agent-setup.md)** — SOUL personalities, heartbeats, config sync, agent sources
- **[Orchestration Patterns](orchestration.md)** — Auto-dispatch, quality review, multi-agent workflows
- **[CLI Reference](cli-agent-control.md)** — Full CLI command list for headless/scripted usage

---

### Openclaw Config Compatibility (`docs/openclaw-config-compatibility.md`)

# OpenClaw Config Compatibility Note

Date: 2026-04-01

## Incident

An OpenClaw install failed to start the gateway because `~/.openclaw/openclaw.json`
contained a legacy top-level `fallbacks` key inside `agents.list[*]`.

The runtime schema rejected entries like:

```json
{
  "id": "coder",
  "model": "anthropic/claude-sonnet-4-6",
  "fallbacks": []
}
```

Doctor output showed:

```text
Invalid config:
- agents.list.0: Unrecognized key: "fallbacks"
```

## Root Cause

Mission Control still normalized `model.fallbacks`, but it also preserved any old
top-level `agent.fallbacks` already present in `openclaw.json` during write-back.

That meant any agent edited from the dashboard could keep re-saving an invalid
gateway config even if the current UI no longer depended on that field.

## Fix

The write-back normalizer in `src/lib/agent-sync.ts` now removes legacy
top-level `agent.fallbacks` before writing back to `openclaw.json`.

Regression coverage lives in:

- `src/lib/__tests__/agent-sync.test.ts`

## Recovery

If this happens again on a live install:

1. Remove `fallbacks` from each entry in `agents.list` inside `~/.openclaw/openclaw.json`.
2. Run `openclaw doctor`.
3. Verify with `openclaw gateway status`.

Expected result:

- `openclaw doctor` no longer reports `Unrecognized key: "fallbacks"`.
- `openclaw gateway status` shows `Runtime: running` and `RPC probe: ok`.

---

### Orchestration (`docs/orchestration.md`)

# Orchestration Patterns

This guide covers the task orchestration patterns available in Mission Control, from simple manual assignment to fully automated multi-agent workflows.

## Task Lifecycle

Every task in Mission Control follows this status flow:

```
inbox ──► assigned ──► in_progress ──► review ──► done
  │          │             │              │
  │          │             │              └──► rejected ──► assigned (retry)
  │          │             │
  │          │             └──► failed (max retries or timeout)
  │          │
  │          └──► cancelled
  │
  └──► assigned (triaged by human or auto-dispatch)
```

Key transitions:
- **inbox → assigned**: Human triages or auto-dispatch picks it up
- **assigned → in_progress**: Agent claims via queue poll or auto-dispatch sends it
- **in_progress → review**: Agent completes work, awaits quality check
- **review → done**: Aegis approves the work
- **review → assigned**: Aegis rejects, task is requeued with feedback

## Pattern 1: Manual Assignment

The simplest pattern. A human creates a task and assigns it to a specific agent.

```bash
# Create and assign in one step
curl -X POST "$MC_URL/api/tasks" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Fix login page CSS",
    "description": "The login button overlaps the form on mobile viewports.",
    "priority": "high",
    "assigned_to": "scout"
  }'
```

The agent picks it up on the next queue poll:

```bash
curl "$MC_URL/api/tasks/queue?agent=scout" \
  -H "Authorization: Bearer $MC_API_KEY"
```

**When to use**: Small teams, well-known agent capabilities, human-driven task triage.

## Pattern 2: Queue-Based Dispatch

Agents poll the queue and MC assigns the highest-priority available task. No human triage needed.

### Setup

1. Create tasks in `inbox` status (no `assigned_to`):

```bash
curl -X POST "$MC_URL/api/tasks" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Update API documentation",
    "priority": "medium"
  }'
```

2. Agents poll the queue. MC atomically claims the best task:

```bash
# Agent "scout" asks for work
curl "$MC_URL/api/tasks/queue?agent=scout" \
  -H "Authorization: Bearer $MC_API_KEY"

# Agent "iris" also asks — gets a different task (no race condition)
curl "$MC_URL/api/tasks/queue?agent=iris" \
  -H "Authorization: Bearer $MC_API_KEY"
```

### Priority Ordering

Tasks are assigned in this order:
1. **Priority**: critical > high > medium > low
2. **Due date**: Earliest due date first (null = last)
3. **Created at**: Oldest first (FIFO within same priority)

### Capacity Control

Each agent can set `max_capacity` to limit concurrent tasks:

```bash
# Agent can handle 3 tasks at once
curl "$MC_URL/api/tasks/queue?agent=scout&max_capacity=3" \
  -H "Authorization: Bearer $MC_API_KEY"
```

If the agent already has `max_capacity` tasks in `in_progress`, the response returns `"reason": "at_capacity"` with no task.

**When to use**: Multiple agents with overlapping capabilities, want automatic load balancing.

## Pattern 3: Auto-Dispatch (Gateway Required)

The scheduler automatically dispatches `assigned` tasks to agents through the OpenClaw gateway. This is the fully hands-off mode.

### How It Works

1. Tasks are created with `assigned_to` set
2. The scheduler's `dispatchAssignedTasks` job runs periodically
3. For each task, MC:
   - Marks it `in_progress`
   - Classifies the task complexity to select a model
   - Sends the task prompt to the agent via the gateway
   - Parses the response and stores the resolution
   - Moves the task to `review` status

### Model Routing

MC automatically selects a model based on task content:

| Tier | Model | Signals |
|------|-------|---------|
| **Complex** | Opus | debug, diagnose, architect, security audit, incident, refactor, migration |
| **Routine** | Haiku | status check, format, rename, ping, summarize, translate, simple, minor |
| **Default** | Agent's configured model | Everything else |

Critical priority tasks always get Opus. Low priority with routine signals get Haiku.

Override per-agent by setting `config.dispatchModel`:

```bash
curl -X PUT "$MC_URL/api/agents" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"id": 1, "config": {"dispatchModel": "9router/cc/claude-opus-4-6"}}'
```

### Retry Handling

- Failed dispatches increment `dispatch_attempts` and revert to `assigned`
- After 5 failed attempts, task moves to `failed`
- Each failure is logged as a comment on the task

**When to use**: Fully autonomous operation with an OpenClaw gateway. Best for production agent fleets.

## Pattern 4: Quality Review (Aegis)

Aegis is MC's built-in quality gate. When a task reaches `review` status, the scheduler sends it to the Aegis reviewer agent for sign-off.

### Flow

```
in_progress ──► review ──► Aegis reviews ──► APPROVED ──► done
                                          └─► REJECTED ──► assigned (with feedback)
```

### How Aegis Reviews

1. Scheduler's `runAegisReviews` job picks up tasks in `review` status
2. Builds a review prompt with the task description and agent's resolution
3. Sends to the Aegis agent (configurable via `MC_COORDINATOR_AGENT`)
4. Parses the verdict:
   - `VERDICT: APPROVED` → task moves to `done`
   - `VERDICT: REJECTED` → feedback is attached as a comment, task reverts to `assigned`
5. Rejected tasks are re-dispatched with the feedback included in the prompt

### Retry Limits

- Up to 3 Aegis review cycles per task
- After 3 rejections, task moves to `failed` with accumulated feedback
- All review results are stored in the `quality_reviews` table

### Setting Up Aegis

Aegis is just a regular agent with a reviewer SOUL. Create it:

```bash
# Register the Aegis agent
curl -X POST "$MC_URL/api/agents/register" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "aegis", "role": "reviewer"}'

# Set its SOUL
curl -X PUT "$MC_URL/api/agents/1/soul" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template_name": "reviewer"}'
```

**When to use**: When you want automated quality checks before tasks are marked complete.

## Pattern 5: Recurring Tasks (Cron)

Schedule tasks to be created automatically on a recurring basis using natural language or cron expressions.

### CLI

```bash
node scripts/mc-cli.cjs cron create --body '{
  "name": "daily-standup-report",
  "schedule": "0 9 * * 1-5",
  "task_template": {
    "title": "Generate daily standup report",
    "description": "Summarize all completed tasks from the past 24 hours.",
    "priority": "medium",
    "assigned_to": "iris"
  }
}'
```

### API

```bash
curl -X POST "$MC_URL/api/cron" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "weekly-security-scan",
    "schedule": "0 2 * * 0",
    "task_template": {
      "title": "Weekly security audit",
      "priority": "high",
      "assigned_to": "aegis"
    }
  }'
```

The scheduler spawns dated child tasks from the template on each trigger. Manage cron jobs with `pause`, `resume`, and `remove` actions.

**When to use**: Reports, health checks, periodic audits, maintenance tasks.

## Pattern 6: Multi-Agent Handoff

Agent A completes a task, then creates a follow-up task assigned to Agent B. This chains agents into a pipeline.

### Example: Research → Implement → Review

```bash
# Step 1: Research task for iris
curl -X POST "$MC_URL/api/tasks" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Research caching strategies for API layer",
    "priority": "high",
    "assigned_to": "iris"
  }'
```

When iris completes the research, create the implementation task:

```bash
# Step 2: Implementation task for scout (after iris finishes)
curl -X POST "$MC_URL/api/tasks" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Implement Redis caching for /api/products",
    "description": "Based on research in TASK-1: Use cache-aside pattern with 5min TTL...",
    "priority": "high",
    "assigned_to": "scout"
  }'
```

After scout finishes, Aegis reviews automatically (if auto-dispatch is active), or you create a review task:

```bash
# Step 3: Review task for aegis
curl -X POST "$MC_URL/api/tasks" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Review caching implementation in TASK-2",
    "priority": "high",
    "assigned_to": "aegis"
  }'
```

**When to use**: Complex workflows where different agents have different specializations.

## Pattern 7: Stale Task Recovery

MC automatically recovers from stuck agents. The `requeueStaleTasks` scheduler job:

1. Finds tasks stuck in `in_progress` for 10+ minutes with an offline agent
2. Reverts them to `assigned` with a comment explaining the stall
3. After 5 stale requeues, moves the task to `failed`

This happens automatically — no configuration needed.

## Combining Patterns

In practice, you'll combine these patterns. A typical production setup:

1. **Cron** creates recurring tasks (Pattern 5)
2. **Queue-based dispatch** distributes tasks to available agents (Pattern 2)
3. **Model routing** picks the right model per task (Pattern 3)
4. **Aegis** reviews all completed work (Pattern 4)
5. **Stale recovery** handles agent failures (Pattern 7)

```
 Cron ──► inbox ──► Queue assigns ──► Agent works ──► Aegis reviews ──► done
                                          │                  │
                                          └── timeout ───────┘── requeue
```

## Event Streaming

Monitor orchestration in real time with SSE:

```bash
# Watch all task and agent events
node scripts/mc-cli.cjs events watch --types task,agent --json
```

Or via API:

```bash
curl -N "$MC_URL/api/events" \
  -H "Authorization: Bearer $MC_API_KEY" \
  -H "Accept: text/event-stream"
```

Events include: `task.created`, `task.updated`, `task.completed`, `agent.created`, `agent.status_changed`, and more.

## Reference

- **[Quickstart](quickstart.md)** — 5-minute first agent tutorial
- **[Agent Setup](agent-setup.md)** — Registration, SOUL, configuration
- **[CLI Reference](cli-agent-control.md)** — Full CLI command list
- **[CLI Integration](cli-integration.md)** — Direct connections without a gateway

---

### Home (`wiki/Home.md`)

# Mission Control Wiki

Last reviewed: 2026-03-05

Mission Control is an open-source dashboard for orchestrating AI agents: agents, tasks, costs, workflows, and gateway connectivity in one place.

## Start Here

- Product overview: [README](../README.md)
- Local + production setup: [docs/deployment.md](../docs/deployment.md)
- Direct CLI integration (without gateway): [docs/cli-integration.md](../docs/cli-integration.md)
- Security policy: [SECURITY.md](../SECURITY.md)
- Contribution guide: [CONTRIBUTING.md](../CONTRIBUTING.md)
- Release history: [CHANGELOG.md](../CHANGELOG.md)

## Quick Start (5 Minutes)

```bash
git clone https://github.com/builderz-labs/mission-control.git
cd mission-control
pnpm install
cp .env.example .env
pnpm dev
```

Then open `http://localhost:3000` and sign in with the seeded `AUTH_USER`/`AUTH_PASS` values from your environment.

## Core Concepts

- Agent: A worker connected to Mission Control that executes tasks and reports status/usage.
- Task: A unit of work tracked across workflow columns (`inbox -> done`) with comments and ownership.
- Gateway: Real-time connection layer (OpenClaw and compatible providers) for session/event streaming.
- Workspace/Tenant: Isolated environment for multi-client operations, managed via `/api/super/*` endpoints.

## Recommended Wiki Structure

- `Home` (this page)
- `Getting-Started` - install, auth, first login, and initial checks
- `Architecture` - runtime model, data flow, and component map
- `Operations-Runbook` - backups, upgrades, troubleshooting, incident steps
- `API-Guide` - endpoint groups, auth patterns, and examples
- `Security-Model` - auth, RBAC, API keys, host/network controls
- `Integrations` - webhooks, GitHub sync, direct CLI, multi-gateway setup
- `FAQ` - common operator/admin questions

## Notes For Maintainers

- Keep wiki pages aligned with shipped behavior in the same PR when features change.
- Add a `Last reviewed` line to each operational page.
- Prefer linking to source-of-truth docs in this repo when possible.

---

### STYLE GUIDE (`wiki/STYLE_GUIDE.md`)

# Mission Control Style Guide

> "Mission Control in the Void" — a futuristic command center floating in a digital void.

---

## 1. Design Philosophy

Mission Control uses a deep-navy void aesthetic with luminous cyan accents. The visual language evokes a space-age command center: dark surfaces, glowing edges, monospace readouts, and subtle grid patterns that anchor UI elements in a digital void.

Key principles:
- **Dark by default** — app defaults to dark mode (`enableSystem={false}`)
- **Semantic tokens** — all colors flow through CSS custom properties
- **Additive light** — glow effects and luminous borders create depth without bright fills
- **Motion with purpose** — animations signal state, never decoration

---

## 2. Color System

### Void Palette (Dark Mode)

| Token | CSS Variable | HSL | Hex | Usage |
|-------|-------------|-----|-----|-------|
| Background | `--background` | `215 27% 4%` | #07090C | Page background, deepest layer |
| Card | `--card` | `220 30% 8%` | #0F141C | Panel/card surfaces |
| Primary | `--primary` | `187 82% 53%` | #22D3EE | Primary actions, focus rings |
| Secondary | `--secondary` | `220 25% 11%` | — | Secondary surfaces |
| Muted | `--muted` | `220 20% 14%` | — | Disabled states, subtle fills |
| Border | `--border` | `220 20% 14%` | — | Card/panel borders |
| Foreground | `--foreground` | `210 20% 92%` | — | Primary text |

### Accent Colors

| Name | CSS Variable | HSL | Hex | Usage |
|------|-------------|-----|-----|-------|
| Cyan | `--void-cyan` | `187 82% 53%` | #22D3EE | Primary accent, active states |
| Mint | `--void-mint` | `160 60% 52%` | #34D399 | Success, healthy states |
| Amber | `--void-amber` | `38 92% 50%` | #F59E0B | Warning, idle states |
| Violet | `--void-violet` | `263 90% 66%` | #A78BFA | Lead agents, special roles |
| Crimson | `--void-crimson` | `0 72% 51%` | #DC2626 | Errors, destructive actions |

### Surface Hierarchy

| Level | CSS Variable | HSL | Usage |
|-------|-------------|-----|-------|
| 0 | `--surface-0` | `215 27% 4%` | Deepest void (page bg) |
| 1 | `--surface-1` | `222 35% 7%` | Dark navy (elevated cards) |
| 2 | `--surface-2` | `220 30% 10%` | Secondary panels |
| 3 | `--surface-3` | `220 25% 14%` | Raised elements, borders |

### Using Colors in Code

**Tailwind classes** (preferred):
```html
<div class="bg-card text-foreground border-void-cyan">
```

**Inline styles** (ReactFlow, recharts):
```ts
import { hsl, voidAccents } from '@/styles/design-tokens'
const stroke = hsl(voidAccents.cyan)        // "hsl(187 82% 53%)"
const dim = hsl(voidAccents.cyan, 0.4)      // "hsl(187 82% 53% / 0.4)"
```

---

## 3. Typography

| Role | Font | CSS Variable | Tailwind Class |
|------|------|-------------|----------------|
| Body/UI | Inter | `--font-sans` | `font-sans` |
| Code/Data | JetBrains Mono | `--font-mono` | `font-mono` |

Both fonts are loaded via `next/font/google` (self-hosted, no external requests).

### Type Scale

Follow Tailwind's default scale. Key usage:
- `text-2xl font-bold font-mono` — stat card values
- `text-sm font-medium` — labels, nav items
- `text-xs font-mono` — metadata, timestamps, model names
- `text-[10px] tracking-wider font-semibold` — section headers (OBSERVE, AUTOMATE, etc.)

---

## 4. Spacing

Base grid: **4px**

Use Tailwind's spacing scale (1 = 0.25rem = 4px). Panel padding is typically `p-4` (16px) or `p-6` (24px). Gaps between grid items use `gap-6` (24px).

---

## 5. Border Radius

| Token | Value | Usage |
|-------|-------|-------|
| `rounded-xl` | 16px | Large panels, modals |
| `rounded-lg` | 12px | Standard panels, cards |
| `rounded-md` | 10px | Buttons, inputs |
| `rounded-sm` | 8px | Small elements |
| `rounded-xs` | 6px | Badges, tags |

---

## 6. Elevation & Glow

### Glow Utilities

| Class | Color | Usage |
|-------|-------|-------|
| `.glow-cyan` | Cyan | Active states, primary focus |
| `.glow-mint` | Mint | Success states |
| `.glow-amber` | Amber | Warning states |
| `.glow-violet` | Violet | Special/lead roles |

### Badge Glow

| Class | Usage |
|-------|-------|
| `.badge-glow-success` | Success status badges |
| `.badge-glow-warning` | Warning status badges |
| `.badge-glow-error` | Error status badges |

### Panel Classes

| Class | Description |
|-------|-------------|
| `.void-panel` | Glass card with luminous border, inner highlight, float shadow |
| `.void-border-glow` | Animated gradient border via `::before` pseudo-element |
| `.panel` | Basic card: `bg-card border rounded-xl` |
| `.btn-neon` | Button with cyan glow on hover |

---

## 7. Component Patterns

### Panel Anatomy

```html
<div class="void-panel">
  <div class="panel-header">
    <h3 class="font-semibold text-foreground">Title</h3>
  </div>
  <div class="panel-body">
    
  </div>
</div>
```

### Stat Card

- Use `void-panel` base
- Numeric values: `font-mono text-2xl font-bold`
- Icons: SVG, 24x24 (w-6 h-6), colored with void accent classes
- Color-specific glow via `badge-glow-*` classes

### Agent Node (ReactFlow)

- Base: `void-panel` with status-based border color
- Active: `border-void-cyan glow-cyan`
- Idle: `border-void-amber/50`
- Error: `border-void-crimson badge-glow-error`
- Badges: `font-mono text-xs` with accent background/border

### CORE Node

- Central orchestration hub in agent network
- Concentric pulsing rings (CSS keyframes, no framer-motion)
- `font-mono tracking-widest` for "CORE" label

---

## 8. Animation

### Keyframe Inventory

| Name | Duration | Effect | Usage |
|------|----------|--------|-------|
| `glowPulse` | 3s | Opacity + brightness oscillation | Active agent indicators |
| `float` | 6s | Vertical float (-6px) | Floating UI elements |
| `gridFlow` | 20s | Background position shift | Background grid animation |
| `edgeGlow` | 2s | Opacity oscillation | Border glow effects |
| `pulse-live` | 2s | Opacity fade | Live status indicators |
| `pulse-dot` | 2s | Scale + opacity | Connection status dots |

### Guidelines

- Prefer CSS `@keyframes` over JavaScript animation
- Duration: 2-3s for ambient loops, 150-200ms for interactions
- Easing: `ease-in-out` for loops, `ease-out` for entrances
- Always respect `prefers-reduced-motion: reduce`

---

## 9. Icon System

- **ViewBox**: `0 0 16 16`
- **Style**: Stroke-based, not filled
- **Stroke width**: `1.5`
- **Line caps/joins**: `round`
- **Size in UI**: `w-5 h-5` (nav), `w-4 h-4` (inline), `w-6 h-6` (stat cards)
- **Color**: Inherits via `stroke="currentColor"`

Example:
```tsx
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor"
  strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"
  className="w-5 h-5">
  <circle cx="8" cy="8" r="6" />
</svg>
```

---

## 10. Accessibility

### Contrast

- Text on void background: minimum 4.5:1 ratio (WCAG AA)
- `--foreground` (92% lightness) on `--background` (4% lightness) exceeds 15:1
- Cyan accent on dark: 5.2:1 — passes AA for normal text

### Focus Indicators

- Use `ring` utility: `focus-visible:ring-2 focus-visible:ring-ring`
- Ring color matches `--void-cyan`

### Reduced Motion

Global rule in `globals.css`:
```css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
```

### Semantic HTML

- Nav uses `role="navigation"` and `aria-label`
- Active nav items use `aria-current="page"`
- Disabled items use `aria-disabled`
- Decorative elements use `aria-hidden="true"`

---

### Plans 2026 03 10 Onboarding Walkthrough Hardening (`docs/plans/2026-03-10-onboarding-walkthrough-hardening.md`)

# Onboarding + Walkthrough hardening plan

Base branch: `fix/refactor`
Working branch: `fix/refactor-onboarding-walkthrough`

## Goals
- Verify current onboarding and walkthrough flows are functional.
- Fix edge cases for first-run, skip, replay, and recovery states.
- Improve UX discoverability of walkthrough entry points.
- Add regression tests to keep flows stable.

## Phase 1: audit and test map
1. Identify current onboarding/walkthrough code paths.
2. Document triggers, persistence flags, and routing.
3. Add failing tests for first-run, skip, replay, and already-seen states.

## Phase 2: implementation hardening
1. Fix state transitions and persistence updates.
2. Ensure walkthrough can be reopened from primary UI.
3. Add visible hint/help entry to improve discoverability.
4. Handle corrupted or partial onboarding state safely.

## Phase 3: verification
1. Run targeted tests for onboarding/walkthrough.
2. Run full project checks.
3. Validate end-to-end flow manually in local dev.

## Deliverables
- Code changes in onboarding/walkthrough modules
- Automated tests covering key onboarding paths
- Updated docs/help text for walkthrough discoverability

---

### Plans 2026 03 20 Mission Control Platform Cli Tui Prd (`docs/plans/2026-03-20-mission-control-platform-cli-tui-prd.md`)

# Mission Control Platform Hardening + Full Agent CLI/TUI PRD

> For Hermes: execute this plan in iterative vertical slices (contract parity -> CLI core -> TUI -> hardening), with tests at each slice.

Goal
Build a production-grade Mission Control operator surface for autonomous agents via a first-party CLI (and optional lightweight TUI), while fixing platform inconsistencies discovered in audit: API contract drift, uneven reliability controls, and incomplete automation ergonomics.

Architecture
Mission Control remains the source of truth with REST + SSE endpoints. A first-party CLI consumes those APIs with profile-based auth and machine-friendly output. TUI is layered on top of CLI API client primitives for shared behavior. API contract reliability is enforced through route-to-spec parity checks in CI.

Tech Stack
- Existing: Next.js app-router API, SQLite, Node runtime, SSE
- New: Node CLI runtime (no heavy deps required for v1), optional TUI in terminal ANSI mode
- Testing: existing Playwright/Vitest patterns + CLI smoke tests + OpenAPI parity checks

---

## 1) Problem statement

Current Mission Control backend has strong capabilities for agent orchestration, but external automation quality is constrained by:
1. API surface drift between route handlers, openapi.json, and /api/index.
2. No first-party comprehensive CLI for operators/agents.
3. Uneven hardening around operational concerns (auth posture defaults, multi-instance rate limiting strategy, spawn history durability).
4. Incomplete UX for non-interactive agent workflows (idempotent commands, stable JSON output, strict exit codes).

Result: agents can use Mission Control partially, but not yet with high confidence as a full control plane.

## 2) Product objectives

Primary objectives
1. Deliver a first-party CLI with functional parity across core agent workflows.
2. Add optional TUI for rapid situational awareness and interactive operations.
3. Establish API contract parity as an enforceable quality gate.
4. Improve reliability and security defaults for autonomous operation.

Success criteria
- 95%+ of documented operator workflows executable via CLI without web UI.
- Contract parity CI gate blocks drift between route handlers and OpenAPI.
- CLI supports machine mode: stable JSON schemas and deterministic exit codes.
- TUI can monitor and trigger core actions (agents/tasks/sessions/events).

Non-goals (v1)
- Replacing the web UI.
- Building an advanced ncurses framework dependency stack if not needed.
- Supporting all historical/legacy endpoint aliases immediately.

## 3) Personas and workflows

Personas
1. Autonomous agent runtime (headless, non-interactive).
2. Human operator (terminal-first incident response).
3. Platform maintainer (release and contract governance).

Critical workflows
- Poll task queue and claim work.
- Manage agents (register/update/diagnose/wake).
- Manage sessions (list/control/continue/transcript).
- Observe events in real time.
- Track token usage and attribution.
- Manage skills, cron jobs, and direct CLI connections.

## 4) Functional requirements

### A. API contract governance
- FR-A1: A parity checker must compare discovered route handlers and OpenAPI paths/methods.
- FR-A2: CI fails on non-ignored mismatches.
- FR-A3: Ignore list must be explicit and reviewable.
- FR-A4: /api/index should be validated or generated from same contract source.

### B. CLI v1 requirements
- FR-B1: Profile-based configuration (URL + auth mode + key/cookie).
- FR-B2: Commands must support --json output and strict exit codes.
- FR-B3: Support key domains:
  - auth
  - agents
  - tasks
  - sessions
  - connect
  - tokens
  - skills
  - cron
  - events watch
  - raw request fallback
- FR-B4: Non-interactive defaults suitable for autonomous agents.
- FR-B5: Request timeout + retry controls for reliable automation.

### C. TUI v1 requirements (optional but included)
- FR-C1: Dashboard with agents/tasks/sessions summary panels.
- FR-C2: Keyboard-driven refresh/navigation.
- FR-C3: Trigger key operations (wake agent, queue poll, session controls).
- FR-C4: Clear degraded mode messaging if endpoints unavailable.

### D. Platform hardening requirements
- FR-D1: Document and enforce least-privilege auth guidance for agent keys.
- FR-D2: Expose explicit warning/controls for global admin API key usage.
- FR-D3: Add durable spawn history persistence (DB-backed) replacing log scraping fallback.
- FR-D4: Add scalable rate-limit strategy plan (in-memory now, pluggable backend next).

## 5) CLI command map (v1)

mc auth
- login --username --password
- logout
- whoami

mc agents
- list
- get --id
- create --name --role
- update --id ...fields
- delete --id
- wake --id
- diagnostics --id
- heartbeat --id
- memory get|set --id
- soul get|set --id

mc tasks
- list [filters]
- get --id
- create --title [--description --priority --assigned-to]
- update --id ...fields
- delete --id
- queue --agent [--max-capacity]
- comments list/add --id
- broadcast --id

mc sessions
- list
- control --id --action monitor|pause|terminate
- continue --kind claude-code|codex-cli --id --prompt
- transcript --id [--source]

mc connect
- register --tool-name --agent-name [...]
- list
- disconnect --connection-id

mc tokens
- list
- stats
- by-agent [--days]
- export --format json|csv

mc skills
- list
- content --source --name
- upsert --source --name --file
- delete --source --name
- check --source --name

mc cron
- list
- create/update/pause/resume/remove/run

mc events
- watch [--types]

mc raw
- raw --method GET --path /api/... [--body '{}']

## 6) UX and interface requirements

- Default output must be concise human-readable; --json returns machine-stable payload.
- All non-2xx responses include normalized error object and non-zero exit.
- Exit code taxonomy:
  - 0 success
  - 2 usage error
  - 3 auth error
  - 4 permission error
  - 5 network/timeout
  - 6 server error
- Pagination/filter flags normalized across list commands.

## 7) Security requirements

- Do not log raw API keys or cookies.
- Redact sensitive headers in verbose/debug output.
- Provide per-profile auth scope awareness (viewer/operator/admin implied risk labeling).
- Strong guidance: prefer agent-scoped keys over global admin key.

## 8) Reliability requirements

- Configurable timeout/retry/backoff.
- Safe JSON parsing and clear error surfaces.
- SSE reconnection strategy for watch mode.
- Graceful handling for partial endpoint availability.

## 9) Testing strategy

Unit
- CLI arg parsing and request mapping.
- Output modes and exit codes.
- API parity checker route extraction and mismatch detection.

Integration
- CLI against local Mission Control test server.
- Auth modes (API key, login session where enabled).
- Session control, queue polling, skills CRUD.

E2E
- Playwright/terminal-driven smoke for critical command paths.
- TUI render and keyboard navigation smoke tests.

Contract tests
- OpenAPI parity check in CI.
- Optional index parity check in CI.

## 10) Rollout plan

Phase 0: Contract stabilization
- Add parity checker and fail CI on drift.
- Resolve existing mismatches.

Phase 1: CLI core
- Ship profile/auth client + core command groups (auth/agents/tasks/sessions/connect).

Phase 2: CLI expansion
- tokens/skills/cron/events/raw + transcript ergonomics.

Phase 3: TUI
- Live dashboard + action shortcuts.

Phase 4: Hardening
- durable spawn history
- auth warnings and safeguards
- scalable rate-limit backend abstraction

## 11) Risks and mitigations

Risk: Large API surface causes long-tail parity gaps.
Mitigation: enforce parity checker + allowlist for temporary exceptions.

Risk: Auth complexity across cookie/key/proxy modes.
Mitigation: profile abstraction + explicit mode selection and diagnostics.

Risk: CLI churn if endpoint contracts continue changing.
Mitigation: typed response normalizers + compatibility layer + semver release notes.

## 12) Acceptance criteria

- PRD approved by maintainers.
- CLI provides end-to-end control for core workflows.
- Contract parity CI gate active and green.
- TUI displays operational state and triggers key actions.
- Security and reliability hardening changes documented and tested.

## 13) Immediate implementation tasks (next 1-2 PRs)

PR 1
1. Add API parity checker script and CI command.
2. Add first-party CLI scaffold with command routing and normalized request layer.
3. Add docs for CLI profiles/auth/output contract.

PR 2
1. Implement full command matrix.
2. Add TUI dashboard shell.
3. Add CLI integration tests.
4. Introduce durable spawn history model and endpoint alignment.

---

### Releases 2.0.0 (`docs/releases/2.0.0.md`)

# Mission Control 2.0.0

Released: 2026-03-11

Mission Control 2.0.0 is the major release that lands the `feat/refactor` branch as the new baseline for the project. It rolls up 189 commits on top of `main` and shifts Mission Control from an early dashboard into a broader agent operations console for both local and gateway-driven setups.

## Highlights

### Dual-mode operation
- Mission Control now supports both OpenClaw gateway mode and local workstation mode cleanly.
- Onboarding, runtime detection, security checks, and panel behavior were reworked so the app can adapt to the active environment instead of assuming one deployment shape.

### Broader agent observability
- Hermes observability was added across sessions, memory, tasks, cron, and transcripts.
- OpenClaw coverage was expanded across channels, chat, sessions, cron, devices, approvals, logs, usage, and config editing.
- Agent communication, session routing, and inline transcript visibility were strengthened throughout the app.

### Memory system redesign
- The memory panel was redesigned into an Obsidian-style knowledge surface.
- Mission Control now ships with a filesystem memory browser, link/context endpoints, memory health signals, and an interactive graph view for linked knowledge.
- Loading and navigation performance in the memory panel were improved substantially, including lazy tree loading and graph prefetching.

### Onboarding, security, and doctor workflows
- The onboarding experience was rebuilt into a guided walkthrough with stronger separation between per-user progress and per-session display behavior.
- The security scan now has clearer severity handling, improved autofix behavior, and better reporting of manual vs auto-fixable issues.
- OpenClaw doctor warnings, doctor fix, and state-integrity handling are now surfaced directly in the UI.

### Deployment and runtime hardening
- Node support was standardized on `22.x` across local development, CI, Docker, and standalone deploys.
- Build-time SQLite handling was isolated from runtime SQLite state to avoid noisy or fragile deploy behavior.
- Standalone deploys were hardened around asset inclusion, runtime data directories, backups, and restart detection.
- Dynamic host handling and safer env mutation behavior improved self-hosted reliability.

### Agent lifecycle and operator UX
- Agent/workspace creation and deletion flows were hardened end to end, including OpenClaw config normalization and cleanup.
- The boot loader was redesigned with real progress phases and framework logos.
- Cost tracking, approvals, channels, chat, and session controls were all tightened during the refactor.

## Everything Included In The v2 Update

### Core platform and mode handling
- Local mode and OpenClaw gateway mode were hardened into first-class operating modes.
- Gateway discovery and connection handling improved across configured runtimes, systemd-managed gateways, Tailscale Serve, proxied websocket paths, forwarded-proto setups, and token-preserving websocket URLs.
- Mission Control can register itself as the dashboard for an OpenClaw runtime without the earlier device-auth and dashboard URL failure cases.
- Managed-gateway UX was tightened across health, status, mode badges, and startup auto-connect behavior.

### Agents, sessions, chat, and comms
- Embedded chat became a shared workspace rather than a fragmented set of views.
- Session navigation was unified into Chat, with local Claude/Codex sessions included alongside gateway sessions.
- Hermes sessions, transcripts, memory, tasks, and cron surfaced throughout the app.
- Session transcript handling improved across local, Hermes, aggregated gateway, and disk-backed OpenClaw transcript sources.
- Agent comms, runtime tool visibility, coordinator inbox behavior, session-thread routing, and agent feed ergonomics were hardened.
- Agent registration, self-registration, rate limiting, attribution, wake/spawn actions, and agent detail editing all received follow-up fixes.

### Tasks, quality flow, and automation
- Task dispatch now polls assigned tasks and runs agents through OpenClaw with session linkage.
- Aegis quality review became an automated scheduled workflow for review-stage tasks.
- Natural-language recurring tasks now parse into cron-backed template spawning.
- Spawn/task flows were consolidated, old spawn-only UI was removed, and task/session linking became more traceable.
- Cost tracking moved into a unified Cost Tracker panel.

### Memory, knowledge, and browsing
- The memory experience was redesigned into a graph-first, Obsidian-style knowledge system.
- The memory browser now supports faster loading, lazy directory hydration, better overflow handling, and improved graph fitting behavior.
- Memory APIs expanded around graph, health, links, context, and processing actions.
- Boot-time prefetching and panel persistence reduced the need to re-fetch heavy memory state on every navigation.

### Skills and local discovery
- Skills Hub support expanded across browsing, installation, bidirectional sync, registry search, security scanning, and local disk roots.
- Local agent discovery now covers `~/.agents`, `~/.codex/agents`, and Claude agent roots more reliably.
- Skill roots and E2E skill paths can now be overridden cleanly for isolated test and self-hosted environments.

### Security, audit, and approvals
- Security audit posture scoring, secret detection, evals, optimization, and security events were substantially expanded.
- Security scan severity scoring, infrastructure checks, OpenClaw hardening checks, autofix behavior, and agent-side scan APIs improved.
- Global exec approval overlay and approval flows were added/refined.
- Auth hardening covered timing-safe behavior, CSRF, session revocation, host allowlists, and safer trusted-host resolution.
- Audit trail coverage expanded across grouped action types and more complete operator activity logging.

### Onboarding and first-run experience
- The onboarding wizard went through several iterations and now combines runtime capability detection, gateway setup, security scan, credentials, and guided getting-started flow.
- Walkthrough visibility is session-aware while progress persists per user.
- The loading experience was redesigned with branded motion, framework logos, and real boot phases instead of generic spinner states.

### UI, navigation, and operator polish
- Agent cards, the agent detail modal, the cron calendar, activity/history views, interface mode toggles, sidebar categories, and panel loading states were redesigned.
- Shared loader patterns replaced ad-hoc spinners across more panels.
- Navigation state, URL synchronization, and panel persistence were tightened to reduce remount churn and stale data flashes.
- Branding assets and logos for Mission Control, OpenClaw, Claude, Codex, and Hermes were refreshed across the interface.

### Runtime, deployment, and template hardening
- Standalone deploys were hardened across static assets, runtime data directories, sqlite migration/backup flow, restart detection, and build/runtime separation.
- Build-time DB/token isolation removed noisy runtime coupling during `next build`.
- Node support was standardized on `22.x`, with matching local, CI, Docker, and deploy expectations.
- Proxy and host validation logic became more template-safe and more dynamic for self-hosted environments.
- OpenClaw doctor drift handling, doctor fix, config normalization, and workspace lifecycle cleanup were tightened to better support real self-hosted installs.

### E2E, CI, and release readiness
- The E2E harness now uses isolated OpenClaw runtime state, isolated skill roots, deterministic scheduler behavior, and safer env handling.
- Several regressions that only showed up in CI were fixed around security autofix, workload signals, and agent deletion behavior.
- README, landing page assets, and release documentation were refreshed for the v2 release.

## Notable Improvements

- Unified cost tracker replacing the split token/cost views
- Global exec approval overlay
- Better local agent discovery and skill sync behavior
- More reliable gateway config concurrency handling
- Better navigation responsiveness and less panel reload churn
- Stronger E2E runtime isolation for CI and local test harnesses

## Detailed Functional Additions

- Framework adapters and normalized multi-agent registration flow
- Self-update banner and admin-triggered update flow
- Tenant-scoped workspaces and free-tier extraction cleanup
- Google Workspace integration
- Plugin capabilities system and Hyperbrowser integration
- Claude Code task bridge
- OpenClaw backup creation and restore-oriented backup directory handling
- Embedded `/chat` panel and provider-session-first chat workspace
- Memory graph upgrades from Canvas to Reagraph WebGL
- Security audit panel, agent eval framework, and optimization endpoint
- OpenClaw update-now trigger from the UI
- Approvals overlay, channels parity, chat parity, usage parity, device parity, and logs parity with the newer OpenClaw surface

## Detailed Fix Areas

- Login autofill, redirect race, CSP/theme flash, and auth/session regressions
- Channels auth and RPC fallback behavior
- Gateway websocket stability and device identity handshake behavior
- Memory graph blank states, overflow, sizing, auto-fit, and speed issues
- Agent detail/model-shape crashes and delete/provisioning edge cases
- Doctor warning misclassification and state-integrity surfacing
- Security scan autofix false positives and active-host preservation
- Standalone deploy asset/runtime drift and SQLite migration contention
- README and docs freshness so product marketing reflects the shipped interface

## Upgrade Notes

- Mission Control 2.0.0 expects Node `22.x`.
- Self-hosted installs should verify env files, host allowlist configuration, and runtime data directory settings after upgrade.
- If you run OpenClaw, use the in-app doctor and security panels after upgrade to catch any stale config drift.

## Links

- Changelog: [`CHANGELOG.md`](../../CHANGELOG.md)
- README: [`README.md`](../../README.md)
- Security hardening guide: [`docs/SECURITY-HARDENING.md`](../SECURITY-HARDENING.md)

---

### Releases 2.0.1 (`docs/releases/2.0.1.md`)

# Mission Control 2.0.1

Released: 2026-03-18

Mission Control 2.0.1 is the patch release that consolidates everything shipped after the `v2.0.0` launch. It includes the operational fixes that stabilized HTTP/Tailscale deployments, a zero-config first-run path, full application internationalization, broader task-routing automation, and the latest OpenClaw compatibility updates needed for current self-hosted installs.

## Highlights

### HTTP, Tailscale, and gateway stability
- Login now works reliably on HTTP Docker installs and Tailscale-served deployments.
- CSP handling was tightened so SSR nonces, theme bootstrapping, and inline script policy stay aligned during login and chunk loading.
- Public websocket URL selection and Tailscale Serve detection were hardened for proxied gateway setups.
- Gateway startup and runtime checks now better tolerate read-only configs, missing `OPENCLAW_HOME`, and container health-probe requirements.

### Better first-run setup
- A first-time setup wizard now guides fresh installs through bootstrap and initial configuration.
- Zero-config startup paths reduce the amount of manual environment setup needed for local and Docker-based installs.
- Doctor and onboarding follow-ups are more resilient, including banner persistence and safer health-check behavior.

### Stronger task and automation flow
- Task routing now preserves implementation metadata, targets the correct gateway session/agent identifiers, and can classify complexity for model-tier routing.
- GNAP sync landed for git-native task persistence.
- `awaiting_owner` state detection and other dispatch/runtime fixes improve workflow accuracy after the v2 cut.

### Broader self-hosted platform support
- Full app localization now ships across 10 languages.
- Windows setup improved with a PowerShell installer and stronger password-generation behavior.
- Workspace skill-root discovery and filtering are now surfaced throughout the app for operators running mixed local/gateway environments.
- The Docker/image pipeline now supports publishing the official image to Docker Hub when release secrets are configured.

## Full Changelog

### Added
- First-time setup wizard and zero-config startup flow
- Full i18n across the app with 10 language packs
- Trusted reverse proxy/header-auth support
- Gateway health history timeline
- Port-based Tailscale Serve proxy detection
- Task implementation-target persistence, session targeting, and complexity-based model-tier routing
- GNAP sync for git-native task persistence
- Hybrid gateway/local dashboard mode
- Workspace skill-root discovery and per-agent display
- Windows PowerShell installer
- `awaiting_owner` task status detection

### Changed
- Node runtime support is now `>=22`
- CSP/browser-security helpers were split into dedicated modules
- Release automation now supports Docker Hub publishing when configured
- Repository/release metadata now consistently points at `builderz-labs/mission-control`

### Fixed
- HTTP/Tailscale login and CSP nonce regressions
- Fresh HTTP Docker login failures caused by secure-cookie mismatch
- Gateway auth/token detection in mixed runtime setups
- Task dispatch using display names instead of gateway IDs
- Docker/runtime regressions around Compose, assets, probes, `OPENCLAW_HOME`, and read-only configs
- SQLite `SQLITE_BUSY` contention during build/runtime crossover
- Doctor banner persistence, cron panel crash handling, and null-safe model config editing
- Public websocket URL preference and onboarding gateway health probe handling
- Notification refresh timing, agent empty-state UX, delete handling, and duplicate task-title behavior
- Memory diagnostics scoping, gateway notification delivery, session labels, and missing i18n namespaces
- Windows installer password generation via CSPRNG
- Reagraph CSP regression from `style-src` nonce handling
- OpenClaw spawn compatibility when agents use configured default models
- Regression coverage for gateway dashboard registration preserving device-auth posture

### Security
- Removed `unsafe-inline` in favor of nonce-based CSP
- Added stronger SSRF/path-traversal detection in the skill registry
- Stopped forcing `dangerouslyDisableDeviceAuth` when registering Mission Control as a dashboard

### Tests
- Utility coverage improvements to satisfy the Vitest coverage threshold
- Gateway health history E2E coverage
- Docker-mode integration coverage for gateway connectivity regressions
- Regression tests for spawn compatibility and gateway registration behavior

## Contributors

- @0xNyk
- @Brixyy
- @clintbaxley
- @dk-blackfuel
- @firefloc-nox
- @HonzysClawdbot
- @hectorse.88
- @jonathan-squaredlemons
- @jonboirama
- @joshua-mo-143
- @jrrcdev
- @lucascr
- @RazorFin
- @topshelfmedia

---

### Releases 2.2.0 (`docs/releases/2.2.0.md`)

# Mission Control 2.2.0

Mission Control 2.2.0 is a security and workspace-isolation release. It rolls the post-2.1 work into a reviewed baseline for self-hosted operators while keeping the existing trunk-based OSS workflow.

## Highlights

- Native workspace brand and isolation fields, backed by migration `052`
- Strict workspace boundaries across request, scheduler, event, audit, gateway, filesystem, and background-dispatch paths
- Safer host CLI dispatch with explicit tool, budget, and workspace-root constraints
- Hardened privileged mutations for gateway control, runtime setup, users, skills, backups, updates, approvals, and host maintenance
- Tailwind CSS v4 migration with visual verification across core surfaces and themes
- Stronger protected CI with immutable action-pin and standalone artifact-boundary checks
- Structured OSS issue and PR intake with clearer provenance, risk, and verification contracts

## Security posture

The security work in this release concentrates on authority boundaries rather than UI-only controls. Ambiguous workspace ownership fails closed, sensitive mutations are throttled and strictly validated, command output is bounded or redacted, audit records avoid host paths and secrets, and privileged client calls reject failed API responses.

The release-preparation audit found no known high-severity dependency vulnerabilities. The protected quality gate covers API parity, lint, typecheck, unit tests, production build, standalone artifact boundaries, and the full Playwright suite.

## Upgrade notes

1. Back up the Mission Control database and runtime configuration.
2. Upgrade from a protected `v2.2.0` tag or corresponding immutable container digest.
3. Run migrations before enabling strict isolation on existing workspaces.
4. Review `MC_WORKSPACE_ROOT`, trusted proxies, gateway credentials, and host-runtime permissions.
5. Re-test downstream theme customizations against Tailwind CSS v4 CSS tokens.

Workspace classification and isolation metadata do not grant execution authority. The declarative approval-policy engine remains future roadmap work.

## Compatibility

- Node.js 22 or newer remains required.
- Existing shared workspaces remain supported.
- The release does not intentionally remove public API routes.
- Custom Tailwind configuration is the primary downstream migration surface.

## Verification

The release commit must pass the repository's protected `quality-gate` and screenshot-drift checks before tagging. Tags are created only from the merged `main` commit.

---

### Releases 2.3.0 (`docs/releases/2.3.0.md`)

# Mission Control 2.3.0

Mission Control 2.3.0 is a dependency-security and maintenance release. It patches 13 known vulnerabilities in the dependency tree (8 high severity), refreshes the test toolchain to current majors, and closes a locale-integrity gap — all behind the same protected quality gate as feature work.

## Highlights

- 13 OSV advisories patched: next 16.2.11 (SSRF in Server Actions, middleware/proxy bypass, cache confusion, DoS), sharp 0.35.3, brace-expansion across three major lines, transitive postcss ≥8.5.18
- Supply-chain posture retained: fixes younger than the 7-day release-age gate are excluded explicitly and age out naturally; every workspace override carries an explicit major-line upper bound
- `MC_DISABLE_RUNTIME_SCAN` opt-out for local CLI probing during runtime detection
- Locale parity restored across all 10 locales, now enforced by a guard test in the quality gate
- Test toolchain on current majors: vite 8, vitest 4, @vitejs/plugin-react 6 (production builds remain webpack)

## Security posture

This release concentrates on the dependency boundary. The patched advisories include server-side request forgery in Server Actions and a middleware/proxy bypass in the framework the dashboard runs on — self-hosted operators exposing Mission Control beyond localhost should treat this as a priority upgrade. No Mission Control application code required security changes; the protected quality gate (API parity, lint, typecheck, unit tests, production build, standalone artifact boundaries, Playwright suite) passed on the patch series unchanged.

A note for downstream forks: pnpm overrides replace a dependent's declared version range entirely, so an unbounded override range can jump major API lines in transitive dependencies. Every override this release ships carries an explicit upper bound; keep that pattern if you extend them.

## Upgrade notes

1. Back up the Mission Control database and runtime configuration.
2. Upgrade from the protected `v2.3.0` tag or corresponding immutable container digest.
3. No migrations in this release; no configuration changes are required.
4. Optionally set `MC_DISABLE_RUNTIME_SCAN=1` on hosts where local CLI probing is unwanted.
5. Forks that patched dependencies independently should reconcile against the `pnpm-workspace.yaml` overrides and release-age exclusions.

## Compatibility

- Node.js 22 or newer remains required.
- No public API routes were added or removed.
- No database schema changes.
- The vite/vitest major migration affects the test toolchain only; downstream forks with custom tests should review the vitest 4 mock-constructor semantics (constructible implementations for mocks invoked with `new`).

## Verification

The release commit must pass the repository's protected `quality-gate` before tagging. Tags are created only from the merged `main` commit.

---

--- METRICS ---
- Files Extracted: 21
- Estimated Token Budget: ~33825 tokens
- Canonical Reference: https://codewiki.google/github.com/builderz-labs/mission-control
