MCP server: One MCP server.

The High Council

@muad-yasinMCP server · External

Several models from different labs plan in a blind proposal, debate and review loop. Your own keys.

LLM access & routingv0.8.2MITJavaScript
Freeno charge per call

Runs on your machine from its package; the steps are below.

The council chamber from the project website: the debate graph of a real recorded run (a water-collector design), with the Claude seat in the middle.
From the README

What it does

  1. Reads
  2. Writes
  3. High impact

At most: moves money, runs code or commands, deletes data, or sends messages for you.

What it costs

Free

Odel charges nothing per call. The publisher may charge for its own service.

Runs locally over stdio

This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).

npmthe-high-councilv0.8.2

Run

npx -y the-high-council

MCP client config

{
  "mcpServers": {
    "the-high-council": {
      "command": "npx",
      "args": [
        "-y",
        "the-high-council"
      ]
    }
  }
}
README54 min read
Sower Industries diamond logo

The High Council

Several AI models from different labs argue about your idea, then debate on Software Engineering choices.
The goal is to get everyone to work together, in harmony and with manners. Effectiveness is unproven, but it is a fun way to spend your tokens!

npm MCP Registry License: MIT

Website · Releases · Changelog · Known limits

The council chamber from the project website: the debate graph of a real recorded run (a water-collector design), with the Claude seat in the middle.

Try it in 30 seconds

npx the-high-council council demo

No keys, no network, $0. Add it to Claude Code as an MCP server:

claude mcp add council -- npx -y the-high-council council --mcp

For Claude Desktop, download the .mcpb bundle (the-high-council-<version>.mcpb) from Releases.

Contents

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: plan-daily-7 (plan-highest-7's stages at a lower price, for planning one feature; it needs an OpenRouter key, a Claude subscription for its Claude Opus 5.5 seats and a Claude Code session to write the plan; this roster has not run yet), cheap-7-v2, plan-premium-7 and plan-highest-7 (the top models, GPT-6 Astra, Claude Opus 5.5, DeepSeek V4 Pro and GLM-5.3, write the alternative architectures; cheaper seats write the proposals and the debate; in plan-highest-7 and plan-daily-7 every seat in the chain also votes, blind, the plan's writer too). You can also edit a chain to suit yourself, or run every seat on your own machine with local-ollama. For a quick second opinion on one decision, the advisor add-on asks a single seat: GPT-6.1 Sol by default (council_advise with mode: "single", see Available tools).

See it work right now - no keys, no setup, no cost:

npx the-high-council council demo

The 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 two figures before anything is called: what the chain's own size assumptions expect a run to cost, and the most the planned calls could cost if every one used its seat's whole output allowance (re-asks and the cut-off retry of a seat that is not Anthropic are not priced; the spend cap is the only bound). 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 either figure: 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-run

Which chain. Prices as council doctor prints them (expected / at most), from the shipped price table (prices as of 2026-09-06) and the default task-size estimate; a long task costs more.

ChainWho does whatNeedsExpected / at most
plan-daily-7plan-highest-7's stages at a lower price, for planning one feature; every seat, the plan's writer included, also votes, blind; Claude Opus 5.5 on your Claude subscription takes the criteria, one architecture and one vote, and a Claude Code session writes the skeleton, the plan and the handoff (details under "Chains" below). This roster has not run.OpenRouter key + a Claude subscription + a Claude Code session$12.59 / $33.25
cheap-7-v2Claude 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$11.22 / $22.36
plan-premium-7A 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$36.75 / $78.59
plan-highest-7Seven low-cost models propose and debate; four top models write whole architectures; one deep-dive seat checks the first draft against the task; every seat, the plan's writer included, also votes, blind (the owner's deliberate choice, 7 Oct 2026). Untested with real models.OpenRouter key + Claude Code sessions$18.49 / $50.43
local-ollamaEvery seat on your own machine, through Ollama.Ollama and the models pulled$0 / $0

