the-high-council 0.6.0 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/.env.example +2 -3
  2. package/README.md +191 -23
  3. package/TROUBLESHOOTING.md +13 -0
  4. package/chains/cheap-7-v2.json +98 -0
  5. package/chains/cheap-7.json +93 -0
  6. package/chains/coder-gate-v1.json +56 -0
  7. package/chains/coder-gate-v2.json +55 -0
  8. package/chains/eu-only.json +44 -0
  9. package/chains/gp-judge-v1.json +31 -7
  10. package/chains/idea-open-c2.json +2 -13
  11. package/chains/local-ollama.json +43 -0
  12. package/chains/mock-dispute.json +47 -0
  13. package/chains/mock-partitioned.json +62 -0
  14. package/chains/mock-patch-fallback.json +41 -0
  15. package/chains/mock-patch.json +41 -0
  16. package/chains/mock-proposals.json +4 -2
  17. package/chains/mock-security-review.json +45 -0
  18. package/chains/plan-auto-mistral.json +6 -6
  19. package/chains/plan-auto.json +2 -2
  20. package/chains/plan-debate-c2.json +1 -1
  21. package/chains/plan-debate-open-c2.json +2 -13
  22. package/chains/plan-debate-roles-c1.json +25 -67
  23. package/chains/plan-debate.json +1 -1
  24. package/chains/plan-open-7.json +93 -0
  25. package/chains/plan-premium-7.json +113 -0
  26. package/chains/plan-two-strong.json +74 -0
  27. package/chains/seven.json +1 -6
  28. package/chains/single-vendor-anthropic.json +43 -0
  29. package/chains/single-vendor-openai.json +43 -0
  30. package/chains/us-only.json +44 -0
  31. package/chains/verify.json +1 -1
  32. package/package.json +24 -4
  33. package/src/audit.js +194 -0
  34. package/src/board-export.js +40 -1
  35. package/src/budget.js +18 -6
  36. package/src/buys.js +8 -0
  37. package/src/cache-integrity.js +39 -16
  38. package/src/canary.js +126 -0
  39. package/src/chain-lint.js +660 -7
  40. package/src/chain.js +2191 -140
  41. package/src/claims.js +135 -0
  42. package/src/cli.js +1210 -155
  43. package/src/cost.js +87 -3
  44. package/src/council-replay.js +122 -0
  45. package/src/denied-models.js +139 -0
  46. package/src/disagreement-groups.js +54 -0
  47. package/src/dissent-digest.js +105 -0
  48. package/src/errors.js +14 -0
  49. package/src/fence.js +145 -0
  50. package/src/http-server.js +1 -1
  51. package/src/key-redaction.js +15 -45
  52. package/src/lints.js +135 -0
  53. package/src/mcp/server.js +248 -54
  54. package/src/metrics.js +420 -0
  55. package/src/name-lint.js +54 -9
  56. package/src/outcome.js +29 -0
  57. package/src/partial-deliverable.js +29 -4
  58. package/src/patch-revise.js +91 -0
  59. package/src/peer-claim.js +65 -13
  60. package/src/pii-gate.js +149 -0
  61. package/src/policy.js +265 -0
  62. package/src/preflight.js +119 -8
  63. package/src/pricing.json +126 -18
  64. package/src/progress-spans.js +72 -0
  65. package/src/providers.js +529 -40
  66. package/src/quote-check.js +134 -0
  67. package/src/rematch.js +70 -0
  68. package/src/report-shape.js +119 -0
  69. package/src/role-diagnostics.js +10 -3
  70. package/src/roles.js +651 -40
  71. package/src/run-lock.js +106 -0
  72. package/src/run-state.js +54 -0
  73. package/src/run-status.js +84 -0
  74. package/src/scope-freeze.js +19 -3
  75. package/src/seat-role.js +5 -1
  76. package/src/secret-patterns.js +113 -0
  77. package/src/security-review.js +201 -0
  78. package/src/shape-rounds.js +5 -1
  79. package/src/spans.js +84 -0
  80. package/src/spend.js +44 -8
  81. package/src/stage-contract.js +46 -10
  82. package/src/superseded.js +73 -0
  83. package/src/tools.js +455 -0
  84. package/src/verdict-diff.js +63 -0
  85. package/src/verdict-stats.js +81 -7
  86. package/src/version.js +18 -0
package/.env.example CHANGED
@@ -3,7 +3,6 @@
3
3
  ANTHROPIC_API_KEY=
4
4
  OPENAI_API_KEY=
5
5
  GOOGLE_API_KEY=
6
- XAI_API_KEY=
7
6
  MISTRAL_API_KEY=
8
7
  DEEPSEEK_API_KEY=
9
8
  GROQ_API_KEY=
@@ -14,6 +13,6 @@ ZAI_API_KEY=
14
13
 
15
14
  # Default per-run spend ceiling in USD. Overridden per run by --max-usd.
16
15
  # A run stops cleanly before any stage that could take it past this, and
17
- # resumes with a higher ceiling. Unset means $5. Use --max-usd none to run
16
+ # resumes with a higher ceiling. Unset means $7. Use --max-usd none to run
18
17
  # without a ceiling.
19
- MAX_USD_PER_RUN=5
18
+ MAX_USD_PER_RUN=7
package/README.md CHANGED
@@ -1,24 +1,29 @@
1
1
  # The High Council
2
2
 
