amicus 3.2.2 → 4.0.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 (53) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +78 -0
  3. package/README.md +15 -3
  4. package/electron/main.js +4 -1
  5. package/package.json +3 -1
  6. package/schemas/abort.schema.json +17 -0
  7. package/schemas/alias-audit.schema.json +17 -0
  8. package/schemas/council-run.schema.json +37 -0
  9. package/schemas/council-stats.schema.json +28 -0
  10. package/schemas/council-tally.schema.json +70 -0
  11. package/schemas/council-validate.schema.json +22 -0
  12. package/schemas/council-verdict.schema.json +47 -0
  13. package/schemas/doctor.schema.json +29 -0
  14. package/schemas/error.schema.json +23 -0
  15. package/schemas/model-catalog.schema.json +19 -0
  16. package/schemas/run.schema.json +26 -0
  17. package/schemas/spend.schema.json +16 -0
  18. package/schemas/wave.schema.json +33 -0
  19. package/skills/second-opinion/SEAT-BRIEFS.md +5 -3
  20. package/skills/second-opinion/SKILL.md +8 -0
  21. package/src/cli-handlers-abort.js +29 -0
  22. package/src/cli-handlers-council-run.js +168 -0
  23. package/src/cli-handlers-council.js +8 -5
  24. package/src/cli-handlers-status.js +35 -4
  25. package/src/cli.js +9 -0
  26. package/src/council/anonymize.js +76 -0
  27. package/src/council/briefings-stage2.js +150 -0
  28. package/src/council/briefings.js +141 -0
  29. package/src/council/findings.js +13 -1
  30. package/src/council/ledger.js +13 -1
  31. package/src/council/parse-stage2.js +103 -0
  32. package/src/council/run-assemble.js +100 -0
  33. package/src/council/run-launch.js +99 -0
  34. package/src/council/run-stages.js +187 -0
  35. package/src/council/run-state.js +122 -0
  36. package/src/council/run.js +269 -0
  37. package/src/council/tally.js +3 -1
  38. package/src/council/verdict.js +9 -2
  39. package/src/headless.js +24 -25
  40. package/src/mcp-council-run.js +267 -0
  41. package/src/mcp-server.js +87 -28
  42. package/src/mcp-tools.js +50 -0
  43. package/src/prompt-builder.js +36 -19
  44. package/src/sidecar/electron-lock.js +4 -1
  45. package/src/sidecar/fanout-leg.js +2 -2
  46. package/src/sidecar/fanout.js +1 -1
  47. package/src/sidecar/resume.js +7 -2
  48. package/src/utils/abort-result.js +1 -1
  49. package/src/utils/error-doc.js +2 -0
  50. package/src/utils/fold-marker.js +21 -0
  51. package/src/utils/route-error.js +26 -0
  52. package/src/utils/start-helpers.js +19 -10
  53. package/src/utils/untrusted-fence.js +8 -7
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amicus",
3
- "version": "3.2.2",
3
+ "version": "4.0.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,84 @@ All notable changes to Amicus are documented here. Format follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [4.0.0] - 2026-07-20
9
+
10
+ The **headless council engine** release. `amicus council run` (CLI) and `amicus_council_run`
11
+ (MCP) execute the full adjudicated pipeline — Stage-1 independent reviews → anonymized peer
12
+ cross-review → deterministic tally → non-Claude chair verdict — with **no Claude runtime**,
13
+ reusing the existing pure primitives (`validateFindings`, `tally`, `buildVerdict`, the report
14
+ renderers, the ledger) under a run-directory state machine. On top of it, the **Council Review
15
+ GitHub Action v2** posts a real adjudicated verdict on labeled PRs (check run + annotations,
16
+ sticky comment, evidence artifact, opt-in gating). The major bump exists for the three trust
17
+ changes below — see **Migration**.
18
+
19
+ ### Migration (v3 → v4)
20
+
21
+ | v3 behavior | v4 behavior / remedy |
22
+ | --- | --- |
23
+ | MCP council tools (`amicus_council_tally`, `amicus_council_stats`, `amicus_verdict`) returned **bare JSON** tool text | Their JSON is now wrapped in the `<untrusted_sidecar_output>` fence (same mechanism as `amicus_read`), and the new `amicus_council_run` returns fenced text too. MCP consumers that parse the tool text must unwrap the fence first; the JSON inside is byte-intact. **CLI `--json` output is unchanged and stays the byte-stable programmatic channel.** |
24
+ | `amicus council stats --json` printed a **bare array** of per-model rows | It now prints `{"schemaVersion": 2, "type": "council-stats", "models": [...]}` — the one breaking shape change in the envelope unification. Update scripts to read `.models`. Every other envelope change is additive (`schemaVersion`/`type` injected onto existing docs; council family bumps 1 → 2; `verdict.json` gains nullable `overallVerdict`). |
25
+ | Some `--json` failure paths printed **plain text on stderr** (no model configured, model-selection cancelled, route errors, `status` with a missing/invalid task id; MCP validation/route errors as unstructured text) | Under `--json` these now emit the standard **error envelope on stdout** with the documented exit codes; MCP error text is error-doc-shaped (`{schemaVersion, type: "error", ...}`). Scripts that scraped stderr strings must read the stdout envelope. Human-mode (no `--json`) stderr behavior is unchanged. |
26
+ | Bare `[SIDECAR_FOLD]` markers were still written/parsed on legacy internal paths | The fold marker is **nonce-required** end to end: the bare literal survives only as the prefix inside the nonced form, resume replay strips residual fold-marker lines, and the internal legacy bare-marker finder/writer fallbacks are removed (`docs/SHIMS.md` updated). Wire-format consumers of the **nonced** form are unaffected. |
27
+ | Council Review Action v1 (fanout + synthesis; `max_cost` default `1.00`) | Action v2 runs `amicus council run` and posts an adjudicated verdict. `workflow_call` callers: new optional inputs `chair` (default `deepseek`), `critic`, `fail_on` (`none`\|`fix`\|`rethink`, default `none` = report-only); **`max_cost` default is now `2.00`** (a council is ~2 waves + chair + repairs vs v1's wave + synthesis) — pass `max_cost: '1.00'` explicitly to keep the old ceiling. `models`/`require_label`/secrets semantics unchanged. A chair listed in `models` is excluded from the bench at run time (the engine requires the chair not to be seated). |
28
+
29
+ ### Added
30
+
31
+ - **`amicus council run`** — the headless council engine (CLI): `--prompt-file` briefing,
32
+ `--models`/`--council` bench (≥2 seats), `--chair` (default `deepseek`, never a bench seat),
33
+ optional `--critic` / `--lenses` (mutually exclusive), whole-run `--max-cost`, per-leg
34
+ `--timeout`, durable `--out-dir` run directory (`review-*.md`, `bundle-stage2.md`,
35
+ `judge-*.md`, `chair-output.md`, `tally-input.json`, `tally.json`, `verdict.json` with
36
+ **`overallVerdict`**, `report.html`, `run.json`), exit contract `0` full / `2` degraded /
37
+ `1` failed, SIGINT/SIGTERM finalization, and `status`/`wait`/`list`/`abort` integration via a
38
+ sessions-dir pointer file. Stage 4 stays human: the engine is report-only.
39
+ - **`amicus_council_run`** MCP tool (15th tool): briefing-via-file like `amicus_fanout`, returns
40
+ `{runId, runDir}` immediately (async).
41
+ - **Council Review GitHub Action v2** (`.github/workflows/council-review.yml`): adjudicated
42
+ verdict as a **check run** ("Council Review") with Confirmed-finding annotations (best-effort
43
+ `file:line` parse, 50-per-request chunking, file-level fallback, unmapped findings listed in
44
+ the summary), **sticky comment v2** (chair verdict line, tier table, per-tier lists,
45
+ street-cred table, cost line, artifact link), **evidence artifact** (the full run directory),
46
+ and opt-in gating via `fail_on`. Label gate, fork soft-skip, no-checkout, and the duplicated
47
+ `neutralize()` rules carry forward from v1.
48
+ - **Published JSON Schemas** (`schemas/`, draft 2020-12, one file per doc type) shipped in the
49
+ npm tarball and documented in `docs/schemas.md`; every builder's real output is
50
+ schema-validated in tests (ajv as a devDependency only).
51
+ - `docs/council.md` § `amicus council run` (headless reference), usage.md/README coverage, and a
52
+ headless-context pointer in the `second-opinion` skill.
53
+
54
+ ### Changed
55
+
56
+ - **Unified JSON envelope convention:** every emitted doc carries `{schemaVersion, type}`; the
57
+ council family bumps **1 → 2** (additive fields, no re-nesting); `council validate --json`
58
+ gains the envelope fields; CLI `status --json` gains `schemaVersion`; MCP success returns get
59
+ `schemaVersion`/`type` injected additively. Ledger JSONL stays internal at v1 (documented
60
+ exclusion). Interactive-only commands (`setup`, `update`, `key`) are documented envelope
61
+ exclusions.
62
+ - `--json` failure paths routed through the error envelope on stdout (see Migration).
63
+ - MCP council-tool JSON is fenced with `<untrusted_sidecar_output>` (see Migration);
64
+ `untrusted-fence.js`'s module doc and the skill's Cowork-transport note updated to match.
65
+
66
+ ### Removed
67
+
68
+ - The legacy bare fold-marker internals: `findLegacyBareTrailingMarker` and the bare-writer
69
+ fallback in `formatFoldOutput` (`nonce` is now a required argument). See Migration.
70
+
71
+ ## [3.2.3] - 2026-07-18
72
+
73
+ ### Fixed
74
+
75
+ - **The Electron repair lockfile key is per-install again.** `lockPathFor()`
76
+ derived its temp-lockfile key from only the first 8 characters of the Electron
77
+ dir path (its hex encoding truncated to 16 chars), so distinct installs that
78
+ share a leading path segment (`C:\Users…`, `/home/us…`) collapsed onto a single
79
+ shared lockfile — defeating the intended per-install isolation and causing
80
+ intermittent cross-worktree test failures, where suites run from different
81
+ `.claude/worktrees/*` raced on the same lock. The key now hashes the full
82
+ Electron dir with sha1, mirroring the engine-lock fix shipped in v3.2.2. The
83
+ public `acquireRepairLock` interface is unchanged, so there is no downstream
84
+ impact; stale lockfiles from the old key simply age out (#69).
85
+
8
86
  ## [3.2.2] - 2026-07-17
9
87
 
10
88
  ### Fixed
package/README.md CHANGED
@@ -227,6 +227,15 @@ Then the council waits for your confirmation.
227
227
 
228
228
  The skill lives at **[`skills/second-opinion/SKILL.md`](./skills/second-opinion/SKILL.md)**; the design spec behind it is **[`skills/second-opinion/COUNCIL-DESIGN.md`](./skills/second-opinion/COUNCIL-DESIGN.md)**. For what `amicus council tally|verdict|report|stats` actually take as input and produce — field-by-field schemas, verdict.json's provenance, and a full worked example run against the real CLI — see **[docs/council.md](./docs/council.md)**.
229
229
 
230
+ **Headless council (CI).** The same pipeline runs with no Claude runtime at all: `amicus council
231
+ run --prompt-file briefing.md --models gemini,glm --chair deepseek --json` executes the review
232
+ waves, the anonymized cross-review, the tally, and the chair verdict in one command, and writes
233
+ the full run directory (`verdict.json` with the chair's parsed `overallVerdict`, `report.html`,
234
+ every review and judge output). That is what powers the repo's own **Council Review GitHub Action
235
+ v2** — on PRs labeled `council-review` it posts an adjudicated verdict as a check run plus a
236
+ sticky comment, uploads the run directory as an evidence artifact, and can optionally gate merges
237
+ via its `fail_on` input (default: report-only). Reference: [docs/council.md](./docs/council.md#amicus-council-run).
238
+
230
239
  **Free council (zero-cost).** Want the cross-examination without the model spend? `amicus setup` offers a **Free OpenRouter council** mode — readline wizard option 2, and the Electron **Models** step. It detects the free `:free` models live from the catalog, lets you multi-pick (Enter takes a vendor-diverse default), and saves them as `councils.free` — a first-class `councils` config primitive seeded under collision-safe `free-*` aliases. Your `config.default` is left untouched, and all you need is an `OPENROUTER_API_KEY`.
231
240
 
232
241
  Run it anywhere a council runs:
@@ -292,6 +301,7 @@ amicus update
292
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). |
293
302
  | `amicus key` | Manage API keys non-interactively: `amicus key <provider> <key>` saves after live validation; `--remove`; bare `amicus key` lists providers. |
294
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). |
295
305
  | `amicus abort` | Abort a running session (or `--all`). |
296
306
  | `amicus setup` | Configure default model, API keys, and aliases. |
297
307
  | `amicus update` | Update to the latest version. |
@@ -319,7 +329,7 @@ $ amicus status demo123 --json
319
329
  "taskId": "demo123",
320
330
  "status": "complete",
321
331
  "elapsed": "5m 0s",
322
- "version": "3.2.2",
332
+ "version": "4.0.0",
323
333
  "model": "google/gemini-2.5-flash",
324
334
  "phase": "terminal"
325
335
  }
