amicus 4.0.1 → 4.1.0

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 (36) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +75 -0
  3. package/README.md +3 -3
  4. package/commands/council.md +6 -6
  5. package/package.json +1 -1
  6. package/schemas/council-run.schema.json +15 -1
  7. package/schemas/council-tally.schema.json +10 -1
  8. package/schemas/council-verdict.schema.json +10 -1
  9. package/schemas/error.schema.json +1 -1
  10. package/scripts/postinstall.js +6 -3
  11. package/skills/second-opinion/COUNCIL-DESIGN.md +40 -0
  12. package/skills/second-opinion/MANUAL-ORCHESTRATION.md +266 -0
  13. package/skills/second-opinion/MODEL-NOTES.md +21 -0
  14. package/skills/second-opinion/SEAT-BRIEFS.md +4 -0
  15. package/skills/second-opinion/SKILL.md +319 -333
  16. package/src/cli-handlers-council-run.js +9 -0
  17. package/src/cli-handlers-council.js +20 -2
  18. package/src/cli.js +8 -0
  19. package/src/council/briefings-debate.js +158 -0
  20. package/src/council/briefings-stage2.js +16 -9
  21. package/src/council/debate.js +98 -0
  22. package/src/council/ledger.js +2 -1
  23. package/src/council/parse-stage2.js +83 -1
  24. package/src/council/report-html.js +28 -1
  25. package/src/council/report.js +50 -2
  26. package/src/council/run-assemble.js +91 -9
  27. package/src/council/run-chair.js +145 -0
  28. package/src/council/run-debate.js +289 -0
  29. package/src/council/run-launch.js +27 -1
  30. package/src/council/run-stages.js +19 -7
  31. package/src/council/run.js +100 -110
  32. package/src/council/verdict.js +43 -2
  33. package/src/mcp-council-run.js +7 -0
  34. package/src/mcp-server.js +28 -3
  35. package/src/mcp-tools.js +22 -2
  36. package/src/utils/error-doc.js +2 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amicus",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "description": "Multi-model LLM Council + parallel AI window for Claude Code. Run structured council reviews across Gemini, GPT, DeepSeek and more — or fork a conversation to any model and fold the results back.",
