QUORUM.md format

Define an entire organization — name, budget, mission, and every agent — in a single Markdown file. The complete reference.

Last updated

A QUORUM.md in the org root is the org definition — its name, budget, mission, and every agent, all in one file. Nothing else is scaffolded, and edits take effect on the next boot. (The mission, as always, only seeds the board on the first boot.)

This file is yours. The running org treats QUORUM.md as read-only and won’t rewrite its own charter — change the team, budget, or mission by editing it yourself and rebooting. The org shapes what it does through its goals, tasks, and hires; it never edits the definition it runs on.

The whole thing

# Acme Labs

A two-person studio shipping weekend projects.

- budget: 25
- defaults: { "provider": { "type": "claude", "model": "claude-opus-5" } }

## Mission

Launch the landing page and collect 100 signups.

## Agents

### CEO

You are the CEO. Set direction, break the mission into tasks, delegate.

### Engineer

- reports to: CEO
- capabilities: { "crm": "allow" }

You are the engineer. Build what's asked and verify it works.

One rule throughout

A key: value line (optionally - bulleted) whose key is recognized for its scope is metadata; every other line is prose. Values are single-line and parse as JSON when possible, exactly like agent-file frontmatter. Keys match loosely — reports to, reports-to, and reportsTo are the same key.

That means:

  • The # title is the org name; prose under it is the description.
  • ## Mission is the mission — everything in that section, headings and all, verbatim.
  • Each ### under ## Agents is one agent: the heading is its role (and id), the prose is its system prompt.
  • Each ### under ## Triggers is one event trigger — a schedule, an inbound webhook, a polled inbox, or a process watcher. See Triggers & scheduling.
  • Unrecognized ## sections are ignored, so the file can hold notes for humans too.
  • Anything inside a code fence is verbatim prose — headings and key: lines there are never parsed as structure, so a mission can safely contain examples.

Two caveats worth knowing while you iterate: the only hard parse error is a file with no agents — everything else degrades quietly (an unrecognized key becomes prose, a malformed value stays a string). And the parser doesn’t validate inside JSON objects like provider or capabilities, so a misspelled field passes through silently rather than erroring; if a setting seems ignored, check its spelling first.

Org keys

Placed as key: value lines under the # title.