3
- [![Test](https://github.com/muad-yasin/the-high-council-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/muad-yasin/the-high-council-mcp/actions/workflows/test.yml)
3
+ > **Repository status (2026-09-22): going private until the open-source release.** Development
4
+ > continues in a private repository, and the public open-source release is planned for later this
5
+ > year. Until then, the published npm package `the-high-council` (0.7.6) stays installable as it
6
+ > is, and the `npx github:...` lines below only work for someone with access to this repository.
7
+ > The licence of everything already released stays MIT.
4
8
 
5
9
  See it work right now - no keys, no setup, no cost:
6
10
 
7
- npx github:muad-yasin/the-high-council-mcp council demo
11
+ npx the-high-council council demo
8
12
 
9
13
  Add it to Claude Code as an MCP server the same way:
10
14
 
11
- claude mcp add council -- npx -y github:muad-yasin/the-high-council-mcp council --mcp
15
+ claude mcp add council -- npx -y the-high-council council --mcp
12
16
 
13
- *(An npm package is coming - not yet published. Both lines above work today, straight from this
14
- GitHub repo, no npm account needed.)*
17
+ *(With access to this repository, `npx github:muad-yasin/the-high-council-mcp council demo` runs
18
+ the current source instead of the published package.)*
15
19
 
16
20
  A planning harness that runs one idea past several AI models from different labs, makes them
17
21
  argue about it on the record, and stops at a checkable result.
18
22
 
19
23
  Runs as an **MCP server** (so an agent like Claude Code can drive it) or as a **CLI**. Bring your
20
- own API keys. Nothing is resold, nothing is hosted for you, and no key ever leaves your machine.
21
- Run `npx github:muad-yasin/the-high-council-mcp council doctor` to see which of your own keys are
24
+ own API keys. Nothing is resold, nothing is hosted for you, and your keys go only to the
25
+ providers you choose, never to us.
26
+ Run `npx the-high-council council doctor` to see which of your own keys are
22
27
  set, which shipped chains you can already run with them, and what each would cost - before
23
28
  spending anything.
24
29
 
@@ -76,6 +81,15 @@ anything on top of a run, read that instead. Do not parse the markdown.
76
81
  "replies": [ { "id": "DEEPSEEK-1", "action": "keep|amend|withdraw",
77
82
  "text": "...", "replaced_by": "GLM-1" } ]
78
83
  },
84
+ // Only on chains with `alternatives: { enabled: true }`: one whole architecture per lab, written
85
+ // blind before the skeleton, and the same post/reply board the proposals get.
86
+ "alternatives": {
87
+ "items": [ { "id": "GLM-ALT", "lab": "glm", "model": "...", "name": "...", "shape": "...",
88
+ "key_tradeoffs": "...", "bad_at": "...", "amended": true, "withdrawn": false } ],
89
+ "posts": [ { "by": "qwen", "on": "GLM-ALT", "stance": "object|support|merge", "text": "..." } ],
90
+ "replies": [ { "id": "GLM-ALT", "action": "keep|amend|withdraw", "text": "..." } ],
91
+ "dropouts": [ { "lab": "...", "model": "...", "stage": "alternatives", "reason": "..." } ]
92
+ },
79
93
  "signoff": [ { "provider": "qwen", "model": "...", "signedOff": false,
80
94
  "objections": [ { "criterion": "...", "problem": "...", "fix": "..." } ] } ],
81
95
  "lastCritique": { "meets": false, "failures": [ { "criterion": "...", "lab": "qwen" } ] },
@@ -136,10 +150,63 @@ Fill in `.env` with only the keys your chosen chain needs. Supported providers:
136
150
 
137
151
  `ANTHROPIC_API_KEY` · `OPENAI_API_KEY` · `GOOGLE_API_KEY` · `MISTRAL_API_KEY` ·
138
152
  `DEEPSEEK_API_KEY` · `GROQ_API_KEY` · `TOGETHER_API_KEY` · `COHERE_API_KEY` ·
139
- `OPENROUTER_API_KEY` · `ZAI_API_KEY` · `XAI_API_KEY`
153
+ `OPENROUTER_API_KEY` · `ZAI_API_KEY`
154
+
155
+ xAI/Grok and Kimi/Moonshot are never seated, and neither is a router id (`openrouter/auto`, the
156
+ Pareto Code router) that could route to them: chain-lint refuses such a chain and the run itself
157
+ refuses such a seat, with no override. There is no `xai` provider.
140
158
 
141
159
  The CLI refuses to start if any seat in the chosen chain is missing its key, rather than failing
142
- halfway through a paid run.
160
+ halfway through a paid run. `ollama` (below) is the one exception - it needs no key at all.
161
+
162
+ ### Standalone binaries (build them yourself)
163
+
164
+ There are no published binary downloads yet. From a clone you can build a single-file `council`
165
+ that needs no Node install to run: a Linux binary, a Linux AppImage, and a Windows `.exe`, all
166
+ built on Linux.
167
+
168
+ ```bash
169
+ npm run build:bin # dist/the-high-council-linux, dist/the-high-council-win.exe
170
+ npm run build:appimage # dist/the-high-council-x86_64.AppImage (downloads a pinned appimagetool)
171
+ npm run smoke:bin -- dist/the-high-council-linux # demo + an MCP session, offline, $0
172
+ ```
173
+
174
+ Stated plainly: the `.exe` is tested under Wine on Linux, not on a real Windows machine, and none
175
+ of the binaries are code-signed, so Windows SmartScreen will warn. Put `.env` in the directory you
176
+ run the binary from.
177
+
178
+ ### Local models (Ollama, LM Studio, ...)
179
+
180
+ A seat can run on a model you're hosting yourself instead of a paid API. Set its provider to
181
+ `ollama`:
182
+
183
+ ```json
184
+ { "provider": "ollama", "model": "llama3.1" }
185
+ ```
186
+
187
+ This talks to Ollama's own OpenAI-compatibility endpoint (`http://localhost:11434/v1` by
188
+ default) - no `OLLAMA_API_KEY` needed; Ollama's docs describe a key as "required, but unused."
189
+ If your local runner listens somewhere else (LM Studio, a different port, a remote box), add
190
+ `baseUrl` to that seat:
191
+
192
+ ```json
193
+ { "provider": "ollama", "model": "mistral", "baseUrl": "http://localhost:1234/v1" }
194
+ ```
195
+
196
+ A local seat prices at $0 in every estimate and run report - `dry_run` shows it as priced, not
197
+ "unpriced," and it can never trip the spend cap. See `chains/local-ollama.json` for a full
198
+ example chain with every seat local. As with every other seat in this project: BYOK is really
199
+ BYO-compute here, and no efficacy claim is made about local models versus hosted ones - nothing
200
+ has been measured.
201
+
202
+ ### Final security-review gate
203
+
204
+ `"security_review": { "enabled": true }` adds one read-only reviewer as the last stage of a chain,
205
+ after the build and everything else. It returns typed findings, and any critical or high finding
206
+ fails the run (exit 7). A reviewer with no usable verdict fails it too (exit 8); that never counts
207
+ as a pass. The default reviewer is `anthropic/claude-fable-5-1` (your key, priced, capped);
208
+ `seats.security_reviewer` can be any seat, including a local `ollama` one as an offline option.
209
+ Full details: [docs/security-review-gate.md](docs/security-review-gate.md).
143
210
 
