Mission Control: unified AI usage after the OpenClaw pivot
Mission Control is a unified AI usage dashboard. It answers a practical question: when you run coding agents, CLI tools, local LLM routers, and image pipelines side by side, where do sessions, tokens, failures, and machine load actually live?
Today the answer is one React app backed by Express and SQLite. Collectors and pollers feed a shared ingest contract. The UI stitches that into Dashboard, Activities, Sessions, Runtime, Failures, Consumption, Jobs, Generations, and Settings.
The source lives on GitHub at BenBish/mission-control.
What It Is Now
Mission Control does not try to be another agent product. It is observability for AI work that already happens elsewhere.
Agentic sources - Claude Code and Codex CLI session logs. Collectors scan JSONL incrementally (offset cursors, rotation-aware), emit sessions and activities, and push batches to the ingest API. Session aggregates survive restarts so a mid-session collector restart does not under-count lifetime totals.
Runtime / inference sources - Hermes (llama-swap and llama-server) for local model routing: health, slot occupancy, loaded models, per-request inference telemetry, saturation and contention signals. Lemonade is wired as an optional poller and treated carefully where live verification is incomplete.
Generation sources - ComfyUI queue and history for image generation jobs, surfaced on a Generations page with honest empty states when polling is disabled.
Quota - Codex rate-limit windows land as quota snapshots rather than being forced into the same shape as token-billed API costs.
The nav matches that split: high-level dashboard and consumption, drill-down into activities and sessions, a Runtime view for the lab box, Failures across kinds, Jobs (including contention context), Generations, and Settings.
Architecture In One Pass
Think hub-and-spoke, not “one app on one laptop.”
- Hub - Install Mission Control on a central host (API, SQLite, SPA). That box is where you look at the dashboard. Server-side pollers for Hermes, ComfyUI, and optional Lemonade usually run on that host because those services live next to it.
- Spokes - On each machine where you actually do AI work with coding agents, run a desktop collector. It tails Claude Code / Codex JSONL locally and POSTs to the hub. Add another spoke whenever you get another workstation.
- Network - Hub and spokes talk over a private network; collectors do not need a public internet path to each other, only to the hub’s ingest endpoint.
[workstation] Claude Code / Codex JSONL
│
▼
desktop collector ──────────────┐
│
[hub / lab box] ▼
Hermes / ComfyUI / Lemonade → server pollers → POST /api/ingest/batch
│
Zod + natural-key dedupe
▼
SQLite
│
Express REST + SSE ──▶ React SPA (browser)
Collectors never write SQLite directly. They emit IngestEvents - a single wire contract shared by desktop collectors and in-process pollers. The hub validates, dedupes on (source_id, instance_id, kind, natural_key), and upserts mutable entities (sessions grow as logs grow) differently from immutable one-shot records (activities, quota snapshots). The SPA only reads via REST and SSE; it is not on the write path from collectors.
That design choice matters more than any particular chart. At-least-once delivery is the normal case for log tailing and polling. Without a stable natural key and an explicit dedupe table, every restart becomes double-counting theater.
The frontend uses TanStack Query and SSE invalidation so new activity can refresh lists and stats without inventing a second real-time protocol per page.
Why The Product Had To Pivot
Mission Control started as an OpenClaw activity feed: profiles, agent identity files, skill/permission matrices, and openclaw cron shell-outs. That made sense when OpenClaw was the primary multi-agent surface.
OpenClaw was retired. The dashboard still needed to exist - usage and cost pressure did not go away - but almost every product concept was wrong for the tools that replaced it:
- Claude Code and Codex do not ship SOUL.md-style agent workspaces the OpenClaw Agents UI expected.
- Local Hermes traffic is about slots, backends, and journal-derived request telemetry, not agent permission matrices.
- ComfyUI is a generation job lifecycle, not a tool-call activity stream.
- Multi-profile OpenClaw migrations and identity models did not map cleanly onto source/instance registries.
Shipping more features on top of that shape would have been a long apology tour. The recent rebuild (merged mid-July 2026 as a full v2) did the opposite: purge the OpenClaw coupling, replace the schema, and reintroduce sources through a generic ingest path.
What The Rebuild Actually Changed
Purge first
Agents, permissions, profile-scoped OpenClaw services, and cron backends that shell out to OpenClaw went away. Docs and status-report cruft tied to the old program went with them. Some UI shells were deliberately kept unrouted or reshaped (Skills → Generations, Cron → Jobs) so layout work was not thrown away with the backend assumptions.
Fresh data model
The OpenClaw-shaped tables and profile migrations were replaced with a baseline schema that matches three workloads:
- Agentic sessions and activities (Claude Code, Codex)
- Inference / runtime requests, snapshots, and events (Hermes, and later Lemonade)
- Generation jobs (ComfyUI)
Plus a source/instance registry, quota snapshots, background jobs/runs, and ingest_dedupe. Historical OpenClaw data was already gone, so this was a clean cut rather than an endless migration series.
Collectors against real files and real machines
Parsers were not designed only from documentation. Claude Code and Codex collectors were built against real session logs on the machine - which immediately exposed wire-format quirks:
- Codex nests user/agent/token events under payload types rather than top-level record kinds.
- Rate limits arrive as primary/secondary windows that expand into multiple quota snapshots.
- Codex session identity is recovered from the rollout filename, not a field on every line.
Hermes work had a similar honesty tax. Per-request token and timing data lived in systemd journal logs, not only in the HTTP log endpoint the original design assumed. Slot saturation and contention logic needed unit tests that simulate transitions without killing production routers under live agent traffic.
ComfyUI was verified end-to-end against real submitted workflows (queued → running → success). Lemonade was implemented from documented API shapes and mocks only - no live daemon access - and is labeled as unverified where that matters.
Production friction that only shows up when you deploy
Several fixes were not glamorous product features:
- Vite output directory did not match where the server served the SPA until someone actually built and served through the real process.
- SQLite
CURRENT_TIMESTAMPwithout a timezone marker produced “last seen −7 hours” style bugs when browsers parsed naive timestamps as local time. - High-frequency runtime snapshots needed retention and hourly rollups once polling ran continuously, or the table would grow without bound.
- Collector state persistence had to be atomic (temp file + rename) so a crash mid-write could not corrupt cursors.
Those details are part of the project’s real shape: a dashboard is only as trustworthy as its clocks, dedupe, and deploy path.
What You Can See In The UI
| Area | Role |
|---|---|
| Dashboard | Sources health, recent activity, consumption snapshot, failure highlights |
| Activities / Sessions | Tool calls and session timelines from coding agents |
| Runtime | Hermes (and related) instance health, slots, models, inference traffic |
| Failures | Cross-kind failure analysis (activities, inference, runtime events) |
| Consumption | Tokens / compute / USD views where units actually apply |
| Jobs / Generations | Background work and ComfyUI-style generation lifecycles |
| Settings | Operational configuration and system-facing controls |
Source filters keep multi-source data from collapsing into a single undifferentiated firehose.
Design Principles Worth Keeping
Source-agnostic ingest beats platform-native UI. When the product platform changes, the dashboard should not need a second rewrite of every page. Shared event kinds + specialized collectors scale better than embedding one vendor’s ontology in the React tree.
Dedupe is a first-class schema concern. Log tailers and pollers will redeliver. Natural keys and an ingest-level dedupe table are cheaper than forever debugging double charts.
Do not invent dollars. Local inference and some agent logs do not yield honest USD. Prefer tokens, slots, and durations unless the source supplies real cost fields.
Verify against the running system. Design docs for Codex JSONL, Hermes logs, and ComfyUI history were wrong in small but load-bearing ways. Live samples and production deploy are part of the build, not a later ops chore.
Empty and partial are valid states. Lemonade disabled, ComfyUI off, or a collector not running should look calm and explicit - not filled with demo data.
Status And Boundaries
Mission Control runs as a continuous local/lab deployment in that hub-and-spoke shape: dashboard and server-side pollers on the central host, desktop collectors on the machines where coding agents run, private network between them. The public repository describes architecture and process; it does not ship credentials, hostnames for production access, or internal secrets.
It is also unfinished in the good sense. New sources should plug into the ingest contract rather than forking the product model. Lemonade needs live verification before its numbers are trusted the way Claude Code, Codex, Hermes, and ComfyUI paths are. UI depth will keep tracking whichever tools actually generate load day to day.
The Larger Point
The OpenClaw-era product was tightly coupled to a platform that went away. The useful problem - see AI work as a system of sessions, tokens, failures, and machine capacity - did not go away with it.
The pivot is therefore not a rebrand. It is a bet that observability for personal and lab-scale AI stacks should be multi-source by default, boring about delivery guarantees, and honest when a source is local, free, unverified, or simply off.
That is Mission Control today: one dashboard, several collectors, a shared ingest contract, and a deliberate refusal to pretend every AI tool still looks like the platform you started with.