5
5
  "author": {
6
6
  "name": "Christian Wagner"
package/CHANGELOG.md CHANGED
@@ -5,6 +5,81 @@ All notable changes to Amicus are documented here. Format follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [4.1.0] - 2026-07-21
9
+
10
+ The `second-opinion` skill stops hand-driving councils. Stages 1–3 and the Stage-5 artifacts
11
+ collapse into a single `amicus council run`, leaving Claude only the stages that genuinely need
12
+ judgement — intake, decisions, and lessons. The engine gains an optional rebuttal round so a
13
+ finding's author can answer the reviewers who disputed it, and Claude can now enter its own review
14
+ into the bundle without ever being launched as a model leg.
15
+
16
+ ### Added
17
+
18
+ - **Skill fast path.** `skills/second-opinion/SKILL.md` now delegates Stages 1–3 (and the Stage-5
19
+ artifact materialization) to one `amicus council run` invocation; the human stages (0 intake,
20
+ 4 decisions, 6 lessons) stay Claude-orchestrated. The manual mechanics are preserved verbatim in
21
+ the new `skills/second-opinion/MANUAL-ORCHESTRATION.md` as the documented fallback for when the
22
+ engine is unavailable or a case the fast path cannot express.
23
+ - **Headless debate mode** — `amicus council run --debate` / `amicus_council_run {debate:true}`.
24
+ A Stage-2.5 rebuttal round runs between cross-review and the final tally: findings that came out
25
+ Contested or Disputed go back to the model that raised them, which defends, amends, or withdraws
26
+ each; the judges who disputed them then re-vote; a final tally folds the outcome in. Exactly one
27
+ round, structurally — there is no edge back into a debate stage. `run.json` gains an additive
28
+ `debate` summary, tally/verdict findings gain a `debate` decoration, and both report renderers
29
+ gain a "Debate round" section. The Council Review Action gains a `debate` input (default off),
30
+ and withdrawn findings are excluded from its PR annotations.
31
+ - **`--claude-review <file>` / `claudeReviewFile`.** Enters Claude's own review as judged review
32
+ N+1 from a file. No model leg is ever launched for it and it may never chair — `claude` is a
33
+ reserved seat name that is rejected pre-flight in `--models`, `--chair` and `--critic` on such a
34
+ run.
35
+ - **`--render` on `council verdict`, `render:true` on `amicus_verdict`.** Refreshes `report.html`
36
+ from the decided verdict. The MCP tool also returns the markdown rendering; it writes only when
37
+ an `outDir` inside the project is supplied, and its `readOnlyHint` is now correctly `false`.
38
+ - **`--no-cost-gate` on `council run`.** Disables the per-leg price gate for the whole run —
39
+ repairs, chair chain and debate legs included — in one place instead of per invocation.
40
+
41
+ ### Fixed
42
+
43
+ - **The Council Review Action no longer defaults to a bench that cannot lose a leg.** Its default
44
+ `models` were `deepseek,gemini,glm` with `deepseek` as chair; because the chair is excluded from
45
+ the bench, that left **two** seats against a quorum minimum of two, so one stalled leg failed the
46
+ entire review. The default is now four seats (`glm,qwen,minimax,qwen-coder`), leaving real slack.
47
+ - **`postinstall` now installs `SEAT-BRIEFS.md`.** It shipped in the tarball but was never copied
48
+ into `~/.claude/skills/second-opinion/`, so the seat briefing reference has been missing from
49
+ every installation to date.
50
+ - **`amicus council verdict` no longer discards the chair's verdict.** Writing the decided verdict
51
+ over the engine's one dropped `overallVerdict` to `null`, because the tally record it is built
52
+ from does not carry it. `runVerdict` now recovers it from the run folder — the engine's
53
+ `verdict.json` when present (guarded on `runId`, so a foreign file cannot inject another run's
54
+ verdict), otherwise by re-parsing `chair-output.md` with the engine's own chair parser. A run
55
+ whose chair was skipped still yields `null`; nothing is ever invented. `amicus_verdict` had the
56
+ same loss on the Cowork path and gains an explicit optional `overallVerdict` input, since the MCP
57
+ tool receives a record inline with no run folder to recover from.
58
+
59
+ ### Documentation
60
+
61
+ - **The skill's Stage 4 and Stage 5 now name where finding claims actually live.** Both stages
62
+ instructed the reader to show each finding's claim while pointing only at `tally.json`, whose
63
+ findings carry tiers and adjudications but no `claim`. The claim and location live in
64
+ `tally-input.json`; both stages now state the join (on finding `id`) explicitly.
65
+
66
+ ### Changed
67
+
68
+ - **`claude` can no longer be promoted as fallback chair on any run.** When a configured chair
69
+ dies, the engine promotes another model by reliability; `claude` is now excluded unconditionally.
70
+ This affects runs that never use `--claude-review`, because the reliability ledger has no way to
71
+ distinguish a file-sourced `claude` row from a real leg — and promoting it would select a chair
72
+ the engine cannot launch.
73
+ - **`npm i -g amicus@4.1` rewrites the installed `SKILL.md`** to the fast path (existing
74
+ product-code overwrite policy). `MODEL-NOTES.md` remains machine-local and is never overwritten.
75
+ Rollback is a reinstall of 4.0.x.
76
+
77
+ ### Notes
78
+
79
+ - All changes are additive: the council document family stays `schemaVersion: 2`, the MCP tool
80
+ count stays 15 (new inputs only), and a run using none of the new flags produces byte-identical
81
+ artifacts to 4.0.1. No migration is required.
82
+
8
83
  ## [4.0.1] - 2026-07-20
9
84
 
10
85
  Follow-up fixes to the v4.0.0 council engine: `amicus abort` and `amicus status` now see every
package/README.md CHANGED
@@ -301,7 +301,7 @@ amicus update
301
301
  | `amicus spend` | Cross-run cost rollup from the spend ledger — total + per-model spend, tokens, and source mix, most-expensive first (`--since 7d` windows it; `--json` for a versioned doc; shows remaining OpenRouter credit when a key is configured). |
302
302
  | `amicus key` | Manage API keys non-interactively: `amicus key <provider> <key>` saves after live validation; `--remove`; bare `amicus key` lists providers. |
303
303
  | `amicus council` | Council math: `tally <input.json>` (deterministic tiers + ledger append), `stats` (reviewer reliability), `report <verdict.json> [--md\|--html]`, `validate <file>` (findings-block check, exit 0/2/1), `verdict <tally.json> [--decisions <d.json>] [-o <out.json>]` (build + write verdict.json). Presets: `save <name> --models a,b,c`, `list [--json]`, `show <name> [--json]` — see [The Council](#the-council) for the built-in `free`/`budget`/`frontier` benches. |
304
- | `amicus council run` | The headless council engine (v4.0): Stage-1 reviews → anonymized cross-review → deterministic tally → non-Claude chair verdict, in one command with no Claude runtime. Writes a run directory with `verdict.json` (including `overallVerdict`) and `report.html` — see [docs/council.md](./docs/council.md#amicus-council-run). |
304
+ | `amicus council run` | The headless council engine: Stage-1 reviews → anonymized cross-review → deterministic tally → non-Claude chair verdict, in one command with no Claude runtime. Add `--debate` for a Stage-2.5 rebuttal round (raisers defend/amend/withdraw, disputing judges re-vote) and `--claude-review <file>` to enter Claude's own review as judged review N+1. Writes a run directory with `verdict.json` (including `overallVerdict`) and `report.html` — see [docs/council.md](./docs/council.md#amicus-council-run). |
305
305
  | `amicus abort` | Abort a running session (or `--all`). |
306
306
  | `amicus setup` | Configure default model, API keys, and aliases. |
307
307
  | `amicus update` | Update to the latest version. |
@@ -329,7 +329,7 @@ $ amicus status demo123 --json
329
329
  "taskId": "demo123",
330
330
  "status": "complete",
331
331
  "elapsed": "5m 0s",
332
- "version": "4.0.1",
332
+ "version": "4.1.0",
333
333
  "model": "google/gemini-2.5-flash",
334
334
  "phase": "terminal"
335
335
  }
@@ -380,7 +380,7 @@ The MCP server is auto-registered on install (Claude Code and Claude Desktop / C
380
380
  | `amicus_fanout` | Launch a same-prompt wave; returns `{ waveId, taskIds[] }`. |
381
381
  | `amicus_council_tally` | Aggregate a council wave's reviews into a scored tally. |
382
382
  | `amicus_council_stats` | Reviewer-reliability stats from past council runs. |
383
- | `amicus_verdict` | Build the final council verdict from a tally + decisions. |
383
+ | `amicus_verdict` | Build the final council verdict from a tally + decisions; writes `<outDir>/report.html` when `render:true` and `outDir` are given. |
384
384
  | `amicus_council_run` | Run the full headless council engine (Stage-1 reviews → anonymized cross-review → tally → chair verdict); returns `{ runId, runDir }`, async. |
385
385
 
386
386
  The async pattern is **start → status → read** — `amicus_start`/`amicus_fanout` return immediately, then you poll `amicus_status` and call `amicus_read`; `amicus_wait` collapses that poll loop into one blocking call.
@@ -17,13 +17,13 @@ the **analysis request**, and the **criteria**. If any of the three is missing o
17
17
  ambiguous, ask for it before launching any model (the skill's Stage 0 covers this —
18
18
  don't re-ask for what is already present).
19
19
 
20
- Then follow the second-opinion skill end to end, in pipeline order: Stage 0
20
+ Then follow the second-opinion skill's engine fast path, in pipeline order: Stage 0
21
21
  intake/prep and run-folder setup, then council selection with a cost estimate
22
- and explicit user confirmation; Stage 1 independent reviews, running
23
- `amicus council validate` on each leg's findings block as it lands; Stage 2
24
- cross-review, followed by `amicus council tally` once cross-review settles;
25
- Stage 3 council-chair synthesis; Stage 4 the accept/deny decision pass; and
26
- Stage 5, which runs `amicus council verdict` to write the final `verdict.json`.
22
+ and explicit user confirmation; one `amicus council run` call — the engine runs
23
+ validate, cross-review, tally, and chair internally, covering the Stage-1
24
+ independent reviews through the Stage-3 chair synthesis with no Claude runtime
25
+ in between; Stage 4, the accept/deny decision pass, once the run returns; and
26
+ Stage 5, which runs `amicus council verdict` to write the decided `verdict.json`.
27
27
 
28
28
  The user may also name **optional council elements** in the arguments (critic seat,
29
29
  expert lenses, debate mode, verdict scale, Claude in the council). All elements
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amicus",
3
- "version": "4.0.1",
3
+ "version": "4.1.0",
4
4
  "mcpName": "io.github.BourbonDog/amicus",
5
5
  "description": "Multi-model LLM Council + parallel AI window for Claude Code. Run structured council reviews across Gemini, GPT, DeepSeek and more — or fork a conversation to any model and fold the results back.",
6
6
  "keywords": [
@@ -33,6 +33,20 @@
33
33
  "labelMap": { "type": ["object", "null"], "additionalProperties": { "type": "string" } },
34
34
  "options": { "type": "object" },
35
35
  "usage": { "type": "object" },
36
- "exitCode": { "type": ["number", "null"] }
36
+ "exitCode": { "type": ["number", "null"] },
37
+ "debate": {
38
+ "type": "object",
39
+ "properties": {
40
+ "enabled": { "type": "boolean" },
41
+ "outcome": { "enum": ["ran", "nothing-to-debate", "skipped-cost-ceiling"] },
42
+ "contested": { "type": "integer" }, "disputed": { "type": "integer" },
43
+ "defended": { "type": "integer" }, "amended": { "type": "integer" },
44
+ "withdrawn": { "type": "integer" }, "noResponse": { "type": "integer" },
45
+ "revoteJudges": { "type": "integer" }, "revoteApplied": { "type": "integer" },
46
+ "verdictChanges": { "type": "integer" }
47
+ },
48
+ "required": ["enabled"],
49
+ "additionalProperties": false
50
+ }
37
51
  }
38
52
  }
@@ -51,7 +51,16 @@
51
51
  },
52
52
  "confidence": { "enum": ["thin", "solid"] },
53
53
  "tierOverride": { "type": ["object", "null"] },
54
- "adjudications": { "type": "array", "items": { "type": "object" } }
54
+ "adjudications": { "type": "array", "items": { "type": "object" } },
55
+ "debate": {
56
+ "type": "object",
57
+ "properties": {
58
+ "action": { "enum": ["defended", "amended", "withdrawn", "no-response"] },
59
+ "previousTier": { "type": ["string", "null"] }
60
+ },
61
+ "required": ["action"],
62
+ "additionalProperties": false
63
+ }
55
64
  }
56
65
  }