144
211
  ## Quick start (CLI)
145
212
 
@@ -163,6 +230,34 @@ them stay on your machine - if you fork this repo, you will not accidentally pub
163
230
 
164
231
  `verify` is the cheap default: two labs, a hard two-round cap. Start there.
165
232
 
233
+ ### Exit codes
234
+
235
+ Each outcome has its own code, so a script or CI job can branch on it:
236
+
237
+ | Code | Meaning |
238
+ |---|---|
239
+ | 0 | Finished: a deliverable and `report.json` were written. |
240
+ | 1 | The chain failed lint, or an input is missing (no task file, a resume from the wrong directory). |
241
+ | 2 | Usage error: a flag is missing its value or has an invalid one. |
242
+ | 3 | Paused at an external seat: answer `NEEDS-<stage>.md`, then `--resume`. |
243
+ | 4 | Stopped at the per-run spend cap before the next stage was paid for; resume with a higher `--max-usd`. |
244
+ | 5 | A provider key the chain needs is missing (degradable: set it and run again). |
245
+ | 6 | Fatal: the chain file cannot be parsed, or the audit key cannot be loaded. |
246
+ | 7 | Finished, but the final security review blocked the deliverable. |
247
+ | 8 | Finished, but the final security review could not judge it (never a pass). |
248
+ | 9 | Artifact gate: the task names files whose content it never includes (`BLOCKED-ARTIFACTS.md`). |
249
+ | 10 | Preflight: a seat objected to the task description itself (`STOPPED-preflight.md`). |
250
+ | 11 | PII gate (`--pii-gate hard-stop`): the input matches a PII shape or one of the key formats listed in `src/secret-patterns.js`. |
251
+ | 12 | `policy.json` refused the chain. |
252
+ | 13 | Another process is already running this run folder. |
253
+ | 14 | The task file changed since the run started and `AMENDMENTS.md` does not cover it. |
254
+ | 15 | `--resume` of a run that already finished (it has a `report.json`); nothing is run or spent. |
255
+ | 16 | The 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. |
256
+ | 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 (`STOPPED-truncated.md`). |
257
+
258
+ Codes 9-17 were split out or added on 2026-09-23. Before that, several of these outcomes shared a code (2, 5,
259
+ 6 or 1).
260
+
166
261
  ### Telling the council what your build session can actually use
167
262
 
168
263
  One optional convention, worth the four lines it costs. If your task file ends with a section
@@ -187,7 +282,7 @@ before building it."*
187
282
 
188
283
  ### The spend cap
189
284
 
190
- Every run has a per-run ceiling in USD. It defaults to **$5**, and is checked *before* each paid
285
+ Every run has a per-run ceiling in USD. It defaults to **$7**, and is checked *before* each paid
191
286
  stage - a stage that could take the run past the ceiling is never called, so the cap holds rather
192
287
  than reporting the overspend afterwards.
193
288
 
@@ -206,6 +301,14 @@ with a higher ceiling - completed stages replay from disk and cost nothing the s
206
301
  node src/cli.js --resume runs/<id> --max-usd 10
207
302
  ```
208
303
 
304
+ A stage replays only if it would be asked the same thing again: the task text, the chain config
305
+ and the stage's own prompt must all match what it answered. If one changed (you edited the chain,
306
+ or an earlier stage came out differently this time), the stage runs again and its old files move
307
+ into `superseded/` inside the run folder. What the old answer cost still counts toward the ceiling,
308
+ `--spend` and `report.json`'s `totals.usd` (shown separately as `totals.supersededUsd`), so a resume
309
+ cannot spend past the cap. An answer you wrote for an external stage is never re-used against a
310
+ changed prompt: it is set aside the same way and the run asks you again.
311
+
209
312
  The cap governs one run. To see what you have spent across all of them:
210
313
 
211
314
  ```bash
