amicus 1.9.1 → 2.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 (67) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +138 -0
  3. package/README.md +40 -170
  4. package/bin/amicus.js +14 -20
  5. package/commands/council.md +3 -1
  6. package/electron/fold.js +10 -1
  7. package/electron/ipc-setup.js +10 -15
  8. package/electron/main.js +21 -16
  9. package/electron/preload-setup.js +0 -1
  10. package/electron/setup-ui-council.js +64 -10
  11. package/electron/setup-ui-styles.js +34 -3
  12. package/electron/setup-ui.js +44 -12
  13. package/package.json +2 -5
  14. package/skills/second-opinion/MODEL-NOTES.md +2 -2
  15. package/skills/second-opinion/SKILL.md +24 -23
  16. package/skills/sidecar/SKILL.md +3 -3
  17. package/src/cli-handlers-council.js +101 -1
  18. package/src/cli-handlers-doctor.js +7 -0
  19. package/src/cli-handlers-run.js +4 -4
  20. package/src/cli-handlers-spend.js +198 -0
  21. package/src/cli.js +35 -0
  22. package/src/council/presets-cli.js +141 -0
  23. package/src/headless.js +146 -38
  24. package/src/index.js +1 -9
  25. package/src/mcp-server.js +132 -108
  26. package/src/mcp-tools.js +27 -3
  27. package/src/mcp-wait.js +8 -5
  28. package/src/opencode-client.js +33 -10
  29. package/src/prompt-builder.js +32 -11
  30. package/src/session-manager.js +7 -14
  31. package/src/sidecar/continue.js +12 -5
  32. package/src/sidecar/conversation-mirror.js +22 -1
  33. package/src/sidecar/crash-handler.js +2 -1
  34. package/src/sidecar/fanout-leg.js +12 -3
  35. package/src/sidecar/fanout.js +27 -10
  36. package/src/sidecar/interactive-process.js +6 -17
  37. package/src/sidecar/interactive.js +5 -6
  38. package/src/sidecar/models.js +33 -4
  39. package/src/sidecar/progress.js +2 -1
  40. package/src/sidecar/read.js +4 -6
  41. package/src/sidecar/resume.js +19 -4
  42. package/src/sidecar/session-finalize.js +2 -1
  43. package/src/sidecar/session-utils.js +13 -35
  44. package/src/sidecar/setup-window.js +2 -3
  45. package/src/sidecar/start.js +22 -7
  46. package/src/utils/abort-coordinator.js +57 -7
  47. package/src/utils/api-key-store.js +2 -13
  48. package/src/utils/config.js +30 -43
  49. package/src/utils/council-presets.js +87 -0
  50. package/src/utils/env-loader.js +1 -2
  51. package/src/utils/fold-marker.js +79 -0
  52. package/src/utils/idle-watchdog.js +9 -12
  53. package/src/utils/lifecycle.js +1 -1
  54. package/src/utils/mcp-discovery.js +29 -5
  55. package/src/utils/mcp-self-identity.js +12 -5
  56. package/src/utils/model-catalog.js +54 -6
  57. package/src/utils/read-slice.js +73 -0
  58. package/src/utils/remediation-hints.js +9 -0
  59. package/src/utils/result-schema.js +8 -2
  60. package/src/utils/session-abort.js +1 -1
  61. package/src/utils/session-index-tmp-sweep.js +80 -0
  62. package/src/utils/session-index.js +4 -5
  63. package/src/utils/session-path.js +6 -10
  64. package/src/utils/shared-server.js +7 -5
  65. package/src/utils/spend-ledger.js +80 -0
  66. package/src/utils/updater.js +2 -3
  67. package/src/utils/env-compat.js +0 -38
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "amicus",
3
- "version": "1.9.1",
3
+ "version": "2.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,144 @@ All notable changes to Amicus are documented here. Format follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [2.0.0] - 2026-07-03
9
+
10
+ Amicus's first major release: the **`sidecar*` shim removal** (#19). v1.x carried a full
11
+ compatibility surface so installs and integrations from before the Amicus rebrand kept working —
12
+ legacy env vars, CLI bin names, config/session directory fallbacks, MCP tool aliases, and deprecated
13
+ public-API exports. v2.0.0 removes all of it in one pass; see **Migration** below for the exact old
14
+ form → new form for every removed shim, including the one that needs a manual one-time step. Most
15
+ installs need zero action (config/session data auto-migrated forward across v1.x; plugin-channel
16
+ installs float to the latest version automatically). Beyond the shim removal, this release rolls up
17
+ five phases of engine and docs work that shipped since 1.9.1: a fully deterministic council CLI
18
+ transport (`validate`/`verdict`/presets/spend ledger), `amicus_read` paging for large content, a
19
+ per-tool-call stall detector, per-run-nonced fold markers, atomic metadata writes throughout, POSIX
20
+ server teardown hardening, and a full documentation overhaul (`docs/council.md`, restructured
21
+ README, "where things live" config-dir reference).
22
+
23
+ ### Migration (from any sidecar*-era setup)
24
+
25
+ Full removal record and rationale: [docs/SHIMS.md](docs/SHIMS.md). Per-shim remedy:
26
+
27
+ | Old form (sidecar*-era) | New form / remedy |
28
+ | --- | --- |
29
+ | `SIDECAR_*` env vars (`SIDECAR_ENV_DIR`, `SIDECAR_IDLE_TIMEOUT*`, `SIDECAR_DEBUG_PORT`, `SIDECAR_MOCK_UPDATE`) | Rename to the `AMICUS_*` equivalent (`AMICUS_ENV_DIR`, `AMICUS_IDLE_TIMEOUT*`, `AMICUS_DEBUG_PORT`, `AMICUS_MOCK_UPDATE`). Unrenamed vars are now silently ignored — no warning, no fallback. |
30
+ | `SIDECAR_MAX_SESSIONS` | Rename to `AMICUS_MAX_SESSIONS` — this was the last legacy-prefixed env var read anywhere in the codebase. |
31
+ | `sidecar` / `claude-sidecar` CLI commands | Use `amicus` (or the `am` short alias). An `EEXIST` on `npm install -g amicus` naming an old `claude-sidecar`/`sidecar` file means a *stale* global install of the old upstream package, not this shim — see [docs/troubleshooting.md](docs/troubleshooting.md#install-fails-with-eexist--claude-sidecar). |
32
+ | `~/.config/sidecar` config dir | No action for most users — every v1.x launch auto-copied `~/.config/sidecar/` into `~/.config/amicus/` once, non-destructively. Only if you skipped every v1.x release and jump straight from pre-rebrand to v2.0.0: copy `~/.config/sidecar/` to `~/.config/amicus/` by hand — `getConfigDir()` no longer reads the old location at all. |
33
+ | `.claude/sidecar_sessions/` | Not auto-migrated (per-project). Rename to `.claude/amicus_sessions/` in any project whose history you want `amicus list`/`amicus read` to see again. |
34
+ | `[SIDECAR_CONFIG_UPDATE]` stderr marker / `sidecar-config-hash` HTML-comment | The `sidecar` skill now instructs the canonical forms only: `[AMICUS_CONFIG_UPDATE]` / `<!-- amicus-config-hash: ... -->`. A stale `<!-- sidecar-config-hash: ... -->` comment in an old CLAUDE.md is simply no longer recognized; the next `amicus setup` alias change writes a fresh one, and the stale comment can be deleted by hand. |
35
+ | `sidecar_*` MCP tool names / `AMICUS_LEGACY_ALIASES=1` | The tool surface is `amicus_*` only, unconditionally — `AMICUS_LEGACY_ALIASES=1` is now a no-op (regression-pinned in `tests/mcp-server-legacy-aliases.test.js`). Update any MCP client config or tooling that still calls a `sidecar_*` tool name. |
36
+ | `startSidecar`/`listSidecars`/`resumeSidecar`/`continueSidecar`/`readSidecar` (package-root exports) | These were deprecated aliases present on npm through v1.9.1. Only `startAmicus`/`listAmicus`/`resumeAmicus`/`continueAmicus`/`readAmicus` remain exported from `amicus`'s package root — rename any import. |
37
+
38
+ **Kept, not removed** (not part of this migration): the `[SIDECAR_FOLD]`/`[SIDECAR_FOLD:<nonce>]`
39
+ wire-format token (deliberate transport continuity, unrelated to the compat shims), the `sidecar`
40
+ chat-skill's directory name, and the one-shot legacy-`'sidecar'`-MCP-entry cleanup in
41
+ `src/utils/legacy-mcp-migration.js` (re-scoped as a permanent healing tool for stale pre-1.8.0
42
+ dual-registrations — it only removes a `'sidecar'` MCP entry verified identical-in-effect to the
43
+ `'amicus'` one; a customized entry is left alone). The `mcp-self-identity` recursive-spawn guard also
44
+ continues to recognize the old `sidecar`/`claude-sidecar` bin/server names — a defense against a
45
+ stale PATH or MCP config causing amicus to spawn itself, not a restoration of removed behavior.
46
+
47
+ **Plugin-channel installs float automatically.** If you installed Amicus via the Claude Code plugin
48
+ channel, `.claude-plugin/plugin.json` runs `npx -y amicus@latest mcp` — you adopt v2.0.0 on your
49
+ next MCP server start with no upgrade action required. The only thing that can still break for you:
50
+ if your client config or tooling relies on `sidecar_*` tool names or sets
51
+ `AMICUS_LEGACY_ALIASES=1` expecting it to do something, update it — that opt-in is now a no-op and
52
+ the legacy tool names are gone.
53
+
54
+ ### Added
55
+ - **`docs/council.md` — the council pipeline documented end-to-end**: the stage flow, the tally-input and
56
+ tally-record schemas field-by-field (test-locked against the real validators), verdict.json provenance,
57
+ presets, and a complete worked example whose every command and output was executed against the binary.
58
+ - **"Where things live"** (docs/configuration.md): the full config-dir tree (config.json shape, catalog
59
+ cache + refresh-outcome fields, both ledgers, tmp files and the doctor sweep), per-client session
60
+ storage, log reality (stderr-only — `LOG_LEVEL` never writes a file), and honest uninstall instructions
61
+ covering what `npm uninstall -g` does NOT clean.
62
+ - README now leads with the **two install channels** (npm global vs Claude Code plugin, with the
63
+ `npx -y amicus@latest` translation note) and surfaces **`/amicus:council`** in the quick start and
64
+ council sections.
65
+ - **`amicus council validate <file>` and `amicus council verdict <tally.json>`** — thin CLI wrappers over the
66
+ existing findings-validation and verdict-builder internals, making the second-opinion skill's council
67
+ transport fully deterministic. `validate` exits 0 (ok) / 2 (validation failed) / 1 (bad args); `verdict`
68
+ writes atomically to `-o` (default `./verdict.json`), `--decisions` optional. The skill's Stage-1 and
69
+ Stage-5 instructions now invoke these commands, and the Stage-2 recipe persists the tally record to
70
+ `<run-folder>/tally.json` (previously it existed only on stdout — the verdict step had nothing to read).
71
+ - **Council presets: `amicus council save/list/show <name>` + built-in `free`/`budget`/`frontier` benches.**
72
+ Built-ins resolve only when the name isn't in your config (your saved councils shadow them; `list` marks
73
+ shadowing). `free` resolves dynamically against the catalog (pinned offline fallback); `budget` and
74
+ `frontier` are alias-based (cheapest / most premium distinct-vendor picks) so alias drift tooling covers
75
+ them. `show` resolves against the cached catalog, including the dynamic free pick.
76
+ - **Per-run cost ledger + `amicus spend`.** Every completed run (headless, interactive, fanout legs)
77
+ appends a best-effort JSONL row (`spend-ledger.jsonl` in the config dir); `amicus spend` rolls up total
78
+ and per-model cost/tokens/source-mix with `--since <N>d` windowing and `--json`, plus an OpenRouter
79
+ remaining-credit footer when a key is configured. Ledger appends can never fail a run.
80
+ - **`amicus_read` paging and size caps.** Responses are capped at ~50KB (default: the TAIL of the content,
81
+ with a truncation notice reporting true byte counts at the start of the body); new optional `offset`,
82
+ `limit`, and `tail` params page through large content. Under-cap reads are byte-identical to before;
83
+ slicing happens before the untrusted-output fence is applied; `metadata` mode is param-exempt but
84
+ defensively capped.
85
+ - **Per-tool-call stall detector in headless runs.** A wedged tool call (pending `tool_use`, no result, no
86
+ other progress for `AMICUS_TOOL_CALL_STALL_MS`, default 3 min) now fails fast with a distinct
87
+ `Tool call stalled: …` reason instead of burning the full run timeout. Fanout legs inherit automatically.
88
+ - **`amicus doctor --fix` sweeps orphaned sessions-index tmp files** (atomic-write artifacts from killed
89
+ processes; only files older than 60s are removed).
90
+
91
+ ### Changed
92
+ - **README restructured for audience separation**: discovery + quick start + compact command table with
93
+ pointers; `docs/usage.md` is now the complete CLI reference (the ~30% duplicated content has one
94
+ canonical home each — nothing was dropped); deep dives live under `docs/`.
95
+ - The second-opinion skill's Stage-2 briefing prose reads cleanly again (hardening sentence moved before
96
+ the sentence it interrupted), and `report.md`'s contract is stated once, coherently: `report.html` is
97
+ the deterministic renderer default; `report.md` is the chair-synthesis document that embeds the
98
+ rendered Markdown as one section.
99
+ - **The fold completion marker is now per-run nonced: `[SIDECAR_FOLD:<nonce>]`.** Model output that
100
+ genuinely ends with a bare `[SIDECAR_FOLD]` can no longer force premature completion — the detector
101
+ requires the run's own nonce (BL-7's final hardening layer). The nonce is crypto-random, threaded through
102
+ every mode (headless, fanout, MCP shared-server, interactive GUI), and instructed to the model in the
103
+ prompt; `amicus resume` re-derives it from the transcript.
104
+ - **All session/wave metadata writes are atomic** (`writeFileAtomic` tmp+rename), retiring the torn-read
105
+ race class that pollers previously tolerated via missed-tick workarounds.
106
+
107
+ ### Fixed
108
+ - `amicus council --help` now lists `save`/`list`/`show` (the Phase-16 usage-string omission caught by
109
+ a later binary-verification pass).
110
+ - **Setup wizard Step 3 (alias editor) now consumes the same TTL-cached catalog as Step 2** (#12) — one
111
+ catalog load for the whole wizard instead of a separate uncached network fetch per run; the redundant
112
+ `fetch-models` IPC channel is removed.
113
+ - **Stale catalog data is now labeled** (#13): a failed refresh records the attempt and reason in the cache
114
+ doc (never touching the good data), `amicus models` shows a stale memo when refreshing keeps failing,
115
+ `amicus models refresh` reports failure honestly instead of "Refreshed catalog: 0 models" (and its
116
+ `--json` reports the real stale `fetchedAt` instead of `null`), and the wizard shows a stale hint.
117
+ - **The free-council picker is readable** (#27): models grouped by provider with friendly names (raw id as
118
+ the mono secondary line), a roomier scroll area, and a provider count — selection values remain raw model
119
+ ids throughout.
120
+ - **Orphaned `opencode serve` processes on macOS/Linux.** Server teardown now SIGTERMs the Go binary
121
+ directly and escalates to SIGKILL after a bounded grace window on a ref'd poll (the old unref'd 2s timer
122
+ silently died with fast-exiting parents). Windows semantics unchanged.
123
+ - **Aborting a wave immediately after starting it can no longer flip its status back to `running`** — the
124
+ wave metadata merge now honors abort-wins precedence (same rule the per-leg writer already had).
125
+ - **`kill(pid, 0)` throwing `EPERM` now classifies a process as ALIVE** (signal denied ≠ dead) in
126
+ `isProcessAlive`/`checkSessionLiveness` and both MCP crash-detection probes. EPERM no longer marks
127
+ healthy sessions crashed.
128
+ - **A committed successful terminal status can no longer be clobbered to `error`** by a cleanup-step
129
+ failure in the MCP shared-server finalize chain (the Phase-5 review's residual gap).
130
+ - **`discoverCoworkMcps` now checks `%APPDATA%\Claude` on Windows** instead of the XDG path — Claude
131
+ Desktop discovery and doctor's Cowork signal were always wrong on win32.
132
+
133
+ ### Removed
134
+ - **Every pre-rebrand `sidecar*` compatibility shim** — see **Migration** above for the full old-form →
135
+ new-form mapping. Also removed: **`sidecar_*` MCP tool aliases + the `AMICUS_LEGACY_ALIASES=1` opt-in**
136
+ (`src/mcp-server.js`) and the **public API `*Sidecar` aliases** (`src/index.js` `module.exports`) —
137
+ both covered in Migration.
138
+
139
+ ### Documentation
140
+ - Full sweep of every doc describing the shims as live (README, docs/usage.md, docs/configuration.md,
141
+ docs/testing.md, docs/troubleshooting.md, docs/opencode-integration.md, docs/architecture.md,
142
+ skills/sidecar/SKILL.md, skills/second-opinion/MODEL-NOTES.md) rewritten to v2.0.0 reality.
143
+ `docs/SHIMS.md` re-scoped from a live shim inventory into the removal record the Migration section
144
+ above is built from.
145
+
8
146
  ## [1.9.1] - 2026-07-03
9
147
 
10
148
  ### Fixed
package/README.md CHANGED
@@ -57,6 +57,13 @@ Claude is the orchestrator. The council and chat skills run *on top of* the engi
57
57
 
58
58
  ## Quick start
59
59
 
60
+ > **Two install channels — read this first.** Amicus ships two ways, and CLI commands look different in each:
61
+ >
62
+ > - **npm global** (`npm install -g amicus` or the install script) puts `amicus`/`am` on your `PATH`. Every `amicus <command>` example in this README works as written.
63
+ > - **Claude Code plugin** (`/plugin install amicus@bourbondog-amicus`) does **not** put a CLI on your `PATH`. CLI calls go through `npx -y amicus@latest <command>` instead — e.g. `amicus doctor` becomes `npx -y amicus@latest doctor`. In exchange, the plugin channel gets two things npm does **not**: the slash commands `/amicus:council` and `/amicus:sidecar`. **These are plugin-channel-ONLY — npm users don't get them** and drive the same skills by saying "council review this" / talking to Claude instead.
64
+ >
65
+ > **Convention used throughout this README:** plugin-channel users: prefix CLI examples with `npx -y amicus@latest` (skip the bare `amicus`/`am`). Individual code blocks are not duplicated per channel — this note is the one translation you need.
66
+
60
67
  **Install** — pick whichever fits. Every path delivers the MCP server and both skills; the `amicus`/`am` CLI lands on your PATH with the **npm and install-script paths** (the plugin path runs the CLI on demand via `npx -y amicus@latest <command>`):
61
68
 
62
69
  **As a Claude Code plugin** — the most native path if you use Claude Code:
@@ -67,7 +74,7 @@ Claude is the orchestrator. The council and chat skills run *on top of* the engi
67
74
  /reload-plugins
68
75
  ```
69
76
 
70
- Claude Code registers the MCP server and both skills for you — nothing to configure. (The plugin does not put `amicus` on your PATH — CLI calls go through `npx -y amicus@latest <command>`; the standalone Electron window is npm-only; and the first council/sidecar call downloads the OpenCode engine.)
77
+ Claude Code registers the MCP server and both skills for you — nothing to configure. It also gets you two slash commands the npm/install-script paths don't: **`/amicus:council`** (run a full council review) and **`/amicus:sidecar`** (fork a conversation to another model). (The plugin does not put `amicus` on your PATH — CLI calls go through `npx -y amicus@latest <command>`; the standalone Electron window is npm-only; and the first council/sidecar call downloads the OpenCode engine.)
71
78
 
72
79
  **With the install script** — macOS, Linux, or Windows (needs [Node.js](https://nodejs.org) ≥ 18):
73
80
 
@@ -115,6 +122,8 @@ This opens a graphical wizard:
115
122
 
116
123
  > *council review this*
117
124
 
125
+ Plugin-channel users can also type **`/amicus:council`** directly instead of phrasing it as a request — same skill, explicit invocation.
126
+
118
127
  Claude prepares the material, recommends a bench of models, discloses the run shape and cost, and orchestrates the rest. You make the accept/deny calls at the end. (The `second-opinion` skill is what teaches Claude to recognize this — if nothing happens, run `amicus doctor` (or `npx -y amicus@latest doctor`). npm/install-script installs place the skill at `~/.claude/skills/second-opinion/`; plugin installs keep it inside the plugin itself — check `/plugin` in Claude Code to confirm amicus is enabled.)
119
128
 
120
129
  **Your first sidecar.** The sidecar is the lower-level path — you can invoke it by phrase through Claude too, but the CLI gives you the flags directly:
@@ -178,12 +187,14 @@ Everything you need before your first run, and what's optional.
178
187
 
179
188
  ## The Council
180
189
 
190
+ > Trigger it by saying *"council review this"* to Claude, or, on the plugin channel, run **`/amicus:council`** directly.
191
+
181
192
  **Why multi-model.** Any single model — including the one running your session — has consistent blind spots. Route the *same* material through models from *different* families and the disagreements surface: missed issues, overstated confidence, claims one model alone would have waved through. The council is the structured version of that idea.
182
193
 
183
194
  **The flow, in five beats:**
184
195
 
185
196
  1. **Independent reviews.** Each council model reviews the artifact on its own (one parallel wave), producing a structured findings list — claim, severity (`blocker | major | minor | nit`), location, rationale.
186
- 2. **Anonymized cross-review.** Claude relabels every review (Review A, B, C…) and sends the identical bundle to every model. Each model ranks the reviews and adjudicates every finding (`agree | dispute | neutral`) — *unknowingly judging its own*, so self-bias washes out. This yields a **street-cred** ranking and sorts findings into **Confirmed / Contested / Singleton** tiers.
197
+ 2. **Anonymized cross-review.** Claude relabels every review (Review A, B, C…) and sends the identical bundle to every model. Each model ranks the reviews and adjudicates every finding (`agree | dispute | neutral`) — *unknowingly judging its own*, so self-bias washes out. This yields a **street-cred** ranking and sorts findings into **Disputed / Confirmed / Contested / Singleton** tiers.
187
198
  3. **Chair verdict.** A designated **non-Claude** chair receives the de-anonymized picture — all reviews, rankings, and adjudications — and synthesizes an independent verdict. Claude presents it verbatim; Claude does not synthesize.
188
199
  4. **Tiered decisions.** Confirmed findings get one bulk accept/deny; Contested and Singleton findings are decided one at a time (accept / deny / modify).
189
200
  5. **Outputs applied.** Accepted findings are written into a reviewed copy of the source; the full run is captured in the run folder.
@@ -194,6 +205,8 @@ Everything you need before your first run, and what's optional.
194
205
  - `crossreview-matrix.md` — the adjudication grid plus the de-anonymized street-cred table.
195
206
  - `verdict.md` — the chair's synthesis.
196
207
  - `report.md` — synthesis + the full decision log + a per-call run-stats table.
208
+ - `report.html` — the deterministic renderer output (adjudication matrix, street-cred table,
209
+ findings-by-tier, cost — no chair prose). This is the default artifact handed to the user.
197
210
  - For an **editable source**, the accepted edits land in `<stem>-reviewed.<ext>` next to the original.
198
211
 
199
212
  **Claude in the council** (default off): you can add Claude's own fresh review to the bundle so the bench ranks and adjudicates it — Claude is *judged* but never votes or chairs, so the verdict stays independent.
@@ -204,7 +217,7 @@ Everything you need before your first run, and what's optional.
204
217
 
205
218
  Then the council waits for your confirmation.
206
219
 
207
- 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)**.
220
+ 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)**.
208
221
 
209
222
  **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`.
210
223
 
@@ -216,6 +229,8 @@ amicus fanout --council free --prompt "Review this design"
216
229
 
217
230
  The `amicus_fanout` MCP tool takes the same `council` parameter, and the `second-opinion` skill reads `councils.free` automatically. A member that gets delisted is dropped with a warning — the council still runs as long as ≥2 survive. Free models are **rate-limited and quality-variable**, and some return 404 unless you enable data-sharing at [openrouter.ai/settings/privacy](https://openrouter.ai/settings/privacy).
218
231
 
232
+ **Council presets.** Save your own named member lists with `amicus council save <name> --models a,b,c` (≥2 resolvable aliases or `provider/model` IDs), then run them with `--council <name>` anywhere a council runs. `amicus council list` shows saved presets plus three built-in benches that work with no setup at all — `free` (the same zero-cost dynamic pick described above, used when you haven't seeded `councils.free`), `budget` (cheap workhorses, one per vendor family), and `frontier` (premium flagships, one per vendor family). `amicus council show <name>` resolves any of them (saved or built-in) and reports which members are currently usable. A saved council always shadows a built-in of the same name — exactly how the wizard's `councils.free` seeding already worked.
233
+
219
234
  ---
220
235
 
221
236
  ## The parallel window
@@ -266,8 +281,9 @@ amicus update
266
281
  | `amicus status <id>` | One-shot status for a session or fan-out wave (human or `--json`; `--wave <id>` alternative spelling). |
267
282
  | `amicus models` | List, search, refresh the catalog, or audit aliases. |
268
283
  | `amicus doctor` | Diagnose your setup — keys, default model, catalog, aliases, OpenCode binary, Electron, skills, MCP registration, OpenRouter credit (`--json`; `--fix` self-heals what it can). |
284
+ | `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). |
269
285
  | `amicus key` | Manage API keys non-interactively: `amicus key <provider> <key>` saves after live validation; `--remove`; bare `amicus key` lists providers. |
270
- | `amicus council` | Council math: `tally <input.json>` (deterministic tiers + ledger append), `stats` (reviewer reliability), `report <verdict.json> [--md\|--html]`. |
286
+ | `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. |
271
287
  | `amicus abort` | Abort a running session (or `--all`). |
272
288
  | `amicus setup` | Configure default model, API keys, and aliases. |
273
289
  | `amicus update` | Update to the latest version. |
@@ -275,85 +291,9 @@ amicus update
275
291
 
276
292
  The `am` alias is interchangeable with `amicus` everywhere.
277
293
 
278
- ### `amicus start` options
279
-
280
- | Option | Description | Default |
281
- |--------|-------------|---------|
282
- | `--model <model>` | Alias, `provider/model`, or `openrouter/provider/model`. | config default |
283
- | `--prompt <text>` | Task description. | *(required unless `--prompt-file`)* |
284
- | `--prompt-file <path>` | Read the prompt from a UTF-8 file (XOR `--prompt`). | |
285
- | `--agent <agent>` | OpenCode agent: `Chat`, `Build`, `Plan`. | `Chat` interactive / `Build` headless |
286
- | `--no-ui` | Run headless (autonomous, no window). | off |
287
- | `--json` | Emit the run result as stable JSON (requires `--no-ui`). | off |
288
- | `--timeout <minutes>` | Headless timeout. | 15 |
289
- | `--context-turns <N>` | Max conversation turns to include. | 50 |
290
- | `--context-since <duration>` | Time filter (e.g. `2h`); overrides turns. | |
291
- | `--context-max-tokens <N>` | Max context tokens. | 80000 |
292
- | `--no-context` | Skip parent conversation history. | off |
293
- | `--thinking <level>` | Reasoning effort: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`. | model default |
294
- | `--summary-length <length>` | Fold summary verbosity: `brief`, `normal`, `verbose`. | `normal` |
295
- | `--mcp <spec>` | Add an MCP server (`name=url` or `name=command`). | |
296
- | `--mcp-config <path>` | Path to an `opencode.json` with MCP config. | |
297
- | `--no-mcp` | Don't inherit MCP servers from the parent. | off |
298
- | `--exclude-mcp <name>` | Exclude a specific inherited MCP server (repeatable). | |
299
- | `--session-id <id\|current>` | Session to pull context from. | `current` |
300
- | `--cwd <path>` | Project directory. | cwd |
301
- | `--client <type>` | Client context: `code-local`, `code-web`, `cowork`. | `code-local` |
302
- | `--position <pos>` | Window position: `right`, `left`, `center`. | `right` |
303
- | `--fold-shortcut <key>` | Customize the fold keyboard shortcut. | `Cmd/Ctrl+Shift+F` |
304
- | `--opencode-port <port>` | Port override for the OpenCode server. | |
305
- | `--session-dir <path>` | Explicit session-data directory. | |
306
- | `--setup` | Force-open configuration before launching. Does **not** relax the `--prompt`/`--prompt-file` requirement — `start --setup` still fails fast with "Error: --prompt or --prompt-file is required" if neither is given. | |
307
- | `--no-validate-model` | Skip model-catalog validation before launch. | validation on |
308
-
309
- > Agents: **Chat** auto-approves reads and asks before writes/bash (interactive default); **Build** has full tool access (headless default); **Plan** is read-only analysis. `--agent Chat` is interactive-only and incompatible with `--no-ui`.
310
-
311
- ### `amicus fanout` — same prompt, many models
312
-
313
- ```bash
314
- amicus fanout --models "gemini,deepseek,gpt" --prompt "Review this design" --json
315
- ```
316
-
317
- Fanout runs one **headless wave**: every leg gets the **same** prompt (this is the shared-prompt model the council's review stages are built on). When all legs are terminal it prints **one** JSON wave document on stdout.
318
-
319
- - `--models <a,b,c>` — comma-separated aliases or `provider/model` IDs (required, unless `--council`).
320
- - `--council <name>` — run a saved council (e.g. `free`) instead of `--models`; mutually exclusive with `--models`.
321
- - `--prompt <text>` / `--prompt-file <path>` — the shared briefing. `--prompt-file` avoids the ~32 KB Windows argument cap and is mutually exclusive with `--prompt`.
322
- - `--wave-id <id>` — set the wave ID explicitly (leg IDs become `<id>-1..N`).
323
- - `--json` — emit the wave document.
324
- - `--session-id <id|current>` — session to pull shared context from (same as `start`; supported on `fanout` too).
325
- - Shared per-leg knobs: `--agent`, `--thinking`, `--timeout`, `--summary-length`, `--no-context`, the `--context-*` flags, the `--mcp*` flags, `--no-validate-model`, `--cwd`.
326
- - **Exit codes:** `0` all legs complete, `2` partial wave, `1` none complete / hard failure.
327
-
328
- ### Other commands
329
-
330
- ```bash
331
- amicus list # current project
332
- amicus list --status running # filter by status: running, complete, error,
333
- # timed-out, aborted, crashed, idle-timeout
334
- amicus list --all # all projects
335
- amicus list --json # machine-readable
336
-
337
- amicus read <id> # summary (default)
338
- amicus read <id> --conversation # full conversation
339
- amicus read <id> --metadata # session metadata
340
- amicus read <id> --json # stable JSON (run or wave document)
341
-
342
- amicus status <id> # one-shot status for a session or wave
343
- amicus status --wave <id> # alternative spelling for a wave ID
344
- amicus status <id> --json # machine-readable output
294
+ **Every flag, every subcommand, every example** — including the full `amicus start` option table, `amicus fanout` (supports `--session-id`, `--council <name>` as an alternative to `--models`), council presets, and every other command — lives in **[docs/usage.md](./docs/usage.md)**, the canonical CLI reference. What follows here is just enough to see the shape of a run.
345
295
 
346
- amicus resume <id> # reopen with full history
347
- amicus continue <id> --prompt "..." # new session, previous one as read-only context
348
-
349
- amicus abort <id> # stop one running session
350
- amicus abort --all # stop all running sessions in this project
351
-
352
- amicus setup --api-keys # open just the API-key window
353
- amicus setup --add-alias fast=openrouter/google/gemini-2.5-flash # add/override one alias
354
- ```
355
-
356
- **`amicus status <id>` output.** Human-readable:
296
+ `amicus status <id>` output. Human-readable:
357
297
 
358
298
  ```
359
299
  $ amicus status demo123
@@ -371,41 +311,26 @@ $ amicus status demo123 --json
371
311
  "taskId": "demo123",
372
312
  "status": "complete",
373
313
  "elapsed": "5m 0s",
374
- "version": "1.9.0",
314
+ "version": "2.0.0",
375
315
  "model": "google/gemini-2.5-flash",
376
316
  "phase": "terminal"
377
317
  }
378
318
  ```
379
319
 
380
- A running session additionally reports `messages`, `lastActivity`/`latest`, and (if stalled) a `STALLED` line with recovery guidance in `--json`. A wave ID (`amicus status <waveId>` / `--wave <waveId>`) instead reports `legsComplete`/`legsTotal` and a per-leg breakdown.
320
+ `amicus list --status` accepts `running`, `complete`, `error`, `timed-out`, `aborted`, `crashed`, `idle-timeout`. Full field-by-field docs (a running session's `messages`/`STALLED` reporting, wave-ID status shape, etc.) are in [docs/usage.md](./docs/usage.md).
381
321
 
382
322
  ---
383
323
 
384
324
  ## Models
385
325
 
386
- Amicus does **not** ship a frozen table of model names. Aliases and validation resolve against a **live catalog** fetched from provider APIs and cached at `~/.config/amicus/model-catalog.json` (24-hour TTL; the fetch works without an API key).
326
+ Amicus does **not** ship a frozen table of model names. Aliases and validation resolve against a **live catalog** fetched from provider APIs and cached at `~/.config/amicus/model-catalog.json` (24-hour TTL; the fetch works without an API key). Run `amicus models` to see exactly what resolves on *your* machine — that's the source of truth, not this README.
387
327
 
388
328
  ```bash
389
329
  amicus models # list the catalog
390
- amicus models --search gemini # filter by substring over id and name
391
- amicus models --refresh # force-refresh from provider APIs
392
- amicus models --check # audit your aliases against the catalog
330
+ amicus models --search gemini # filter by substring
393
331
  ```
394
332
 
395
- `amicus models --check` exits with the **number of stale aliases** (capped at 100) and prints same-vendor replacement suggestions for each, so it drops cleanly into CI.
396
-
397
- **Validation on launch.** `start` and `fanout` validate the model against the catalog before launching. For an explicit `--model` on `continue`/`resume` this is **blocking** (a typo'd model fails fast with suggestions); for a model *inherited* from a prior session it's **advisory**. Skip it any time with `--no-validate-model`, or fix the catalog with `amicus models --refresh`.
398
-
399
- **Aliases are a curated seed, not a fixed list.** `amicus setup` seeds a curated set of short aliases (e.g. `gemini`, `gpt`, `opus`, `deepseek`), and you add or override them with `amicus setup --add-alias name=provider/model`. To see exactly what resolves on *your* machine, run `amicus models` — that is the source of truth, not this README.
400
-
401
- **Full-id passthrough.** You can always bypass aliases and name a model directly. The prefix decides which credentials are used:
402
-
403
- | Format | Example | Credentials |
404
- |--------|---------|-------------|
405
- | `openrouter/provider/model` | `openrouter/google/gemini-2.5-flash` | `OPENROUTER_API_KEY` |
406
- | `google/model` | `google/gemini-2.5-flash` | `GOOGLE_GENERATIVE_AI_API_KEY` |
407
- | `openai/model` | `openai/gpt-5` | `OPENAI_API_KEY` |
408
- | `anthropic/model` | `anthropic/claude-opus-4` (the `opus` alias resolves here by default) | `ANTHROPIC_API_KEY` |
333
+ `start`/`fanout` validate your model against the catalog before launching (skip with `--no-validate-model`). You can also always bypass aliases and pass a full `provider/model` or `openrouter/provider/model` ID directly. Catalog internals, alias management, and the full-id passthrough table are in **[docs/usage.md § Models](./docs/usage.md#amicus-models--the-model-catalog)**.
409
334
 
410
335
  ---
411
336
 
@@ -430,68 +355,25 @@ The MCP server is auto-registered on install (Claude Code and Claude Desktop / C
430
355
  | `amicus_council_stats` | Reviewer-reliability stats from past council runs. |
431
356
  | `amicus_verdict` | Build the final council verdict from a tally + decisions. |
432
357
 
433
- The async pattern is **start → status → read**: `amicus_start` (or `amicus_fanout`) returns immediately, you poll `amicus_status`, then `amicus_read` once it's done — so the calling agent never blocks. Prefer `amicus_wait` over manual sleep+status polling for headless runs: it collapses the poll loop into a single blocking call that returns as soon as the run finishes (or the wait window closes).
358
+ 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.
434
359
 
435
- To register manually (user scope):
360
+ > Legacy `sidecar_*` tool names were removed entirely in v2.0.0 — only `amicus_*` tools exist now. `AMICUS_LEGACY_ALIASES=1` is a no-op left over from the v1.8.0 opt-in switch. See [docs/SHIMS.md](./docs/SHIMS.md).
436
361
 
437
- ```bash
438
- claude mcp add-json amicus '{"command":"npx","args":["-y","amicus@latest","mcp"]}' --scope user
439
- ```
440
-
441
- > Legacy `sidecar_*` tool names are no longer registered by default (v1.8.0). To restore them, add `"env": {"AMICUS_LEGACY_ALIASES": "1"}` to the server entry. They will be removed entirely in the next major.
362
+ Manual registration and per-tool detail are in **[docs/usage.md § MCP Server](./docs/usage.md#mcp-server)**.
442
363
 
443
364
  ---
444
365
 
445
366
  ## Configuration
446
367
 
447
- `amicus setup` is the recommended way to configure Amicus — it writes API keys to `~/.config/amicus/.env` (`0600`) and persists your default model and aliases. The environment variables below are for overrides and tuning. Dev-only variables (mock/update testing) are documented in [docs/configuration.md](./docs/configuration.md).
448
-
449
- **API keys**
450
-
451
- | Variable | Purpose |
452
- |----------|---------|
453
- | `OPENROUTER_API_KEY` | OpenRouter (multi-provider access). |
454
- | `GOOGLE_GENERATIVE_AI_API_KEY` | Direct Google access. |
455
- | `OPENAI_API_KEY` | Direct OpenAI access. |
456
- | `ANTHROPIC_API_KEY` | Direct Anthropic access. |
457
- | `DEEPSEEK_API_KEY` | Direct DeepSeek access. |
458
-
459
- **Behavior**
460
-
461
- | Variable | Purpose | Default |
462
- |----------|---------|---------|
463
- | `LOG_LEVEL` | Log verbosity: `error`, `warn`, `info`, `debug`. | `error` |
464
- | `AMICUS_CONFIG_DIR` | Override the config directory (keys, catalog, sessions). | `~/.config/amicus` |
465
- | `AMICUS_FANOUT_MAX_LEGS` | Cap the number of legs in a single fanout wave; non-positive values fall back to 10. | `10` |
466
- | `AMICUS_SHARED_SERVER` | When `1`, multiple MCP sessions share a single OpenCode Go process, eliminating cold-start latency. Set to `0` for per-process isolation or to diagnose a crash loop. | `1` |
467
- | `AMICUS_MCP_CLIENT` | Override the auto-detected MCP caller (`code-local`, `code-web`, or `cowork`). Amicus detects Claude Code vs. Claude Desktop/Cowork from the MCP `initialize` handshake; set this only if detection picks the wrong one. Note: `code-web` requires an explicit `--session-dir` and is not usable for MCP-spawned sessions. | auto-detected |
468
-
469
- **Headless poller tuning** (advanced — rarely needed)
470
-
471
- | Variable | Purpose | Default |
472
- |----------|---------|---------|
473
- | `AMICUS_POLL_INTERVAL_MS` | Delay between poll cycles. | `2000` |
474
- | `AMICUS_POLL_CALL_TIMEOUT_MS` | Per-poll call timeout. | `30000` |
475
- | `AMICUS_STABLE_FINISHED_POLLS` | Stable polls required after a completion signal. | `2` |
476
- | `AMICUS_STABLE_IDLE_POLLS` | Stable polls required with no completion signal (~60 s at 2 s). | `30` |
477
- | `AMICUS_MAX_CONSECUTIVE_POLL_FAILURES` | Consecutive poll failures before bailing. | `15` |
478
-
479
- **GUI & debug**
480
-
481
- | Variable | Purpose | Default |
482
- |----------|---------|---------|
483
- | `AMICUS_GUI_LOAD_TIMEOUT_MS` | Max wait for the Electron UI to load before showing what's in flight. | `15000` |
484
- | `AMICUS_DEBUG_PORT` | Chrome DevTools Protocol port for the Electron window. | `9222` |
368
+ `amicus setup` is the recommended way to configure Amicus — it writes API keys to `~/.config/amicus/.env` (`0600`) and persists your default model and aliases. Every environment variable (API keys, behavior tuning, headless poller, GUI/debug, process lifecycle) is documented in **[docs/configuration.md](./docs/configuration.md)**. v2.0.0 removed the legacy `SIDECAR_*` → `AMICUS_*` env-var mapping entirely; see [docs/SHIMS.md](./docs/SHIMS.md) for the removal record and rename table.
485
369
 
486
- > **Legacy names.** The pre-rebrand `SIDECAR_*` environment variables are still honored (with a one-time deprecation warning) and map to their `AMICUS_*` equivalents. See **[docs/SHIMS.md](./docs/SHIMS.md)** for the full mapping.
370
+ **New to the disk footprint?** The config tree's file-by-file contents, session storage layout, where (and whether) logs are written, `config.json`'s exact shape, and full uninstall instructions all live in **[docs/configuration.md § Where things live](./docs/configuration.md#where-things-live)**.
487
371
 
488
372
  ---
489
373
 
490
374
  ## JSON output
491
375
 
492
- With `--json`, Amicus emits stable, versioned documents on stdout — built for scripting and agent consumption.
493
-
494
- **Run document** (a single session — `start`, `read`, each fanout leg):
376
+ With `--json`, Amicus emits stable, versioned run/wave documents on stdout — built for scripting and agent consumption:
495
377
 
496
378
  ```json
497
379
  {
@@ -501,22 +383,7 @@ With `--json`, Amicus emits stable, versioned documents on stdout — built for
501
383
  }
502
384
  ```
503
385
 
504
- `modelInput` is the alias you passed; `model` is the resolved id. `status` is one of `complete | error | timeout | aborted` (plus `crashed` / `idle-timeout`); `summary` carries the fold output.
505
-
506
- **Wave document** (`fanout`, and `read <waveId> --json`):
507
-
508
- ```json
509
- {
510
- "schemaVersion": 1, "waveId": "...",
511
- "status": "complete",
512
- "counts": { "total": 0, "complete": 0, "error": 0, "timeout": 0, "aborted": 0 },
513
- "legs": [ /* one run document per model, in --models order */ ]
514
- }
515
- ```
516
-
517
- `status` is `complete | partial | error | aborted`. A leg's `summary` is that model's full response.
518
-
519
- **Exit codes** (for `--no-ui` / `fanout`): `0` success / all legs complete · `2` partial wave · `1` error, nothing completed, or hard failure · `130` interrupted (SIGINT) · `143` terminated (SIGTERM).
386
+ 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)**.
520
387
 
521
388
  ---
522
389
 
@@ -535,10 +402,12 @@ Most Claude-adjacent tooling assumes macOS/Linux; Amicus doesn't.
535
402
 
536
403
  ## Troubleshooting
537
404
 
405
+ Run `amicus doctor` first — it checks keys, catalog, OpenCode binary, Electron, skills, and MCP registration in one pass and prints a targeted fix for whatever's failing. For symptoms not covered below, or more diagnostic depth on any of these, see **[docs/troubleshooting.md](./docs/troubleshooting.md)**.
406
+
538
407
  | Symptom | Likely cause | Fix |
539
408
  |---------|--------------|-----|
540
409
  | "council review this" does nothing | The `second-opinion` skill isn't installed | Check `~/.claude/skills/second-opinion/SKILL.md` exists; re-run `npm install -g amicus` (postinstall installs both skills) |
541
- | `npm install -g amicus` fails with `EEXIST: … claude-sidecar` | The old upstream `claude-sidecar` package is still installed globally; npm won't overwrite another package's bin shims | `npm uninstall -g claude-sidecar`, then `npm install -g amicus`. Your config and sessions carry over (legacy paths are still read). |
410
+ | `npm install -g amicus` fails with `EEXIST: … claude-sidecar` | The old upstream `claude-sidecar` package is still installed globally; npm won't overwrite another package's bin shims | `npm uninstall -g claude-sidecar`, then `npm install -g amicus`. Your keys and past sessions are not lost, but v2.0.0 no longer reads the old paths automatically see [docs/SHIMS.md](./docs/SHIMS.md) for the one-time migration steps (rename `~/.config/sidecar/` and any `.claude/sidecar_sessions/` dirs). |
542
411
  | Install fails partway, or `amicus doctor` reports the OpenCode binary "not found" | A **transient** error during the OpenCode engine's own postinstall (a spawn `ENOENT`, or an antivirus file-lock while it lays down its 11 per-platform binaries) can roll back the whole atomic install — retrying usually succeeds | Just re-run `npm install -g amicus`. If it still fails, clear the cache first: `npm cache clean --force && npm install -g amicus`. |
543
412
  | `401` / auth error | API key missing, or the model prefix doesn't match the key you have | Run `amicus setup`; make sure the prefix (`openrouter/…` vs `google/…` vs `openai/…` vs `anthropic/…`) matches the credentials you configured. |
544
413
  | `402` / "Payment Required" on first council review / `start` / `fanout` call | Your OpenRouter key is real but has no credit. Key save (`amicus key openrouter <key>` or the setup wizard's key step) only checks that the key **authenticates** — it doesn't check balance, so a zero-credit key saves cleanly and only fails later, on the first real model call. (The `amicus council` subcommand itself is deterministic math and never calls a model.) | Add credit at [openrouter.ai/credits](https://openrouter.ai/credits), **or** switch to a zero-cost council: `amicus setup` → option 2 (Free OpenRouter council) builds one from live `:free`-suffixed models and saves it as `councils.free` — then run `amicus fanout --council free …`. See "Free council (zero-cost)" under [The Council](#the-council) above. |
@@ -562,7 +431,8 @@ LOG_LEVEL=debug amicus start --model gemini --prompt "test" --no-ui
562
431
 
563
432
  | Doc | Description |
564
433
  |-----|-------------|
565
- | [docs/usage.md](./docs/usage.md) | Command-by-command usage guide. |
434
+ | [docs/usage.md](./docs/usage.md) | The complete CLI & MCP reference — every flag, every subcommand, every example. |
435
+ | [docs/council.md](./docs/council.md) | Council pipeline reference: `tally`/`verdict`/`report` schemas, provenance, and a worked example. |
566
436
  | [docs/configuration.md](./docs/configuration.md) | Full configuration and environment reference. |
567
437
  | [docs/architecture.md](./docs/architecture.md) | How the engine, Electron shell, and context sharing fit together. |
568
438
  | [docs/opencode-integration.md](./docs/opencode-integration.md) | How Amicus drives the OpenCode runtime. |
@@ -570,7 +440,7 @@ LOG_LEVEL=debug amicus start --model gemini --prompt "test" --no-ui
570
440
  | [docs/electron-testing.md](./docs/electron-testing.md) | Chrome DevTools Protocol patterns for UI testing. |
571
441
  | [docs/testing.md](./docs/testing.md) | Test suite layout and how to run it. |
572
442
  | [docs/publishing.md](./docs/publishing.md) | Release and publish process. |
573
- | [docs/SHIMS.md](./docs/SHIMS.md) | Legacy `SIDECAR_*` `AMICUS_*` compatibility shims. |
443
+ | [docs/SHIMS.md](./docs/SHIMS.md) | v2.0.0 removal record for the pre-rebrand `sidecar*` compatibility shims — what was removed and how to migrate. |
574
444
  | [skills/second-opinion/SKILL.md](./skills/second-opinion/SKILL.md) | The LLM Council skill. |
575
445
  | [skills/sidecar/SKILL.md](./skills/sidecar/SKILL.md) | The `sidecar` chat skill. |
576
446
  | [evals/README.md](./evals/README.md) | End-to-end eval harness for LLM interactions. |
package/bin/amicus.js CHANGED
@@ -7,18 +7,7 @@
7
7
  * Routes commands to appropriate handlers.
8
8
  */
9
9
 
10
- // One-time, non-destructive migration of the legacy ~/.config/sidecar dir onto
11
- // the canonical ~/.config/amicus (copy; legacy kept as a backup). Runs before
12
- // any config/credential read so both resolve to the unified dir. Best-effort.
13
- try {
14
- const { migrateLegacyConfigDir } = require('../src/utils/config');
15
- const _m = migrateLegacyConfigDir();
16
- if (_m && _m.migrated) {
17
- process.stderr.write(`[amicus] Migrated config ${_m.from} → ${_m.to} (legacy kept as a backup).\n`);
18
- }
19
- } catch { /* best-effort: never block startup on migration */ }
20
-
21
- // Load API keys from all sources: process.env > sidecar .env > auth.json
10
+ // Load API keys from all sources: process.env > amicus .env > auth.json
22
11
  const { loadCredentials } = require('../src/utils/env-loader');
23
12
  loadCredentials();
24
13
 
@@ -123,6 +112,11 @@ async function main() {
123
112
  exitCode = await handleDoctor(args);
124
113
  break;
125
114
  }
115
+ case 'spend': {
116
+ const { handleSpend } = require('../src/cli-handlers-spend');
117
+ exitCode = await handleSpend(args);
118
+ break;
119
+ }
126
120
  case 'setup':
127
121
  await handleSetup(args);
128
122
  break;
@@ -162,9 +156,9 @@ async function main() {
162
156
  * Spec Reference: §4.2
163
157
  */
164
158
  async function handleList(args) {
165
- const { listSidecars } = require('../src/index');
159
+ const { listAmicus } = require('../src/index');
166
160
 
167
- await listSidecars({
161
+ await listAmicus({
168
162
  status: args.status,
169
163
  all: args.all,
170
164
  json: args.json,
@@ -181,7 +175,7 @@ async function handleResume(args) {
181
175
 
182
176
  if (!taskId) {
183
177
  console.error('Error: task_id is required for resume');
184
- console.error('Usage: sidecar resume <task_id>');
178
+ console.error('Usage: amicus resume <task_id>');
185
179
  process.exit(1);
186
180
  }
187
181
 
@@ -191,9 +185,9 @@ async function handleResume(args) {
191
185
  process.exit(1);
192
186
  }
193
187
 
194
- const { resumeSidecar } = require('../src/index');
188
+ const { resumeAmicus } = require('../src/index');
195
189
 
196
- return await resumeSidecar({
190
+ return await resumeAmicus({
197
191
  taskId,
198
192
  project: args.cwd,
199
193
  headless: args['no-ui'],
@@ -210,7 +204,7 @@ async function handleContinue(args) {
210
204
 
211
205
  if (!taskId) {
212
206
  console.error('Error: task_id is required for continue');
213
- console.error('Usage: sidecar continue <task_id> --prompt "..."');
207
+ console.error('Usage: amicus continue <task_id> --prompt "..."');
214
208
  process.exit(1);
215
209
  }
216
210
 
@@ -245,9 +239,9 @@ async function handleContinue(args) {
245
239
  args.model = await validateFallbackModel(args, alias);
246
240
  }
247
241
 
248
- const { continueSidecar } = require('../src/index');
242
+ const { continueAmicus } = require('../src/index');
249
243
 
250
- return await continueSidecar({
244
+ return await continueAmicus({
251
245
  taskId,
252
246
  newTaskId: args['task-id'],
253
247
  briefing: args.prompt || args.briefing,
@@ -19,4 +19,6 @@ don't re-ask for what is already present).
19
19
 
20
20
  Then follow the second-opinion skill end to end: Stage 0 intake/prep and run-folder
21
21
  setup, council selection with a cost estimate and explicit user confirmation, the
22
- three review waves, `amicus council tally`, and the accept/deny decision pass.
22
+ three review waves, `amicus council validate` on each leg's findings block,
23
+ `amicus council tally`, the accept/deny decision pass, and `amicus council verdict`
24
+ to write the final `verdict.json`.