Multi-agent orchestration daemon. C++20 daemon spawns claude -p subprocesses, manages conversations via ball-passing HANDOFF protocol, coordinates agents through filesystem vaults.
Local-first, single machine. No blockchain.
Phase status, roadmap, and design context live in the maintainer's design vault. This file is a CLI cheatsheet for running Quorum day to day. For "what is it / how does it work" — see
README.md.
# Dependencies (macOS)
brew install openssl@3 sqlite
# Build
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
# Run tests
cd build && ctest --output-on-failure
# Put the `quorum` CLI on PATH (~/.local/bin) + role skills + supervisor agent (make uninstall removes)
make install
# Scaffold .quorum/ in a project (once per project, from its root)
quorum init# Basic — leader receives goal, team takes over (auto-discovers .quorum/)
quorum converse "Analyze mm-bot spread performance"
# Brainstorm mode — read-only team; human-gated knower self-write
quorum converse --mode brainstorm "Where should we draw module boundaries?"
# With a turn limit
quorum converse --max-rounds 5 "goal"
# Suppress vault writes for an experimental run (no knowledge pollution)
quorum converse --no-vault-write "explore X without shaping future runs"converse exits when the conversation reaches a terminal state (the one-shot
default; pass --keep-alive to keep the daemon running afterward).
The second engine: a single interactive supervisor session runs an
operator-prepared flight plan by fanning out parallel subagents. See
templates/specs/autopilot-protocol.md.
# 1. Generate the flight-plan config (auto-fills the roster from .quorum/agents/)
quorum supervisor init # writes ./SUPERVISOR.md + .quorum/autopilot/checkpoint.md
# 2. Edit the "## Flight plan" section of SUPERVISOR.md (the startup gate stops on the placeholder)
# 3. Run it INTERACTIVELY (never headless `claude -p` — billing rides the 5h windows)
claude --agent supervisor # cwd = the project with SUPERVISOR.md# Re-survey the codebase after a build — the knowers re-run their scans and self-write their vaults (the accumulation command)
quorum knower refresh [--all | --knower <name>] [--project <path|name>]
# Ask a project's manager (or a specific --agent) a question — LLM answer from knower vaults + live code, read-only
quorum ask "what did we decide about durability?" [--project <path|name>] [--agent <name>]
# Deterministic $0 ranked keyword search over accumulated ref-*.md notes (no LLM)
quorum search "durability decision" [--project <path|name>] [--agent <name>] [--limit N]
# Vault hygiene
quorum vault dedup [--dry-run] # cluster near-duplicate rule-*/ref-* notes
quorum vault audit [--days N] # list stale (last_reviewed) + expired notes
# Calibration benchmarks for a specialty
quorum benchmark --role move-dev [--task <name>]
quorum benchmark --role cpp-dev [--task <name>]
quorum benchmark --role ts-dev [--task <name>]quorum statusWhen the leader is waiting for human input (waiting_for_human state):
quorum respond --conversation 1 "response text"quorum resume --conversation 1quorum close --conversation 1Run without a conversation subcommand (processes existing queue):
./build/quorum_daemonAPI server (Hono + Bun, port 3100) + React frontend (Vite + Tailwind, port 3101).
One command (recommended) — runs both in the background, installs deps if needed:
./scripts/web.sh start # → dashboard at http://localhost:3101
./scripts/web.sh status # running state
./scripts/web.sh stop # stop both
./scripts/web.sh logs # tail both logs
# (or: make web / make web-status / make web-stop)Foreground dev (two terminals) — when you want live-reload output in view:
cd quorum-web && bun run dev # Terminal 1 — API (http://localhost:3100)
cd quorum-web && bun run dev:client # Terminal 2 — UI (http://localhost:3101)API endpoints:
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/conversations |
List all conversations |
| GET | /api/conversations/:id |
Conversation detail with tasks |
| GET | /api/stats |
Aggregate stats |
| GET | /api/events |
SSE stream (real-time updates) |
| POST | /api/converse |
Start a conversation |
| POST | /api/respond/:id |
Respond to leader |
| POST | /api/close/:id |
Close a conversation |
| POST | /api/resume/:id |
Resume a paused conversation |
| Location | What |
|---|---|
.quorum/quorum.db |
SQLite: task queue, conversations, agent sessions |
.quorum/vaults/{agent}/ |
Agent vaults: CONTEXT.md + knowledge/ |
.quorum/agents/*.yaml |
Agent definitions (role, class, vault paths) |
.quorum/config.yaml |
Project config (daemon settings, budget, conversations) |
.quorum/autopilot/checkpoint.md |
Autopilot resume + morning-review state (Phase 13) |
SUPERVISOR.md (project root) |
Autopilot flight plan — generated by quorum supervisor init |
.quorum/quorum.pid |
PID lock file |
- Per-task token cap: kills
claude -psubprocess if exceeded - Window budget: daemon pauses all invocations when the window budget is exhausted (resets after
window_hours) - Max turns per conversation: set via
--max-rounds, pauses conversation when reached - Sequential dispatch: one task at a time, no concurrent agent invocations
- PID lock: prevents duplicate daemons on the same machine
# Check if daemon is running
cat .quorum/quorum.pid && kill -0 $(cat .quorum/quorum.pid) 2>/dev/null && echo "running" || echo "stopped"
# Recent tasks (column-agnostic — avoids drift; use .headers for names)
sqlite3 -header -column .quorum/quorum.db "SELECT * FROM tasks ORDER BY rowid DESC LIMIT 10;"
# Active conversations
sqlite3 -header -column .quorum/quorum.db "SELECT * FROM conversations WHERE state != 'closed' ORDER BY rowid DESC;"
# Inspect the live schema (the source of truth is quorum-core/src/storage/schema.h)
sqlite3 .quorum/quorum.db ".schema tasks"The canonical schema lives in code at
quorum-core/src/storage/schema.h. These checks useSELECT */.schemarather than hardcoded column names so they never drift as the schema evolves — read the columns off the output (or the header) instead of memorizing them here.
claude -prefuses to launch inside another Claude Code session (CLAUDECODEenv var). Must run from a regular terminal.- Buffered stdout when redirected to file — add
std::flushfor real-time tailing.
- Runs on: macOS (local, single machine)
- Runtime dependency:
claudeCLI must be installed and authenticated - DB:
.quorum/quorum.db(SQLite, WAL mode) - PID file:
.quorum/quorum.pid
| Problem | Fix |
|---|---|
| "PID file exists" on start | rm .quorum/quorum.pid if process is dead |
| Stale SQLite WAL/SHM | rm -f .quorum/quorum.db-wal .quorum/quorum.db-shm |
| Agent invocation hangs | Check claude CLI auth; verify API key is valid |
| Tasks stuck in pending | Check daemon log for invoker errors; verify token budget not exhausted |
Conversation stuck in waiting_for_human |
Use respond --conversation <id> "text" to unblock |
| Window budget exhausted | Daemon pauses dispatch; increase budget via web UI or wait for window reset |