@@ -238,12 +341,16 @@ node src/cli.js --resume runs/<id>
238
341
 
239
342
  ## Quick start (MCP)
240
343
 
241
- Register the server with your MCP client. No clone needed - straight from GitHub:
344
+ Register the server with your MCP client. No clone needed - from the published npm package:
242
345
 
243
346
  ```bash
244
- claude mcp add council -- npx -y github:muad-yasin/the-high-council-mcp council --mcp
347
+ claude mcp add council -- npx -y the-high-council council --mcp
245
348
  ```
246
349
 
350
+ With access to this repository (private until the open-source release), the same line with
351
+ `npx -y github:muad-yasin/the-high-council-mcp` runs the current source instead. The clone and
352
+ plugin-marketplace routes below need that access too.
353
+
247
354
  Or from a clone of this repo:
248
355
 
249
356
  ```bash
@@ -253,7 +360,25 @@ claude mcp add high-council -- node /absolute/path/to/the-high-council-mcp/src/m
253
360
  **The path must be absolute.** The client starts the server from its own working directory, not
254
361
  from this one, so a relative path resolves somewhere unexpected and the server never starts.
255
362
 
256
- An npm package is coming - not yet published, no date. Once it lands:
363
+ Or as a Claude Code plugin, which registers the same server and also installs the skills in
364
+ [`skills/`](skills/README.md):
365
+
366
+ ```bash
367
+ claude plugin marketplace add muad-yasin/the-high-council-mcp
368
+ claude plugin install the-high-council@the-high-council
369
+ ```
370
+
371
+ Claude Code copies the plugin into its plugin cache and runs `npm ci` there itself, so the first
372
+ install takes a little longer. Start a new session (or run `/reload-plugins`) and the server shows
373
+ up in `claude mcp list` as `plugin:the-high-council:high-council`. Remove it with
374
+ `claude plugin uninstall the-high-council@the-high-council`. If you add the marketplace from a
375
+ local clone instead (`claude plugin marketplace add /path/to/clone`), the server runs from the
376
+ clone itself, so run `npm install` in it first.
377
+
378
+ Registering with a client other than Claude Code (DeepSeek Harness, OpenHands, Cline, goose,
379
+ Continue): [docs/mcp-clients.md](docs/mcp-clients.md) has the real config for each.
380
+
381
+ An npm package is also live:
257
382
 
258
383
  ```bash
259
384
  claude mcp add high-council -- npx -y the-high-council --mcp
@@ -280,6 +405,7 @@ Then drive it with these tools:
280
405
  | `run_status` | Stage reached, panel verdicts, scoreboard, cost, budget remaining |
281
406
  | `spend_report` | What every run has cost across a window of days, plus `session_cost_today` (calendar-day, per-model breakdown), derived from disk |
282
407
  | `verdict_stats` | 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 |
408
+ | `metrics_report` | 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 [`docs/paid-comparison-run.md`](docs/paid-comparison-run.md) for what a *real* comparison against a single model would need - not built, not this metric |
283
409
  | `external_prompt` | 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 |
284
410
  | `prepare_stage_prompt` | 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 [`docs/dispatch-pattern.md`](docs/dispatch-pattern.md) |
285
411
  | `submit_stage` | Answer a paused stage and resume. 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 |
@@ -299,7 +425,7 @@ for anyone with a subscription, since the project's cost story depends on it.
299
425
 
300
426
  ## Chains
301
427
 
302
- 31 chain configs live in `chains/`. Each one is plain JSON - the seat roster, which models fill
428
+ 48 chain configs live in `chains/`. Each one is plain JSON - the seat roster, which models fill
303
429
  which seat, the round cap, and whether proposals/debate/handoff stages run. They are meant to be
304
430
  copied and edited.
305
431
 
@@ -309,7 +435,8 @@ A few worth knowing:
309
435
  - **`cheap`** - small models throughout. For testing the harness itself, not for real work.
310
436
  - **`plan-debate`** - five labs propose blind, debate each other's proposals anonymised, then a
311
437
  blind panel grades the integrated draft.
312
- - **`plan-auto`** - the full open-scope chain, every seat on a real API, runs unattended end to end.
438
+ - **`plan-auto`** - the full open-scope chain with every seat on a real API, so no stage waits for
439
+ an external session. It still pauses once for your answers to its questions.
313
440
  - **`plan-unanimous`** - every critic must independently sign off on the *same* draft. Three rounds
314
441
  here means up to fifteen critic calls, not five.
315
442
 
@@ -361,8 +488,9 @@ Read a chain's `description` field before running it; they say what they cost yo
361
488
  review round can't run), or a seat naming a provider this codebase doesn't know. The same check
362
489
  also runs automatically, fail-loud, the moment you try to actually run a broken chain - before
363
490
  any paid call.
364
- - **`council doctor --scan-artifacts`** - scans your `tasks/` and `chains/` for API-key-shaped
365
- strings before you commit or share them. Reports the file and line, never the matched text.
491
+ - **`council doctor --scan-artifacts`** - scans your `tasks/` and `chains/` for the key formats
492
+ listed in `src/secret-patterns.js` before you commit or share them. A format not on that list is
493
+ not caught. Reports the file and line, never the matched text.
366
494
  - **`council --forecast-cost --chain <name> [--days N]`** - a realistic-case USD range for a