key meaning
name org name (default: the # title)
description one-liner (default: the prose under the title)
budget spend caps in USD — a bare number means { "totalUsd": n }; the full object takes totalUsd (lifetime — the org halts for good), dailyUsd, monthlyUsd, perCycleUsd, and a warnAt fraction (default 0.8) at which a budget warning is audited; omitted fields mean no cap. See Cost & budget
defaults org-wide agent defaults: { "provider": {...}, "capabilities": {...} }
provider shorthand for defaults.provider
channels named outbound routes the org sends through — types slack, resend (transactional email), webhook — e.g. { "slack": { "type": "slack", "channel": "#general", "secret": "slack-bot-token" } }; see Acting in the world
payments the payment provider the org charges customers through — { "provider": "stripe", "secret": "stripe-secret-key", "mode": "test", "currency": "usd" } (provider also accepts the merchant-of-record paddle / lemonsqueezy); see Acting in the world
telemetry the observability backend the org reads its own servers’ logs & metrics from — { "provider": "cloudflare", "account": "<account-id>", "secret": "cloudflare-analytics-token", "window": "1h" }; see Acting in the world
errors the error tracker (Sentry) the org reads its own unresolved issues from — { "provider": "sentry", "org": "<org-slug>", "project": "api", "secret": "sentry-token", "window": "24h" }; a host field points at a self-hosted Sentry (default https://sentry.io); see Acting in the world

Agent keys

Placed as key: value lines under a ### agent heading.

key meaning
id bus address and directory name (default: slug of the heading); what other agents’ reports to must reference. Repeat a heading and the id is auto-numbered (engineer, engineer-2)
role the agent’s label / job title (default: the heading)
goal the agent’s own standing goal, injected alongside the org mission
reports to the manager’s id; omit it to make the agent a root (the org lead)
provider this agent’s brain — overrides defaults.provider
capabilities per-agent allow / ask / deny overrides
skills skill packs from the org’s skills/ folder injected into this agent’s task prompts — a JSON array or comma-separated names; see Skills
budget this agent’s own spend caps in USD — a bare number means { "totalUsd": n }; the object takes dailyUsd, monthlyUsd, totalUsd, warnAt. Past a cap the agent is benched — its open work moves to an in-budget colleague — while the rest of the org keeps running; see Cost & budget

The reporting tree’s root (an agent with no reports to) is the lead — it coordinates, plans, and reviews. There is normally exactly one.

The provider object

Used as provider: on an org default or a single agent. See The brain for the full story.

field meaning
type the brain: "claude", "codex", an agent-CLI family member ("opencode" / "cline" / "copilot" / "cursor" / "grok" / "qwen" / "amp" / "pi" / "goose" / "hermes" / "kimi" / "droid" / "antigravity"), the lightweight "llm" text brain, "openai" (any OpenAI-compatible server over direct HTTP — LM Studio, vLLM, OpenRouter, remote OpenAI), or "fake" (deterministic, offline)
model model id, e.g. claude-opus-5, gpt-5-codex, gpt-oss:20b. Unset, the tool runs the model it’s configured with (required for openai)
baseUrl API root of an OpenAI-compatible server, e.g. http://localhost:1234/v1 for LM Studio (openai; default https://api.openai.com/v1)
apiKeyEnv name of the env var holding the bearer token; unset means no auth header (openai; default OPENAI_API_KEY)
effort reasoning effort: low | medium | high | xhigh | max (claude)
maxBudgetUsd hard per-session spend ceiling enforced by the binary (claude)
bin path to the binary (default $CLAUDE_BIN / $CODEX_BIN / the binary name on PATH)
timeoutMs per-call timeout (default 10 minutes)
retries retry count on failure (default 3)
args extra raw CLI args appended to every call
mcp path(s) to MCP server config JSON the org owns; null disables
strictMcp isolate from the operator’s own MCP servers (default true)
settingSources --setting-sources value (e.g. "project,local") limiting which settings the binary loads
browser true gives the brain the org-owned browser as MCP tools (claude)
bare true opts out of session persistence — every turn starts fresh (claude)
fallbacks failover chain — each entry inherits this config and overrides what it sets
pricing override the cost-per-token table used by the cost ledger

Capabilities

Each capability is "allow", "ask" (routes an approval request to you), or "deny". Set org-wide via defaults.capabilities, per agent via capabilities. Built-in defaults are allow for everything except crm and charge (both ask). Capabilities that gate a declared backend stay inert until you declare it: charge / revenue (payments), logs (pull the org’s own server telemetry — read-only, needs a telemetry backend), and errors (pull the org’s own unresolved issues — read-only, needs an errors backend). Three namespaces add capabilities of their own: secret:<name> (stored credentials — deny unless granted), channel:<name> (outbound channels — ask holds each message for your approval), and each MCP server’s name. Full details in Tools & permissions.

- defaults: { "capabilities": { "crm": "allow", "hire": "ask", "channel:email": "ask" } }

### Builder
- capabilities: { "secret:github-token": "allow", "secret:cloudflare-api-token": "allow" }

Skills (reusable know-how)

A skill pack is one markdown file in a skills/ folder beside QUORUM.md — reusable, versioned know-how below the persona: a coding standard, an outreach playbook, a deploy recipe. An agent’s skills: key names the packs injected into its task prompts, the same way the runtime’s own hints are:

### Engineer

- skills: ["shipping-standards", "code-review-checklist"]

Names match the pack’s filename case-insensitively, with or without .md, and packs are injected in the order declared. The folder is read fresh on every activation, so editing a pack takes effect on the agent’s next task — no restart. A name with no matching pack is flagged once in the log and audit trail, never fatal.

When the know-how needs more than prose, a pack can be a folderskills/<name>/ with a SKILL.md entry and its resources (templates, scripts, reference docs) beside it. Only the SKILL.md is injected; the prompt names the folder’s path, and agents that can use tools read the resources on demand instead of paying for them in every prompt. A folder pack shadows a same-named flat file, so upgrading foo.md to foo/SKILL.md wins even if the old file lingers:

skills/
  shipping-standards.md          ← a flat pack: injected verbatim
  deploy-recipe/                 ← a folder pack
    SKILL.md                     ← injected; the rest is read on demand
    wrangler.toml.tmpl
    checklist.md

Personas stay business prose — the persona describes the job; a skill holds the mechanics and playbooks, where several roles can share one pack and your version control tracks every revision. There is no store and no marketplace behind this: the folder is the registry, and installing a shared pack is copying it in — deliberately no bundle or archive format, so packs stay plain files you can diff and review.

A fuller example

This example uses nearly every option — custom ids, per-agent brains, standing goals, capability overrides, and outbound channels.

# Cedar Loft

A four-person product studio that ships small SaaS products end to end.

- budget: { "totalUsd": 50, "dailyUsd": 10, "monthlyUsd": 40, "perCycleUsd": 2 }
- defaults: { "provider": { "type": "claude", "model": "claude-opus-5", "effort": "medium" }, "capabilities": { "crm": "allow", "hire": "ask", "channel:email": "ask" } }
- channels: { "slack": { "type": "slack", "channel": "#studio", "secret": "slack-bot-token" }, "email": { "type": "webhook", "url": "https://mail.cedarloft.dev/send", "secret": "mail-hook-secret", "from": "hello@cedarloft.dev" } }

## Mission

Launch a paid landing page for the scheduling product and collect the first
100 signups. Validate pricing with at least ten real customer conversations.

## Agents

### CEO

You are the CEO. Set direction, break the mission into tasks, and delegate to your
leads.

### CTO

- id: ren
- goal: Keep the product shippable at all times.
- reports to: CEO
- provider: { "type": "claude", "model": "claude-opus-5", "effort": "high" }
- capabilities: { "hire": "allow" }

You are the CTO. Own technical strategy and direct the engineer.

### Engineer

- reports to: ren
- provider: { "type": "claude", "model": "claude-sonnet-5", "effort": "medium", "maxBudgetUsd": 2 }
- capabilities: { "hire": "deny", "delegate": "deny", "secret:github-token": "allow", "secret:cloudflare-api-token": "allow" }
- skills: ["shipping-standards"]

You are the engineer. Keep every project in a GitHub repository, publish to
Cloudflare, and register what you ship.

### Dry-Run Analyst

- reports to: CEO
- provider: { "type": "fake" }

You are the analyst. Sanity-check plans and numbers before the org commits
to them.

A few things this file shows: the CEO omits reports to, which is what makes it the root — the lead. The engineer’s reports to: ren points at the CTO’s custom id, not the heading. And the analyst’s "fake" provider is the no-API brain — deterministic echoes, no key needed; give one agent (or defaults.provider) that type to dry-run a QUORUM.md for free.

The channels line gives every agent a voice (SEND[slack]: … posts to #studio; email waits for your approval), and the two secret: grants give only the engineer the tokens it ships with — seeded once via quorum secret set. The full flow is in Acting in the world. The engineer’s skills line injects the org’s skills/shipping-standards.md pack into its every build task — see Skills.

Notice what the personas don’t say: nothing about quorum’s own mechanics. Personas describe the job — what the role owns, does, and delegates. Every agent is taught how to use the org’s systems (registering services, sending on channels, recording contacts, asking you for credentials) automatically; you never write that into QUORUM.md.

Drafting one from a brief

Don’t want to write it by hand? Describe the org in plain words and let Claude draft the file — one call, validated against the real parser, which you review before spending anything more:

quorum init --prompt "a newsletter studio: an editor leading a writer and a researcher"

Booting the drafted file never calls the LLM again. See the CLI reference.