57
66
  },
@@ -36,7 +36,16 @@
36
36
  "duplicateOf": { "type": ["string", "null"] },
37
37
  "adjudications": { "type": "array" },
38
38
  "decision": { "type": ["string", "null"] },
39
- "applied": { "type": "boolean" }
39
+ "applied": { "type": "boolean" },
40
+ "debate": {
41
+ "type": "object",
42
+ "properties": {
43
+ "action": { "enum": ["defended", "amended", "withdrawn", "no-response"] },
44
+ "previousTier": { "type": ["string", "null"] }
45
+ },
46
+ "required": ["action"],
47
+ "additionalProperties": false
48
+ }
40
49
  }
41
50
  }
42
51
  },
@@ -13,7 +13,7 @@
13
13
  "type": "object",
14
14
  "required": ["code", "message"],
15
15
  "properties": {
16
- "code": { "enum": ["BAD_ARGS", "MISSING_PROMPT", "BAD_MODEL", "MISSING_KEY", "BAD_SESSION", "BUDGET_EXCEEDED", "INTERNAL"] },
16
+ "code": { "enum": ["BAD_ARGS", "MISSING_PROMPT", "BAD_MODEL", "MISSING_KEY", "BAD_SESSION", "BUDGET_EXCEEDED", "INTERNAL", "COUNCIL_QUORUM", "COST_EXCEEDED", "COUNCIL_CLAUDE_REVIEW_INVALID"] },
17
17
  "message": { "type": "string" },
18
18
  "hint": { "type": ["string", "null"] },
19
19
  "command": { "type": ["string", "null"] }
@@ -25,12 +25,15 @@ const PROVISION_TIMEOUT_MS = 15000;
25
25
  const SKILL_SOURCE = path.join(__dirname, '..', 'skills', 'sidecar', 'SKILL.md');
26
26
  const COUNCIL_SOURCE_DIR = path.join(__dirname, '..', 'skills', 'second-opinion');
27
27
 
28
- /** Council files + per-file install semantics: SKILL/COUNCIL-DESIGN are product code
29
- * (overwrite on update); MODEL-NOTES is user data its reviewer-reliability table evolves
30
- * per-run, so it is seeded once and never clobbered. */
28
+ /** Council files + per-file install semantics: SKILL/COUNCIL-DESIGN/SEAT-BRIEFS are
29
+ * product code (overwrite on update, so upgrades keep them in sync with the package);
30
+ * MODEL-NOTES is user data — its reviewer-reliability table evolves per-run, so it is
31
+ * seeded once and never clobbered. */
31
32
  const COUNCIL_FILES = [
32
33
  { file: 'SKILL.md', mode: 'overwrite' },
33
34
  { file: 'COUNCIL-DESIGN.md', mode: 'overwrite' },
35
+ { file: 'SEAT-BRIEFS.md', mode: 'overwrite' },
36
+ { file: 'MANUAL-ORCHESTRATION.md', mode: 'overwrite' },
34
37
  { file: 'MODEL-NOTES.md', mode: 'if-missing' },
35
38
  ];
36
39
 
@@ -36,6 +36,10 @@ non-Claude chairman + per-model inspectable artifacts.
36
36
  is now engine-native — each review wave is ONE `amicus fanout --json` call returning structured
37
37
  run documents — but scoring, tallying, anonymization, and synthesis remain Claude's manual work.
38
38
  No backend, no parsing code beyond reading JSON fields. Deterministic arithmetic/formatting/schema helpers under `amicus council` (findings validation, tier tally, street-cred, ledger) are sanctioned; judgment, synthesis, anonymization, and de-anonymization remain Claude's inline work.
39
+ _(v4.1 annotation — superseded by the engine in the fast path: `amicus council run` now performs
40
+ the anonymization, scoring, tallying, and chair-dispatch steps above headlessly, with no Claude
41
+ runtime in the loop. This v3 note remains an accurate historical record of the design this repo
42
+ shipped from v3 through v4.0's manual path; see §13.)_
39
43
 
40
44
  ## 3. What changes vs. v1
41
45
 
@@ -156,6 +160,9 @@ The cross-review matrix shows both; the ledger and Stage-0 bench recommendations
156
160
  - Default: Claude **recommends a non-Claude chair** from the council each run (often the
157
161
  strongest reasoner / best reviewer-reliability) and the user confirms at launch.
158
162
  - The chair **may** also be a Stage-1 council member (it sees the anonymized bundle + scores).
163
+ _(v4.1 annotation: the engine fast path's `amicus council run` rejects this — the chair must
164
+ NOT be a bench seat, checked pre-flight, exit 1 before any spend. This flexibility survives only
165
+ in the manual path; see `MANUAL-ORCHESTRATION.md` and §13.)_
159
166
  - **Fallback order if the chair fails:** re-run → promote next-best council model →
160
167
  **Claude chairs only as last resort, with explicit disclosure** that the verdict is no longer
161
168
  fully independent.
@@ -291,3 +298,36 @@ The debate agent's parallel-panels + cross-panel synthesis maps to two full coun
291
298
  different benches or lens-sets plus a super-chair synthesis of where the panels agree,
292
299
  disagree, and what each missed. Deferred: cost doubles and the run-folder conventions need
293
300
  namespacing. Revisit if lens runs prove valuable.
301
+
302
+ ## 13. v4.1 — the engine fast path
303
+
304
+ `amicus council run` (v4.0; extended in v4.1 with `--debate`, `--claude-review`, and `council
305
+ verdict --render`) is the **headless realization of Stages 1–3 plus the Stage-5 deterministic
306
+ artifacts** described above: the Stage-1 review wave, per-leg findings validation and bounded
307
+ repair, anonymization and run-global finding-id rewriting, the identical judge bundle, the
308
+ Stage-2 cross-review wave, the optional Stage-2.5 debate round (§12.3), the tally, the chair
309
+ synthesis, and the deterministic `verdict.json` (undecided) + `report.html` — all as **one
310
+ command with no Claude runtime** in the loop. `SKILL.md`'s engine fast path drives this directly.
311
+ The hand-driven Stage 1 → 2 → 3 waves this document describes above remain available as
312
+ `MANUAL-ORCHESTRATION.md` — the fallback for the engine being unavailable/misbehaving, a fully
313
+ custom per-seat brief beyond `--critic`/`--lenses`, or deliberate mid-stage inspection.
314
+
315
+ **Stage 4 stays human, always.** The engine is report-only: `amicus council run` never
316
+ fabricates an accept/deny decision. Claude still drives Stage 4 (§4) and finalizes the verdict via
317
+ `amicus council verdict --decisions <decisions.json> --render` (§4, Stage 5) — the fast path
318
+ changes the *transport* for Stages 1–3 plus the Stage-5 artifacts, not the decision authority of
319
+ Stage 4.
320
+
321
+ **§12.4 (chair verdict scale) is standard-on in the fast path.** What was an opt-in menu item in
322
+ the manual path is now baked into `amicus council run`'s chair packet unconditionally — every
323
+ headless chair closes with the hard questions and a parseable `VERDICT:` line, surfaced as
324
+ `overallVerdict` in `verdict.json`. There is no toggle for it on the engine path; it is always on.
325
+
326
+ **§12.3 (debate mode) headless realization: `--debate` on `council run`.** The Stage-2.5 rebuttal
327
+ round described in §12.3 is implemented headlessly in `src/council/run-debate.js`
328
+ (orchestration) + `src/council/debate.js` (pure tally-input reassembly) +
329
+ `src/council/briefings-debate.js` (rebuttal/re-vote prompt templates) — same mechanics, same
330
+ exactly-one-round rule, same withdrawn-findings-auto-denied outcome (§12.3), now driven by the
331
+ engine instead of Claude's hand-launched solos/waves. The round's summary lands in `run.json`'s
332
+ `debate` object and each affected finding's `findings[].debate` decoration — see
333
+ [docs/council.md](../../docs/council.md) for the field-by-field reference.
@@ -0,0 +1,266 @@
1
+ # Manual Orchestration (fallback path)
2
+
3
+ This is the **fallback path**; the engine is primary since v4.1 (`amicus council run --prompt-file <briefing.md> --models "a,b,c" --chair <model> --json`). Use this doc when: the engine is unavailable or misbehaving, you need a fully custom per-seat brief beyond `--critic`/`--lenses`, you need to inspect or intervene mid-stage, or you are running a 1-model scale-down. SKILL.md's §4.7 fallback rules point here.
4
+
5
+ ---
6
+
7
+ ### Stage 1 (manual)
8
+
9
+ Each council model reviews **the artifact** independently. Write one Stage-1 briefing file
10
+ (`_tmp-briefing-stage1.md` in the run folder) and launch the whole wave as ONE background call:
11
+
12
+ ```
13
+ amicus fanout --models "<m1,m2,m3>" --prompt-file <run-folder>/_tmp-briefing-stage1.md --json \
14
+ --agent Plan --no-context --summary-length verbose --timeout <minutes>
15
+ ```
16
+
17
+ Always quote the `--models` list — unquoted, PowerShell splits on commas and the CLI receives one mangled alias (instant arg-parse failure).
18
+
19
+ Run it in the background (`run_in_background: true`); you are notified on completion — do not
20
+ poll. `fanout` is headless by definition. The command exits when every leg is terminal and prints
21
+ ONE JSON wave document on stdout (`schemaVersion: 2`; the wave's id field is `waveId`, each leg's id is `taskId`): check `status` (`complete` | `partial` |
22
+ `error`), `counts`, and each leg in `legs[]` — a leg's `summary` field IS that model's review;
23
+ `model`/`modelInput` identify the reviewer (`model` is the resolved id, `modelInput` the alias you passed — use the alias for `review-<model>.md` filenames); `status`/`error` identify failures. Exit code 0 =
24
+ all legs complete, 2 = partial (apply the wave-degrade rules below), 1 = error/aborted. (To re-fetch a single leg later: `amicus read <taskId> --json`.)
25
+
26
+ **Red-team variant:** fanout legs share a single prompt by design. When one model gets a distinct
27
+ red-team brief, launch it as a separate concurrent solo run alongside the wave:
28
+
29
+ ```
30
+ amicus start --model <redteam-model> --no-ui --json \
31
+ --prompt-file <run-folder>/_tmp-briefing-redteam.md \
32
+ --agent Plan --no-context --summary-length verbose --timeout <minutes>
33
+ ```
34
+
35
+ Its stdout is a single run document; the `summary` field is the review.
36
+
37
+ **Critic seat (optional element, when ON):** one bench member — recommended by Claude at Stage 0, typically a strong reasoner that is not the chair — receives the critic brief from `SEAT-BRIEFS.md § Critic seat brief` **instead of** the standard review brief. Launch it exactly like the red-team variant: a separate concurrent solo run (`_tmp-briefing-critic.md`) alongside the fanout wave of the remaining members — same total review count. Everything downstream is unchanged: same structured-output contract, same `council validate` + repair loop, same anonymization into the Stage-2 bundle (judges are never told a critic seat exists). Record `role: "critic"` on that seat's `runStats` entry. One standing disclosure for `report.md`: the critic model can recognize its own review in the Stage-2 bundle by its adversarial shape, so self-bias wash-out is weakened for that one seat.
38
+
39
+ **Expert lenses (optional element, when ON):** every seat gets a distinct per-seat brief, so there is no shared-prompt wave — launch **all** legs as concurrent solo runs (`_tmp-briefing-lens-<slug>.md`, one per seat), using the lens templates and panel-scoping rules in `SEAT-BRIEFS.md § Expert lens briefs`. The lens↔model assignment is random and lives only in the private label map — no reviewer learns the other seats' lenses. Same structured-output contract and validation. Record `role: "lens:<slug>"` on each `runStats` entry. Two standing consequences, both disclosed in `report.md`: Stage-2 anonymity is weakened (each judge can spot its own lens-flavored review), and the Stage-2 tally runs `--no-ledger` (lens reviews are not comparable to standard reviews and must not feed cross-run reliability stats). Wave-degrade rules apply to these solos exactly as to fanout legs.
40
+
41
+ **Cowork / no-Bash environments:** use the MCP tools instead — `amicus_fanout` (briefing via
42
+ file) returns `{waveId, taskIds[]}` immediately. Preferred: call `amicus_wait` with the waveId —
43
+ one blocking call per wave; re-call it while it returns `timedOut: true`. Fallback: poll
44
+ `amicus_status`. Either way, `amicus_read` each leg when done. The council's briefings are always
45
+ self-contained (`--no-context`), so MCP transport is equivalent.
46
+ Council JSON returned by the MCP tools (`amicus_council_tally`, `amicus_council_stats`, `amicus_verdict`) arrives wrapped in the `<untrusted_sidecar_output>` fence since v4.0 — parse the JSON from inside the fence; CLI `--json` output remains unfenced.
47
+
48
+ **Required structured output from every model.** Instruct each council model to produce:
49
+
50
+ 1. A **prose review** — the reviewer's full narrative assessment of the artifact.
51
+
52
+ 2. A **trailing fenced ` ```json ` block** immediately after the prose, containing:
53
+ ```json
54
+ {
55
+ "overall": "one-paragraph take",
56
+ "findings": [
57
+ { "id": 1, "severity": "blocker",
58
+ "claim": "…", "location": "…", "rationale": "…" }
59
+ ]
60
+ }
61
+ ```
62
+ - `id` — sequential integer within this review (`1..n`); at Stage-2 assembly Claude rewrites each into a **run-global label id** (`A1`, `B1`, …) by prefixing the review's anonymized label.
63
+ - `severity ∈ {blocker, major, minor, nit}`
64
+ - `claim`, `location`, `rationale` — non-empty strings.
65
+
66
+ Instruct models to emit the structured JSON verbatim after the prose, without preamble, so it parses cleanly.
67
+
68
+ **Every Stage-1 briefing — standard seats included — must contain the standard anti-sycophancy clause from `SEAT-BRIEFS.md` verbatim** (do not soften, lead with the most severe finding, no praise cushions, no padding — an empty severity category is a valid result). This is briefing hygiene, not an optional element.
69
+
70
+ Save each leg's full output (prose + findings block) to the run folder as `review-<model>.md`
71
+ (one file per reviewer) before moving on.
72
+
73
+ **After the wave returns, validate each leg's findings block** by running `amicus council validate <leg-file> --json` (a thin CLI wrapper over `validateFindings`, Unit A — `src/council/findings.js`). It reads the leg's saved `review-<model>.md` and prints `{ok, findings, errors}`. Exit codes are a **tri-state** contract: `0` when `ok:true` (well-formed, proceed), `2` when `ok:false` (validation failed — a distinct, scriptable outcome, not a crash), `1` (`BAD_ARGS`) for a missing/unreadable file. If a leg's JSON fails validation (`ok:false` / exit 2):
74
+ 1. Issue a **solo `start --json`** re-prompt to that one model: "re-emit only the findings JSON, fixing: \<errors\>." Keep the first-pass prose. (Solo `start` passes through the **same budget gate** as `fanout`. If launching the wave required `--max-cost <$>` or `--no-cost-gate`, pass the **same flag on every repair re-prompt and on the chair call** — otherwise the gate can refuse a repair or the chair mid-council.)
75
+ 2. If still malformed, retry **once more** (cap = **2** re-prompts total).
76
+ 3. If still malformed after 2 retries, mark the review `unstructured` and hand-parse its prose into the schema. The review proceeds — never dropped for a formatting miss.
77
+
78
+ Record per-model **conformance** (`clean` | `repaired` | `unstructured`) for inclusion in the tally input's `runStats` and the Stage-6 MODEL-NOTES note.
79
+
80
+ **"Claude in the council" (when toggled on):** Claude also produces a **fresh** Stage-1 review on the artifact in the identical findings format — a new structured pass on the artifact, not a formalization of anything said upstream. This review is added to the bundle as one more anonymous entry. Claude does not rank or adjudicate in Stage 2 (it holds the label map), and does not chair in Stage 3. Save it as `review-claude.md`.
81
+
82
+ **Wave-degrade rules (Stage 1).** Read failures from the wave document — never silently ignore
83
+ them:
84
+ - All legs `complete` → proceed normally.
85
+ - A leg ends `error`/`timeout`/`crashed`/`aborted` but **≥ 2 reviews survive** → proceed with the
86
+ survivors; name the dead leg and its `error` when presenting; the bench shrinks accordingly. If this leaves exactly 2 surviving reviews, the run is now effectively a 2-model council — apply the thin-ranking disclosure (Stage 0 / Stage 4) from here on.
87
+ - **Fewer than 2 reviews survive** → offer the user a re-run of the dead leg(s) (solo
88
+ `amicus start --json`, same briefing file) or a disclosed downgrade to single-pass mode
89
+ (Stage 2 and Stage 3 skipped, per the scale-down rules).
90
+
91
+ ---
92
+
93
+ ### Stage 2 (manual)
94
+
95
+ This is the peer-validation step. Claude builds one shared anonymized bundle, distributes it to every council model for ranking and finding adjudication, then de-anonymizes for scoring.
96
+
97
+ **Build the shared anonymized bundle.** After all Stage-1 reviews are in hand, Claude:
98
+ 1. Assigns stable labels: **Review A**, **Review B**, **Review C**, … (one per review, including Claude's if the toggle is on).
99
+ 2. Keeps a **private label↔model map** (e.g., `Review A → deepseek`, `Review B → gemini`, `Review C → claude`) that is never sent to any sidecar model.
100
+ 3. Assembles one bundle document containing all labeled reviews. The bundle is identical for every judge.
101
+
102
+ Each model **unknowingly ranks and adjudicates its own review** — this is the anti-favoritism mechanism, not a bug. Because no model knows which review is its own, self-bias washes out symmetrically across judges.
103
+
104
+ **Distribute the same bundle to every council model** — this is exactly fanout's shared-prompt
105
+ model. Write the bundle + judging instructions to `_tmp-bundle-stage2.md` and launch one wave:
106
+
107
+ ```
108
+ amicus fanout --models "<m1,m2,m3>" --prompt-file <run-folder>/_tmp-bundle-stage2.md --json \
109
+ --agent Plan --no-context --summary-length verbose --timeout <minutes>
110
+ ```
111
+
112
+ (Background, same JSON handling as Stage 1.) Each judge's leg `summary` is its ranking +
113
+ adjudication response. **Stage-2 degrade:** a judge leg dies → tally over the surviving judges
114
+ (≥ 1) and disclose the reduced bench in `crossreview-matrix.md`; tier definitions are unchanged
115
+ (they already count "judges engaged").
116
+
117
+ **Judge-briefing hardening (required).** Open `_tmp-bundle-stage2.md` with this preamble, verbatim, as its first line:
118
+
119
+ > Do NOT use any tools or read any files; everything is in this message; begin immediately with A1:
120
+
121
+ Plan-agent judges have wandered to tools mid-adjudication (reading files instead of judging and returning only narration), and a tool-capable judge can read the de-anonymized `review-<model>.md` files in the run folder — an anonymization leak. The preamble closes both. **Scratch-cwd (optional second layer):** launch the Stage-2 wave (and the Stage-3 chair call) with `--cwd <run-folder>/_scratch/` — create the empty directory first — so even a wandering agent finds nothing to read. Caveat: those legs' session records then live under `_scratch/.claude/amicus_sessions/`, so any later `amicus read <taskId>` for them needs the same `--cwd`.
122
+
123
+ Each judge is asked to do two things on the bundle:
124
+
125
+ **Task A — Rank.** Order the reviews from most to least accurate and insightful. End the response with a parseable block in exactly this format (no other text on those lines):
126
+
127
+ ```
128
+ FINAL RANKING:
129
+ 1. Review C
130
+ 2. Review A
131
+ 3. Review B
132
+ ```
133
+
134
+ **Task B — Adjudicate findings.** For every finding in the bundle, state: `agree | dispute | neutral` plus one-line reason. Reference each finding as **review-label + finding-id** — for example, `A2` means Review A's 2nd finding, `B1` means Review B's 1st finding. An "I missed this — it's valid" counts as `agree`.
135
+
136
+ **When critic seat or expert lenses are ON:** the bundle and judging instructions must not mention seats, lenses, or briefs — judges rank and adjudicate on accuracy and insight only. The element briefs are Stage-1 information; leaking them into Stage 2 tells every judge which review is which.
137
+
138
+ As each judge's ranking + adjudication response returns, collect it (the raw per-judge responses are working intermediates, not separate run-folder artifacts). Once all are in, **assemble the de-anonymized tally input** and then call `amicus council tally`:
139
+
140
+ **Stage-2 → tally assembly recipe (Claude's work before calling `tally`):**
141
+ 0. **Build `meta` and `findings[]` first — `tally` requires both** (missing either fails with `BAD_ARGS: Cannot read properties of undefined (reading 'map')`):
142
+ - `meta` = `{ "runId": "<run-folder stem>", "models": [<every reviewed model id, including "claude" when the toggle is on — this is the street-cred universe>], "chair": "<confirmed chair model id>", "claudeInCouncil": <Stage-0 toggle> }`. Optional extras: `runType`, `date`.
143
+ - `findings[]` = one entry per finding across ALL reviews: `{ "id": "<run-global label id from step 1, e.g. A1>", "raiser": "<de-anonymized model that raised it>", "severity": "<from the review JSON>" }` (`claim` may be carried along but is not required).
144
+ 1. **Rewrite finding ids to run-global label ids.** Each Stage-1 review's local integer ids (`1`, `2`, `3`…) become `A1`, `A2`, `A3`… (where `A` is that review's anonymized label). The label↔model map (`Review A → deepseek`, etc.) is the key.
145
+ 2. **Build `adjudications`** — for every judge across all findings: `findingId` = run-global label id; `judge` = the model id (de-anonymized via the map); `verdict ∈ {agree, dispute, neutral}`. Include every judge's verdict on every finding. The raiser's own adjudication of its own finding is **included in the input** (the tally engine excludes it when computing peers-only tiers — do not pre-filter it).
146
+ 3. **Translate each judge's `FINAL RANKING:` block** — convert the label order (`1. Review C / 2. Review A / 3. Review B`) into a model `order` array via the same map (e.g. `{C→mistral, A→deepseek, B→gpt}` ⇒ `order: ["mistral","deepseek","gpt"]`). This is each entry in `rankings[]`.
147
+ 4. **Populate `runStats`** from the per-leg run documents emitted by `fanout --json` (and any solo red-team/chair `start --json` docs): copy `model`, `status`, `durationMs`, `usage` verbatim. Any leg with no run doc gets `durationMs: null` and `usage: null` — never invent a value. Attach `role` (`council` | `redteam` | `claude`), `wasChair`, and `conformance` (`clean` | `repaired` | `unstructured`) as council-domain labels.
148
+
149
+ **Five-keys checklist — verify `tally-input.json` has ALL of:** `meta` (with `meta.models`), `findings`, `adjudications`, `rankings`, `runStats` (`runStats` may be `[]`; the other four are required). Do not call `tally` until all five are present.
150
+
151
+ Then call, saving the printed `record` to `<run-folder>/tally.json` (Stage 5's `amicus council verdict` reads it back from disk):
152
+
153
+ ```
154
+ amicus council tally <run-folder>/tally-input.json --json > <run-folder>/tally.json
155
+ ```
156
+
157
+ **Ledger flags for optional elements:** when **expert lenses** are ON, always pass `--no-ledger` — lens runs never feed cross-run reliability stats. When **debate mode** is ON, this Stage-2 tally is *provisional* — pass `--no-ledger` here; the final, ledger-recorded tally happens at the end of Stage 2.5 (the critic seat and Claude-in-the-council change nothing about ledger handling).
158
+
159
+ **Windows PowerShell 5.1 caveat:** that `>` redirect writes UTF-16 under legacy Windows PowerShell 5.1 (fine on pwsh 7+ or bash), which corrupts `tally.json` for Stage 5's `amicus council verdict` and surfaces as a confusing `BAD_ARGS` there instead of here — on 5.1 pipe through `| Out-File -Encoding utf8` (or run under pwsh 7+) instead of a bare `>`.
160
+
161
+ The output `record` carries the deterministic tiers (Disputed / Confirmed / Contested / Singleton), `confidence` (`solid` | `thin`), both street-cred numbers (`withSelf` and `peersOnly`), the validated `runStats`, and `tierCounts`. **Claude may override a `thin`-confidence tier at the margins** before Stage 4 — record the override in `tierOverride: {from, to, reason}`; the matrix and `verdict.json` surface it. De-anonymize and write the tally results to `crossreview-matrix.md` — the adjudication grid plus the street-cred table. This data feeds Stage 3 (chair briefing) and is never re-anonymized or forwarded to any council model.
162
+
163
+ ---
164
+
165
+ ### Stage 2.5 (manual rebuttal round)
166
+
167
+ One structured challenge round on the findings the bench did not settle: every **Contested** and **Disputed** finding goes back to its raiser to defend, amend, or withdraw; the judges that disputed it re-vote; then the final tally. **Exactly ONE round, ever** — never iterate further; whatever remains unsettled after the re-vote keeps its final tier. Briefing templates are in `SEAT-BRIEFS.md § Rebuttal-round templates`; every rebuttal briefing opens with the no-tools preamble, same as Stage 2.
168
+
169
+ The Stage-2 tally above ran `--no-ledger` (provisional). If it produced **zero Contested + Disputed findings**, skip the rebuttal waves entirely: re-run the tally on the unchanged input *without* `--no-ledger` to record it, note "debate mode: nothing to debate" for `report.md`, and proceed to Stage 3.
170
+
171
+ **1. Defense mini-wave.** For each raiser with ≥ 1 Contested/Disputed finding, write `_tmp-rebuttal-<label>.md`: its findings (run-global ids and claims), each with the peers' dispute reasons — anonymized, no judge identities. Launch one concurrent solo run per raiser (same flags and budget-gate handling as the Stage-1 solos). Parse each response line: `<id>: DEFEND — …` | `<id>: AMEND — <replacement claim>` | `<id>: WITHDRAW`. A missing or unparseable line = the original claim stands undefended (original verdicts carry).
172
+
173
+ **2. Re-vote mini-wave.** Build ONE shared `_tmp-revote-bundle.md` holding every defended or amended finding plus its (anonymous) defense. Send it as a single fanout wave to the judges that disputed at least one of those findings — judges that never disputed sit this round out. Parse verdict lines `<id>: agree | dispute | neutral — <reason>`; a judge's missing line = its original verdict stands.
174
+
175
+ **3. Final tally.** Re-assemble the tally input: re-vote verdicts replace those judges' original adjudications on those findings; AMENDED claims replace the originals (`id`, `raiser`, and `severity` unchanged); WITHDRAWN findings **stay in `findings[]`** (they were raised) and take whatever tier the final cascade assigns. Run `amicus council tally` **without** `--no-ledger` (unless expert lenses are also ON — lens runs never ledger) and save this record as the run's `tally.json`. This final record — not the provisional one — is what Stages 3–5 consume; the chair packet and `crossreview-matrix.md` are built from it, with verdict changes from the re-vote called out before/after.
176
+
177
+ **Withdrawals downstream:** WITHDRAWN findings are auto-recorded in `decisions.json` as `{"id": …, "decision": "denied"}` — never presented for a user decision in Stage 4 — and listed in `report.md` under "Withdrawn by raiser (debate mode)".
178
+
179
+ **Degrade rules:** a dead defense leg → all of that raiser's contested findings stand undefended. A dead re-vote leg → that judge's original verdicts carry. Never re-run the round.
180
+
181
+ **Cost/shape:** adds up to 2 short waves (≤ N defense solos + 1 re-vote fanout), disclosed at Stage 0. If the actual rebuttal surface turns out much larger than estimated (many contested findings), say so before launching the mini-waves.
182
+
183
+ ---
184
+
185
+ ### Stage 3 (manual chair)
186
+
187
+ A designated **non-Claude** chair synthesizes the verdict across all reviews, rankings, and adjudications. The chair produces an independent verdict that Claude then presents — Claude does not paraphrase, edit, or re-synthesize it.
188
+
189
+ **Chair selection (confirmed in Stage 0).** Default: Claude recommends the strongest reasoner in the council (guided by `amicus council stats` (peers-only street-cred) and the qualitative quirks in `MODEL-NOTES.md`) and the user confirms before the run launches. The chair may be a council member who already participated in Stages 1 and 2 — it receives the de-anonymized full bundle, all ranking outputs, and all adjudications so it has the complete picture.
190
+
191
+ **Fallback order if the chair fails:**
192
+ 1. Re-run the chair call (transient failure — `MODEL-NOTES.md` mitigations apply).
193
+ 2. Promote the next-best non-Claude council model as chair.
194
+ 3. **Claude chairs only as last resort — with explicit disclosure** that the verdict is no longer fully independent of the orchestrator.
195
+
196
+ **Chair briefing.** Write the chair packet to `_tmp-chair-packet.md` and send one solo run
197
+ (background):
198
+
199
+ ```
200
+ amicus start --model <chair> --no-ui --json \
201
+ --prompt-file <run-folder>/_tmp-chair-packet.md \
202
+ --agent Plan --no-context --summary-length verbose --timeout <minutes>
203
+ ```
204
+
205
+ (The budget gate applies to this solo call too — if Stage 0 needed `--max-cost <$>` or `--no-cost-gate` to launch the wave, the chair call needs the same flag.)
206
+
207
+ The run document's `summary` is the verdict. The packet contains:
208
+ - All Stage-1 reviews (de-anonymized — model attribution restored)
209
+ - All cross-review ranking outputs (with model attribution)
210
+ - All adjudication outputs (with model attribution and `agree | dispute | neutral` verdicts per finding)
211
+
212
+ Open `_tmp-chair-packet.md` with the no-tools preamble, adjusted for the chair: *'Do NOT use any tools or read any files; everything is in this message; begin immediately with the verdict.'* The packet is complete by construction — the chair must never go looking for files.
213
+
214
+ Instruct the chair to write a **synthesized verdict** that:
215
+ - Weighs each reviewer's findings by their peer-validated standing (street-cred rank and adjudication pattern)
216
+ - Distinguishes findings the bench broadly endorsed from contested or singleton claims
217
+ - Arrives at an overall assessment of the artifact
218
+
219
+ **Chair verdict scale (optional element, when ON):** append the addendum from `SEAT-BRIEFS.md § Chair verdict-scale addendum` to the chair packet — the chair must close with 3–5 **hard questions** the artifact's author probably hasn't asked themselves, then a final parseable line: `VERDICT: Ship it | Fix these first | Fundamental rethink`. Surface that line verbatim at the top of `report.md` and in the inline chat presentation. When debate mode is also ON, the chair packet is built from the *final* (post-rebuttal) tally and includes the defense/re-vote outcomes.
220
+
221
+ Save the chair's output to the run folder as `verdict.md`.
222
+
223
+ ---
224
+
225
+ ### Stage 5 artifacts (manual)
226
+
227
+ **Editable source** (the artifact is a file you can write — `.md`, `.docx`, `.py`, any text format):
228
+ - Apply only the **accepted findings** from Stage 4.
229
+ - Write the result as `<stem>-reviewed.<ext>` **next to the original file** — same directory, same extension, `-reviewed` appended before the extension.
230
+ - Before writing, validate structural integrity: check that headings are balanced, code blocks close, front-matter is valid, etc. Fix any structural integrity issues **your edits introduce** — do not touch pre-existing issues in the original. Do not alter any content beyond the accepted findings.
231
+
232
+ **Fixed source** (the artifact is a link, PDF, or something you cannot directly edit):
233
+ - Do not attempt to produce a modified copy.
234
+ - Write a **standalone reviewed report** instead: the full decision log, the chair's verdict, and clear callouts of what should be changed and where — formatted so the user can apply the changes manually.
235
+
236
+ **Run-folder artifacts — always write these** regardless of source type. The full artifact set and naming conventions are defined in the *Output & naming* section of this skill; write every artifact specified there. The canonical run-folder files are:
237
+ - `review-<model>.md` × N (already saved in Stage 1)
238
+ - `crossreview-matrix.md` — the de-anonymized adjudication grid and street-cred table
239
+ - `verdict.md` (already saved in Stage 3)
240
+ - `verdict.json` — write by running `amicus council verdict <run-folder>/tally.json --decisions <run-folder>/decisions.json -o <run-folder>/verdict.json` (a thin CLI wrapper over `buildVerdict(record, decisions)` + `writeVerdictAtomic`, `src/council/verdict.js`). `<run-folder>/tally.json` is the `record` saved from the Stage-2 `amicus council tally` call. `<run-folder>/decisions.json` is a **JSON array**, one object per finding: `{id, decision, applied?, duplicateOf?, tierOverride?}` — `id` is the run-global label id (e.g. `A1`); `decision` is the Stage-4 outcome (accepted / denied / modified / deferred); `applied` (optional bool) marks whether the accepted change was actually applied to the artifact in Stage 5; `duplicateOf` (optional) links to another finding's id when Claude identified a duplicate; `tierOverride` (optional) carries any `{from, to, reason}` override recorded in Stage 2. Save this array to `<run-folder>/decisions.json` first, then run the command — it parses the tally record and the decisions file, calls `buildVerdict`, and writes the schema-stamped machine-readable record to the run folder via the same atomic tmp+rename convention the function always used.
241
+ - `report.md` — the chair's synthesis + the full Stage-4 decision log + a summary of what was
242
+ applied (+ the "How Claude's review fared" readout when "Claude in the council" is on) + an
243
+ **Optional elements** section whenever any element was ON: which elements ran; the chair's
244
+ `VERDICT:` line verbatim at the top of the report (chair verdict scale); the "Withdrawn by
245
+ raiser (debate mode)" list and re-vote verdict changes (debate mode); and the standing
246
+ disclosures — critic self-identification in cross-review (critic seat), weakened anonymity +
247
+ non-comparable street-cred + `--no-ledger` (expert lenses) + a
248
+ **run-stats table**: one row per model call — **stage** (which stage you launched the call for)
249
+ plus **model, status, durationMs, and cost** read from the wave/run JSON `usage`
250
+ block. Cost is `usage.cost.amount` (USD); mark it with its `usage.cost.source`
251
+ — exact for `reported`, `~` for `estimated`, `?` for `unknown` — and never
252
+ invent a figure. Add a wave **total cost** row from the wave document's
253
+ `usage.cost` (`source: reported|estimated|mixed|unknown`). Any leg with no run doc → `durationMs: null`, `usage: null`; never invent a value.
254
+ - **Renderer:** once `verdict.json` is written, run
255
+ `amicus council report <run-folder>/verdict.json --html > <run-folder>/report.html` — a
256
+ **separate, deterministic** artifact, not report.md itself. **`report.html` is the default
257
+ final artifact to hand the user** — a self-contained, shareable page. This emits the
258
+ adjudication matrix (finding × judge), the peers-only street-cred table, the
259
+ findings-by-tier groupings (Disputed-first), and the per-model + wave cost —
260
+ deterministic data only. To assemble report.md, also run
261
+ `amicus council report <run-folder>/verdict.json --md` (no redirect — read its stdout) and
262
+ paste that Markdown into report.md as one section; reserve the rest of report.md's prose for
263
+ the chair's synthesis and the decision log. Prefer the renderer's Markdown over
264
+ hand-assembling the matrix by hand.
265
+
266
+ Tell the user exactly which files were written and where, leading with `report.html`, **and present the verdict inline in chat** — the chair's overall assessment (verbatim or lightly trimmed) plus the tier counts (Confirmed/Disputed/Contested/Singleton) and what was applied. Never hand over only file paths.
@@ -8,6 +8,9 @@ _Last updated: 2026-07-14 (v2.2.0 fold-back: v3.1 optional council elements veri
8
8
  claim-class dedup adjudication limit; minimax and qwen-coder debut notes; see changelog)._
9
9
 
10
10
  ## Global operating rules (all models)
11
+ - **Fast path:** `council run` applies `--agent Plan` / `--no-context` / `--summary-length
12
+ verbose` and the no-tools preambles automatically; the flag rules below govern the manual path
13
+ and sidecar solos.
11
14
  - **Council runs are headless by design** (autonomous batch work): `fanout` is headless by
12
15
  definition; solo runs use `--no-ui`. Interactive GUI sessions are for the `sidecar` chat skill,
13
16
  not councils.
@@ -37,6 +40,24 @@ claim-class dedup adjudication limit; minimax and qwen-coder debut notes; see ch
37
40
  gpt/deepseek/grok have handled 82k-word agentic reads; gemini(-flash) and kimi stalled (narrate-
38
41
  stall / 25-min timeout / poller "Incomplete"). Pre-select proven long-read models or inline the
39
42
  text for large-context models.
43
+ - **Debate mode rarely fires on correctness questions — design for it or expect a no-op.**
44
+ `--debate` only engages findings the tally marked Contested or Disputed, and judges agree far
45
+ more than expected: **2 disputes in 123 adjudications across four councils** (gemini/gpt/qwen).
46
+ Three of those four runs produced zero debatable findings, so the round never ran. Bug hunts
47
+ converge — a race condition either exists or it does not. If you want a rebuttal round, brief a
48
+ genuine judgement call (architecture, tradeoffs, "is this over-engineered"), not a defect hunt.
49
+ - **Read spend from `run.json`, never from a provider credit balance.** `usage.cost.amount` is the
50
+ run total; per-leg costs are in `runStats[].usage.cost`. Only OpenRouter-routed legs move the
51
+ OpenRouter balance — gemini/gpt/anthropic bill directly against their own keys, so inferring cost
52
+ from that balance under-reports it badly (observed: ~6x low). A 3-model bench + chair + debate is
53
+ roughly **$0.60-0.80 per run**, not cents; budget `--max-cost` accordingly or the chair gets
54
+ skipped mid-run (exit 2, degraded) when the debate legs push the total past the ceiling.
55
+ - **Expect agreement inflation in Stage-2 adjudication.** The judge contract defines `agree` by
56
+ worked example ("an 'I missed this — it's valid' counts as agree") but gives no example for
57
+ `dispute` and no positive definition of `neutral`, while requiring a verdict on EVERY finding —
58
+ including ones outside a judge's focus. A council reviewing this contract flagged the asymmetry
59
+ unanimously. Weigh a lone `Confirmed` tier accordingly, and prefer `Contested` evidence over
60
+ vote counts when a finding matters.
40
61
  - **Stage-6 approvals:** write the proposed MODEL-NOTES diff to a run-folder file and put that path
41
62
  in the approval prompt — chat-text diffs can be hidden behind the approval dialog.
42
63