367
495
  chain, built from its own historical runs on your machine and repriced at today's rates -
368
496
  distinct from `--dry-run`'s worst-case estimate from a chain's declared token assumptions.
@@ -370,7 +498,7 @@ Read a chain's `description` field before running it; they say what they cost yo
370
498
  verdict as one self-contained HTML file. No external assets, no server, `<details>` sections.
371
499
  - **`council replay --run <folder> [--json]`** - a numbered, step-by-step transcript of a run's
372
500
  reasoning in your terminal, with a `--json` mode for scripting.
373
- - **A structured error catalog** (`COUNCIL-E001`-`COUNCIL-E004`, see [TROUBLESHOOTING.md](TROUBLESHOOTING.md))
501
+ - **A structured error catalog** (`COUNCIL-E001`-`COUNCIL-E005`, see [TROUBLESHOOTING.md](TROUBLESHOOTING.md))
374
502
  for the hard-fail paths this project actually has - a missing key, an unpriced model, a
375
503
  malformed chain file, an unreadable stage reply - each with a plain-words cause, a concrete fix
376
504
  naming the real file, and a doc pointer. Degradable conditions exit 5; fatal ones exit 6.
@@ -417,6 +545,24 @@ claiming 29 chains and 12 tools when there were 30 and 11.
417
545
 
418
546
  No claim is made here that any of this produces better plans. It has not been measured.
419
547
 
548
+ ## Skills
549
+
550
+ `skills/` carries a small set of Claude Code skills shipped alongside this harness, not part of
551
+ it - usable in any project, with or without the harness, and needing no API key:
552
+
553
+ - **Core agentic work:** `task-scoping`, `research-and-sourcing`, `verification-and-critique`,
554
+ `context-and-handoff`, `tool-and-action-discipline` - the work around the work, for any agent
555
+ task, including setups where several models propose, critique, and hand off to each other.
556
+ - **Building software:** `backend-developer`, `frontend-developer`, `ux-design`, `visual-craft`.
557
+ - **Writing:** `good-news-writing`.
558
+
559
+ The full catalog, with when to use each and what it guards against, is
560
+ [`skills/README.md`](skills/README.md); a shareable presentation page is `docs/skills.html`. Both
561
+ are checked by the test suite against the real `skills/` folder. Same MIT/BYOK ethos as the
562
+ harness: the skills don't claim to make results better - nothing has been measured - they describe
563
+ what each rule guards against and why. Copy the folders you want into your project's
564
+ `.claude/skills/`, or point Claude Code at this repo's `skills/` directory.
565
+
420
566
  ## Known limits, stated plainly
421
567
 
422
568
  - The spend cap is enforced against a **worst case**, not a prediction: the whole prompt billed as
@@ -425,7 +571,20 @@ No claim is made here that any of this produces better plans. It has not been me
425
571
  left. That is the intended trade - resume it with a higher ceiling.
426
572
  - A seat whose model has no entry in `src/pricing.json` is **unpriced, and therefore uncapped**.
427
573
  It contributes $0 to the running total no matter what it really costs. Check `dry_run` output
428
- for `unpriced` before trusting a ceiling.
574
+ for `unpriced` before trusting a ceiling. `ollama` seats are the one deliberate exception: they
575
+ price at an explicit $0 for any model name (they are genuinely free to run), so they never show
576
+ up in that `unpriced` list and never need a pricing.json entry.
577
+ - A call that fails **after** it reached the provider - the connection drops while a 200 reply is
578
+ being read, a 200 carries a body that is not JSON, or the request times out waiting for headers -
579
+ is not retried, because the generation was probably already billed. Its real usage cannot be
580
+ read, so it is counted toward the per-run cap at its worst-case projection. It leaves no
581
+ `<label>.usage.json`, so `council --spend` does not see it.
582
+ - Some hosted reasoning models stop at a provider-side reasoning ceiling well below the seat's own
583
+ cap, before writing any answer (seen 2026-09-23: `deepseek/deepseek-v4.1-flash` via OpenRouter, 6 of
584
+ 28 calls stopped at ~4.2k tokens, all reasoning, under a 36k cap). A bigger cap cannot fix that, so
585
+ such a reply is recorded as `REASONING_EXHAUSTED` and is not retried: the seat abstains, which
586
+ blocks unanimity and never counts as consent. Whether to change a chain's reasoning settings for it
587
+ is a roster decision, not something the harness does for you.
429
588
  - Prices in `src/pricing.json` are hand-maintained list prices, last verified 2026-09-06. They are
430
589
  estimates, not invoices. Your provider's bill is the real number.
431
590
  - Chains with many labs and high round caps get expensive quickly. `plan-unanimous` at three rounds
@@ -436,6 +595,10 @@ No claim is made here that any of this produces better plans. It has not been me
436
595
  produce sign-offs that mean nothing - the quality of the run depends heavily on the quality of
437
596
  the criteria stage.
438
597
  - Some chains pause for human input by design. They are not stuck.
598
+ - The audit log (`audit.jsonl`) detects an edited line or a cut-off end, but **with no HMAC key,
599
+ which is the default, it does not detect a full rewrite**: anyone who can edit the file can
600
+ recompute every hash. Set `AUDIT_HMAC_KEY_FILE` to a key kept outside the run folder if the log
601
+ has to stand up to that.
439
602
 
