Structured AI specialist discussions for OpenCode — produce high-quality specifications through multi-agent analysis, debate, and consensus.
Single-agent AI coding has a fundamental limitation: there's no peer review, no debate, no structured analysis. When one AI produces a specification, there's nobody to challenge assumptions, spot blind spots, or push back on weak ideas. The result is often a shallow, one-perspective document that looks complete but falls apart under scrutiny.
Mesa fixes this by orchestrating multiple AI specialists — each with distinct domain expertise — who analyze your project from different angles, debate their findings, and reach consensus before producing a specification. A backend architect sees things a security specialist misses; a product manager catches gaps an engineer overlooks.
Think of Mesa as a round table for AI agents: you bring the problem, Mesa assembles the right experts, and the structured workflow ensures every voice is heard before anything gets written down.
Mesa is an adaptive orchestrator, not a fixed pipeline. The Manager reads your briefing, designs a workflow tailored to your scope, gets it approved, and executes it using one universal primitive — the discussion round — composing parallel/sequential rounds with variable casts.
flowchart TD
Start([User types /agent briefing-writer]) --> Briefing
subgraph "Briefing"
Briefing[Briefing Writer\nstructured discovery] --> BReview{User reviews}
BReview -->|Changes| Briefing
BReview -->|Approved| BApprove[approve_briefing]
end
BApprove --> Team
subgraph "Team"
Team[Manager browses catalog\nlist_specialists] --> Propose[propose_team]
Propose --> TReview{User reviews}
TReview -->|Changes| Propose
TReview -->|Approved| Summon[summon_team]
end
Summon --> Plan
subgraph "Workflow Plan — Gate 0"
Plan[Manager writes\nworkflow-plan.md] --> PReview{User approves plan}
PReview -->|Changes| Plan
PReview -->|Approved| Gate0["record_decision(type='gate', target='plan')"]
end
Gate0 --> Rounds
subgraph "Rounds — the universal primitive"
Rounds[open_round\ntopic + participants ⊆ team] --> Analyses[register_analysis × N\nPOSITION: agree / agree-with-reservations / disagree]
Analyses --> Close{close_round}
Close -->|disagree| Subset[subset round\nwith dissenters]
Subset --> Analyses
Close -->|converged / open-tensions| Next{More rounds\nin plan?}
Next -->|Yes| Rounds
end
Next -->|No| Deliverable
subgraph "Deliverable"
Deliverable[produce_deliverable] --> DReview{User reviews}
DReview -->|Rejected| Deliverable
DReview -->|Approved| DApprove[approve_deliverable]
end
DApprove --> Done([Done])
style Start fill:#4CAF50,color:#fff
style Done fill:#4CAF50,color:#fff
style Briefing fill:#2196F3,color:#fff
style Team fill:#FF9800,color:#fff
style Plan fill:#9C27B0,color:#fff
style Rounds fill:#F44336,color:#fff
style Deliverable fill:#00BCD4,color:#fff
The flow:
- Briefing — The Briefing Writer conducts a structured discovery interview, drafts a briefing document, and waits for your approval. Approval is a fact, not a phase —
approve_briefingis the only path to an approved briefing. - Team — The Manager browses the specialist catalog, proposes a team with justifications, and waits for your approval (
summon_team). - Workflow plan (gate 0) — The Manager writes
workflow-plan.md: deliverable, scope class, planned rounds, gates, and an explicitSkipped:line for every optional step. You approve the document; the Manager records it viarecord_decision. No round can open without an approved plan. - Rounds — For each round,
open_roundsets the topic and cast (a subset of the team). Specialists analyze and self-register their work, ending with a declaredPOSITION:block.close_roundrecords the outcome:converged,converged-with-open-tensions(tensions copied verbatim), orescalated(you judge). A declareddisagreevetoes "converged" — the Manager opens a subset round with the dissenters. - Deliverable —
produce_deliverablewrites the canonical artifact (specification, overview, journeys, appendix, …) with round provenance. You approve it viaapprove_deliverable.
Every approval gate — briefing, team, plan, deliverable — requires explicit human approval recorded through a tool. Verbal approval in chat is never sufficient.
Consensus is emergent: specialists declare positions; the Manager judges whether the process converged, never who is right. There is no structured voting.
# Install Mesa in under 2 minutes
curl -fsSL https://raw.githubusercontent.com/hacklabr/opencode-mesa/main/install.sh | bashThe script clones the repo, builds the plugin, generates the Mesa agents, and prints the plugin path to add to your opencode.json. Restart OpenCode, then start a discussion:
/agent briefing-writer
That's it. The Briefing Writer will guide you through discovery, and the workflow proceeds from there.
- OpenCode V2 (any recent version) or OpenCode V1 ≥ 1.18.29 — the plugin ships a dual-host entrypoint (
setup()for V2,server()for V1). On V1, the object entrypoint requires 1.18.29 or newer; older 1.x releases must pin Mesa v4.0.x. - Node ≥ 22.5.0 (the SQLite driver uses
node:sqlite) or Bun ≥ 1.3.0.
curl -fsSL https://raw.githubusercontent.com/hacklabr/opencode-mesa/main/install.sh | bashThis single command:
- Clones the repository to
~/.local/share/opencode-mesa - Installs dependencies and builds the plugin
- Generates the Mesa agents (
briefing-writer,manager, and the genericmesa/specialistsubagent) - Configures the plugin for your OpenCode version:
- V2: writes a discovery stub to
~/.config/opencode/plugins/mesa.js - V1: adds the plugin path to
~/.config/opencode/opencode.json(pluginkey)
- V2: writes a discovery stub to
git clone https://github.com/hacklabr/opencode-mesa.git ~/.local/share/opencode-mesa
cd ~/.local/share/opencode-mesa
bun install && bun run build && bun run setup:agentsOpenCode V2 — create ~/.config/opencode/plugins/mesa.js (the plugins config key does not load local file:// entries on V2):
export { default } from "file:///home/YOURUSER/.local/share/opencode-mesa/dist/index.js"On OpenCode V2, Mesa tools live in the Code Mode catalog under the mesa namespace (one catalog line instead of 24 inline tool descriptions, with search for discovery). If your environment runs without Code Mode, register the plugin with { "options": { "codemode": false } } to restore direct tool exposure.
OpenCode V1 — add to ~/.config/opencode/opencode.json:
{
"plugin": ["file:///home/YOURUSER/.local/share/opencode-mesa/dist/index.js"]
}curl -fsSL https://raw.githubusercontent.com/hacklabr/opencode-mesa/main/install.sh | bash -s -- \
https://github.com/hacklabr/opencode-mesa /path/to/installAfter restarting OpenCode, verify Mesa is loaded:
> mesa_status
You should see the plugin version and the current session summary (briefing, team, plan, rounds, deliverables).
curl -fsSL https://raw.githubusercontent.com/hacklabr/opencode-mesa/main/uninstall.sh | bashRemoves the Mesa agents (briefing-writer, manager, mesa/specialist), the plugin entry from opencode.json, and the clone at ~/.local/share/opencode-mesa. Your opencode.json is preserved otherwise.
Switch to the Briefing Writer agent and describe what you need:
/agent briefing-writer
The Briefing Writer conducts a structured discovery interview — goals, constraints, scope, success criteria. When complete, it calls create_briefing to save the document, and waits for your approval via approve_briefing. Approval also hands the briefing to the Manager — switch agents manually:
/agent manager
You can also import an existing document as a briefing (skips the interview):
> import_briefing(file_path="/path/to/my-briefing.md", slug="my-project", title="My Project")
The Manager browses the catalog with list_specialists / get_specialist and proposes a team:
> propose_team(specialists=[
{ personaId: "engineering-backend-architect", name: "Backend Architect", division: "engineering", justification: "..." },
{ personaId: "security-specialist", name: "Security Specialist", division: "specialized", justification: "..." }
])
If you approve, the Manager calls summon_team. Only summoned team members can participate in rounds.
Before the first round, the Manager writes workflow-plan.md in the session folder and presents it to you. On your approval:
> record_decision(type="gate", target="plan",
reason="Human approved workflow plan v1",
payload={path: ".mesa/sessions/<id>/workflow-plan.md"})
Mid-flight changes require a new file version plus record_decision(type="plan-amendment", ...) — silent replanning is detectable and forbidden.
> open_round(topic="API design for order management",
participants=["engineering-backend-architect", "security-specialist"])
The Manager invokes each participant via OpenCode's native task tool against the generic mesa/specialist subagent. Each specialist self-registers from its own session:
> register_analysis(agent_id="engineering-backend-architect", agent_name="Backend Architect", content="...", turn=1)
Every participant's final artifact ends with a declared position:
POSITION: agree | agree-with-reservations | disagree — [reason]
> close_round(
decision="converged-with-open-tensions",
summary="...",
tensions=["Rate limiting strategy unresolved — Security Specialist"],
evidencePaths=[".mesa/sessions/<id>/analyses/turn1/security-specialist.md", ...]
)
- A declared
disagreevetoesconverged— open a subset round with the dissenters, record the tension verbatim, or escalate to the human. evidencePaths[]is mandatory — decisions without cited evidence are rubber-stamping.- Analyses registered by the Manager on a specialist's behalf never satisfy the position requirement.
> produce_deliverable(kind="specification", topic="Order Management API", content="...")
> approve_deliverable(path=".mesa/sessions/<id>/specification.md", approved=true)
Kinds: specification, overview, journeys, appendix, other. Approved deliverables are immutable; each records the rounds it derives from.
The session has a single status — active, paused, or cancelled. All mutating tools require active.
stateDiagram-v2
[*] --> active
active --> paused : pause_discussion
paused --> active : resume_discussion
active --> cancelled : cancel_discussion
paused --> cancelled : cancel_discussion
Cancelling clears analysis data but preserves the briefing, team, and deliverables. On resume, the Manager re-reads the plan and round trace and declares its position before acting.
graph TB
subgraph "OpenCode Host"
User[User]
Agents[Agent Sessions\nbriefing-writer · manager]
TaskTool[task tool\nnative]
SubAgents["Generic Specialist Subagent\nmesa/specialist (empty body)"]
end
subgraph "Mesa Plugin"
Tools["24 Tools\nkernel 16 + peripheral 8"]
State["State Layer\nstate.ts · SQLite"]
Catalog["Catalog\nloader.ts · 367 specialists"]
Hooks["Hooks\nconfig · tool.execute.before\nchat.system.transform"]
end
subgraph "Workspace (.mesa/)"
Db[state.db]
Sessions["sessions/\nbriefing · plan · analyses\ndeliverables"]
AuditFile[audit.log]
end
Tools --> State --> Db
Tools --> Sessions
Tools --> Catalog
Hooks --> Agents
Agents --> Tools
Agents --> TaskTool --> SubAgents
style Tools fill:#E91E63,color:#fff
style State fill:#FFC107,color:#000
style Catalog fill:#4CAF50,color:#fff
style Hooks fill:#9C27B0,color:#fff
Mesa is an OpenCode plugin that registers 24 tools, a 367-persona specialist catalog, and three hooks. The plugin manages seams — cross-session capture, artifact integrity, human gates, circuit breakers, audit — while the workflow itself lives in the Manager's prompt. Specialist invocation happens through OpenCode's native task tool.
Key design decisions:
- Kernel/shell model — code keeps only what is a seam (K1–K5): cross-session capture, artifact integrity, human approval gates, circuit breakers, tamper-evident audit. Workflow topology, consensus format, and rigor live in the prompt.
- Data preconditions, not phases — guards check that required artifacts exist and are approved, never that the session sits at a pipeline position. Every error message teaches recovery.
- Specialists are real subagents — each runs in its own session with its own system prompt, injected at delegation time.
- Emergent consensus — specialists declare POSITION blocks; the Manager tabulates process state, never infers positions or judges content merit.
- The plan is the contract — intention (
workflow-plan.md), fact (state pointer), trace (rounds[]). Amendments bump the version with an audited reason. - Tool visibility filtering — specialist sessions receive only their 7-tool seam; denied tools are removed from the LLM payload, saving ~5.3k tokens per specialist session.
See docs/architecture.md for the full reference.
Mesa provides 24 tools: a 16-tool workflow kernel plus 8 peripherals.
| Tool | Description |
|---|---|
mesa_status |
Plugin status, session summary, and plan-gate instruction |
list_specialists |
List specialist personas (division?, search? filters) |
get_specialist |
Full details and system prompt of a persona (id) |
create_briefing |
Create a briefing document (slug, title, content) |
import_briefing |
Import an existing file as a briefing (file_path, slug, title?) |
approve_briefing |
Approve the briefing and hand it to the Manager — the only path to approved |
propose_team |
Propose a team with justifications for human approval |
summon_team |
Summon the approved team |
open_round |
Open a discussion round (topic, participants ⊆ team, briefing_content?) |
register_analysis |
Register a specialist's analysis in the open round (agent_id, agent_name, content, turn, file_path?, kind?, turn_type?) |
get_peer_analyses |
List analysis file paths and metadata (read-only) |
close_round |
Close the open round with an audited outcome (decision, summary, tensions, evidencePaths, humanOverride?) |
record_decision |
Record an audited decision — plan gate, amendments, overrides, delegations, notes (type, target?, reason, payload?) |
produce_deliverable |
Produce a canonical deliverable in the session folder (kind, topic, content, humanOverride?) |
approve_deliverable |
Approve or reject a deliverable — the only path to approved (path, approved, feedback?) |
ask_peer |
Ask a peer specialist a direct question with full session context |
| Tool | Description |
|---|---|
pause_discussion |
Pause the session; state preserved |
resume_discussion |
Resume a paused session |
cancel_discussion |
Cancel the session; clears analyses, preserves briefing/team/deliverables |
memory_store |
Store a cross-session memory entry (deduplicated) |
memory_recall |
Recall project memories by category/query |
memory_forget |
Soft-delete a memory entry |
mesa_check_update |
Check for a newer plugin version |
mesa_update |
Update the plugin (requires restart) |
All session state lives in .mesa/ within your workspace:
.mesa/
├── state.db # SQLite state (v15): briefing, team, rounds, deliverables, plan
├── audit.log # Tamper-evident action trail
└── sessions/
└── {timestamp}_{id}_{slug}/
├── briefing.md
├── workflow-plan.md # The approved plan (gate 0)
├── analyses/ # Per-turn analysis files
├── specification.md # + overview.md, appendices/, deliverables/
└── ...
Integrity is protected by data preconditions, not a phase state machine — every tool validates that the artifacts it depends on exist and are approved. The audit log records every significant action with the current plan version.
| Agent | Description |
|---|---|
briefing-writer |
Conducts structured discovery sessions to produce professional briefings |
manager |
Designs the workflow plan and orchestrates specialist rounds |
All 367 personas from the agency-agents catalog run through a single generic hidden subagent, mesa/specialist, registered with mode: subagent and an intentionally empty body. At delegation time the plugin resolves the persona (via the tool.execute.before hook):
- Inline persona block (primary) — the Manager includes
<specialist-persona id="...">...</specialist-persona>in the task prompt. Required on runtimes that reject non-ses_task IDs. task_idslug —task_id="mesa-{personaId}"; the hook injects the persona from the catalog. A stabletask_idpreserves specialist memory across rounds.
Specialist sessions see only their seam tools (register_analysis, get_peer_analyses, ask_peer, memory tools, mesa_status) — everything else is filtered out of the request payload.
To regenerate the agent files after plugin updates:
bun run setup:agentsbun install # Install dependencies
bun run build # Build the plugin (tsc + copy catalog)
bun run lint # Type-check without emitting
bun run typecheck # Type-check without emitting
bun test # Run test suite (vitest)
bun run dev # Watch mode (tsc --watch)
bun run setup:agents # Generate .opencode/agents/ (briefing-writer, manager, mesa/specialist)Prerequisites: Bun runtime, TypeScript 5+
Contributions are welcome. Please follow the conventions in AGENTS.md:
- Code in English (variables, functions, types, comments)
- Commits: concise, imperative present (
feat: add catalog loader,fix: handle missing frontmatter) - Run
bun run lintandbun run typecheckbefore every commit - Every new feature must include tests
See AGENTS.md for the full contribution guidelines.
The specialist catalog is sourced from agency-agents — see its license for catalog usage terms.