@@ -353,7 +363,7 @@ Full details, the API-key/prefix table, and the migration notice are in **[docs/
353
363
 
354
364
  ## MCP integration
355
365
 
356
- The MCP server is auto-registered on install (Claude Code and Claude Desktop / Cowork). It exposes fourteen tools:
366
+ The MCP server is auto-registered on install (Claude Code and Claude Desktop / Cowork). It exposes fifteen tools:
357
367
 
358
368
  | Tool | What it does |
359
369
  |------|--------------|
@@ -371,6 +381,7 @@ The MCP server is auto-registered on install (Claude Code and Claude Desktop / C
371
381
  | `amicus_council_tally` | Aggregate a council wave's reviews into a scored tally. |
372
382
  | `amicus_council_stats` | Reviewer-reliability stats from past council runs. |
373
383
  | `amicus_verdict` | Build the final council verdict from a tally + decisions. |
384
+ | `amicus_council_run` | Run the full headless council engine (Stage-1 reviews → anonymized cross-review → tally → chair verdict); returns `{ runId, runDir }`, async. |
374
385
 
375
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.
376
387
 
@@ -400,7 +411,7 @@ With `--json`, Amicus emits stable, versioned run/wave documents on stdout — b
400
411
  }
401
412
  ```
402
413
 
403
- The wave-document shape (for `fanout`), field meanings, and the full exit-code table are in **[docs/usage.md § JSON Output](./docs/usage.md#json-output)**.
414
+ The wave-document shape (for `fanout`), field meanings, and the full exit-code table are in **[docs/usage.md § JSON Output](./docs/usage.md#json-output)**. Every `--json` document also has a published JSON Schema — see **[docs/schemas.md](./docs/schemas.md)** (shipped in the npm tarball under `schemas/`).
404
415
 
405
416
  ---
406
417
 
@@ -450,6 +461,7 @@ LOG_LEVEL=debug amicus start --model gemini --prompt "test" --no-ui
450
461
  |-----|-------------|
451
462
  | [docs/usage.md](./docs/usage.md) | The complete CLI & MCP reference — every flag, every subcommand, every example. |
452
463
  | [docs/council.md](./docs/council.md) | Council pipeline reference: `tally`/`verdict`/`report` schemas, provenance, and a worked example. |
464
+ | [docs/schemas.md](./docs/schemas.md) | Published JSON Schemas for every `--json` document (result + council families). |
453
465
  | [docs/configuration.md](./docs/configuration.md) | Full configuration and environment reference. |
454
466
  | [docs/architecture.md](./docs/architecture.md) | How the engine, Electron shell, and context sharing fit together. |
455
467
  | [docs/opencode-integration.md](./docs/opencode-integration.md) | How Amicus drives the OpenCode runtime. |
package/electron/main.js CHANGED
@@ -74,7 +74,10 @@ const WINDOW_POSITION = process.env.AMICUS_WINDOW_POSITION || 'right';
74
74
  // 15b.3: per-run fold nonce (#BL-7 residual). Set by the interactive launcher
75
75
  // (src/sidecar/interactive-process.js buildElectronEnv) from the SAME value
76
76
  // baked into the system prompt's fold instruction. undefined when a launcher
77
- // predates this env var — fold.js falls back to the legacy bare marker.
77
+ // predates this env var — fold.js then falls back to a freshly generated nonce
78
+ // (createFoldHandler: `state.nonce || generateFoldNonce()`), NOT the legacy bare
79
+ // marker. That's safe here because the GUI fold write is exit-code driven, not
80
+ // marker-detected, so an un-advertised fallback nonce can't be exploited.
78
81
  const FOLD_NONCE = process.env.AMICUS_FOLD_NONCE;
79
82
 
80
83
  const OPENCODE_URL = `http://localhost:${OPENCODE_PORT}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amicus",
3
- "version": "3.2.2",
3
+ "version": "4.0.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": [
@@ -37,6 +37,7 @@
37
37
  "files": [
38
38
  "bin/",
39
39
  "src/",
40
+ "schemas/",
40
41
  "electron/",
41
42
  "skills/",
42
43
  "commands/",
@@ -83,6 +84,7 @@
83
84
  "electron": "^43.1.1"
84
85
  },
85
86
  "devDependencies": {
87
+ "ajv": "^8.20.0",
86
88
  "chrome-remote-interface": "^0.33.3",
87
89
  "eslint": "^8.0.0",
88
90
  "jest": "^29.0.0",
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/abort.schema.json",
4
+ "title": "amicus abort result document",
5
+ "description": "`abort <taskId|--all> --json` result.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "ok", "scope", "aborted", "count"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "abort" },
11
+ "ok": { "type": "boolean" },
12
+ "scope": { "enum": ["session", "wave", "all", "council-run"] },
13
+ "taskId": { "type": ["string", "null"] },
14
+ "aborted": { "type": "array", "items": { "type": "string" } },
15
+ "count": { "type": "number" }
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/alias-audit.schema.json",
4
+ "title": "amicus alias-audit document",
5
+ "description": "`models --check --json` result.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "catalogAvailable", "staleCount", "stale"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "alias-audit" },
11
+ "catalogAvailable": { "type": "boolean" },
12
+ "staleCount": { "type": "number" },
13
+ "stale": { "type": "array", "items": { "type": "object" } },
14
+ "gatewayFindingsCount": { "type": "number" },
15
+ "gatewayFindings": { "type": "array", "items": { "type": "object" } }
16
+ }
17
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/council-run.schema.json",
4
+ "title": "amicus council-run manifest",
5
+ "description": "Headless council run manifest (run.json, spec 2026-07-19 §4). Authored ahead of the engine (v4.0 Plan B) — the run-state writer must satisfy this schema.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "runId", "status", "stages", "bench", "chair"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "council-run" },
11
+ "runId": { "type": "string" },
12
+ "status": { "type": "string" },
13
+ "stages": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "object",
17
+ "required": ["name", "status"],
18
+ "properties": {
19
+ "name": { "type": "string" },
20
+ "status": { "type": "string" },
21
+ "startedAt": { "type": ["string", "null"] },
22
+ "completedAt": { "type": ["string", "null"] },
23
+ "waveId": { "type": "string" },
24
+ "taskIds": { "type": "array", "items": { "type": "string" } }
25
+ }
26
+ }
27
+ },
28
+ "bench": { "type": "array", "items": { "type": "string" } },
29
+ "chair": { "type": "string" },
30
+ "critic": { "type": ["string", "null"] },
31
+ "lenses": { "type": ["array", "null"], "items": { "type": "string" } },
32
+ "labelMap": { "type": ["object", "null"], "additionalProperties": { "type": "string" } },
33
+ "options": { "type": "object" },
34
+ "usage": { "type": "object" },
35
+ "exitCode": { "type": ["number", "null"] }
36
+ }
37
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/council-stats.schema.json",
4
+ "title": "amicus council-stats document",
5
+ "description": "Ledger-derived reviewer reliability (`council stats --json`, amicus_council_stats). v2 wraps the pre-4.0 bare array in {schemaVersion, type, models} — THE one breaking council shape change.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "models"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "council-stats" },
11
+ "models": {
12
+ "type": "array",
13
+ "items": {
14
+ "type": "object",
15
+ "required": ["model", "runs", "lowN"],
16
+ "properties": {
17
+ "model": { "type": "string" },
18
+ "runs": { "type": "number" },
19
+ "lowN": { "type": "boolean" },
20
+ "avgStreetCredPeersOnly": { "type": ["number", "null"] },
21
+ "lifetimeConfirmRate": { "type": ["number", "null"] },
22
+ "lifetimeFactErrorRate": { "type": ["number", "null"] },
23
+ "conformance": { "type": "object" }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/council-tally.schema.json",
4
+ "title": "amicus council-tally document",
5
+ "description": "Deterministic council tally (`council tally --json`, amicus_council_tally). Council family v2.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "meta", "judged", "streetCred", "findings", "runStats", "tierCounts"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "council-tally" },
11
+ "meta": {
12
+ "type": "object",
13
+ "required": ["runId", "models"],
14
+ "properties": {
15
+ "runId": { "type": "string" },
16
+ "runType": { "type": "string" },
17
+ "date": { "type": "string" },
18
+ "models": { "type": "array", "items": { "type": "string" } },
19
+ "chair": { "type": ["string", "null"] },
20
+ "claudeInCouncil": { "type": "boolean" }
21
+ }
22
+ },
23
+ "judged": { "type": "boolean" },
24
+ "streetCred": {
25
+ "type": "array",
26
+ "items": {
27
+ "type": "object",
28
+ "required": ["model"],
29
+ "properties": {
30
+ "model": { "type": "string" },
31
+ "withSelf": { "type": ["number", "null"] },
32
+ "peersOnly": { "type": ["number", "null"] },
33
+ "perJudgeRank": { "type": "object" }
34
+ }
35
+ }
36
+ },
37
+ "findings": {
38
+ "type": "array",
39
+ "items": {
40
+ "type": "object",
41
+ "required": ["id", "tier", "basis", "confidence"],
42
+ "properties": {
43
+ "id": { "type": "string" },
44
+ "raiser": { "type": ["string", "null"] },
45
+ "severity": { "type": ["string", "null"] },
46
+ "tier": { "enum": ["Confirmed", "Contested", "Singleton", "Disputed"] },
47
+ "basis": {
48
+ "type": "object",
49
+ "required": ["a", "d", "n"],
50
+ "properties": { "a": { "type": "number" }, "d": { "type": "number" }, "n": { "type": "number" } }
51
+ },
52
+ "confidence": { "enum": ["thin", "solid"] },
53
+ "tierOverride": { "type": ["object", "null"] },
54
+ "adjudications": { "type": "array", "items": { "type": "object" } }
55
+ }
56
+ }
57
+ },
58
+ "runStats": { "type": "array", "items": { "type": "object" } },
59
+ "tierCounts": {
60
+ "type": "object",
61
+ "required": ["Confirmed", "Contested", "Singleton", "Disputed"],
62
+ "properties": {
63
+ "Confirmed": { "type": "number" },
64
+ "Contested": { "type": "number" },
65
+ "Singleton": { "type": "number" },
66
+ "Disputed": { "type": "number" }
67
+ }
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/council-validate.schema.json",
4
+ "title": "amicus council-validate document",
5
+ "description": "Stage-1 findings validation (`council validate --json`). Tri-state exit: 0 ok, 2 parsed-but-invalid, 1 BAD_ARGS error doc.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "ok", "findings", "errors"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "council-validate" },
11
+ "ok": { "type": "boolean" },
12
+ "findings": { "type": "array", "items": { "type": "object" } },
13
+ "errors": {
14
+ "type": "array",
15
+ "items": {
16
+ "type": "object",
17
+ "required": ["code", "detail"],
18
+ "properties": { "code": { "type": "string" }, "detail": { "type": "string" } }
19
+ }
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/council-verdict.schema.json",
4
+ "title": "amicus council-verdict document",
5
+ "description": "Verdict record (`council verdict --json`, amicus_verdict, verdict.json). overallVerdict is the chair's parsed VERDICT line — null in every Stage-4 manual path, populated by the headless engine.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "runId", "council", "overallVerdict", "findings", "streetCred", "runStats", "tierCounts"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "council-verdict" },
11
+ "runId": { "type": "string" },
12
+ "runType": { "type": ["string", "null"] },
13
+ "date": { "type": ["string", "null"] },
14
+ "chair": { "type": ["string", "null"] },
15
+ "council": { "type": "array", "items": { "type": "string" } },
16
+ "claudeInCouncil": { "type": "boolean" },
17
+ "overallVerdict": {
18
+ "oneOf": [
19
+ { "enum": ["Ship it", "Fix these first", "Fundamental rethink"] },
20
+ { "type": "null" }
21
+ ]
22
+ },
23
+ "findings": {
24
+ "type": "array",
25
+ "items": {
26
+ "type": "object",
27
+ "required": ["id", "tier", "decision", "applied"],
28
+ "properties": {
29
+ "id": { "type": "string" },
30
+ "raiser": { "type": ["string", "null"] },
31
+ "severity": { "type": ["string", "null"] },
32
+ "tier": { "enum": ["Confirmed", "Contested", "Singleton", "Disputed"] },
33
+ "basis": { "type": "object" },
34
+ "confidence": { "enum": ["thin", "solid"] },
35
+ "tierOverride": { "type": ["object", "null"] },
36
+ "duplicateOf": { "type": ["string", "null"] },
37
+ "adjudications": { "type": "array" },
38
+ "decision": { "type": ["string", "null"] },
39
+ "applied": { "type": "boolean" }
40
+ }
41
+ }
42
+ },
43
+ "streetCred": { "type": "array", "items": { "type": "object" } },
44
+ "runStats": { "type": "array", "items": { "type": "object" } },
45
+ "tierCounts": { "type": "object" }
46
+ }
47
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/doctor.schema.json",
4
+ "title": "amicus doctor document",
5
+ "description": "`doctor --json` health-check result.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "ok", "version", "timestamp", "checks"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "doctor" },
11
+ "ok": { "type": "boolean" },
12
+ "version": { "type": "string" },
13
+ "timestamp": { "type": "string" },
14
+ "checks": {
15
+ "type": "array",
16
+ "items": {
17
+ "type": "object",
18
+ "required": ["id", "name", "status"],
19
+ "properties": {
20
+ "id": { "type": "string" },
21
+ "name": { "type": "string" },
22
+ "status": { "type": "string" },
23
+ "message": { "type": ["string", "null"] },
24
+ "hint": { "type": ["string", "null"] }
25
+ }
26
+ }
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/error.schema.json",
4
+ "title": "amicus error document",
5
+ "description": "Structured failure envelope: every pre-flight/validation/route failure under --json (stdout) and every MCP error tool-text.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "ok", "error"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "error" },
11
+ "ok": { "const": false },
12
+ "error": {
13
+ "type": "object",
14
+ "required": ["code", "message"],
15
+ "properties": {
16
+ "code": { "enum": ["BAD_ARGS", "MISSING_PROMPT", "BAD_MODEL", "MISSING_KEY", "BAD_SESSION", "BUDGET_EXCEEDED", "INTERNAL"] },
17
+ "message": { "type": "string" },
18
+ "hint": { "type": ["string", "null"] },
19
+ "command": { "type": ["string", "null"] }
20
+ }
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/model-catalog.schema.json",
4
+ "title": "amicus model-catalog document",
5
+ "description": "`models [--search|--refresh] --json` result.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "count", "models"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "model-catalog" },
11
+ "fetchedAt": { "type": ["number", "null"] },
12
+ "refreshed": { "type": "boolean" },
13
+ "search": { "type": ["string", "null"] },
14
+ "count": { "type": "number" },
15
+ "models": { "type": "array", "items": { "type": "object" } },
16
+ "lastRefreshAttempt": { "type": ["number", "null"] },
17
+ "lastRefreshError": { "type": ["string", "null"] }
18
+ }
19
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/run.schema.json",
4
+ "title": "amicus run result document",
5
+ "description": "Single-session result (`start|read|resume|continue --json`; every wave leg). Fields are only ADDED within a schemaVersion.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "taskId", "status"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "run" },
11
+ "taskId": { "type": "string" },
12
+ "waveId": { "type": ["string", "null"] },
13
+ "model": { "type": ["string", "null"] },
14
+ "modelInput": { "type": ["string", "null"] },
15
+ "agent": { "type": ["string", "null"] },
16
+ "status": { "type": "string" },
17
+ "summary": { "type": ["string", "null"] },
18
+ "error": { "type": ["string", "null"] },
19
+ "createdAt": { "type": ["string", "null"] },
20
+ "completedAt": { "type": ["string", "null"] },
21
+ "durationMs": { "type": ["number", "null"] },
22
+ "sessionDir": { "type": ["string", "null"] },
23
+ "opencodeSessionId": { "type": ["string", "null"] },
24
+ "usage": { "type": ["object", "null"] }
25
+ }
26
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/spend.schema.json",
4
+ "title": "amicus spend document",
5
+ "description": "`spend --json` aggregation.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "total", "byModel"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "spend" },
11
+ "windowDays": { "type": ["number", "null"] },
12
+ "total": { "type": "object" },
13
+ "byModel": { "type": "array", "items": { "type": "object" } },
14
+ "credit": { "type": ["object", "null"] }
15
+ }
16
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/wave.schema.json",
4
+ "title": "amicus wave result document",
5
+ "description": "Fan-out wave result (`fanout --json`, wave.json). counts named buckets may not sum to total (see result-schema.js COUNTS REMAINDER RULE).",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "type", "waveId", "status", "counts", "legs"],
8
+ "properties": {
9
+ "schemaVersion": { "const": 2 },
10
+ "type": { "const": "wave" },
11
+ "waveId": { "type": "string" },
12
+ "status": { "type": "string" },
13
+ "error": { "type": ["string", "null"] },
14
+ "counts": {
15
+ "type": "object",
16
+ "required": ["total", "complete", "error", "timeout", "aborted"],
17
+ "properties": {
18
+ "total": { "type": "number" },
19
+ "complete": { "type": "number" },
20
+ "error": { "type": "number" },
21
+ "timeout": { "type": "number" },
22
+ "aborted": { "type": "number" }
23
+ }
24
+ },
25
+ "legs": { "type": "array", "items": { "type": "object" } },
26
+ "prompt": { "type": ["object", "null"] },
27
+ "createdAt": { "type": ["string", "null"] },
28
+ "completedAt": { "type": ["string", "null"] },
29
+ "durationMs": { "type": ["number", "null"] },
30
+ "usage": { "type": "object" },
31
+ "notices": { "type": "array", "items": { "type": "string" } }
32
+ }
33
+ }
@@ -178,13 +178,15 @@ Append to the chair packet (`_tmp-chair-packet.md`) when the element is toggled
178
178
  > 1. **HARD QUESTIONS** — three to five questions the artifact's author has probably not
179
179
  > asked themselves, chosen so that an unanswerable question reveals a structural gap in
180
180
  > the artifact (not gotchas — questions whose answers should exist).
181
- > 2. A final line, alone on the last line, in exactly this format:
181
+ > 2. A final line, alone on the last line, containing ONLY the phrase — no rationale, no
182
+ > dash, no trailing text of any kind — exactly one of:
182
183
  >
183
184
  > `VERDICT: Ship it` | `VERDICT: Fix these first` | `VERDICT: Fundamental rethink`
184
185
  >
185
186
  > Pick one. "Ship it" = solid, nothing blocking. "Fix these first" = specific gaps must
186
- > be resolved before the artifact is useful name them. "Fundamental rethink" =
187
- > structural problems that cannot be patched say what is wrong at the foundation.
187
+ > be resolved first. "Fundamental rethink" = structural problems that cannot be patched.
188
+ > Name the gaps or the structural problems in the synthesis ABOVE, not on the VERDICT
189
+ > line itself — that line carries the phrase and nothing else.
188
190
 
189
191
  **Orchestration note:** surface the chair's `VERDICT:` line verbatim at the top of
190
192
  `report.md` and in the inline chat presentation of the results.