440
603
  ## Privacy
441
604
 
@@ -447,16 +610,21 @@ collect nothing. Stated plainly, not as a claim about quality:
447
610
  your own keys (`ANTHROPIC_API_KEY`, `OPENROUTER_API_KEY`, and so on) - and only when you start
448
611
  a real run with a non-mock, non-external seat. `council doctor` and `council demo` make zero
449
612
  network calls; both are implemented to read only local files and environment variable names.
450
- - The GitHub Pages site (`docs/`) ships no JavaScript and loads no third-party resource - see
613
+ - The landing page (`docs/`, moving from GitHub Pages to sower-industries.de while this
614
+ repository is private) ships no JavaScript and loads no third-party resource - see
451
615
  `test/landing-page.test.js`, which fails the build if either ever changes.
452
616
  - Everything a run produces - the task, the debate, the deliverable, the cost - is written to a
453
617
  folder on your own disk (`runs/<id>/`) and nowhere else. Deleting that folder deletes the
454
618
  record. See `src/spend.js`'s own documentation for why spend accounting is derived from those
455
619
  folders rather than kept in a separate log.
620
+ - If you opt in to the audit export (`"audit": true`, and on automatically whenever a `policy.json`
621
+ exists), each run also writes `audit.jsonl` into its own folder: signed, hash-chained lines (each carries the previous line's hash) that
622
+ `verifyAuditLog` in `src/audit.js` checks offline. Seat, cost and timing only, never task or
623
+ prompt text. Format: `docs/audit-schema.md`.
456
624
 
457
625
  ## Accessibility
458
626
 
459
- The GitHub Pages site (`docs/`) uses only native HTML elements for interaction - `<a href>`
627
+ The landing page (`docs/`) uses only native HTML elements for interaction - `<a href>`
460
628
  links and `<details>/<summary>` for the expandable demo sections - specifically because those
461
629
  are keyboard-operable by the browser itself, with no custom JavaScript to get wrong. Tested by
462
630
  hand, 2026-09-13, on the live site:
@@ -478,8 +646,8 @@ hand, 2026-09-13, on the live site:
478
646
 
479
647
  ## Reporting a bug
480
648
 
481
- Open an issue: [github.com/muad-yasin/the-high-council-mcp/issues](https://github.com/muad-yasin/the-high-council-mcp/issues).
482
- Or write to [contact@sower-industries.de](mailto:contact@sower-industries.de).
649
+ Write to [contact@sower-industries.de](mailto:contact@sower-industries.de). (GitHub issues open
650
+ again with the public release; while the repository is private, email is the only route.)
483
651
 
484
652
  ## If this makes you money
485
653
 
@@ -43,3 +43,16 @@ lab actually returned. The run log also says why it was unreadable: truncated
43
43
  (hit its token cap), malformed JSON, or the provider itself returned an error
44
44
  mid-generation - each needs a different fix (a higher `maxTokens`, a smaller
45
45
  prompt, or just retrying).
46
+
47
+ ## COUNCIL-E005 - Policy refusal (fatal)
48
+
49
+ Either `policy.json` itself isn't valid JSON, or the chain you're about to run
50
+ violates one of its limits (an unlisted provider or region, over the per-run or
51
+ per-month spend cap, a missing required tag, or an unpriced seat when
52
+ `refuse_unpriced_seats` is set). A policy file is a locked, operator-set set of
53
+ limits checked before any provider is called - a run that would violate it never
54
+ starts, so nothing was spent.
55
+
56
+ **Fix:** if the file itself won't parse, fix its JSON syntax. Otherwise, either
57
+ change the chain so it no longer violates the listed limit(s), or change
58
+ `policy.json` if the limit itself was wrong. See [docs/policy.md](docs/policy.md).
@@ -0,0 +1,98 @@
1
+ {
2
+ "name": "cheap-7-v2",
3
+ "description": "Seven independent labs vote, none of them the author's, all on current-generation models through one OpenRouter key: OpenAI GPT-5.6 Luna, Google Gemini 3.8 Flash, DeepSeek v4.1 Flash, Z.ai GLM 5.3 Flash, Qwen 3.7 Plus, MiniMax M3, Mistral Medium 3.5. Blind proposals, debate, unanimous signoff, with a round cap of 7 and a stall rule: if the same objections from the same labs survive two rounds running, the revise loop stops rather than buying more rounds of the same argument, and the unresolved dissent is recorded at the top of the deliverable. A run that ends that way reports no consensus - the dispute stage records disagreement, it never resolves it. Anthropic Sonnet 5 writes the skeleton, the draft, every revision and the handoff and holds NO panel seat; Meta Llama 4 Maverick writes the criteria and also holds no panel seat, so neither the lab that drafts nor the lab that sets the bar votes on whether the bar was cleared. This is the revision of cheap-7 after its first real run, where one lab held the criteria, skeleton, builder, reviser and handoff seats AND a critic seat, voted on its own draft, and a claim it wrote survived to the deliverable. Anthropic is deliberately absent from the panel: plans from this chain are read by a Claude session before anything is built, so that review happens downstream rather than inside the vote. Kimi K3 is deliberately absent too - a seat that may route through another lab is not an independent seat. Every seat gets a 36000-token ceiling and reasoning is left on: a debate is not squeezed to a short answer, and a reply cut off at the ceiling is retried once, then the seat is re-asked alone - it is never counted as agreement. The cap is a ceiling, not a price; only generated tokens are billed. Prices are from src/pricing.json, refreshed against OpenRouter's live model list on 2026-09-20 - price a real task with `npm run dry` before running.",
4
+ "maxRounds": 7,
5
+ "signoff": "unanimous",
6
+ "dispute": {
7
+ "enabled": true,
8
+ "stall_rounds": 2
9
+ },
10
+ "proposals": {
11
+ "parts": 3,
12
+ "maxTokens": 4000
13
+ },
14
+ "debate": true,
15
+ "canary": { "enabled": true, "sampleRate": 0.1 },
16
+ "handoff": true,
17
+ "estimate": {
18
+ "promptTokens": 10000,
19
+ "draftTokens": 10000,
20
+ "critiqueTokens": 5000
21
+ },
22
+ "seats": {
23
+ "criteria": {
24
+ "provider": "openrouter",
25
+ "model": "meta-llama/llama-4-maverick",
26
+ "maxTokens": 36000,
27
+ "lab": "llama4-maverick"
28
+ },
29
+ "skeleton": {
30
+ "provider": "openrouter",
31
+ "model": "anthropic/claude-sonnet-5",
32
+ "maxTokens": 36000,
33
+ "lab": "sonnet5"
34
+ },
35
+ "builder": {
36
+ "provider": "openrouter",
37
+ "model": "anthropic/claude-sonnet-5",
38
+ "maxTokens": 36000,
39
+ "lab": "sonnet5"
40
+ },
41
+ "reviser": {
42
+ "provider": "openrouter",
43
+ "model": "anthropic/claude-sonnet-5",
44
+ "maxTokens": 36000,
45
+ "lab": "sonnet5"
46
+ },
47
+ "handoff": {
48
+ "provider": "openrouter",
49
+ "model": "anthropic/claude-sonnet-5",
50
+ "maxTokens": 36000,
51
+ "lab": "sonnet5"
52
+ },
53
+ "critics": [
54
+ {
55
+ "provider": "openrouter",
56
+ "model": "openai/gpt-5.6-luna",
57
+ "maxTokens": 36000,
58
+ "lab": "gpt5.6-luna"
59
+ },
60
+ {
61
+ "provider": "openrouter",
62
+ "model": "google/gemini-3.8-flash",
63
+ "maxTokens": 36000,
64
+ "lab": "gemini3.8-flash"
65
+ },
66
+ {
67
+ "provider": "openrouter",
68
+ "model": "deepseek/deepseek-v4.1-flash",
69
+ "maxTokens": 36000,
70
+ "lab": "deepseek-v4.1-flash"
71
+ },
72
+ {
73
+ "provider": "openrouter",
74
+ "model": "z-ai/glm-5.3-flash",
75
+ "maxTokens": 36000,
76
+ "lab": "glm5.3-flash"
77
+ },
78
+ {
79
+ "provider": "openrouter",
80
+ "model": "qwen/qwen3.7-plus",
81
+ "maxTokens": 36000,
82
+ "lab": "qwen3.7-plus"
83
+ },
84
+ {
85
+ "provider": "openrouter",
86
+ "model": "minimax/minimax-m3",
87
+ "maxTokens": 36000,
88
+ "lab": "minimax-m3"
89
+ },
90
+ {
91
+ "provider": "openrouter",
92
+ "model": "mistralai/mistral-medium-3-5",
93
+ "maxTokens": 36000,
94
+ "lab": "mistral-medium3.5"
95
+ }
96
+ ]
97
+ }
98
+ }
@@ -0,0 +1,93 @@
1
+ {
2
+ "name": "cheap-7",
3
+ "description": "SUPERSEDED by cheap-7-v2, and deliberately left failing chain-lint's self-review check, so it will not run - kept unmodified as the record of what the 2026-09-20 run actually used. Sonnet 5 holds the criteria, skeleton, builder, reviser and handoff seats AND a critic seat here, so it voted on its own draft under unanimous signoff; that is the defect cheap-7-v2 fixes. Do not add \"selfReview\": \"allowed\" to make this runnable again - use cheap-7-v2. Original description follows. Seven labs' small/cheap models, one seat each, all through one OpenRouter key: Anthropic Sonnet 5, OpenAI GPT-5 mini, Google Gemini 3.7 Flash, DeepSeek v3.2, Z.ai GLM 5.3 Flash, Qwen 3.5 Plus, MiniMax M3. Blind proposals, debate, unanimous signoff. Every seat gets a 36000-token ceiling and reasoning is left on: a debate is not squeezed to a short answer, and a reply cut off at the ceiling is retried once, then the seat is re-asked alone - it is never counted as agreement. The cap is a ceiling, not a price; only generated tokens are billed. Sonnet 5 builds and revises. For small questions where every model should still get a say; the frontier equivalent is reserved for questions worth its price. Prices are from src/pricing.json - price a real task with `npm run dry` before running.",
4
+ "maxRounds": 3,
5
+ "signoff": "unanimous",
6
+ "proposals": {
7
+ "parts": 3,
8
+ "maxTokens": 4000
9
+ },
10
+ "debate": true,
11
+ "handoff": true,
12
+ "estimate": {
13
+ "promptTokens": 10000,
14
+ "draftTokens": 10000,
15
+ "critiqueTokens": 5000
16
+ },
17
+ "seats": {
18
+ "criteria": {
19
+ "provider": "openrouter",
20
+ "model": "anthropic/claude-sonnet-5",
21
+ "maxTokens": 36000,
22
+ "lab": "sonnet5"
23
+ },
24
+ "skeleton": {
25
+ "provider": "openrouter",
26
+ "model": "anthropic/claude-sonnet-5",
27
+ "maxTokens": 36000,
28
+ "lab": "sonnet5"
29
+ },
30
+ "builder": {
31
+ "provider": "openrouter",
32
+ "model": "anthropic/claude-sonnet-5",
33
+ "maxTokens": 36000,
34
+ "lab": "sonnet5"
35
+ },
36
+ "reviser": {
37
+ "provider": "openrouter",
38
+ "model": "anthropic/claude-sonnet-5",
39
+ "maxTokens": 36000,
40
+ "lab": "sonnet5"
41
+ },
42
+ "handoff": {
43
+ "provider": "openrouter",
44
+ "model": "anthropic/claude-sonnet-5",
45
+ "maxTokens": 36000,
46
+ "lab": "sonnet5"
47
+ },
48
+ "critics": [
49
+ {
50
+ "provider": "openrouter",
51
+ "model": "anthropic/claude-sonnet-5",
52
+ "maxTokens": 36000,
53
+ "lab": "sonnet5"
54
+ },
55
+ {
56
+ "provider": "openrouter",
57
+ "model": "openai/gpt-5-mini",
58
+ "maxTokens": 36000,
59
+ "lab": "gpt5-mini"
60
+ },
61
+ {
62
+ "provider": "openrouter",
63
+ "model": "google/gemini-3.7-flash",
64
+ "maxTokens": 36000,
65
+ "lab": "gemini3.7-flash"
66
+ },
67
+ {
68
+ "provider": "openrouter",
69
+ "model": "deepseek/deepseek-v3.2",
70
+ "maxTokens": 36000,
71
+ "lab": "deepseek-v3.2"
72
+ },
73
+ {
74
+ "provider": "openrouter",
75
+ "model": "z-ai/glm-5.3-flash",
76
+ "maxTokens": 36000,
77
+ "lab": "glm5.3-flash"
78
+ },
79
+ {
80
+ "provider": "openrouter",
81
+ "model": "qwen/qwen3.5-plus-20260420",
82
+ "maxTokens": 36000,
83
+ "lab": "qwen3.5-plus"
84
+ },
85
+ {
86
+ "provider": "openrouter",
87
+ "model": "minimax/minimax-m3",
88
+ "maxTokens": 36000,
89
+ "lab": "minimax-m3"
90
+ }
91
+ ]
92
+ }
93
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "coder-gate-v1",
3
+ "description": "MLLM Coder v1 (relay/runs/2026-09-14T16-14-10-757Z/deliverable.md). The governed unit is one diff against one pre-named file/hunk, not prose. The `propose` seat is external: THCMCP never writes code itself, it hands the change-request task file to an outside coding session and gets one fenced diff back (docs/coder-gate-diff-format.md). The `builder` seat is also external, held to the same session, and must return the proposal's diff verbatim as this chain's draft - there is no second, independent code-writing step; `builder` exists only because every chain needs one to reach a draft, not because a second author writes anything. `verify` (config.verify.enabled: true) wires the existing run_tests mechanism, but `verify.tools` ships empty here by design, not oversight: runVerification runs before any change-request/diff exists, and this repo has no `{{...}}` templating to inject a per-run target file/test command into a static chain config - a filled-in entry as specced would be inert. No test command runs automatically today (see test/coder-gate-verify.test.js's IN-3 fixture for how the mechanism works when a real, per-run `verify.tools` entry IS supplied downstream). No write-capable tool is used anywhere - applying the diff to a real working tree stays a human/external action. Built from existing stage types (proposal, critic, unanimous signoff); `debate: true` is set for forward compatibility but is currently unreachable - with one proposer and `proposals.parts: 1`, at most one proposal ever exists, and `runChain`'s debate stage only runs when `proposals.length > 1`, so v1 has no live debate today. No change to src/chain.js or src/tools.js.",
4
+ "maxRounds": 2,
5
+ "signoff": "unanimous",
6
+ "proposals": {
7
+ "parts": 1,
8
+ "maxTokens": 4000
9
+ },
10
+ "estimate": {
11
+ "promptTokens": 3000,
12
+ "draftTokens": 3000,
13
+ "critiqueTokens": 1000
14
+ },
15
+ "seats": {
16
+ "criteria": {
17
+ "provider": "anthropic",
18
+ "model": "claude-sonnet-5",
19
+ "maxTokens": 2000
20
+ },
21
+ "skeleton": {
22
+ "provider": "anthropic",
23
+ "model": "claude-sonnet-5",
24
+ "maxTokens": 1000
25
+ },
26
+ "proposers": [
27
+ {
28
+ "provider": "external",
29
+ "model": "claude-code-session",
30
+ "lab": "external-proposer"
31
+ }
32
+ ],
33
+ "builder": {
34
+ "provider": "external",
35
+ "model": "claude-code-session"
36
+ },
37
+ "critics": [
38
+ {
39
+ "provider": "anthropic",
40
+ "model": "claude-sonnet-5",
41
+ "maxTokens": 8000
42
+ },
43
+ {
44
+ "provider": "openai",
45
+ "model": "gpt-5",
46
+ "maxTokens": 8000
47
+ }
48
+ ]
49
+ },
50
+ "debate": true,
51
+ "handoff": false,
52
+ "verify": {
53
+ "enabled": true,
54
+ "tools": []
55
+ }
56
+ }