amicus 4.5.1 → 4.5.3
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.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +75 -0
- package/README.md +142 -93
- package/bin/amicus.js +23 -0
- package/docs/configuration.md +16 -0
- package/docs/usage.md +1 -1
- package/package.json +3 -2
- package/schemas/council-verdict.schema.json +183 -29
- package/src/cli.js +21 -5
- package/src/council/run-assemble.js +7 -3
- package/src/council/run.js +2 -1
- package/src/council/verdict.js +44 -1
- package/src/headless.js +6 -0
- package/src/opencode-client.js +79 -2
- package/src/sidecar/session-utils.js +4 -0
- package/src/sidecar/unzip.js +16 -1
- package/src/utils/known-flags.js +90 -0
- package/src/utils/server-setup.js +74 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amicus",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.3",
|
|
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
|
@@ -3,6 +3,81 @@
|
|
|
3
3
|
All notable changes to Amicus are documented here. Format follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow semver.
|
|
5
5
|
|
|
6
|
+
## [4.5.3] - 2026-08-01
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **Unknown CLI flags are rejected instead of silently absorbed.** `parseArgs` treated any
|
|
11
|
+
`--token` as a flag: an unrecognized one landed on the parsed args object, no handler read it,
|
|
12
|
+
and the command ran as though it were never typed. Found while smoke-testing v4.5.2 —
|
|
13
|
+
`amicus start -m deepseek --prompt "…" --headless` printed no error and exited 0, but `start`
|
|
14
|
+
has no `--headless`; the run silently took the **interactive** path, ignored `-m`, and left a
|
|
15
|
+
session running against the default model. A typo (`--modl`), a flag borrowed from another
|
|
16
|
+
command, or an invented one all behaved the same way, and an unknown flag followed by a
|
|
17
|
+
positional would swallow it as its value. Unknown flags now get the same treatment amicus
|
|
18
|
+
already gave an unknown *command*: name it, suggest the nearest real flag, point at `--help`,
|
|
19
|
+
exit 1. The known-flag set is **derived from the usage text** (the same source `getCommandNames()`
|
|
20
|
+
uses, for the same anti-rot reason) plus the boolean-flag list, plus a small explicitly-documented
|
|
21
|
+
allowlist of internal MCP→CLI passthroughs (`--task-id`, `--run-id`, `--council-name`,
|
|
22
|
+
`--cowork-process`) and undocumented-but-working flags (`--briefing`, `--mode`, `--quiet`).
|
|
23
|
+
A regression test asserts every `args.<flag>` any CLI handler reads is in the known set, so the
|
|
24
|
+
check can never silently start rejecting a flag that works.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- **README Quick start is now four numbered steps**, with **Configure** promoted from a bold line
|
|
29
|
+
buried between two callouts to its own step and TOC entry. Installing without configuring is the
|
|
30
|
+
step people skip, and every council fails at the first model call when they do — so it now says
|
|
31
|
+
so plainly, notes that one OpenRouter key is enough to start, and ends with `amicus doctor` as
|
|
32
|
+
the confirmation that setup actually took.
|
|
33
|
+
|
|
34
|
+
## [4.5.2] - 2026-07-31
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **OpenCode server-start timeout is no longer pinned to the SDK's 5000 ms, and a start timeout
|
|
39
|
+
is now retried.** `@opencode-ai/sdk` defaults `createOpencodeServer`'s start timeout to 5 s and
|
|
40
|
+
lets the caller override it; amicus never passed one, so every start on every platform ran on
|
|
41
|
+
that default — undocumented, untunable, and invisible to `amicus doctor`. Worse, the existing
|
|
42
|
+
start retry (`retryOnLockRace`) classified only `database is locked` / `SQLITE_BUSY`, so a start
|
|
43
|
+
timeout fell straight through with **zero** retries, past machinery already wired in at every
|
|
44
|
+
call site. On a Windows box with the project on a OneDrive-synced volume and Defender active, a
|
|
45
|
+
cold OpenCode/SQLite start blew the window: the council's shared server failed to acquire, the
|
|
46
|
+
run degraded to exactly the per-wave configuration `src/council/run-server.js` exists to
|
|
47
|
+
eliminate, and the whole Stage-1 bench died with `COUNCIL_QUORUM: Only 0 Stage-1 review(s)
|
|
48
|
+
survived`. Three of the reporter's runs were lost this way. A start timeout is now classified as
|
|
49
|
+
transient (`isTimeoutClassStartFailure`) and retried on the same bounded 250/500/1000/2000 ms
|
|
50
|
+
schedule, the timeout is threaded through `buildServerOptions` and both upstream start sites,
|
|
51
|
+
and the default is raised to **30 s on Windows / 15 s elsewhere** — a slow start costs latency,
|
|
52
|
+
a failed start costs a review seat.
|
|
53
|
+
- **The Electron self-heal was dead code in every published install.** `src/sidecar/unzip.js`
|
|
54
|
+
did a bare, unguarded `require('extract-zip')` for a package that was never declared in
|
|
55
|
+
`dependencies` or `optionalDependencies`. It resolved in the dev tree only because `puppeteer`
|
|
56
|
+
(a devDependency) pulls it transitively — `npm ls extract-zip --omit=dev` returned empty — so on
|
|
57
|
+
a real `npm i -g amicus` `robustExtract` threw `MODULE_NOT_FOUND` before Strategy 1. That made
|
|
58
|
+
the native-unzip fallback below it unreachable, the bounded idle/max timers from the
|
|
59
|
+
extract-zip-node24 work inert, and `amicus doctor --fix` dead-end at `self-heal incomplete` —
|
|
60
|
+
while routing users toward antivirus allow-listing for what was actually a missing module.
|
|
61
|
+
`extract-zip` is now a declared production dependency, the `require` degrades into the native
|
|
62
|
+
strategies instead of throwing out of the function, and a new `no-phantom-dependencies` test
|
|
63
|
+
fails on any undeclared runtime require anywhere in `src/`, `bin/` or `electron/`.
|
|
64
|
+
- **A lost critic is now recorded on `verdict.json`.** The critic is a solo wave with one leg, and
|
|
65
|
+
unlike a dead bench wave (which trips the quorum gate and fails the run loudly) a dead critic is
|
|
66
|
+
survivable — so a run could reach a full verdict, tally and chair synthesis that had never seen
|
|
67
|
+
the adversarial seat, with the only record being `deadWaves` in `run.json`. Field run `dfb6a692`
|
|
68
|
+
did exactly that. `verdict.json` now carries an optional `seatLoss` block
|
|
69
|
+
(`criticRequested`/`criticSeated`/`reason`/`deadBenchSeats`) whenever `--critic` was requested,
|
|
70
|
+
so a reader of the verdict can see the critic never ran. Additive; `schemaVersion` stays `2`.
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
|
|
74
|
+
- **`AMICUS_SERVER_START_TIMEOUT_MS`** — override the server-start window (see
|
|
75
|
+
[docs/configuration.md](docs/configuration.md#server-startup)). Values ≤ 0 are ignored rather
|
|
76
|
+
than honored, since a zero start timeout fails every start instantly.
|
|
77
|
+
- **Successful server starts are logged at debug level** with both `startMs` and the `timeoutMs`
|
|
78
|
+
ceiling in force, so headroom on a slow box is measurable rather than inferred — the question
|
|
79
|
+
the field report could not answer.
|
|
80
|
+
|
|
6
81
|
## [4.5.1] - 2026-07-30
|
|
7
82
|
|
|
8
83
|
### Added
|
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ Hand Claude a plan, a design, a diff, an architecture decision, a manuscript —
|
|
|
15
15
|
[](https://nodejs.org)
|
|
16
16
|
[](./CONTRIBUTING.md)
|
|
17
17
|
|
|
18
|
+
**[Quick start ↓](#quick-start)** · [Commands](#commands) · [Documentation](#documentation) · [Troubleshooting](#troubleshooting)
|
|
19
|
+
|
|
18
20
|
> **Supported clients:** Claude Code CLI, Claude Desktop, and Claude Cowork are fully tested and supported. Claude Code web is experimental.
|
|
19
21
|
|
|
20
22
|
</div>
|
|
@@ -24,10 +26,14 @@ Hand Claude a plan, a design, a diff, an architecture decision, a manuscript —
|
|
|
24
26
|
## Table of Contents
|
|
25
27
|
|
|
26
28
|
- [What is Amicus](#what-is-amicus)
|
|
29
|
+
- [The Council](#the-council)
|
|
27
30
|
- [Ways to run the council](#ways-to-run-the-council)
|
|
28
31
|
- [Quick start](#quick-start)
|
|
32
|
+
- [1. Install](#1-install)
|
|
33
|
+
- [**2. Configure — don't skip this**](#2-configure--dont-skip-this)
|
|
34
|
+
- [3. Your first council](#3-your-first-council)
|
|
35
|
+
- [4. Your first sidecar](#4-your-first-sidecar)
|
|
29
36
|
- [Requirements & Dependencies](#requirements--dependencies)
|
|
30
|
-
- [The Council](#the-council)
|
|
31
37
|
- [The parallel window](#the-parallel-window)
|
|
32
38
|
- [Commands](#commands)
|
|
33
39
|
- [Models](#models)
|
|
@@ -52,7 +58,7 @@ One install delivers six things that work together:
|
|
|
52
58
|
- **The `amicus` CLI (with an `am` alias) and an MCP server.** The engine underneath both skills: launches sessions, shares context, runs parallel waves, and exposes the same surface to Claude as MCP tools.
|
|
53
59
|
- **A self-updating model catalog.** Aliases and validation resolve against a live catalog fetched from provider APIs (cached locally), so model names stay current without a hard-coded table.
|
|
54
60
|
- **Observability.** `amicus watch <id>` renders any live or finished run (fan-out or council) from any terminal; `--follow` streams milestones as they happen; `--on-complete` fires a hook when a run lands; `--retry-failed` plus opt-in cheaper-model fallbacks recover dead legs without relaunching the whole wave; `amicus spend` answers "what did this cost, and where" with per-run attribution.
|
|
55
|
-
- **Council Workspace.** `amicus watch <runId> --ui`: a window that shows a council *thinking* — live seats, the anonymized judge packet, the adjudication matrix, dissent drill-in, chair verdict, and cost-by-seat — for both live and historical runs. It also **auto-opens** on an MCP-invoked council run from Claude Code (local), so you no longer have to remember the flag (see [
|
|
61
|
+
- **Council Workspace.** `amicus watch <runId> --ui`: a window that shows a council *thinking* — live seats, the anonymized judge packet, the adjudication matrix, dissent drill-in, chair verdict, and cost-by-seat — for both live and historical runs. It also **auto-opens** on an MCP-invoked council run from Claude Code (local), so you no longer have to remember the flag (see [docs/council.md](./docs/council.md#council-workspace-gui)).
|
|
56
62
|
|
|
57
63
|
Claude is the orchestrator. The council and chat skills run *on top of* the engine; you talk to Claude, and Claude drives Amicus.
|
|
58
64
|
|
|
@@ -60,15 +66,103 @@ Claude is the orchestrator. The council and chat skills run *on top of* the engi
|
|
|
60
66
|
|
|
61
67
|
---
|
|
62
68
|
|
|
69
|
+
## The Council
|
|
70
|
+
|
|
71
|
+
> Trigger it by saying *"council review this"* to Claude, or, on the plugin channel, run **`/amicus:council`** directly.
|
|
72
|
+
|
|
73
|
+
**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.
|
|
74
|
+
|
|
75
|
+
**The flow, in five beats:**
|
|
76
|
+
|
|
77
|
+
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.
|
|
78
|
+
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.
|
|
79
|
+
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.
|
|
80
|
+
4. **Tiered decisions.** Confirmed findings get one bulk accept/deny; Contested and Singleton findings are decided one at a time (accept / deny / modify).
|
|
81
|
+
5. **Outputs applied.** Accepted findings are written into a reviewed copy of the source; the full run is captured in the run folder.
|
|
82
|
+
|
|
83
|
+
```mermaid
|
|
84
|
+
flowchart LR
|
|
85
|
+
A["Artifact"] --> B["Independent<br/>reviews"]
|
|
86
|
+
B --> C["Anonymized<br/>cross-review"]
|
|
87
|
+
C --> D["Chair verdict<br/>(non-Claude)"]
|
|
88
|
+
D --> E["Tiered<br/>accept / deny"]
|
|
89
|
+
E --> F["Reviewed copy<br/>+ run folder"]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**What a run produces** (in `output/<stem>-council/`):
|
|
93
|
+
|
|
94
|
+
- `review-<model>.md` × N — each model's independent review.
|
|
95
|
+
- `crossreview-matrix.md` — the adjudication grid plus the de-anonymized street-cred table.
|
|
96
|
+
- `verdict.md` — the chair's synthesis.
|
|
97
|
+
- `report.md` — synthesis + the full decision log + a per-call run-stats table.
|
|
98
|
+
- `report.html` — the deterministic renderer output (adjudication matrix, street-cred table,
|
|
99
|
+
findings-by-tier, cost — no chair prose). This is the default artifact handed to the user.
|
|
100
|
+
- For an **editable source**, the accepted edits land in `<stem>-reviewed.<ext>` next to the original.
|
|
101
|
+
|
|
102
|
+
**Optional council elements** (v2.2.0, all default off): five opt-in behaviors, offered once as a menu at launch — nothing turns on unless you name it, and the confirmation lists exactly what's on.
|
|
103
|
+
|
|
104
|
+
- **Critic seat** — one reviewer swaps to a four-pass adversarial brief (adversarial pass, edge-case hunt, consistency check, executability test). Its findings enter the same anonymized bundle as everyone else's, so the bench disciplines the critic: manufactured negativity lands Disputed and dies in the tally.
|
|
105
|
+
- **Expert lenses** — each reviewer takes a distinct expert perspective; you pick the panel domain (business, technical, customer, financial, or custom). Lens runs never feed the reliability ledger, and the report discloses the weakened cross-review anonymity.
|
|
106
|
+
- **Debate mode** — after cross-review, every Contested or Disputed finding goes back to its raiser to **defend, amend, or withdraw**, and the disputing judges re-vote. Exactly one rebuttal round, then the final tally.
|
|
107
|
+
- **Chair verdict scale** — the chair closes with 3–5 hard questions and one parseable line: `VERDICT: Ship it | Fix these first | Fundamental rethink`.
|
|
108
|
+
- **Claude in the council** — Claude adds its 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.
|
|
109
|
+
|
|
110
|
+
The critic and lens methodologies are adapted from the `/critic` and `/debate` agents in [John Renaldi's product-kit](https://github.com/jrenaldi79/plugin-marketplace) (MIT); the briefing boilerplate lives in [`skills/second-opinion/SEAT-BRIEFS.md`](./skills/second-opinion/SEAT-BRIEFS.md).
|
|
111
|
+
|
|
112
|
+
**Cost is disclosed up front.** Before any model launches, you see the run shape — including any enabled optional elements — for example:
|
|
113
|
+
|
|
114
|
+
> This run uses 3 council models across 2 fanout waves + 1 chair call, with critic seat + debate mode ON (~7 base runs + up to 6 rebuttal calls).
|
|
115
|
+
|
|
116
|
+
Then the council waits for your confirmation.
|
|
117
|
+
|
|
118
|
+
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)**.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
63
122
|
## Ways to run the council
|
|
64
123
|
|
|
65
124
|
The council is the hero — start with the everyday way, and reach for the more powerful ways when you need them:
|
|
66
125
|
|
|
67
|
-
- **Just ask, in Claude Code.** Hand Claude a plan, diff, design, or manuscript and say *"council review this."* The `second-opinion` skill runs the whole ritual in your session
|
|
68
|
-
- **Headless, in CI, with no Claude runtime.** `amicus council run --prompt-file plan.md --council free` runs that same pipeline in one command — reviews → cross-review → tally → chair verdict — writing `verdict.json` and `report.html`. It needs no Claude session, so it drops straight into CI. → [Headless council](
|
|
126
|
+
- **Just ask, in Claude Code.** Hand Claude a plan, diff, design, or manuscript and say *"council review this."* The `second-opinion` skill runs the whole ritual above in your session, with no setup beyond your API keys. This is how most people use it. → [Quick start](#quick-start)
|
|
127
|
+
- **Headless, in CI, with no Claude runtime.** `amicus council run --prompt-file plan.md --council free` runs that same pipeline in one command — reviews → cross-review → tally → chair verdict — writing `verdict.json` and `report.html`. It needs no Claude session, so it drops straight into CI. → [Headless council (CI)](#headless-council-ci)
|
|
69
128
|
- **With a debate round.** Add `--debate` and every Contested or Disputed finding goes back to its raiser to **defend, amend, or withdraw** while the disputing judges re-vote — exactly one rebuttal round, then the final tally. → [The Council](#the-council)
|
|
70
129
|
- **On free, local, private models — at $0.** Point the council (and sidecars) at an OpenAI-compatible server already running on your machine — Ollama, LM Studio, or vLLM — with `amicus provider add`. No API key, no per-token bill, nothing leaves your machine, and it works offline. → [`amicus provider`](./docs/usage.md#amicus-provider)
|
|
71
130
|
|
|
131
|
+
### Headless council (CI)
|
|
132
|
+
|
|
133
|
+
The same pipeline runs with no Claude runtime at all: `amicus council run --prompt-file briefing.md --models gemini,glm --chair deepseek --json` executes the review waves, the anonymized cross-review, the tally, and the chair verdict in one command, and writes the full run directory (`verdict.json` with the chair's parsed `overallVerdict`, `report.html`, every review and judge output). That is what powers the repo's own **Council Review GitHub Action v2** — on PRs labeled `council-review` it posts an adjudicated verdict as a check run plus a sticky comment, uploads the run directory as an evidence artifact, and can optionally gate merges via its `fail_on` input (default: report-only). Reference: [docs/council.md](./docs/council.md#amicus-council-run).
|
|
134
|
+
|
|
135
|
+
### Free council (zero-cost)
|
|
136
|
+
|
|
137
|
+
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`.
|
|
138
|
+
|
|
139
|
+
Run it anywhere a council runs:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
amicus fanout --council free --prompt "Review this design"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
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).
|
|
146
|
+
|
|
147
|
+
### Council presets
|
|
148
|
+
|
|
149
|
+
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.
|
|
150
|
+
|
|
151
|
+
### Policy packs (v4.5)
|
|
152
|
+
|
|
153
|
+
A council preset only saves the bench. A **pack** saves the whole run — bench, chair, critic/lenses, cost/timeout options, and a briefing template — as one named, shareable JSON file:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
amicus pack save review-bench --kind council --bench gemini,deepseek,gpt --chair opus --timeout 20 --max-cost 2
|
|
157
|
+
amicus council run --pack review-bench --prompt-file plan.md --json
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Any flag you also type on that second line overrides just that value — a pack only fills in what you didn't say explicitly, and it's recorded on the run either way. Packs work the same way on `fanout`/`start` and on the `amicus_fanout`/`amicus_start`/`amicus_council_run` MCP tools. `amicus pack list`/`show`/`rm` manage them, and `--from-run <id>` builds one from a run you already liked instead of typing flags at all. Full reference: [docs/usage.md § Policy packs](./docs/usage.md#policy-packs).
|
|
161
|
+
|
|
162
|
+
### Briefing templates (v4.5)
|
|
163
|
+
|
|
164
|
+
`--template <name> --artifact <file>` (plus repeatable `--var k=v`) renders a `{{prompt}}`/`{{artifact}}`-style Markdown template before it's sent, on `start`/`fanout`/`council run` alike — templates live in `~/.config/amicus/templates/`, and a pack's `briefing.template` is how one reaches an MCP-invoked run (MCP has no template param of its own). `amicus template list|show` manage them; v4.5 ships one built-in, `review`. Full reference: [docs/usage.md § Briefing templates](./docs/usage.md#briefing-templates).
|
|
165
|
+
|
|
72
166
|
---
|
|
73
167
|
|
|
74
168
|
## Quick start
|
|
@@ -80,7 +174,9 @@ The council is the hero — start with the everyday way, and reach for the more
|
|
|
80
174
|
>
|
|
81
175
|
> **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.
|
|
82
176
|
|
|
83
|
-
|
|
177
|
+
### 1. Install
|
|
178
|
+
|
|
179
|
+
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>`):
|
|
84
180
|
|
|
85
181
|
**As a Claude Code plugin** — the most native path if you use Claude Code:
|
|
86
182
|
|
|
@@ -117,7 +213,15 @@ For the **npm** and **install-script** paths, a postinstall auto-configures ever
|
|
|
117
213
|
|
|
118
214
|
> **Skipped the postinstall?** `--ignore-scripts` npm installs never run it, and the plugin channel skips it by design (Claude Code registers the plugin's MCP server and skills itself). Either way, run `amicus init` (plugin channel: `npx -y amicus@latest init`) any time to (re)register on demand — e.g. to also wire up Claude Desktop, which the plugin path doesn't touch. See [`amicus init`](./docs/usage.md#amicus-init).
|
|
119
215
|
|
|
120
|
-
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### 2. Configure — don't skip this
|
|
219
|
+
|
|
220
|
+
> ### ⚠️ Installing is not enough. Run this or nothing will work.
|
|
221
|
+
>
|
|
222
|
+
> Amicus has **no API keys of its own** — it drives *your* accounts at OpenRouter, Google,
|
|
223
|
+
> OpenAI, Anthropic, or DeepSeek. Until you add at least one key, every council and every
|
|
224
|
+
> sidecar fails at the first model call. **This is the step people skip.**
|
|
121
225
|
|
|
122
226
|
```bash
|
|
123
227
|
amicus setup
|
|
@@ -125,6 +229,10 @@ amicus setup
|
|
|
125
229
|
npx -y amicus@latest setup
|
|
126
230
|
```
|
|
127
231
|
|
|
232
|
+
**One key is enough to start.** [OpenRouter](https://openrouter.ai/keys) is the usual choice —
|
|
233
|
+
a single key reaches every model in the catalog, which is what makes a mixed-vendor council
|
|
234
|
+
work without four separate accounts.
|
|
235
|
+
|
|
128
236
|
This opens a graphical wizard:
|
|
129
237
|
|
|
130
238
|
| Step | What it does |
|
|
@@ -136,7 +244,20 @@ This opens a graphical wizard:
|
|
|
136
244
|
|
|
137
245
|
> **Headless environments:** if Electron can't open a window, the wizard falls back to a readline-based setup in the terminal.
|
|
138
246
|
|
|
139
|
-
**
|
|
247
|
+
**Confirm it took** — this is the fastest way to know you're actually ready:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
amicus doctor
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Green across the board (`0 error(s)`) means keys, catalog, engine, skills, and MCP registration
|
|
254
|
+
are all in place. Anything red, `amicus doctor` tells you exactly what to run next.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### 3. Your first council
|
|
259
|
+
|
|
260
|
+
No flags to learn. In Claude Code or Cowork, give Claude a document and say:
|
|
140
261
|
|
|
141
262
|
> *council review this*
|
|
142
263
|
|
|
@@ -144,7 +265,9 @@ Plugin-channel users can also type **`/amicus:council`** directly instead of phr
|
|
|
144
265
|
|
|
145
266
|
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.)
|
|
146
267
|
|
|
147
|
-
|
|
268
|
+
### 4. Your first sidecar
|
|
269
|
+
|
|
270
|
+
The sidecar is the lower-level path — you can invoke it by phrase through Claude too, but the CLI gives you the flags directly:
|
|
148
271
|
|
|
149
272
|
```bash
|
|
150
273
|
amicus start --model gemini --prompt "Fact-check the auth approach Claude just proposed"
|
|
@@ -152,6 +275,14 @@ amicus start --model gemini --prompt "Fact-check the auth approach Claude just p
|
|
|
152
275
|
|
|
153
276
|
A window opens alongside your editor with Gemini ready, pre-loaded with your conversation. Work with it, then **Fold** the summary back.
|
|
154
277
|
|
|
278
|
+
### Updating
|
|
279
|
+
|
|
280
|
+
Amicus checks the npm registry at most once every 24 hours (cached background check). When an update exists, the CLI prints a notice and the Electron toolbar shows a one-click **Update** banner. Or run it yourself:
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
amicus update
|
|
284
|
+
```
|
|
285
|
+
|
|
155
286
|
### Install from GitHub
|
|
156
287
|
|
|
157
288
|
The npm package is the primary path. To install straight from the repo instead — the postinstall runs **identically** (same MCP registration, same two skills) — you just need `git` on your `PATH`:
|
|
@@ -204,82 +335,6 @@ Everything you need before your first run, and what's optional.
|
|
|
204
335
|
|
|
205
336
|
---
|
|
206
337
|
|
|
207
|
-
## The Council
|
|
208
|
-
|
|
209
|
-
> Trigger it by saying *"council review this"* to Claude, or, on the plugin channel, run **`/amicus:council`** directly.
|
|
210
|
-
|
|
211
|
-
**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.
|
|
212
|
-
|
|
213
|
-
**The flow, in five beats:**
|
|
214
|
-
|
|
215
|
-
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.
|
|
216
|
-
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.
|
|
217
|
-
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.
|
|
218
|
-
4. **Tiered decisions.** Confirmed findings get one bulk accept/deny; Contested and Singleton findings are decided one at a time (accept / deny / modify).
|
|
219
|
-
5. **Outputs applied.** Accepted findings are written into a reviewed copy of the source; the full run is captured in the run folder.
|
|
220
|
-
|
|
221
|
-
**What a run produces** (in `output/<stem>-council/`):
|
|
222
|
-
|
|
223
|
-
- `review-<model>.md` × N — each model's independent review.
|
|
224
|
-
- `crossreview-matrix.md` — the adjudication grid plus the de-anonymized street-cred table.
|
|
225
|
-
- `verdict.md` — the chair's synthesis.
|
|
226
|
-
- `report.md` — synthesis + the full decision log + a per-call run-stats table.
|
|
227
|
-
- `report.html` — the deterministic renderer output (adjudication matrix, street-cred table,
|
|
228
|
-
findings-by-tier, cost — no chair prose). This is the default artifact handed to the user.
|
|
229
|
-
- For an **editable source**, the accepted edits land in `<stem>-reviewed.<ext>` next to the original.
|
|
230
|
-
|
|
231
|
-
**Optional council elements** (v2.2.0, all default off): five opt-in behaviors, offered once as a menu at launch — nothing turns on unless you name it, and the confirmation lists exactly what's on.
|
|
232
|
-
|
|
233
|
-
- **Critic seat** — one reviewer swaps to a four-pass adversarial brief (adversarial pass, edge-case hunt, consistency check, executability test). Its findings enter the same anonymized bundle as everyone else's, so the bench disciplines the critic: manufactured negativity lands Disputed and dies in the tally.
|
|
234
|
-
- **Expert lenses** — each reviewer takes a distinct expert perspective; you pick the panel domain (business, technical, customer, financial, or custom). Lens runs never feed the reliability ledger, and the report discloses the weakened cross-review anonymity.
|
|
235
|
-
- **Debate mode** — after cross-review, every Contested or Disputed finding goes back to its raiser to **defend, amend, or withdraw**, and the disputing judges re-vote. Exactly one rebuttal round, then the final tally.
|
|
236
|
-
- **Chair verdict scale** — the chair closes with 3–5 hard questions and one parseable line: `VERDICT: Ship it | Fix these first | Fundamental rethink`.
|
|
237
|
-
- **Claude in the council** — Claude adds its 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.
|
|
238
|
-
|
|
239
|
-
The critic and lens methodologies are adapted from the `/critic` and `/debate` agents in [John Renaldi's product-kit](https://github.com/jrenaldi79/plugin-marketplace) (MIT); the briefing boilerplate lives in [`skills/second-opinion/SEAT-BRIEFS.md`](./skills/second-opinion/SEAT-BRIEFS.md).
|
|
240
|
-
|
|
241
|
-
**Cost is disclosed up front.** Before any model launches, you see the run shape — including any enabled optional elements — for example:
|
|
242
|
-
|
|
243
|
-
> This run uses 3 council models across 2 fanout waves + 1 chair call, with critic seat + debate mode ON (~7 base runs + up to 6 rebuttal calls).
|
|
244
|
-
|
|
245
|
-
Then the council waits for your confirmation.
|
|
246
|
-
|
|
247
|
-
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)**.
|
|
248
|
-
|
|
249
|
-
**Headless council (CI).** The same pipeline runs with no Claude runtime at all: `amicus council
|
|
250
|
-
run --prompt-file briefing.md --models gemini,glm --chair deepseek --json` executes the review
|
|
251
|
-
waves, the anonymized cross-review, the tally, and the chair verdict in one command, and writes
|
|
252
|
-
the full run directory (`verdict.json` with the chair's parsed `overallVerdict`, `report.html`,
|
|
253
|
-
every review and judge output). That is what powers the repo's own **Council Review GitHub Action
|
|
254
|
-
v2** — on PRs labeled `council-review` it posts an adjudicated verdict as a check run plus a
|
|
255
|
-
sticky comment, uploads the run directory as an evidence artifact, and can optionally gate merges
|
|
256
|
-
via its `fail_on` input (default: report-only). Reference: [docs/council.md](./docs/council.md#amicus-council-run).
|
|
257
|
-
|
|
258
|
-
**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`.
|
|
259
|
-
|
|
260
|
-
Run it anywhere a council runs:
|
|
261
|
-
|
|
262
|
-
```bash
|
|
263
|
-
amicus fanout --council free --prompt "Review this design"
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
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).
|
|
267
|
-
|
|
268
|
-
**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.
|
|
269
|
-
|
|
270
|
-
**Policy packs (v4.5).** A council preset only saves the bench. A **pack** saves the whole run — bench, chair, critic/lenses, cost/timeout options, and a briefing template — as one named, shareable JSON file:
|
|
271
|
-
|
|
272
|
-
```bash
|
|
273
|
-
amicus pack save review-bench --kind council --bench gemini,deepseek,gpt --chair opus --timeout 20 --max-cost 2
|
|
274
|
-
amicus council run --pack review-bench --prompt-file plan.md --json
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
Any flag you also type on that second line overrides just that value — a pack only fills in what you didn't say explicitly, and it's recorded on the run either way. Packs work the same way on `fanout`/`start` and on the `amicus_fanout`/`amicus_start`/`amicus_council_run` MCP tools. `amicus pack list`/`show`/`rm` manage them, and `--from-run <id>` builds one from a run you already liked instead of typing flags at all. Full reference: [docs/usage.md § Policy packs](./docs/usage.md#policy-packs).
|
|
278
|
-
|
|
279
|
-
**Briefing templates (v4.5).** `--template <name> --artifact <file>` (plus repeatable `--var k=v`) renders a `{{prompt}}`/`{{artifact}}`-style Markdown template before it's sent, on `start`/`fanout`/`council run` alike — templates live in `~/.config/amicus/templates/`, and a pack's `briefing.template` is how one reaches an MCP-invoked run (MCP has no template param of its own). `amicus template list|show` manage them; v4.5 ships one built-in, `review`. Full reference: [docs/usage.md § Briefing templates](./docs/usage.md#briefing-templates).
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
338
|
## The parallel window
|
|
284
339
|
|
|
285
340
|
When you don't need a full council — just one other model's take — fork a conversation. Amicus extracts your current Claude Code context, opens a session pre-loaded with it, you **work** alongside it, and you **fold** a structured summary back into Claude's context when you're done.
|
|
@@ -305,12 +360,6 @@ When you don't need a full council — just one other model's take — fork a co
|
|
|
305
360
|
|
|
306
361
|
**Safety.** Amicus warns on **file conflicts** (a file changed externally while the session ran) and on **context drift** (the shared context may be stale relative to your current session), so a fold never silently overwrites newer work.
|
|
307
362
|
|
|
308
|
-
**Auto-update.** Amicus checks the npm registry at most once every 24 hours (cached background check). When an update exists, the CLI prints a notice and the Electron toolbar shows a one-click **Update** banner. Or run it yourself:
|
|
309
|
-
|
|
310
|
-
```bash
|
|
311
|
-
amicus update
|
|
312
|
-
```
|
|
313
|
-
|
|
314
363
|

|
|
315
364
|
|
|
316
365
|
---
|
|
@@ -332,7 +381,7 @@ amicus update
|
|
|
332
381
|
| `amicus spend` | Cross-run cost rollup from the spend ledger, with per-run attribution — total + per-model spend, tokens, and source mix, most-expensive first (`--wave`/`--council`/`--project`/`--model`/`--op`/`--failed` filter it, `--group-by` buckets it, `--since 7d` windows it; `--json` for a versioned doc; shows remaining OpenRouter credit when a key is configured). |
|
|
333
382
|
| `amicus key` | Manage API keys non-interactively: `amicus key <provider> <key>` saves after live validation; `--remove`; bare `amicus key` lists providers. |
|
|
334
383
|
| `amicus provider` | Add/list/test/remove local, OpenAI-compatible providers (LM Studio, Ollama, vLLM) — configured with `--preset` or `--url`, at **$0** marginal cost (`--json` on every subcommand). |
|
|
335
|
-
| `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 [
|
|
384
|
+
| `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 [Council presets](#council-presets) for the built-in `free`/`budget`/`frontier` benches. |
|
|
336
385
|
| `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). |
|
|
337
386
|
| `amicus pack` | Save a full run configuration — bench, chair/critic/lenses, options, briefing template — and invoke it by name: `save <name> --kind council\|fanout\|solo [flags]` (or `--from-run <id>`), `list`, `show <name>`, `rm <name>`. `--pack <name>` on `start`/`fanout`/`council run` loads one; explicit flags always override it. See [docs/usage.md § Policy packs](./docs/usage.md#policy-packs). |
|
|
338
387
|
| `amicus template` | `list`/`show <name>` a briefing template. `--template <name> [--artifact <file>] [--var k=v]` on `start`/`fanout`/`council run` renders one before the briefing is sent. See [docs/usage.md § Briefing templates](./docs/usage.md#briefing-templates). |
|
|
@@ -364,7 +413,7 @@ $ amicus status demo123 --json
|
|
|
364
413
|
"taskId": "demo123",
|
|
365
414
|
"status": "complete",
|
|
366
415
|
"elapsed": "5m 0s",
|
|
367
|
-
"version": "4.5.
|
|
416
|
+
"version": "4.5.3",
|
|
368
417
|
"model": "google/gemini-2.5-flash",
|
|
369
418
|
"phase": "terminal"
|
|
370
419
|
}
|
|
@@ -474,7 +523,7 @@ Run `amicus doctor` first — it checks keys, catalog, OpenCode binary, Electron
|
|
|
474
523
|
| `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). |
|
|
475
524
|
| 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`. |
|
|
476
525
|
| `401` / auth error | No usable key for the model's vendor — bare `provider/model` ids fall back to `OPENROUTER_API_KEY` automatically, so this means neither the direct key nor an OpenRouter key is configured (or `--gateway direct`/`openrouter` forced a gateway whose key is missing) | Run `amicus setup`, or `amicus key <provider> <key>` to add the missing key; see [Routing](#routing). |
|
|
477
|
-
| `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
|
|
526
|
+
| `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)](#free-council-zero-cost) above. |
|
|
478
527
|
| Every direct `anthropic/…` model (`haiku`, `sonnet`, `opus`, `claude`) errors `Not Found` in ~2 s at zero tokens, but the same model works via `openrouter/anthropic/…` | An inherited `ANTHROPIC_BASE_URL` missing its `/v1` path segment. The engine appends only `/messages`, so requests hit `https://api.anthropic.com/messages` → HTTP 404 with an empty body → the bare status text. A shell spawned by Claude Code sets the `/v1`-less form for you. The model id, alias, and key are all fine. | `export ANTHROPIC_BASE_URL=https://api.anthropic.com/v1`, or unset it entirely, or pass `--gateway openrouter`. In a council a dead seat **degrades the run instead of failing it** — smoke-test each seat with one throwaway `amicus start` before paying for a council. See [docs/troubleshooting.md](./docs/troubleshooting.md#every-direct-anthropic-model-fails-with-not-found). |
|
|
479
528
|
| `Model 'X' is unverified against the direct catalog; attempting anyway` for a model that plainly exists | Not a claim the model is wrong — amicus **couldn't check**. That vendor's direct catalog fetch failed (usually a stale or truncated stored key), leaving its namespace empty, and an empty namespace never blocks a launch. The engine may still run the model from its own credential store, so a working model warns forever. | `amicus models --refresh` and watch for a provider that stays empty; re-save the good key with `amicus key <provider> <apikey>`. See [docs/troubleshooting.md](./docs/troubleshooting.md#model-x-is-unverified-against-the-direct-catalog-attempting-anyway). |
|
|
480
529
|
| Session not found | No session matches the given ID | Run `amicus list`, or omit `--session-id` to use the most recent. |
|
package/bin/amicus.js
CHANGED
|
@@ -22,6 +22,7 @@ const { handleStart, handleFanout, handleRead } = require('../src/cli-handlers-r
|
|
|
22
22
|
const { handleResume, handleContinue } = require('../src/cli-handlers-resume-continue');
|
|
23
23
|
const { isOneShotCommand, armExitWatchdog } = require('../src/utils/lifecycle');
|
|
24
24
|
const { suggestCommand } = require('../src/utils/input-validators');
|
|
25
|
+
const { unknownFlags, getKnownFlags } = require('../src/utils/known-flags');
|
|
25
26
|
const { logger } = require('../src/utils/logger');
|
|
26
27
|
|
|
27
28
|
const VERSION = require('../package.json').version;
|
|
@@ -30,6 +31,28 @@ async function main() {
|
|
|
30
31
|
const args = parseArgs(process.argv.slice(2));
|
|
31
32
|
const command = args._[0];
|
|
32
33
|
|
|
34
|
+
// Reject unknown flags BEFORE anything can act on a half-understood command
|
|
35
|
+
// line. parseArgs accepts any `--token`, so an unrecognized one used to land
|
|
36
|
+
// on `args`, go unread, and let the command run as though it were never typed
|
|
37
|
+
// — `start … --headless` silently took the interactive path, ignored `--model`
|
|
38
|
+
// and left a session running. Same treatment as an unknown command: name it,
|
|
39
|
+
// suggest the nearest real flag, point at help, exit 1. See
|
|
40
|
+
// src/utils/known-flags.js for what counts as known and why.
|
|
41
|
+
const badFlags = unknownFlags(args);
|
|
42
|
+
if (badFlags.length > 0) {
|
|
43
|
+
for (const flag of badFlags) {
|
|
44
|
+
console.error(`Unknown option: --${flag}`);
|
|
45
|
+
const candidates = suggestCommand(flag, [...getKnownFlags()]);
|
|
46
|
+
if (candidates.length > 0) {
|
|
47
|
+
console.error(`Did you mean: ${candidates.map(c => `--${c}`).join(', ')}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
console.error(command
|
|
51
|
+
? `Run \`amicus ${command} --help\` to see valid options.`
|
|
52
|
+
: 'Run `amicus --help` to see valid options.');
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
|
|
33
56
|
// Install crash handler for MCP-spawned processes (have --task-id)
|
|
34
57
|
if (args['task-id'] && (command === 'start' || command === 'continue')) {
|
|
35
58
|
const { installCrashHandler } = require('../src/sidecar/crash-handler');
|
package/docs/configuration.md
CHANGED
|
@@ -137,6 +137,22 @@ Legacy `SIDECAR_IDLE_TIMEOUT*` names were removed in v2.0.0 — rename to the `A
|
|
|
137
137
|
|
|
138
138
|
Set `AMICUS_IDLE_TIMEOUT=0` to disable self-termination entirely.
|
|
139
139
|
|
|
140
|
+
### Server startup
|
|
141
|
+
|
|
142
|
+
| Variable | Purpose | Default |
|
|
143
|
+
|----------|---------|---------|
|
|
144
|
+
| `AMICUS_SERVER_START_TIMEOUT_MS` | How long to wait for OpenCode to report it is listening before treating the start as failed. | `30000` on Windows, `15000` elsewhere |
|
|
145
|
+
|
|
146
|
+
A start that exceeds this window is treated as **transient** and retried on the same bounded schedule as an OpenCode database lock race (5 attempts, 250/500/1000/2000 ms), because retrying costs nothing but the backoff while a failed start costs a whole review seat.
|
|
147
|
+
|
|
148
|
+
Raise it if you see `Timeout waiting for server to start` on a slow box — a project directory on a sync-backed volume (OneDrive, Dropbox) with an antivirus scanner attached can push a cold OpenCode/SQLite start well past the default. Values of `0` or below are ignored rather than honored, since a zero start timeout fails every start instantly.
|
|
149
|
+
|
|
150
|
+
To see how much headroom you actually have, run with `LOG_LEVEL=debug` and look for the `OpenCode server started` line — it reports both `startMs` (what the start took) and `timeoutMs` (the ceiling it ran against):
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{"level":"debug","msg":"OpenCode server started","startMs":561,"timeoutMs":30000}
|
|
154
|
+
```
|
|
155
|
+
|
|
140
156
|
### Shared server
|
|
141
157
|
|
|
142
158
|
The shared-server mode (`AMICUS_SHARED_SERVER=1`, which is the default) lets multiple Amicus sessions reuse a single OpenCode Go binary process rather than spawning one per invocation, eliminating cold-start latency on the second and subsequent calls. Disable it with `AMICUS_SHARED_SERVER=0` if you need per-process isolation or are diagnosing a crash loop.
|
package/docs/usage.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amicus",
|
|
3
|
-
"version": "4.5.
|
|
3
|
+
"version": "4.5.3",
|
|
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": [
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"@modelcontextprotocol/sdk": "^1.27.0",
|
|
78
78
|
"@opencode-ai/sdk": "^1.1.36",
|
|
79
79
|
"dotenv": "^17.2.3",
|
|
80
|
+
"extract-zip": "^2.0.1",
|
|
80
81
|
"opencode-ai": "^1.2.20",
|
|
81
82
|
"tiktoken": "^1.0.0",
|
|
82
83
|
"update-notifier": "^7.3.1",
|
|
@@ -93,7 +94,7 @@
|
|
|
93
94
|
"jest": "^29.0.0",
|
|
94
95
|
"lint-staged": "^16.3.2",
|
|
95
96
|
"puppeteer": "^24.36.0",
|
|
96
|
-
"sharp": "^0.
|
|
97
|
+
"sharp": "^0.35.3",
|
|
97
98
|
"ws": "^8.19.0"
|
|
98
99
|
},
|
|
99
100
|
"engines": {
|