The High Council
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@The High CouncilPlan the data model for an offline-first bookmarking app, single user"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
The High Council
A planning harness that runs one idea past several AI models from different labs and makes them argue about software engineering, architecture, specific features, roadmaps and philosophy. It stops at a checkable result, at a price estimated before you spend anything. You choose the number of debate rounds, the seats and labs (any lab except xAI), and the token limit for each model's replies.
We recommend our own chains: cheap-7-v2, plan-premium-7 and plan-highest-7 (the top
models, GPT-6 Astra, Claude Opus 5.5 (Claude Fable 5.1 in the published 0.7.8), DeepSeek V4 Pro
and GLM-5.3, write the alternative
architectures and are the only seats that vote; cheaper seats write the proposals and the debate). You can also edit a chain to suit yourself, or run every seat on
your own machine with local-ollama.
See it work right now - no keys, no setup, no cost:
npx the-high-council council demoThe demo takes one example request (a tool that renames holiday photos by date) through every stage: blind proposals, an anonymised debate in which one proposal is withdrawn and two are amended, a panel that splits in round 1 and signs off in round 2, and the handoff file. Every model reply in it is written in advance; what is real is the code that runs the stages around them.
What it costs. You pay the model providers directly, with your own API keys. The demo,
doctor, init and the mock chains cost $0 and make no network call. --dry-run prints a
run's worst-case price before anything is called, and every run stops before any stage that could
take it past its spend cap ($7 unless you set --max-usd). Most runs cost less than the worst
case: a panel that signs off early skips the remaining rounds.
Three commands from nothing to a priced run of your own idea (no key needed until you drop
--dry-run; Your first ten minutes walks through them):
npx the-high-council demo # $0: every stage, scripted replies, no network
npx the-high-council init # writes tasks/my-first-task.md for your idea, plus a $0 mock run
npx the-high-council --task tasks/my-first-task.md --chain cheap-7-v2 --dry-runWhich chain. Worst-case prices as council doctor prints them, from the shipped price table
(prices as of 2026-09-06) and the default task-size estimate; a long task costs more.
Chain | Who does what | Needs | Worst case |
| Claude Sonnet 5 writes the plan; low-cost models from seven other labs review it, and all seven must sign off. Up to 7 rounds. | one OpenRouter key | $5.38 |
| A Claude Code session writes the plan; a seven-lab panel of larger models (GPT-6 Astra, Claude Fable 5.1, Gemini 3.8 Flash, Muse Spark 1.2, Qwen 3.8 Max, DeepSeek V4 Pro, GLM-5.3) proposes, debates and reviews. | OpenRouter key + a Claude Code session | $21.59 |
| Seven low-cost models propose and debate; four top models write whole architectures and are the only reviewers; one deep-dive seat checks the first draft against the task. Untested with real models. | OpenRouter key + a Claude Code session | $10.54 ($14.89 in the published 0.7.8) |
| Every seat on your own machine, through Ollama. | Ollama and the models pulled | $0 |
plan-premium-7 and plan-highest-7 cost more than the default cap, so give them a --max-usd at
or above their dry-run price. Their writer seats are external: the run pauses
and a Claude Code session (or you) writes that stage, at no API cost. Nothing about any chain's
output quality has been measured.
Add it to Claude Code as an MCP server:
claude mcp add council -- npx -y the-high-council council --mcpIt is also listed in the official MCP Registry as io.github.muad-yasin/the-high-council, and
there is a one-file Claude Desktop bundle (Quick start (MCP)).
Runs as an MCP server (so an agent like Claude Code can drive it) or as a CLI. Bring your own API keys. Nothing is resold, nothing is hosted for you, and your keys go only to the providers you choose, never to us.
Run npx the-high-council council doctor to see which of your own keys are
set, which shipped chains you can already run with them, and what each would cost - before
spending anything. Where it falls short: Known limits.
On what this does and doesn't claim. This repo publishes the mechanism: the chains, the seat rosters, the stage order. It does not claim to produce better plans than a single good model would. That is an open question and we have not measured it. What it does, concretely, is make disagreement between models visible and recorded instead of averaged away - you can read who objected to what, who withdrew a proposal under argument, and who held their position.
Your first ten minutes
New to API keys, or to this? This path costs nothing until step 4, and step 4 tells you the price before anything is spent.
Watch one.
npx the-high-council demowalks an example request through every stage with scripted replies. No key, no network, $0.Make it yours.
npx the-high-council initwritestasks/my-first-task.md(edit it into your own idea, in plain words) andchains/my-first-chain.json, and runs a $0 mock pass so you can look inside a real run folder.Find the least setup.
npx the-high-council doctorlists what your keys can run. Its "Start here" block names the chains that need one key only: a singleOPENROUTER_API_KEY(one account at openrouter.ai that reaches many labs' models) is enough for a seven-lab panel. Put the key in a file called.envin the folder you run from, asOPENROUTER_API_KEY=..., and add.envto your.gitignoreso it is never committed.Price it, then run it. Add
--dry-runto see the worst-case price for your task, then run it without:npx the-high-council --task tasks/my-first-task.md --chain cheap-7-v2 --dry-run npx the-high-council --task tasks/my-first-task.md --chain cheap-7-v2Every run stops before it would pass its spend cap ($7 unless you set
--max-usd). A run stopped by the cap keeps what it paid for but has no plan yet, so pick a cap at or above the dry run's price. A panel that signs off early costs less than the worst case.The plan lands in
runs/<time>/deliverable.md; the argument behind it is inBOARD.md.
No key and no budget? A chain can run on models on your own machine through
Ollama at $0, if your computer can run them.
Everywhere below, council means npx the-high-council unless you installed it globally.
Related MCP server: polyplan-mcp
Words used here
Lab - a company that makes AI models (Anthropic, OpenAI, Google, DeepSeek, ...). "Different labs" means models trained by different companies.
Provider - where a call goes and who bills it: a lab's own API, OpenRouter (many labs, one key and one bill), or
ollama(your own machine).API key - a secret string from a provider that lets a program use your account there. You pay the provider for what the program uses; nobody else sees the key.
Seat - one job in a run, filled by one model: the one that writes criteria, the builder, a critic, and so on.
Chain - a JSON file that says which model sits in which seat and which stages run. Pick one with
--chain;council doctorlists them all.Task - your request, a plain text file in
tasks/. No format.Criteria - yes/no checks the plan has to pass, written from your task before anyone plans.
Proposal, debate - each lab suggests parts of the plan without seeing the others, then they read each other's (with names hidden) and object, support or merge.
Panel, round, sign-off - the critics grade the draft against the criteria; each failed check goes back for a revision, which is one round. Sign-off means a critic found nothing failing.
Dry run -
--dry-run: price a run, call nothing.Spend cap - the most one run may cost. It is checked before every paid call.
Mock - a fake provider with scripted replies, for trying the machinery for free.
External - a seat that waits for a person or another agent (such as your Claude Code session) to answer it from a file.
Handoff -
HANDOFF.md, the build instructions a coding agent works from.
A visual write-up of all of this, built around one real run, is at sower-industries.de/MCP. What changed in each release: CHANGELOG.md.
How it works
A run moves through fixed stages. Which stages fire depends on the chain you pick.
Questions - a seat reads the request and asks only the questions whose answers would change the output. You answer them (or take its stated defaults).
Criteria - the request becomes a short list of acceptance criteria, each one a yes/no check rather than a matter of taste.
Skeleton - an outline the other models will propose against. Names the parts, decides nothing.
Proposals - every lab proposes buildable parts, blind to each other.
Debate - the labs read each other's proposals, anonymised, and post support / object / merge. Then each author replies: keep, amend, or withdraw.
Build - one seat integrates the surviving proposals into a single document.
Panel review - every critic independently grades the draft against the acceptance criteria, blind. Not unanimous? It revises against the union of every objection and the panel reviews again, up to the chain's round cap.
Handoff - a
HANDOFF.mdwritten for whoever executes the result.
Some chains add optional stages to this: whole alternative architectures written blind before the skeleton, a deep-dive check of the first draft, a dispute stage that records unresolved objections at the top of the plan, and a final security review.
Every run writes a folder: the deliverable, BOARD.md (the full debate - every post, every
withdrawal), HANDOFF.md, a per-lab scoreboard, and the real token/cost accounting.
Reading a run with a program
BOARD.md is for people. report.json is the same board, structured - if you are building
anything on top of a run, read that instead. Do not parse the markdown. The format is versioned
(schemaVersion) and published as a JSON Schema, schemas/report-v1.json; which fields are stable,
which are experimental, and how versions change: docs/report-format.md.
{
"schemaVersion": 1, "runId": "...", "chain": "...", "passed": false, "maxUsd": 7,
"criteria": [ "each acceptance criterion, as written before the debate" ],
"questions": [ { "question": "...", "why": "...", "default": "..." } ], // null if the chain skipped them
"proposals": [ { "id": "DEEPSEEK-1", "lab": "deepseek", "model": "...",
"title": "...", "serves": "...", "what": "...", "why": "...",
"how": "...", "acceptance_test": "...", "attempt": 1,
"withdrawn": true, "amended": true, "replaced_by": "GLM-1" } ],
"dropouts": [ { "lab": "...", "model": "...", "stage": "proposals", "reason": "..." } ],
"debate": {
"posts": [ { "by": "deepseek", "on": "QWEN-1", "stance": "object|support|merge",
"text": "...", "merge_with": "GLM-2" } ],
"replies": [ { "id": "DEEPSEEK-1", "action": "keep|amend|withdraw",
"text": "...", "replaced_by": "GLM-1" } ],
// Since 0.7.8 (experimental): posts and replies the harness rejected, counted per lab and
// reason (unknown_target, own_proposal, bad_stance, not_own_proposal, not_posted_on,
// bad_action, unreadable). [] when nothing was dropped.
"dropped": [ { "stage": "debate|replies", "by": "qwen", "reason": "unknown_target", "count": 1 } ]
},
// Only on chains with `alternatives: { enabled: true }`: one whole architecture per lab, written
// blind before the skeleton, and the same post/reply board the proposals get.
"alternatives": {
"items": [ { "id": "GLM-ALT", "lab": "glm", "model": "...", "name": "...", "shape": "...",
"key_tradeoffs": "...", "bad_at": "...", "amended": true, "withdrawn": false } ],
"posts": [ { "by": "qwen", "on": "GLM-ALT", "stance": "object|support|merge", "text": "..." } ],
"replies": [ { "id": "GLM-ALT", "action": "keep|amend|withdraw", "text": "..." } ],
"dropouts": [ { "lab": "...", "model": "...", "stage": "alternatives", "reason": "..." } ]
},
// Only on chains with `argued: { enabled: true }` (off by default, on in no shipped chain): the
// "How this plan was argued" section, written to ARGUED.md next to deliverable.md (never inside it)
// by the handoff seat, from a fact pack of this run's own record. unknown_refs / unknown_labs are
// ids and labs it named that the run never had; each is also a line in WARNINGS.md.
"argued": {
"file": "ARGUED.md",
"facts_counts": { "labs": 7, "alternatives": 7, "proposals": 14, "objections": 9, "...": 0 },
"unknown_refs": [], "unknown_labs": [], "missing_labs": [], "missing_sections": [],
"refs_cited": 23, "ok": true
},
"signoff": [ { "lab": "qwen", "provider": "qwen", "model": "...", "signedOff": false,
"objections": [ { "criterion": "...", "problem": "...", "fix": "..." } ] } ],
"lastCritique": { "meets": false, "failures": [ { "criterion": "...", "lab": "qwen" } ] },
"scoreboard": {
"rows": [ /* one per proposal, with its outcome */ ],
"labs": [ { "lab": "deepseek", "model": "...", "proposed": 3, "accepted": 0,
"cut": 0, "withdrawn": 3, "unaccounted": 0, "built": null } ]
},
"totals": { "input": 0, "output": 0, "total": 0, "usd": 0, "unpriced": [] }
}proposals plus debate.posts is a directed graph with verifiable edges: one node per proposal,
one edge per posture, and replies[].action says what each author did with their own proposal
once they had read the argument against it. That is the whole artifact, already machine-readable.
scoreboard.labs is the per-lab tally already aggregated for you — start there for a scoreboard
rather than counting proposals yourself.
dropouts is the field you will regret ignoring. A lab whose proposals came back unreadable
after a retry is dropped from the run: it is not in proposals, not in the debate, and not in the
scoreboard. It is only in dropouts. A consumer that counts labs from proposals and reports
"four labs debated this" will be wrong — the roster shrank, and the run log says so loudly at the
time. Report a seated lab that produced nothing as what it was, or you are publishing a panel that
was smaller than you claim. Treat null and [] alike here; runs written by older versions have
no such field at all.
Two of these are not closed schemas. debate.replies[] is built by spreading the model's own
reply object and normalising id, action and replaced_by over it, so an entry carries at least
those plus text and may carry more (an amend often brings a how). replaced_by is only set
when the action is withdraw. proposals[] likewise carries withdrawn / amended /
replaced_by only when they apply. Read defensively: check for a field, do not assume it.
Chains with newer, opt-in stages add their own fields (deep_dive, notQuorate, dispute,
security_review, ...); docs/report-format.md lists which are stable and
which experimental. With the majority guard on, a withdrawal that does not quote the argument it
concedes to carries unargued: true in debate.replies[] and its proposal stays for the builder.
signoff[].lab is the seat's lab; signoff[].provider holds the same value under an older,
misleading name and is deprecated (kept until the report format's version 2).
signoff[].objections is why a seat declined, on the seat's own record. signedOff: null means
the seat gave no usable reply and abstained - neither a pass nor an objection, and objections is
null rather than empty so the two stay apart. A seat that agreed has an empty list.
The same objections also appear flattened in lastCritique.failures[], tagged with lab, because
the reviser wants the union across the whole panel. Both are built in one pass; they cannot drift.
Before you publish a run, note that report.json records task as the path to your task file
(relative to where you started the run, never absolute). Nothing transmits it anywhere - but if you are rendering a board onto a public
page, drop that field. The debate itself is the part worth showing.
Requirements
Node 20+
API keys for whichever labs the chain you choose actually uses
Setup
Nothing to install beyond Node: npx the-high-council council <command> fetches the published
package and runs it. To keep a council command on your PATH instead:
npm install -g the-high-council
council doctorcouncil reads and writes in the directory you run it from: .env for keys, tasks/ for
requests, runs/ for output, and a chains/ of your own there takes precedence over the bundled
ones. Put only the keys your chosen chain needs in that .env, one NAME=value per line
(.env.example in the package lists them all). Supported providers:
ANTHROPIC_API_KEY · OPENAI_API_KEY · GOOGLE_API_KEY · MISTRAL_API_KEY ·
DEEPSEEK_API_KEY · GROQ_API_KEY · TOGETHER_API_KEY · COHERE_API_KEY ·
OPENROUTER_API_KEY · ZAI_API_KEY
xAI/Grok is never seated, and neither is a router id (openrouter/auto, the Pareto Code router)
that could route to it: chain-lint refuses such a chain and the run itself refuses such a seat,
with no override. There is no xai provider. Kimi/Moonshot models are not in any chain this
package ships, but you may seat one in a chain of your own.
The CLI refuses to start if any seat in the chosen chain is missing its key, rather than failing
halfway through a paid run. ollama (below) is the one exception - it needs no key at all.
A keyed seat sends its key only to its own provider's https API. A chain that points a keyed
seat's baseUrl anywhere else is refused before any call (see
Local models).
Other settings, all optional, read from the environment or .env:
Variable | What it does |
| The default per-run spend cap ( |
| MCP server only: the folder for |
| MCP server only: a cap the MCP client cannot raise or remove through |
|
|
| Sent to an |
| Your own persona set for debate seats (PERSONAS.md). |
| Signs the opt-in audit log (see Privacy). |
From source
git clone https://github.com/muad-yasin/the-high-council-mcp.git
cd the-high-council-mcp
npm install
cp .env.example .envIn a clone, node src/cli.js does what council does, on the current source rather than the
published package. npx github:muad-yasin/the-high-council-mcp council demo runs the current
source without cloning.
Standalone binaries (build them yourself)
There are no published binary downloads yet. From a clone you can build a single-file council
that needs no Node install to run: a Linux binary, a Linux AppImage, and a Windows .exe, all
built on Linux.
npm run build:bin # dist/the-high-council-linux, dist/the-high-council-win.exe
npm run build:appimage # dist/the-high-council-x86_64.AppImage (downloads a pinned appimagetool)
npm run smoke:bin -- dist/the-high-council-linux # demo + an MCP session, offline, $0Stated plainly: the .exe is tested under Wine on Linux, not on a real Windows machine, and none
of the binaries are code-signed, so Windows SmartScreen will warn. Put .env in the directory you
run the binary from.
Local models (Ollama, LM Studio, ...)
A seat can run on a model you're hosting yourself instead of a paid API. Set its provider to
ollama:
{ "provider": "ollama", "model": "llama3.1" }This talks to Ollama's own OpenAI-compatibility endpoint (http://localhost:11434/v1 by
default) - no OLLAMA_API_KEY needed; Ollama's docs describe a key as "required, but unused."
If your local runner listens somewhere else (LM Studio, a different port, a remote box), add
baseUrl to that seat:
{ "provider": "ollama", "model": "mistral", "baseUrl": "http://localhost:1234/v1" }Put a local or self-hosted server on an ollama seat, as above. A seat with a keyed provider
(openrouter, openai, ...) sends that provider's key to its baseUrl, so chain lint refuses
one whose baseUrl is anything but that provider's own https API address (key-host), and the
CLI lints before every run and every resume. For a local proxy in front of the provider, set
COUNCIL_ALLOW_LOOPBACK_KEY_HOST=1 in your environment: it allows a loopback address, nothing else.
A local seat prices at $0 in every estimate and run report - dry_run shows it as priced, not
"unpriced," and it can never trip the spend cap. See chains/local-ollama.json for a full
example chain with every seat local. As with every other seat in this project: BYOK is really
BYO-compute here, and no efficacy claim is made about local models versus hosted ones - nothing
has been measured.
Final security-review gate
"security_review": { "enabled": true } adds one read-only reviewer as the last stage of a chain,
after the build and everything else. It returns typed findings, and any critical or high finding
fails the run (exit 7). A reviewer with no usable verdict fails it too (exit 8); that never counts
as a pass. The default reviewer is anthropic/claude-fable-5-1 (your key, priced, capped);
seats.security_reviewer can be any seat, including a local ollama one as an offline option.
Full details: docs/security-review-gate.md.
Quick start (CLI)
A task file is the request the council plans against: plain prose, written by you. There is no template and no format - write what you actually want, including the constraints that matter.
mkdir -p tasks
echo "Plan the data model for a bookmarking app. Single user, offline-first." > tasks/your-idea.md
# see what's available and what it would cost
council --help
council --task tasks/your-idea.md --chain verify --dry-run
# a real run
council --task tasks/your-idea.md --chain verifyYour requests and everything the council writes about them stay on your machine, in tasks/ and
runs/ under the directory you ran from. In a clone of this repo both are gitignored, so a fork
will not accidentally publish them.
verify is the default when you name no chain: a panel of two labs, a hard two-round cap. It
needs three keys (Anthropic, OpenAI and Google, one account each). With one OpenRouter key, start
with cheap-7-v2 instead; council doctor lists every chain that runs on the keys you have.
--chain takes a chain's name (cheap-7-v2), never a file path: a chains/<name>.json of your
own in the working directory is found by its name.
If your task names files. A task that names a file (src/app.js) without including its
content is stopped before any call (exit 9, BLOCKED-ARTIFACTS.md), because the seats would
otherwise plan against code they never saw. Put the real content in with
council fence --task tasks/x.md --repo <path to your repo> src/app.js (it appends each file,
fenced and labelled, and refuses to write if it finds a key), read the task file, then run.
If a name is only a location, pass --allow-unfenced for the whole task or
--allow-unfenced app.js for named files. Everything in the task file goes to every seat.
Exit codes
Each outcome has its own code, so a script or CI job can branch on it:
Code | Meaning |
0 | Finished: a deliverable and |
1 | The chain failed lint, or an input is missing (no task file, a resume from the wrong directory). |
2 | Usage error: a flag is missing its value or has an invalid one, |
3 | Paused at an external seat: answer |
4 | Stopped at the per-run spend cap before the next stage was paid for; resume with a higher |
5 | A provider key the chain needs is missing (degradable: set it and run again). |
6 | Fatal: the chain file cannot be parsed, or the audit key cannot be loaded. |
7 | Finished, but the final security review blocked the deliverable. |
8 | Finished, but the final security review could not judge it (never a pass). |
9 | Artifact gate: the task names files whose content it never includes ( |
10 | Preflight: a seat objected to the task description itself ( |
11 | PII gate ( |
12 |
|
13 | Another process is already running this run folder. |
14 | The task file changed since the run started and |
15 |
|
16 | The run stopped at an unexpected error (a seat that could not be reached, a crash); |
17 | A draft (build, revise, dispute, final edit or handoff) was cut off at its token cap, and its one larger-cap retry was cut off too; the fragment is never graded or shipped ( |
Codes 9-17 were split out or added on 2026-09-23. Before that, several of these outcomes shared a code (2, 5, 6 or 1).
Telling the council what your build session can actually use
One optional convention, worth the four lines it costs. If your task file ends with a section
headed ## Available tools, the handoff seat will name the right one in the acceptance test
for each item of work, instead of inventing a check from nothing:
## Available tools
- `scope-gate` - decides GO / NEEDS-SPEC / KILL before anything is built
- `bug-audit` - reads code line by line, reports verified defects, edits nothing
- `npm test` - the project's own suiteThe council is told what exists, not how it is invoked, and is instructed never to name a tool that is not on your list. Leave the section out and the handoff assumes nothing beyond your test suite - which is what it did before this existed, and what it will keep doing.
This costs no tokens you were not already spending: the task file is already in the handoff seat's
prompt. It is the difference between "write a test for this" and "run scope-gate on this
before building it."
The spend cap
Every run has a per-run ceiling in USD. It defaults to $7, and is checked before each paid stage - a stage that could take the run past the ceiling is never called, so the cap holds rather than reporting the overspend afterwards.
council --task tasks/x.md --max-usd 2 # this run stops at $2
council --task tasks/x.md --max-usd none # no ceiling
export MAX_USD_PER_RUN=20 # change the defaultA run that hits the ceiling stops cleanly and writes STOPPED-budget.md saying what it spent, which
stage it stopped at, and what that stage would have cost. Nothing is half-written: it produces no
deliverable.md and no report.json, so a stopped run never reads as a finished one. What it did
get through is in report-partial.json and BOARD-partial.md
(docs/report-format.md). Continue it with a higher ceiling - completed
stages replay from disk and cost nothing the second time:
council --resume runs/<id> --max-usd 10A stage replays only if it would be asked the same thing again: the task text, the chain config
and the stage's own prompt must all match what it answered. If one changed (you edited the chain,
or an earlier stage came out differently this time), the stage runs again and its old files move
into superseded/ inside the run folder. What the old answer cost still counts toward the ceiling,
--spend and report.json's totals.usd (shown separately as totals.supersededUsd), so a resume
cannot spend past the cap. An answer you wrote for an external stage is never re-used against a
changed prompt: it is set aside the same way and the run asks you again.
The cap governs one run. To see what you have spent across all of them:
council --spend # today
council --spend --days 7 # the last week
council --cost-today # today by calendar day, with a per-model breakdown
council --cost-today --date 2026-09-01
council --stats --days 30 # how the debate mechanism itself is doingThat is read back off the run folders on disk - there is no ledger file, nothing is recorded
anywhere else, and nothing leaves your machine. Runs still going, or stopped by the cap, are
counted from the stages they already paid for. The same figures are available to an MCP client as
spend_report.
To watch this work without spending anything, the mock-budget chain calls no API but carries
fixture prices:
council --task tasks/your-idea.md --chain mock-budget --max-usd 1If a chain pauses for your input, it writes NEEDS-<stage>.md into the run folder and tells you
how to resume:
# write your answer to runs/<id>/answers.md, then:
council --resume runs/<id>Quick start (MCP)
Register the server with your MCP client. No clone needed - from the published npm package:
claude mcp add council -- npx -y the-high-council council --mcpThe same line with npx -y github:muad-yasin/the-high-council-mcp runs the current source
instead.
Or from a clone of this repo:
claude mcp add high-council -- node /absolute/path/to/the-high-council-mcp/src/mcp/server.jsThe path must be absolute. The client starts the server from its own working directory, not from this one, so a relative path resolves somewhere unexpected and the server never starts.
Or as a Claude Code plugin, which registers the same server and also installs the skills in
skills/:
claude plugin marketplace add muad-yasin/the-high-council-mcp
claude plugin install the-high-council@the-high-councilClaude Code copies the plugin into its plugin cache and runs npm ci there itself, so the first
install takes a little longer. Start a new session (or run /reload-plugins) and the server shows
up in claude mcp list as plugin:the-high-council:high-council. Remove it with
claude plugin uninstall the-high-council@the-high-council. If you add the marketplace from a
local clone instead (claude plugin marketplace add /path/to/clone), the server runs from the
clone itself, so run npm install in it first.
Claude Desktop: download the-high-council-<version>.mcpb from the
GitHub Releases page (its SHA-256
is next to it) and open it. Claude Desktop shows a settings form: a council folder for tasks and
runs, a per-run spend ceiling that Claude cannot raise or remove from a chat, and one optional
field per provider key (marked sensitive, so the app keeps them in the OS keychain). The bundle is unsigned. How it is built:
mcpb/README.md.
MCP Registry: the server is listed in the official registry as
io.github.muad-yasin/the-high-council (npm package, stdio). A client that installs from the
registry runs the same npx command as above.
Registering with a client other than Claude Code (DeepSeek Harness, OpenHands, Cline, goose, Continue): docs/mcp-clients.md has the real config for each.
Whichever way you add it, the server reads and writes in your working directory, not inside
the package: .env for keys, tasks/ for requests, runs/ for output, and a chains/ of your
own takes precedence over the bundled ones. In a git project, add .env (and runs/ if your
ideas are private) to .gitignore before an agent commits everything; council doctor warns
when .env is not ignored.
The server only works inside that directory. dry_run and start_run take a chain by name.
Every path start_run is given (task, draft, context, from_run, and each file inside a
context folder or from_run run folder) must resolve inside the working directory, after
symlinks, and must not be on the secret/credential denylist; outside tasks/, runs/ and
context/ a gitignored file is refused too. Set COUNCIL_MAX_USD_LIMIT in the server's
environment to cap what the client's max_usd can ask for.
To run it by hand:
council --mcp # from a clone: npm run mcpThen drive it with these tools:
Tool | What it does |
| Available chains with descriptions and worst-case price |
| Write the request the harness plans against |
| Price a run before spending anything |
| Start a run in the background ( |
| Stage reached, panel verdicts, scoreboard, cost, budget remaining |
| What every run has cost across a window of days, plus |
| How the debate mechanism itself is doing, per chain and per lab: sign-off rate, rounds, objections, dropouts, cost/wall time, largest prompt files - derived from disk |
| Descriptive telemetry only (never an evaluation or baseline): amendment rate, withdrawal rate, objection-follow-through rate, tool-call usage, consensus-induced-regression count - derived from disk. See |
| The prompt a paused external stage is waiting on - read it with this, not by opening the file; the prompts are routinely tens of thousands of tokens and most clients silently truncate a file read. |
| Write a self-contained bundle for a paused stage, so a driving session doing other work at the same time can dispatch it to a fresh subagent instead of authoring it inline - see |
| Answer a paused stage; the run resumes once every stage it waits on has an answer. Optional |
| Resume a paused run, or raise |
| Read any file from a run folder ( |
| Past runs |
| Section tree of a run's deliverable (or a |
External vs. API-backed seats. { "provider": "external" } pauses a run at that seat so a
Claude Code session on a flat-rate subscription plays it - free at the point of use, since the
subagent runs on the same subscription. If you don't hold a flat-rate subscription and pay
metered rates for everything anyway, { "provider": "anthropic" } (or another API provider) may
be simpler for those seats: no dispatch pattern to learn, at roughly 5x the metered cost of the
same debate on external, based on one measured comparison, not a guarantee. Not the default
anywhere in this repo's config, README ordering, or example chains - external stays recommended
for anyone with a subscription, since the project's cost story depends on it.
Chains
52 chain configs live in chains/. Each one is plain JSON - the seat roster, which models fill
which seat, the round cap, and whether proposals/debate/handoff stages run. They are meant to be
copied and edited.
The four recommended ones (cheap-7-v2, plan-premium-7, plan-highest-7, local-ollama) are
in the table at the top. A few more worth knowing:
verify- two labs, two rounds. The default when you name no chain; needs Anthropic, OpenAI and Google keys.plan-open-7- thecheap-7-v2panel, with a Claude Code session writing the plan instead of a paid seat.plan-daily-7-plan-highest-7's stages at a lower price, for planning one feature: Claude Opus 5.5 on your Claude subscription (an external seat), GPT-6 Luna and DeepSeek V4 Pro write the architectures and alone vote; seven low-cost labs propose and debate. Two Claude Code sessions answer its external seats: Opus 5.5 every stage whose label ends inopus5.5-sub, Sonnet 5 the writer stages. $1.90 worst case. Untested with real models.cheap- small models throughout. For testing the harness itself, not for real work.plan-debate- five labs propose blind, debate each other's proposals anonymised, then a blind panel grades the integrated draft.plan-auto- the full open-scope chain with every seat on a real API, so no stage waits for an external session. It still pauses once for your answers to its questions.plan-unanimous- every critic must independently sign off on the same draft. Three rounds here means up to fifteen critic calls, not five.
Read a chain's description field before running it; they say what they cost you in calls.
Optional chain-config fields
schemaVersion- an integer, optional.council doctorwarns (never fails) when a chain omits it or names an older/newer one than this build knows about. A chain file without it keeps working exactly as it always did - this is a warning, not a requirement.max_proposals_per_seat- an integer, opt-in, no default. Debate size stays unlimited unless a chain file explicitly sets this. When it is set and one seat's own proposals still exceed it, that seat gets one merge prompt to fold its own list down before the debate board ever sees the extras.role- optional, on anyseats.proposersentry only (set anywhere else andcouncil doctorrejects it fail-loud, since it would silently do nothing there):{ lens?, persona? }.lensis one ofadversary | integrator | long-horizon | user-advocate | security-and-legal- a critique function.personais a name - a voice, resolved against the default set inPERSONAS.mdwhen it matches, otherwise used as free text. Applies only to that seat's debate-stage prompt; the panel/critique stage that setspassednever sees it, enforced by a source-level guard, not just an intention. A chain with noroleset is byte-identical to before. No efficacy claim: this ships the mechanism, not evidence that it helps - see CHANGELOG.md's 0.6.0 entry.quorum: { "minHeard": N }- opt-in, unanimous chains only, set in no shipped chain. A round's sign-off counts only when at least N reviewers gave a verdict (signed off or objected); a round short of it is recorded asnotQuorate, the run does not pass, and the loop stops.Tiered councils (experimental, used by
plan-highest-7,plan-daily-7andmock-tiered).seats.alternativesnames who writes the whole alternative architectures, separately from the proposers.deep_dive+seats.deep_diveadd one non-voting seat with its own dollar cap (usd, required) inside the run's cap.majority_guard.enabledshows each author every argument once, with no lab name or count, and keeps a proposal whose withdrawal does not quote the argument it gives in to. chain-lint refuses a tiered chain where a lab or model sits both among the proposers and among the reviewers or architecture authors, or where the deep-dive seat shares a lab or model with a reviewer. See CHANGELOG.md's 0.7.8 entry.
How this was built
Vibecoded, with Claude Code doing the writing, by one person at Sower Industries. Parts of it were planned by the harness itself — the build order for its own v2 went through a four-lab council, and the plan came back with one of its findings built on evidence that turned out to be wrong, which is recorded rather than quietly dropped.
The parts worth knowing, because they explain why the code looks the way it does:
Almost every defensive branch here is a headstone. parseJson in chain.js repairs two
specific malformations — an unescaped " inside a markdown-quoted span, and raw newlines inside
string values — because three consecutive real runs died on the first one and silently logged a
pass that never happened. The comments name the run id and the date. The retry that disables
thinking exists because an Anthropic seat burned its entire maxTokens budget thinking and
returned nothing. The ROSTER SHRANK warning exists because a lab can return nothing and vanish
from the scoreboard without saying so. None of these were designed in advance; each one is a day
that went wrong.
The failure modes are testable offline. The mock provider has named models
(mock-unreadable, mock-provider-error, mock-proposer-empty, mock-critic-holdout) that each
drive one of those branches for $0, so the regression tests run without keys and without spend.
docs/ ships no JavaScript on purpose. The landing page arrived from a design tool depending
on an unlicensed runtime that also fetched React and Babel from a CDN at page load. Shipping it
would have relicensed someone else's build artifact as MIT and put a third-party request on a page
shared with a German site. Its loops were pre-rendered to static HTML and the fonts self-hosted
instead. test/landing-page.test.js fails if a script tag or a third-party URL ever comes back —
and if the page's typed-in numbers stop matching the repo, which has already caught the page
claiming 29 chains and 12 tools when there were 30 and 11.
No claim is made here that any of this produces better plans. It has not been measured.
Skills
skills/ carries a small set of Claude Code skills shipped alongside this harness, not part of
it - usable in any project, with or without the harness, and needing no API key:
Core agentic work:
task-scoping,research-and-sourcing,verification-and-critique,context-and-handoff,tool-and-action-discipline- the work around the work, for any agent task, including setups where several models propose, critique, and hand off to each other.Building software:
backend-developer,frontend-developer,ux-design,visual-craft.Writing:
good-news-writing.
The full catalog, with when to use each and what it guards against, is
skills/README.md; a shareable presentation page is docs/skills.html. Both
are checked by the test suite against the real skills/ folder. Same MIT/BYOK ethos as the
harness: the skills don't claim to make results better - nothing has been measured - they describe
what each rule guards against and why. Copy the folders you want into your project's
.claude/skills/, or point Claude Code at this repo's skills/ directory.
Known limits, stated plainly
The spend cap is enforced against a worst case, not a prediction: the whole prompt billed as input plus the seat's entire
maxTokensbudget billed as output (doubled for Anthropic seats, which may retry once). Real stages almost never cost that much, so a run can stop with headroom left. That is the intended trade - resume it with a higher ceiling.A seat whose model has no entry in
src/pricing.jsonis unpriced, and therefore uncapped. It contributes $0 to the running total no matter what it really costs. Checkdry_runoutput forunpricedbefore trusting a ceiling.ollamaseats are the one deliberate exception: they price at an explicit $0 for any model name (they are genuinely free to run), so they never show up in thatunpricedlist and never need a pricing.json entry.A call that fails after it reached the provider - the connection drops while a 200 reply is being read, a 200 carries a body that is not JSON, or the request times out waiting for headers - is not retried, because the generation was probably already billed. Its real usage cannot be read, so it is counted toward the per-run cap at its worst-case projection. It leaves no
<label>.usage.json, socouncil --spenddoes not see it.Some hosted reasoning models stop at a provider-side reasoning ceiling well below the seat's own cap, before writing any answer (seen 2026-09-23:
deepseek/deepseek-v4.1-flashvia OpenRouter, 6 of 28 calls stopped at ~4.2k tokens, all reasoning, under a 36k cap). A bigger cap cannot fix that, so such a reply is recorded asREASONING_EXHAUSTEDand is not retried: the seat abstains, which blocks unanimity and never counts as consent. Whether to change a chain's reasoning settings for it is a roster decision, not something the harness does for you.Prices in
src/pricing.jsonare hand-maintained list prices. ItsasOfdate (2026-09-06: the oldest date every entry was last checked) is printed bycouncil doctorand--dry-run, with a warning once it is more than 60 days old. The spend cap and every estimate use these static prices. They are estimates, not invoices. Your provider's bill is the real number.plan-highest-7andplan-daily-7, the tiered councils, have not been run with real models, and none of their mechanisms (tiers, the deep-dive seat, the majority guard) has been measured. Their dry-run prices are projections.Seats marked
external(the writer seats inplan-premium-7,plan-highest-7,plan-daily-7andplan-open-7, and the Opus 5.5 anchor seat inplan-daily-7) pause the run until someone answers them, and are $0 only because a Claude Code session on a subscription writes them. Nothing checks who wrote the answer.Chains with many labs and high round caps get expensive quickly.
plan-unanimousat three rounds is fifteen critic calls;plan-autoruns several frontier models over multiple rounds. Price before you run.A panel that signs off is not a guarantee the output is correct. It means every critic seat checked it against the stated acceptance criteria and found nothing. Criteria that are vague produce sign-offs that mean nothing - the quality of the run depends heavily on the quality of the criteria stage.
Some chains pause for human input by design. They are not stuck.
The audit log (
audit.jsonl) detects an edited line or a cut-off end, but with no HMAC key, which is the default, it does not detect a full rewrite: anyone who can edit the file can recompute every hash. SetAUDIT_HMAC_KEY_FILEto a key kept outside the run folder if the log has to stand up to that.
Privacy
This tool collects nothing. Stated plainly, not as a claim about quality:
No telemetry, no analytics, no tracking of any kind, anywhere in this repo.
The only network calls this tool ever makes are to the AI provider APIs you configure with your own keys (
ANTHROPIC_API_KEY,OPENROUTER_API_KEY, and so on) - and only when you start a real run with a non-mock, non-external seat.council doctorandcouncil demomake zero network calls; both are implemented to read only local files and environment variable names.The landing page in
docs/ships no JavaScript and loads no third-party resource - seetest/landing-page.test.js, which fails the build if either ever changes.Everything a run produces - the task, the debate, the deliverable, the cost - is written to a folder on your own disk (
runs/<id>/) and nowhere else. Deleting that folder deletes the record. Seesrc/spend.js's own documentation for why spend accounting is derived from those folders rather than kept in a separate log.If you opt in to the audit export (
"audit": true, and on automatically whenever apolicy.jsonexists), each run also writesaudit.jsonlinto its own folder: signed, hash-chained lines (each carries the previous line's hash) thatverifyAuditLoginsrc/audit.jschecks offline. Seat, cost and timing only, never task or prompt text. Format:docs/audit-schema.md.
Accessibility
The landing page (docs/) uses only native HTML elements for interaction - <a href>
links and <details>/<summary> for the expandable demo sections - specifically because those
are keyboard-operable by the browser itself, with no custom JavaScript to get wrong. Tested by
hand, 2026-09-13, on the live site:
index.html: tabbed from the page's first link; focus reached the "Clone the repo", "How it works" and "Try it (demo)" buttons in order, each showing a visible focus ring; pressing Enter on "Try it (demo)" navigated todemo.html, the same as a click.demo.html: tabbed to the first proposal's<summary>("A-1 Synchronous invalidation..."); pressing Enter expanded it in place (the ▶ marker flipped to ▼ and the body text appeared), identical to clicking it.No custom widget on any page (
index.html,board.html,demo.html) uses a<div>or<span>with a click handler in place of a real interactive element - checked directly in the page source, not inferred.The only image in
docs/is the local logo (logo-diamond.png): the header copy carries alt text, the faint background copy onindex.htmlhas an emptyalt=""as decoration.test/landing-page.test.jschecks both on every page.Primary body text (
#8d8a84/#b9b5ad) against the page background (#0a0a0b) measures roughly 5.7:1 contrast by the WCAG relative-luminance formula, above the 4.5:1 AA threshold for normal text.
Reporting a bug
Open an issue at github.com/muad-yasin/the-high-council-mcp/issues. For anything security-related, or that should not be public, write to contact@sower-industries.de instead.
If this makes you money
The licence is MIT. You owe nothing, and that is the whole licence - nothing below changes it.
If The High Council ends up helping you build something that earns, I'd ask for 0.7% of what it earns. Not a fee, not a clause, not a subscription. A request between people who build things.
There is no reporting, no audit, no tracking, and nothing checks. No is a complete answer - use it, fork it, sell what you build with it, and never think about this section again. That is a fine outcome and it's why the licence says what it says.
If you'd rather say yes: pay what you think it's worth.
License
MIT. See LICENSE. The section above is a request, not a term of it.
This server cannot be deployed
Maintenance
Related MCP Connectors
Commission a multi-model AI spec committee from your agent; get rubric-scored, build-ready specs.
Shared projects for people and AI agents: plans, contributions, questions and reviews. Beta.
Run AI agent evaluations on your own model keys, and publish runs others can review and re-run.
1AI work orchestration for plans, tasks, teams, and coding-agent dispatch.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables multi-model code review by fanning out issues to multiple LLMs simultaneously, diffing their unique insights, optionally running debate rounds, and dispatching subagents to implement fixes with git commits.72MIT
- AlicenseAqualityDmaintenanceEnables structured multi-model AI planning sessions across multiple CLI coding tools, orchestrating independent planning, peer review, and final synthesis.167 npm1MIT
- AlicenseAqualityCmaintenanceFacilitates structured multi-agent debates with arguments, rebuttals, and judgments across multiple rounds, enabling diverse AI personas to engage in formal debate and collaborative problem-solving.119 npm17MIT
- FlicenseAqualityDmaintenanceEnables a host AI agent to trigger a multi-agent debate, running N-rounds where agents critique each other's answers, then synthesizes a consensus recommendation with ranked options.3-