A local-first control room for orchestrating multiple coding agents as one disciplined team.
Run one agent, you get a chatbot. Put several agents with real roles in the same room — and gate their actions behind your decisions — you get a team. Multi-Agent Workbench is the room.
CLI coding agents are powerful, but each one is a lonely terminal: you prompt, it works, you review, repeat. Chaining them means copy-pasting context, losing track of who decided what, and trusting an agent to edit your repository without any guardrails.
Multi-Agent Workbench turns that into a structured collaboration system:
- One room, many agents — Claude Code, Codex CLI, generic PTY CLIs, and (soon) GLM/Cursor/Harness-style agents work side by side under explicit roles.
- Roles with teeth — each agent is bound to an editable role card that defines its permissions, speaking style, and decision boundaries.
- Your decisions are the gates — an orchestrator drives the flow, but execution, risky commands, and merges stop at you.
- Everything is recorded — an append-only event log is the source of truth, so every message, decision, approval, and diff is auditable and replayable.
- Your repo stays safe — code-writing agents work inside isolated git worktrees, and changes reach your main workspace only through a review flow you control.
Local-first by design: no accounts, no cloud, no telemetry. It runs on your machine, against your project, with files you can read.
| Capability | Status | Details |
|---|---|---|
| 🗣️ Task Rooms | ✅ shipped | Browser-based rooms with goal, members, timeline, decisions, approvals, artifacts |
| 🤖 Persistent PTY agents | ✅ shipped | Long-lived agent sessions that survive UI refreshes, with status tracking and raw terminal logs |
| 🧩 Agent-agnostic adapters | ✅ shipped | generic-pty, cli-once, codex-cli, claude-cli, experimental glm-cli, harness-agent cloud bridge, and cursor-agent editor bridge; registry extensible via a documented interface |
| 👥 Role cards & task templates | ✅ shipped | Human-readable YAML files — 6 roles, 5 templates, editable and versionable |
| ⚙️ Orchestrator with decision gates | ✅ shipped | Rule-driven engine raises blocking decision requests; request and resolve them from the Decisions panel or the API |
| 🛡️ Risk-based approvals | ✅ shipped | Low/medium/high risk classification with approve / reject / modify resolution and full history; experimental CLI approval-prompt interception |
| 🌳 Worktree isolation & diff review | ✅ shipped | One git worktree per executing agent, diff-stat scanning, patch artifacts, approval-gated merge and discard flow; merged worktrees are cleaned up automatically |
| 📦 Durable artifacts | ✅ shipped | Markdown task reports, decision logs, patches — written as readable files, not just database rows |
| ⚡ Real-time updates | ✅ shipped | SSE event streaming from the backend to every open room |
| 🔍 Event sourcing | ✅ shipped | 23 event types, projected into timeline, decisions, terminals, artifacts, and diff views |
A local event-driven stack. The browser never touches a PTY directly — every action goes through the API, is recorded as an event, and is projected into views.
flowchart LR
subgraph Browser
UI[React Workbench UI]
end
subgraph Server["Fastify Backend (127.0.0.1:3020)"]
API[REST API]
SSE[SSE Realtime Broker]
ORCH[Orchestrator Engine]
SESS[PTY Session Manager]
ADAPT[Agent Adapter Registry]
APPR[Approval Service]
WORK[Worktree Manager]
ART[Artifact Service]
CFG[Role & Template Registries]
end
DB[(SQLite Event Store)]
PTY[Persistent PTY Processes]
WT[Isolated Git Worktrees]
FILES[Markdown Artifacts]
UI <--> API
UI <--> SSE
API <--> DB
API <--> CFG
SSE <--> DB
ORCH --> SESS
SESS --> ADAPT
ADAPT --> PTY
PTY --> DB
ORCH <--> APPR
APPR <--> UI
WORK --> WT
WORK --> DB
ART --> FILES
ART --> DB
The event log is the single source of truth. Raw PTY output, agent messages, decisions, approvals, worktree updates, and artifacts are all append-only events. The UI state you see — the chat timeline, the pending decisions, the terminal drawers — is derived, not stored. That gives you:
- A complete audit trail — reconstruct why a change happened, not just what changed.
- Crash recovery — platform state rebuilds from the log; crashed agent sessions restart with an injected summary.
- Separation of signal and noise — raw terminal traffic is recorded but projected into drawers, keeping the timeline readable.
Adapters turn wildly different agent systems into one common interface: start command, input formatting, output parsing, capabilities, and lifecycle.
| Adapter | Agent | Kind | Maturity | Notes |
|---|---|---|---|---|
generic-pty |
Any terminal CLI | pty-cli |
✅ MVP | Configure any command; use for scripts, fake agents, or CLIs without a dedicated adapter |
cli-once |
One-shot CLI | cli-once |
🟡 Experimental | Run a command once, capture <agent-message>, then exit; no interactive follow-up |
codex-cli |
Codex CLI | pty-cli |
✅ MVP | Auto-discovers codex/codex.exe; structured <agent-message> output |
claude-cli |
Claude Code | pty-cli |
✅ MVP | Auto-discovers claude/claude.exe; structured <agent-message> output |
glm-cli |
GLM CLI | pty-cli |
🟡 Experimental | Auto-discovers glm/glm.exe; same <agent-message> contract as Codex/Claude |
cursor-agent |
Cursor-style agents | editor-bridge |
🟡 Experimental | Local/remote bridge configured via EDITOR_BRIDGE_URL / EDITOR_BRIDGE_API_KEY / EDITOR_BRIDGE_MODEL |
harness-agent |
Harness-style agents | cloud-api |
🟡 Experimental | OpenAI-compatible HTTP bridge configured via HARNESS_API_URL / HARNESS_API_KEY / HARNESS_MODEL |
Adapters declare capabilities honestly — including that approval interception is not yet a complete sandbox. Isolation, audit logs, and visible terminal output are the current safeguards. Full details in docs/agent-compatibility-matrix.md.
Agents don't free-chat into the void. They speak a structured protocol — group-chat for humans, typed events for the platform:
<agent-message intent="proposal">
We should extract the adapter registry behind an interface before adding the GLM adapter.
</agent-message>Role cards are plain YAML with real permissions:
id: reviewer
name: Reviewer
description: Finds risks, contradictions, missing tests, and unsafe assumptions.
permissions:
can_edit_files: false
can_request_decision: true
can_execute_commands: false
speaking:
default_intents: ["critique", "risk", "question"]
verbosity: conciseSix roles ship out of the box — Orchestrator, Architect, Implementer, Reviewer, Researcher, Summarizer — plus five task templates: Architecture Design, Code Implementation, Code Review, Research Discussion, and Bug Fix. Because everything is YAML, you can version your team's roles like code.
Prerequisites: Node.js 20+, npm, and (optionally) a real CLI agent such as Codex CLI or Claude Code.
# 1. Install dependencies
npm install
# 2. Start the backend (Fastify API on 127.0.0.1:3020)
npm run dev
# 3. In a second terminal, start the web app (Vite on 127.0.0.1:5173)
npm run dev:webOpen http://127.0.0.1:5173 and:
- Create a task with the Architecture Design template.
- Open the task room and pick an adapter preset from the runtime panel.
- Start an agent — try a Generic PTY command that prints
<agent-message intent="status">Ready</agent-message>for a zero-dependency smoke test. - Watch its messages land in the timeline; drill into raw output in its terminal drawer.
- Trigger a decision request, resolve it, then generate the task report and check
.multi-agent/tasks/<task-id>/report.md.
For real agents, read docs/adapter-runtime-local-setup.md first — the workbench provides worktree-friendly runtime controls and visible logs, not a complete command sandbox.
npm test # Vitest across the workspace
npm run typecheck # tsc project references across server, web, shared
npm run build # production build of all workspacesThe backend serves the built web app itself on one port — no separate static server needed:
npm run build
npm start # or: ./scripts/start.sh (Windows: .\scripts\start.ps1)Open the URL printed by the server (it includes the access token), or paste the token into
the sign-in screen. Docker is also supported: docker compose up --build (see
Deployment).
The API runs agents that execute arbitrary commands on your machine, so it is locked down by default:
- Random access token — a token is generated on first start and persisted under
.multi-agent/data/server-token(gitignored, 0600). Every/apiand/eventsrequest must present it viaAuthorization: Bearer <token>or themaw_tokenHttpOnly cookie. The terminal prints a ready-to-openhttp://127.0.0.1:3020/?token=...URL. Override withMAW_TOKEN. - Same-origin serving — in production the web app is served from the same origin as the
API, so no cross-origin access is needed at all. CORS is only enabled in development for
http://127.0.0.1:5173(the Vite dev server); override withMAW_CORS_ORIGINS. - Host allowlist — requests with a
Hostheader other than127.0.0.1,localhost, or::1are rejected (403), blocking DNS-rebinding attacks. Extend withMAW_ALLOWED_HOSTS. - Loopback binding — the server listens on
127.0.0.1:3020only. Change the port withMAW_PORT.
Other environment variables: MAW_WORKSPACE_ROOT (workspace/project root, defaults to the
directory you launch the command from), MAW_WEB_DIST (built web app directory).
Dependency notes: the shipped runtime tree (
npm audit --omit=dev) is clean. The only remainingnpm auditfindings are in the dev toolchain (Vite/esbuild dev server advisory, GHSA-67mh-4wv8-2f99) — they never ship and only affect the local dev server. Fixing them requires the breaking Vite 8 upgrade, which is tracked separately.
Approval interception is still not a complete sandbox — isolation, audit logs, and visible terminal output remain the safeguards for agent actions themselves.
npm run build
npm start
# Open the token URL printed in the terminaldocker compose up --buildThe compose file mounts your git repository at /workspace and keeps runtime data in a named
volume. Note that git worktrees created inside the container record container-absolute paths —
run git operations from inside the container when using them.
multi-agent-workbench/
├── apps/
│ ├── server/ # Fastify API, event store, PTY runtime, orchestrator, approvals
│ └── web/ # React + Vite workbench UI
├── packages/
│ └── shared/ # @maw/shared — event protocol, projections, API types (single source of truth)
├── docs/
│ ├── superpowers/ # design spec & MVP implementation plan
│ ├── agent-compatibility-matrix.md
│ ├── adapter-development.md
│ └── adapter-runtime-local-setup.md
└── .multi-agent/ # role cards, task templates (runtime data is gitignored)
Server modules — EventStore · TaskRoomService · SessionManager · AgentRegistry ·
RoleRegistry · TemplateRegistry · OrchestratorEngine · ApprovalService · WorktreeManager ·
ArtifactService · SseBroker
UI views — Task List · Create Task · Task Room · Agent Roster · Message Timeline · Decision Panel · Approval Panel · Terminal Drawer · Artifact Panel · Diff Review
- ✅ Phase 1 — Room skeleton · web app, API, SQLite event store, single PTY agent, live timeline
- ✅ Phase 2 — Multi-agent & roles · role/template registries, multiple agents per room, structured messages, turn assignment
- ✅ Phase 3 — Decisions & approvals · blocking decision gates, risk-based approvals, audit views
- ✅ Phase 4 — Worktrees & diff review · per-agent worktrees, diff scanning, patch artifacts, approval-gated merge/discard flows
- 🟡 Phase 5 — Compatibility expansion ·
cli-once,glm-cli,harness-agent, andcursor-agenteditor bridge are experimental - ✅ Phase 6 — Hardening (core) · token auth, Host allowlist, same-origin serving, crash recovery, worktree auto-cleanup after merge
- 🔶 Phase 6 — Hardening (remaining) · full command sandboxing, sample packs (in progress)
- Design spec — vision, principles, full architecture
- MVP implementation plan — how the MVP was sliced
- Agent compatibility matrix — adapter maturity and availability
- Adapter development guide — build your own agent integration
- Local adapter runtime setup — launching Codex CLI / Claude Code safely
- MVP demo script — the 15-minute guided demo
Released under the MIT License — an OSI-approved permissive license. You are free to use, modify, and distribute this project for any purpose, including commercial, as long as the copyright notice is preserved.
Copyright (c) 2026 sjc88661