The first figure is what the chain's own assumptions expect (the typical output of a review, every round up to the cap); the second is the most the planned calls could cost if every one wrote its seat's whole output allowance (an Anthropic seat's one retry included; re-asks and the cut-off retry of other seats are not priced, so the spend cap is the only bound). The second figure is the larger one by a wide margin because the reasoning models can spend that allowance thinking (since 0.8.1 every shipped seat reasons at high). cheap-7-v2, plan-premium-7, plan-highest-7 and plan-daily-7 expect to cost more than the default cap ($7), so give them a --max-usd of your own: at or above the second figure to rule out a stop at the cap, or lower if you accept that a run that uses much of its allowance stops at the cap with no plan yet (it keeps what it paid for and resumes with a higher --max-usd). A run that signs off early costs far less than either figure. The writer seats of plan-daily-7, plan-premium-7, plan-highest-7 and plan-open-7, and the Claude Opus 5.5 subscription seats of plan-daily-7 and plan-highest-7, 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 --mcp

It 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.

  1. Watch one. npx the-high-council demo walks an example request through every stage with scripted replies. No key, no network, $0.

  2. Make it yours. npx the-high-council init writes tasks/my-first-task.md (edit it into your own idea, in plain words) and chains/my-first-chain.json, and runs a $0 mock pass so you can look inside a real run folder.

  3. Find the least setup. npx the-high-council doctor lists what your keys can run. Its "Start here" block names the chains that need one key only: a single OPENROUTER_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 .env in the folder you run from, as OPENROUTER_API_KEY=..., and add .env to your .gitignore so it is never committed.

  4. Price it, then run it. Add --dry-run to see the expected and the maximum 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-v2 --max-usd 22.37
    

    cheap-7-v2 expects $11.22 and could cost up to $22.36, both above the default cap, so the run command carries its own cap, set just above the maximum (re-asks and retries are not in it, so only the cap is a bound). Every 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; a cap below the maximum can stop a run that uses a lot of its allowance (resume it with a higher --max-usd). A panel that signs off early costs less than either figure.

    The plan lands in runs/<time>/deliverable.md; the argument behind it is in BOARD.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.

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 doctor lists 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/en/THC/. 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.

  1. 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).
  2. Criteria - the request becomes a short list of acceptance criteria, each one a yes/no check rather than a matter of taste.
  3. Skeleton - an outline the other models will propose against. Names the parts, decides nothing.
  4. Proposals - every lab proposes buildable parts, blind to each other.
  5. Debate - the labs read each other's proposals, anonymised, and post support / object / merge. Then each author replies: keep, amend, or withdraw.
  6. Build - one seat integrates the surviving proposals into a single document.
  7. 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.
  8. Handoff - a HANDOFF.md written for whoever executes the result. It ends with a block the harness writes, not a model: the acceptance criteria the run settled, how each checkable one is checked, and a fingerprint for each of the two. council check-lock HANDOFF.md ($0) says whether a copy still carries them; it catches an edit or a slip, and is not a signature. report.json also carries a small thin_contract (0.8.2): full-width hashes of the task, the criteria, the evidence the run recorded as shown to the seats (the --context documents and the tool results; never a repository, seats do not see one, and not material handed in with --draft or --from-run) and the text the panel signed, plus one hash over the record. council contract check runs/<id> ($0) recomputes what the run folder still holds and says sealed, DRIFT (what changed) or cannot check (never a pass for what it could not read). Like the lock, it is tamper-evident, not tamper-proof: whoever can edit report.json can edit the record too. HANDOFF.md also carries two short sections the harness writes (no model does): "Before you build" (read the plan and write down blockers before coding; the criteria are not to be edited; the record's hash in plain text, which council contract check runs/<id> --handoff HANDOFF.md compares with the run) and "Replan triggers" (stop and send the plan back when the contract check or check-lock reports a difference, when a named check fails twice in a row, and so on). The "twice" is handoff_contract.check_failures in a chain, default 2. A chain can also set handoff_contract.milestones (off by default; on in the seven shipped planning chains, where the handoff seat is asked for the milestone shape): the harness then lints the milestones the handoff seat wrote ($0: every criterion discharged by a milestone that has a named check and an expected result) and records what it found in report.json (handoff_milestones), WARNINGS.md and the "Before you build" section; a finding never changes passed.

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.

A run that stopped before it wrote its handoff (the spend cap, an abandoned pause, a crash) can get one from its latest draft: council handoff --from-run runs/<id>. It is one call on the chain's handoff seat, under the run's own spend cap (what the folder already cost counts toward it; --max-usd N is a total, as on --resume), the same policy check and key scan as a run, and a run no panel signed off gets a note at the top, written by the harness, saying so. It never overwrites an existing HANDOFF.md.

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.

jsonc
{
  "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:

bash
npm install -g the-high-council
council doctor

council 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, any other openrouter/<name> id) 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 (except COUNCIL_ADVICE_SENSITIVITY_FLOOR and COUNCIL_ADVICE_CHAINS_DIR, which only the server's own environment sets: a project's .env is something an agent can write):

VariableWhat it does
MAX_USD_PER_RUNThe default per-run spend cap (7 when unset). --max-usd overrides it for one run.
COUNCIL_WORKDIRMCP server only: the folder for tasks/ and runs/, when the client starts the server somewhere else.
COUNCIL_MAX_USD_LIMITMCP server only: a cap the MCP client cannot raise or remove through max_usd.
COUNCIL_ALLOW_LOOPBACK_KEY_HOST1 lets a keyed seat use a loopback baseUrl (a local proxy in front of the provider). Nothing else.
OLLAMA_API_KEYSent to an ollama seat's server only if you set it.
COUNCIL_PERSONAS_FILEYour own persona set for debate seats (PERSONAS.md).
AUDIT_HMAC_KEY / AUDIT_HMAC_KEY_FILESigns the opt-in audit log (see Privacy).

From source

bash
git clone https://github.com/muad-yasin/the-high-council-mcp.git
cd the-high-council-mcp
npm install
cp .env.example .env

In 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.

bash
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, $0

Stated 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:

json
{ "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:

json
{ "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.

bash
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 cheap-7-v2 --dry-run

# a real run
council --task tasks/your-idea.md --chain cheap-7-v2

Your 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.

There is no default chain: since 0.8.2 council --task x.md without --chain stops and names the recommended ones. cheap-7-v2 needs one OpenRouter key; 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 already contains its own acceptance list. A task written like a specification often ends with what the answer must contain and when it fails. The criteria seat can mirror that list: criteria about the format of the answer, not about what makes it right. The criteria stage has two checks that catch some of these (criteria about the criteria list or its JSON shape, or criteria that demand several documents: it asks once more, and stops the run before any paid review round if the second try does the same), after one or two paid criteria calls; a mirrored list that avoids those patterns passes them silently. Write the criteria yourself and hand them in instead: council --task tasks/x.md --chain cheap-7-v2 --criteria criteria.md. The file holds one criterion per line (a leading - , * or 1. is dropped, lines starting with # are skipped), or JSON (an array, or { "criteria": [...] }). A hand-written list skips the criteria stage and gets the same two checks before any paid review: criteria about the criteria list itself, or ones that demand documents one build stage cannot produce, stop the run. council lint-criteria --criteria criteria.md runs the $0 word-level lints on the file first.

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:

CodeMeaning
0Finished: a deliverable and report.json were written.
1The chain failed lint, or an input is missing (no task file, a resume from the wrong directory).
2Usage error: a flag is missing its value or has an invalid one, --chain is not a chain name, a --context file is not a regular file or is over 2 MB, or --rematch/--replay of a run given --criteria.
3Paused at an external seat: answer NEEDS-<stage>.md, then --resume.
4Stopped at the per-run spend cap before the next stage was paid for; resume with a higher --max-usd.
5A provider key the chain needs is missing (degradable: set it and run again).
6Fatal: the chain file cannot be parsed, or the audit key cannot be loaded.
7Finished, but the final security review blocked the deliverable.
8Finished, but the final security review could not judge it (never a pass).
9Artifact gate: the task names files whose content it never includes (BLOCKED-ARTIFACTS.md).
10Preflight: a seat objected to the task description itself (STOPPED-preflight.md).
11Something in the input must not be sent: a prompt matches one of the key formats listed in src/secret-patterns.js (checked by default; --allow-secret-shaped overrides), or, under --pii-gate hard-stop, a PII shape.
12policy.json refused the chain.
13Another process is already running this run folder.
14The task file, or (since 0.8.0) a --context document, changed since the run started and AMENDMENTS.md does not cover it. The message prints the hashes to write; a context hash is written ctx-<hash>.
15--resume of a run that already finished (it has a report.json); nothing is run or spent.
16The run stopped at an unexpected error (a seat that could not be reached, a crash); STOPPED-error.md says what, and --resume continues from the completed stages.
17A 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 (STOPPED-truncated.md).
18An advice call was stopped before finishing: by a person (council stop runs/<id>), by the MCP client that cancelled the call or went away, or by its own wall-clock ceiling (advise.max_wall_ms). Calls already in flight finish and are recorded (a wall-clock stop cuts a call still running at the deadline, recorded as not answering); nothing new starts. It writes report-partial.json (stoppedBy: user, client_cancel or wall_clock; the answers that were paid for under advise), BOARD-partial.md when anything was paid for, and STOPPED-<stoppedBy>.json. An advice call is not resumed: ask again.

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). Code 18 came with the advice tools.

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:

markdown
## 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 suite

The 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.

bash
council --task tasks/x.md --chain cheap-7-v2 --max-usd 2     # this run stops at $2
council --task tasks/x.md --chain cheap-7-v2 --max-usd none  # no ceiling (0 is refused: it used to mean this)
export MAX_USD_PER_RUN=20                         # change the default

A 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:

bash
council --resume runs/<id> --max-usd 10

A 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:

bash
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 doing

That 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:

bash
council --task tasks/your-idea.md --chain mock-budget --max-usd 1

If a chain pauses for your input, it writes NEEDS-<stage>.md into the run folder and tells you how to resume. The run resumes as soon as the answer file exists, so write it under a .partial name and rename it when it is complete:

bash
# write your answer to runs/<id>/answers.md.partial, then:
mv runs/<id>/answers.md.partial runs/<id>/answers.md
council --resume runs/<id>

Quick start (MCP)

Register the server with your MCP client. No clone needed - from the published npm package:

bash
claude mcp add council -- npx -y the-high-council council --mcp

The same line with npx -y github:muad-yasin/the-high-council-mcp runs the current source instead.

Or from a clone of this repo:

bash
claude mcp add high-council -- node /absolute/path/to/the-high-council-mcp/src/mcp/server.js

The 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/:

bash
claude plugin marketplace add muad-yasin/the-high-council-mcp
claude plugin install the-high-council@the-high-council

Claude 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.

Your provider keys can go into the plugin's settings dialog (/plugin, then the plugin's settings): one optional field per lab, marked sensitive, so Claude Code keeps it in the OS keychain. Leave a field empty and the key from your environment or a .env file in your project is used instead; a key in the dialog is used first. The plugin passes each dialog value under its own name (COUNCIL_PLUGIN_<LAB>_API_KEY), so an empty field never replaces a key you exported yourself.

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 (not for advice chains: see Asking other labs for advice). 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. An advice call also leaves council-<id>.log and a .council-advice-lock/ folder in the working folder: ignore those too.

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:

bash
council --mcp        # from a clone: npm run mcp

Then drive it with these tools:

ToolWhat it does
list_chainsAvailable chains with descriptions (price one with dry_run)
write_taskWrite the request the harness plans against
dry_runPrice a run before spending anything
start_runStart a run in the background (max_usd sets its ceiling). chain is a chain name; task, draft, context and from_run must be inside the working directory
run_statusStage reached, panel verdicts, scoreboard, cost, budget remaining
spend_reportWhat every run has cost across a window of days, plus session_cost_today (calendar-day, per-model breakdown), derived from disk
verdict_statsHow 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
metrics_reportDescriptive 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 docs/paid-comparison-run.md for what a real comparison against a single model would need - not built, not this metric
external_promptThe 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. waiting lists every stage the run waits on (a panel of external critics pauses together); pass stage for another one's prompt
prepare_stage_promptWrite 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 docs/dispatch-pattern.md
submit_stageAnswer a paused stage; the run resumes once every stage it waits on has an answer. Optional claimed_by records who's answering; a second submission for an already-answered stage no longer errors - it's kept as <stage>.late.md with a warning instead of being rejected
resume_runResume a paused run, or raise max_usd on one the cap stopped
read_run_fileRead any file from a run folder (report-partial.json for a run the cap stopped)
list_runsPast runs
plan_outlineSection tree of a run's deliverable (or a .md file in the working directory) with word counts
council_quoteExperimental. Preview and price a request for advice from other labs: who would receive the text, its exact size and sha256 after masking, the worst-case and expected price, a quote_id. Sends and spends nothing. See Asking other labs for advice
council_adviseExperimental. Spends. Asks other labs for advice on one decision, once you approve it: a leaning and every dissent in the models' own words. start_run and resume_run refuse advice chains, so this is the only way in over MCP
contract_readRead the locked contract of a run: its version, the obligations a person approved and the amendment requests filed against it. Checked first ($0): if the record, its approval or the ledger disagree, nothing is returned. The text comes back marked as model-written
contract_amendAsk for an obligation of a locked contract to be changed. Free; it only files a request, and a person decides it at a terminal with council contract amend --decide. See The contract record

Text from a run comes back marked as model-written. A deliverable, a board, a log line or an advisor's answer was written by AI models, and a model can be fooled into writing instructions aimed at the agent that reads it. So read_run_file (and run_status with brief: true) returns the text between a notice written by the server and markers whose id changes on every call, with Unicode tag characters, bidi controls and zero-width characters removed and counted; JSON answers that carry such text name those fields in untrusted_fields. Which tool returns what is one table in src/mcp/untrusted.js, and a tool missing from it is refused when the server starts. This is a label, not a filter: it does not make hostile text harmless, and the file on disk is unchanged.

Asking other labs for advice (council_quote, council_advise; experimental)

Two more tools let a coding agent, when you ask it to, put one decision to models from other labs and read back a leaning, every dissent in the models' own words, and what each would need to see to change its answer. It is advice from other models, never an instruction, and it comes in addition to whatever model is already the caller: the default seat is not Anthropic's. Nothing has been measured that shows it improves what an agent does; it is an instrument, and each call leaves a small record (advise-log.json) you can rate later with council advise-rate runs/<id> useful|not-useful|unclear [note] (the only supported way to write the rating: a typo in a hand edit of that file makes every later advice call refuse).

  • council_quote sends nothing and spends nothing. The agent writes a short structured brief (at most 48,000 characters, about 12,000 tokens, all together; over the limit is refused, never cut; no transcript, tool output, environment or file listing). The quote scans the whole text for key shapes, masks emails, IBANs, cards, IPs, internal hostnames and home paths (reversibly: the mapping stays in memory), and returns a send preview: who receives it (lab, model, the endpoint's retention wording), the exact size and sha256 of the text, the worst-case and expected price, and a quote_id valid for ten minutes. The text itself goes to you, not back to the agent: you read all of it in the approval step.
  • council_advise spends, and only after you approved the exact text. It needs the quote id and the hash. It writes the run folder first (runs/<id>/advice-brief.md, the masked text, and a pending approval, a "gate"), then asks you: in your client, if it can show you a dialog (MCP elicitation: the price, the hash, the seats and the whole text), or at a terminal with council gate answer runs/<id> g1, which prints the same and asks y/N. Until you answer, the call returns awaiting_approval with that command; the agent sends the same quote again once you have. The run starts only on an approved gate, and one approval covers one send. Nothing else approves a call an agent asked for: no setting, no flag, no tool argument (the 0.8.0 COUNCIL_ADVISE_APPROVAL=host statement is gone, and a server that still has it set refuses to start). The run is held to the seats and the ceiling the gate showed you, whatever else is in the folder. Running an advice chain yourself at your own terminal (council --chain advise-single --task brief.md) is your own call and has no gate; its record says so (gate: null in advise-log.json). The terminal check is friction, not proof that a person answered: a program can open a pseudo-terminal. Advice calls therefore need a person at the keyboard; scripted or unattended use is not supported. mode: "single" asks one seat: GPT-6.1 Sol through OpenRouter by default, or with the advisor argument GPT-6 Astra (astra), GLM-5.3 Flash (glm-flash, new in 0.8.2) or Qwen3.8 Max (qwen, new in 0.8.2; it has no zero-retention endpoint, so a quote for it is refused unless the operator set the sensitivity floor to public). Three more seats are reachable by name only: gemini, deepseek and opus (Claude Opus 5.5, the experimental control); mode: "council" asks three labs (OpenAI GPT-6.1 Sol, Z.ai GLM-5.3, Google Gemini 3.8 Flash) blind, lets them read each other once, and a seat changes its answer only by quoting an argument. The call holds for up to wait_seconds (default 25, at most 30, the same for every client), your approval included; a run that outlives the hold returns its id, and run_status(run, wait_seconds: 25, until: "settled") (also at most 30) returns the answer. Use the default: a client that gives up on a call cancels it, and a cancel stops the run.
  • Limits, meant to be set by you in the server's environment and not by the agent (a project .env can still set them: see Known limits): COUNCIL_ADVISE_MAX_USD_PER_CALL ($1.50, compared with the call's ceiling, the most it can spend), ..._PER_SESSION ($3), ..._PER_DAY ($10), COUNCIL_ADVISE_CALLS_PER_SESSION (3), ..._CALLS_PER_DAY (8), COUNCIL_ADVISE_COOLDOWN_MS (two minutes). A question asked again needs new_evidence in the brief; an answer with dissent needs an accept, reject or defer, with a reason, for each dissent before the next call. Every refusal says that nothing was spent and what to do next.
  • What may be sent starts from the floor you set in the server's settings, COUNCIL_ADVICE_SENSITIVITY_FLOOR (public, internal, confidential; default internal). A project's policy.json may raise it with advice_sensitivity_floor and can never lower it, since the project folder is something the agent can write. The brief's own label can only tighten it: a missing or unknown label counts as confidential, personal_data and secret_adjacent are never sent, a confidential brief goes to one seat and never to a council, and a model that has no endpoint OpenRouter tags zero-data-retention is reachable only for public material. The label is the agent's word, so the approval text tells you what the text is treated as and who set each part (your floor, the project's policy, the agent's label): you are the check on it.
  • Your own chain, or a $0 trial. COUNCIL_ADVISE_CHAIN_SINGLE and COUNCIL_ADVISE_CHAIN_COUNCIL point a mode at an advise chain by name. An advice chain is read from the package's own chains/ or from one folder you name in COUNCIL_ADVICE_CHAINS_DIR (an absolute path outside the project; anything else stops the server), and never from the project's chains/: a repository's chain file would otherwise choose who receives the text. Your chain must pass the same checks: priced seats, not denied, zero-retention routing where the model has it. COUNCIL_ADVISE_MOCK=1 runs the mock chains, so the whole exchange can be tried with no key and no money.
  • When an advisor asks for more. An answer can list what was missing from the brief. That list is model text, shown to the agent as untrusted, and the next call does not go out on the agent's say-so: its approval text starts with "This call follows an advisor's request for more material", so you see that the new text answers a model's request, and decide whether that material should leave your machine.
  • Stopping. A client that cancels the call or goes away, or council stop runs/<id> at your terminal, stops the run before its next paid step. A stop does not cut a call that is already running: with no clock, it waits for that call, which for a slow reasoning model can take up to two hours (the request deadline), and the call finishes and is billed. The run then exits 18, and the answers that were paid for are kept in report-partial.json, which run_status hands back. A stopped call is not resumed; ask again. No shipped advice chain has a time limit (owner, 6 Oct 2026: if a call takes time it takes time, and if it times out you ask again): a slow reasoning model took 6 to 13 minutes for one answer in the run that measured it, and council_advise hands back a run id within 30 seconds either way. A chain of your own can still set advise.max_wall_ms to end the run at a deadline (then a call still running is cut off, which may still be billed); every request has a 2-hour deadline regardless.

What this does not do, stated plainly: "ZDR" in the preview is OpenRouter's routing tag for an endpoint, not a guarantee about what that host does with your text, and the retention table (src/advice-retention.json) is a dated snapshot (read on 2026-09-30; the preview prints its date and says when it is more than 30 days old). No scanner catches names, addresses, phone numbers or passwords written as prose: read the text the server shows you. The limits above bind these two tools and start_run / resume_run for advice chains, which refuse them; they do not bind a shell that runs council itself, and the ledger they read is in your working folder. Headless use is refused by design: with no dialog and no person at a terminal the call returns awaiting_approval and nothing runs (Claude Code in -p or CI mode included). The models see only the brief: nothing is run or checked. A call takes seconds (one seat) or minutes (a council) and costs real money: see the price in the quote, in your own units.

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.

The contract record (council contract)

After a run has ended, a person can lock a contract from it: a short list of obligations (an id and a sentence or two each) that a build session works against. A model drafts the list. Nothing becomes the contract until a person has read the exact text and approved it at a terminal, through the same approval step the advice add-on uses.

council contract lock runs/<id>                         # shows the exact text, asks, then writes runs/<id>/contract/v1.json and CONTRACT.md
council contract show runs/<id> [--md]                  # the current version, each obligation, the requests filed against it
council contract check runs/<id>                        # $0: do the record, its approval, the ledger and CONTRACT.md still agree?
council contract amend --decide runs/<id> [request]     # a person's decision on an amendment request

A version is never edited. A build session that finds an obligation wrong or impossible does not change it: it calls contract_amend, which is free, files a request and decides nothing. A person decides the request at a terminal, with the exact current and the exact proposed words in front of them. An approval writes the next version, which names the one before it and the request; a refusal is recorded. contract_read hands the build session the current version, after the same check council contract check makes; the obligation text comes back marked as model-written.

The record is tamper-evident, not tamper-proof. It lives in the run folder together with its approval and the ledger; whoever can write that folder can rewrite all three together, and nothing here detects it. council contract check catches an edit of one of them without the others. A 0.8.1 council gate verify reads a ledger that holds contract events as broken; verify it with 0.8.2.

Chains

46 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 five recommended ones (cheap-7-v2, plan-daily-7, plan-premium-7, plan-highest-7, local-ollama) are in the table at the top. The chains the 0.8.2 cleanup moved out of chains/ are in archive/chains/ in the repository (not in the npm package); copy one into your project's own chains/ to run it by name. A run recorded on one of them needs its file there too before it can be resumed, rematched or replayed (the error says so). A few more worth knowing:

  • verify - two labs, two rounds; needs Anthropic, OpenAI and Google keys. It was the default when you named no chain until 0.8.1.
  • plan-lanes-4 (new in 0.8.2, optional and experimental) - one writer (Claude Sonnet 5.5, no panel seat) and three reviewers (GPT-5.6 Luna, Gemini 3.8 Flash, GLM 5.3 Flash), each with an assigned lane: correctness and interfaces, security and failure behaviour, implementation and verification. No blind proposals and no debate; unanimous sign-off, up to 7 rounds, one OpenRouter key. A lane is where a reviewer looks first, never a smaller set of criteria: every reviewer still checks every criterion. Dry run: $1.62 expected at the chain's own task-size estimate, $6.34 at most (every call at its full output allowance, GLM at 360,000 tokens for its panel review, over seven rounds) (under the default $7 at the estimate sizes, by a margin that shrinks as the task grows), and about $8.9 if every GLM review were cut off and retried at its larger cap, in which case the cap stops the run before it is exceeded. The words that tell a reviewer its lane are recorded in the judge prompt (LANE_TEXT in src/roles.js), so each of its three judges is told where its attention goes first, and every judge still writes a row for every criterion. Nothing here claims it plans better than another chain: that cannot be measured without ground truth.
  • plan-open-7 - the cheap-7-v2 panel, 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. Every seat votes, blind, the plan's writer too (the owner's deliberate choice of 7 Oct 2026; it reverses the September rule that no seat both argues and votes, for this chain and plan-highest-7 only): the criteria seat, one of the architects and one of the judges are Claude Opus 5.5 on your Claude subscription (external seats); GPT-6.1 Sol and GLM-5.3 Flash write the other architectures; six low-cost labs propose and debate; thirteen judges (those seats, DeepSeek V4 Pro, GPT-6 Luna, MiniMax M3, the deep-dive seat's lab and the writer) sign off unanimously. Two Claude Code sessions answer its external seats: Opus 5.5 every stage whose label contains opus5.5-sub (including -retry and -reask1/-reask2 forms) and the criteria stage (criteria, criteria-retry, criteria-feasibility-retry: their labels carry no lab name), Sonnet 5 the writer stages and the writer's own panel review. $12.59 expected, $33.25 at most (the 0.8.2 dry run of 7 Oct 2026, on the shipped price table, as of 2026-09-06; pass a --max-usd above the $7 default). The roster before 7 Oct ran once with real models (2026-09-28); this one has not run, and nothing about it has been measured.

Read a chain's description field before running it; they say what they cost you in calls.

Reasoning effort

Every seat in a shipped chain is set to high where its model has a setting for it, and no code path lowers it. What "high" means depends on the model, so src/reasoning-table.json lists, per model, the request field that sets it (Anthropic output_config.effort, OpenRouter reasoning.effort, OpenAI and Google reasoning_effort, Z.ai thinking, Together's Qwen chat template), the model's own default effort and its largest reply. Each row carries the document it was read from and a date. chain-lint refuses a shipped chain whose seat is set below high (a reasoning setting that is off, low, medium, minimal, a smaller token budget, or hidden). That rule binds the chains in this package only: a chain of your own is not refused, and a setting you write in your own chain is sent as written. In your own chain, a seat with no reasoning setting gets the high default for any model the table has a field for.

  • Models that default above high. GLM-5.3, GLM-5.3 Flash and Qwen3.8 Max run at max or xhigh unless told otherwise, so sending "high" would be a lower effort. They are sent nothing and run at their own default.
  • Claude Haiku 4.5 has no effort levels. Its "high" is thinking on with a token budget of half the seat's output cap (at least 1,024), and the cap carries the budget on top of the room the answer had.
  • A reply that spent its whole cap thinking is retried once with the same request and a bigger cap (double, up to the model's own maximum and what its connection can return). At that limit it is not retried; the seat is recorded as no answer: thinking used the whole cap (the no_answer field of that seat's entry in panelVerdicts) and is unheard, never a pass. Until 0.8.0 the retry turned thinking off.
  • Models the table has no field for (for example Cohere, Groq, Mistral Large, the models on Together other than Qwen3.5-9B and DeepSeek V4 Flash, local Ollama models) are sent nothing. DeepSeek V4 Flash on Together is sent the chat-template switch vLLM documents for it; Together's own page for it was not found.
  • gp-judge-v1 (since 0.8.2 in archive/chains/) ran its Sonnet and Qwen seats with reasoning on (it ran with it off before). Scores from that version on come from the hi

Similar modules

Browse LLM access & routing