amicus 4.6.2 → 4.7.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.
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +349 -0
- package/README.md +24 -13
- package/bin/amicus.js +31 -0
- package/docs/ROADMAP.md +172 -36
- package/docs/configuration.md +56 -6
- package/docs/council.md +63 -10
- package/docs/doc-system.md +8 -7
- package/docs/schemas.md +10 -1
- package/docs/troubleshooting.md +27 -1
- package/docs/usage.md +68 -15
- package/electron/workspace-ui/index.html +3 -0
- package/electron/workspace-ui/live-model.js +132 -21
- package/electron/workspace-ui/workspace-app.js +20 -4
- package/electron/workspace-ui/workspace-lazy.js +233 -0
- package/electron/workspace-ui/workspace-matrix.js +12 -1
- package/electron/workspace-ui/workspace-panels.js +24 -171
- package/electron/workspace-ui/workspace-render.js +15 -5
- package/electron/workspace-ui/workspace-seats.js +88 -5
- package/electron/workspace-ui/workspace-verbs.js +1 -1
- package/electron/workspace-ui/workspace.css +6 -0
- package/package.json +5 -2
- package/schemas/council-run.schema.json +1 -0
- package/schemas/council-stats.schema.json +9 -1
- package/schemas/run.schema.json +2 -1
- package/schemas/spend.schema.json +1 -1
- package/schemas/wave.schema.json +2 -1
- package/skills/second-opinion/MANUAL-ORCHESTRATION.md +12 -0
- package/skills/second-opinion/MODEL-NOTES.md +5 -4
- package/skills/sidecar/SKILL.md +7 -2
- package/src/cli-council-run-bench.js +86 -0
- package/src/cli-handlers-council-run.js +65 -81
- package/src/cli-handlers-council.js +24 -3
- package/src/cli-handlers-doctor.js +9 -3
- package/src/cli-handlers-fanout.js +179 -0
- package/src/cli-handlers-pack.js +24 -10
- package/src/cli-handlers-run.js +19 -161
- package/src/cli-template-args.js +48 -0
- package/src/cli.js +39 -46
- package/src/council/debate.js +89 -10
- package/src/council/ledger.js +72 -11
- package/src/council/presets-cli.js +6 -2
- package/src/council/report.js +17 -6
- package/src/council/run-assemble.js +15 -3
- package/src/council/run-budget.js +2 -2
- package/src/council/run-chair.js +70 -11
- package/src/council/run-debate.js +51 -67
- package/src/council/run-launch.js +9 -2
- package/src/council/run-retry.js +4 -1
- package/src/council/run-stage1-launch.js +94 -0
- package/src/council/run-stage2.js +25 -4
- package/src/council/run-stages.js +79 -86
- package/src/council/run-state.js +10 -2
- package/src/council/run.js +26 -2
- package/src/council/tally.js +6 -2
- package/src/mcp-council-awareness.js +1 -0
- package/src/mcp-council-bench.js +4 -0
- package/src/mcp-council-run.js +10 -0
- package/src/mcp-server.js +114 -54
- package/src/mcp-tools.js +12 -5
- package/src/pack/pack-cli.js +1 -1
- package/src/pack/pack-forward.js +12 -4
- package/src/pack/pack-resolve.js +3 -0
- package/src/pack/pack-store.js +20 -3
- package/src/pack/pack-validate.js +5 -1
- package/src/session-manager.js +6 -2
- package/src/sidecar/budget.js +38 -4
- package/src/sidecar/fanout-budget.js +1 -2
- package/src/sidecar/fanout-leg-fallback.js +7 -3
- package/src/sidecar/fanout-wave-io.js +13 -1
- package/src/sidecar/fanout.js +11 -9
- package/src/sidecar/list-limit.js +50 -0
- package/src/sidecar/list-search.js +69 -0
- package/src/sidecar/read.js +90 -5
- package/src/sidecar/start-metadata.js +58 -0
- package/src/sidecar/start.js +8 -43
- package/src/sidecar/workspace-auto-open.js +2 -2
- package/src/spend-query.js +2 -1
- package/src/template/apply.js +7 -4
- package/src/template/render.js +6 -2
- package/src/template/store.js +1 -1
- package/src/utils/alias-audit.js +19 -0
- package/src/utils/cli-preflight.js +27 -1
- package/src/utils/config.js +15 -0
- package/src/utils/curated-models.js +43 -7
- package/src/utils/gateway-route-audit.js +16 -3
- package/src/utils/model-fetcher.js +8 -6
- package/src/utils/remediation-hints.js +14 -0
- package/src/utils/result-schema-rebuild.js +1 -0
- package/src/utils/result-schema.js +6 -1
- package/src/utils/session-index-tmp-sweep.js +18 -3
- package/src/utils/session-index.js +1 -0
- package/src/utils/session-metadata-tmp-sweep.js +156 -0
- package/src/utils/spend-ledger.js +11 -4
- package/src/utils/validators.js +16 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amicus",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.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,344 @@ All notable changes to Amicus are documented here. Format follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [4.7.0] - 2026-08-08
|
|
9
|
+
|
|
10
|
+
**"The count is the count."** Every number Amicus shows you is the number — what a council cost,
|
|
11
|
+
which legs ran, and which model earned the credit. Shipped across ten `v4.7-*` PRs — PR0
|
|
12
|
+
(extractions) through PR7, plus the PR3 riders and a closing documentation pass: the `runStats`
|
|
13
|
+
completeness half of CA-4, the GOA-7 ledger prerequisite, F8 session/wave tagging with `--search`,
|
|
14
|
+
and four correction sweeps.
|
|
15
|
+
|
|
16
|
+
### CI
|
|
17
|
+
|
|
18
|
+
- **The macOS/node-24 unit leg's `--workerIdleMemoryLimit` drops from 1GB to 512MB.** That leg
|
|
19
|
+
segfaulted a jest worker again on 2026-08-07 (PR #126) — killing
|
|
20
|
+
`tests/utils/gateway-route-audit.test.js` while 6791 tests passed and 0 failed, with a green
|
|
21
|
+
rerun — which was the first such hit *with* the 1GB ceiling in force, so 1GB does not bound the
|
|
22
|
+
growth on this runner. Halving recycles a worker sooner, at a small wall-clock cost on a leg
|
|
23
|
+
already mid-pack (~3m59s vs ubuntu's ~3m58s). Three pins in
|
|
24
|
+
`tests/scripts/ci-workflow.test.js` now guard the mitigation, which previously had none: it
|
|
25
|
+
produces no assertion failure when it works and none when it is deleted, so nothing else in the
|
|
26
|
+
repo would notice its loss. If a fifth hit lands at 512MB, the next lever is `--maxWorkers` on
|
|
27
|
+
that leg — fewer concurrent heaps — not a smaller idle ceiling.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **`runStats` gains a row for every paid launch, not just one per requested seat** (v4.7 CA-4,
|
|
32
|
+
the row-per-launch design — closes the chair-cost accounting gap). Three new roles cover legs
|
|
33
|
+
that were billed but never rowed: `chair-attempt` (a failed ch1–ch3 chair launch), `repair`
|
|
34
|
+
(a Stage-1 `-p`, Stage-2 `-q`, chair-ch4, or debate-born `-d<N>r`/`-rv-…r` solo — a failed
|
|
35
|
+
defense or re-vote repair), and `superseded` (a first leg a later attempt replaced — an SL-2
|
|
36
|
+
retry or a debate repair); `wasChair` is always `false` on these. Every dead seat/critic/lens
|
|
37
|
+
with no recovery, and a chair walk that gives up entirely, now get an honest primary error row
|
|
38
|
+
too, extending the #83 judge treatment to every seat.
|
|
39
|
+
- **`runStats[].waveId`** (emit-only-when-set): every row backed by a real billed leg now names
|
|
40
|
+
the exact wave/leg it came from; e.g. the synthetic `claude` row, a give-up chair's error row,
|
|
41
|
+
and a leg-less dead-seat/critic/lens primary error row (the two SL-2 retry note-classes that
|
|
42
|
+
never produced a real leg for the seat at all) carry none.
|
|
43
|
+
- **The run-cost bijection invariant suite** (`tests/council/run-cost-bijection.test.js`): every
|
|
44
|
+
terminal run now proves Σ(`runStats` legged-row usage) equals `run.json`'s `usage` block —
|
|
45
|
+
cost, and the reported/estimated/unpriced/subtreeUnknown leg counts — across clean, repair,
|
|
46
|
+
chair-walk-failure, debate-repair, retry-healed, and retry-failed scenarios.
|
|
47
|
+
- **`runStats[].resolvedModel`** (v4.7 GOA-7, emit-only-when-set): every row built from a served
|
|
48
|
+
leg now records the executable id that actually served (post-fallback-substitution), never the
|
|
49
|
+
alias; carried verbatim through `tally.json`/`verdict.json` and onto `council-ledger.jsonl` rows.
|
|
50
|
+
- **`council stats` rows gain `aliases[]`** (every alias observed for the group, most recent
|
|
51
|
+
first — `aliases[0]` is the launch-preferred name) **and a `legacy` mark** on groups whose rows
|
|
52
|
+
all lack `resolvedModel`; the human table sizes the model column to the longest key (16-char
|
|
53
|
+
floor) and marks `legacy` in the notes column beside `low-N`.
|
|
54
|
+
- **`--tag <t>` on `start`/`fanout`/`council run`** (CLI + MCP, v4.7 F8 D13): labels a session
|
|
55
|
+
for `list`/`--search`/`spend --group-by tag`. Reject-style validation
|
|
56
|
+
(`^[A-Za-z0-9_-]{1,64}$`) — an invalid tag fails fast rather than being silently truncated or
|
|
57
|
+
charset-stripped the way `sanitizeCouncilName` cleans, since a stored tag is a search key.
|
|
58
|
+
Stored absent-not-null on `metadata.json`/`wave.json`/`run.json` and every result doc; the MCP
|
|
59
|
+
shared-server's in-process start path stamps it too. `--tag` is rejected alongside
|
|
60
|
+
`--retry-failed` (`BAD_ARGS`).
|
|
61
|
+
Council sub-waves (Stage-1, critic/lens solos, Stage-2, chair, debate) all carry the run's tag
|
|
62
|
+
on their own wave metadata. Riders: `continue`/`resume` don't yet inherit the parent session's
|
|
63
|
+
tag (their rows group under `(unattributed)` for `--group-by tag`), and `--retry-failed` doesn't
|
|
64
|
+
yet inherit the original wave's tag either — both are future work, not oversights.
|
|
65
|
+
- **`amicus list --search <q>` / MCP `amicus_list {search}`** (F8 D15, errata E-PR3-5):
|
|
66
|
+
case-insensitive substring filter over `id`, `tag`, and briefing material. Fan-out wave rows
|
|
67
|
+
match against the full `briefing.md` text (falling back to the row's 200-char excerpt when
|
|
68
|
+
unreadable); council-run rows match `briefing.md` written at MCP launch, or the
|
|
69
|
+
post-`--- MATERIAL / BRIEFING ---` portion of `briefing-stage1.md` for CLI-launched runs; leg
|
|
70
|
+
rows (spawned by a wave) match `id`/`tag` only, so a wave's briefing never surfaces once per
|
|
71
|
+
leg it spawned. A bare `--search` with no value is a usage error.
|
|
72
|
+
- **`amicus spend --group-by tag`** (F8 D16): spend-ledger rows now carry `tag` (leg and solo
|
|
73
|
+
rows alike); untagged history groups under `(unattributed)`, matching every other dimension's
|
|
74
|
+
convention. `SPEND_LEDGER_SCHEMA_VERSION` stays at `1` — this is an additive field, not the kind
|
|
75
|
+
of change that forced the council-ledger's `LEDGER_SCHEMA_VERSION` 1 → 2 bump above, which
|
|
76
|
+
existed to segment history by resolved-model id, a different need.
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- **Tally/report/GUI cost totals now include legs that used to be silently dropped** — repairs,
|
|
81
|
+
failed chair attempts, and superseded/replaced legs all get a row now. Totals read HIGHER than
|
|
82
|
+
v4.6.x for an identical run, intentionally: this is the fix for the two-numbers-disagree
|
|
83
|
+
symptom (`council tally`'s sum vs. `run.json`'s total quietly diverging by the omitted spend).
|
|
84
|
+
- **The council-ledger join is now an explicit allowlist, not a skip-set**: `seat`, `critic`,
|
|
85
|
+
`lens:*`, `chair`, `claude`, `council`, `redteam`. Fail-closed by design — consumers keying
|
|
86
|
+
`runStats` by model must now exclude every role outside that set, the v4.7 analogue of v4.6's
|
|
87
|
+
"must exclude `role: 'judge'`" rule: a custom/free-form `role` label (e.g. a skill-authored tag)
|
|
88
|
+
still renders in the tally/report artifact but no longer contributes role/wasChair/conformance
|
|
89
|
+
to `amicus council stats` reliability numbers.
|
|
90
|
+
- **The Workspace seats panel no longer renders the three new non-seat launch rows**
|
|
91
|
+
(`chair-attempt`, `repair`, `superseded`) — they still appear in the report/tally cost tables,
|
|
92
|
+
just not as a seat.
|
|
93
|
+
- **`LEDGER_SCHEMA_VERSION` 1 → 2** (v4.7 GOA-7). Legacy-read, no migration: rows without
|
|
94
|
+
`resolvedModel` (all pre-v4.7 history, plus leg-less rows whose resolution is unknowable)
|
|
95
|
+
aggregate under their alias; a group is marked `legacy` only when every row in it lacks
|
|
96
|
+
`resolvedModel`.
|
|
97
|
+
- **`council stats` groups reliability by resolved model id** (`resolvedModel || model`) instead
|
|
98
|
+
of by alias alone — history splits honestly at the bump; a retargeted alias's new rows start
|
|
99
|
+
a fresh `low-N` group.
|
|
100
|
+
- **Chair fallback promotion (`pickFallbackChair`) excludes candidates by their full name set**
|
|
101
|
+
(group key + `aliases[]`) and launches the group's most-recent alias (`aliases[0]`) — a bench
|
|
102
|
+
seat's resolved-keyed group can no longer be promoted as its own chair.
|
|
103
|
+
- **`amicus list` and the MCP `amicus_list` tool now share one enumeration**
|
|
104
|
+
(`src/sidecar/read.js`, F8 D14): MCP rows gain `type`/`parentWave`/`legCount`, CLI rows gain
|
|
105
|
+
`mode`, and both gain `tag`. The MCP `status` input relaxed from a 3-value enum
|
|
106
|
+
(`'all' | 'running' | 'complete'`) to a free string, so `error`/`aborted`/`crashed`/
|
|
107
|
+
`timed-out`/`idle-timeout` — always real statuses, previously rejected outright by MCP's schema
|
|
108
|
+
even though the CLI already accepted them — now filter correctly there too. The CLI table
|
|
109
|
+
gained a `TAG` column.
|
|
110
|
+
- Test/comment/docs sweep (v4.7 PR4, theme a): ~30 census nits dispositioned — no behavior
|
|
111
|
+
changes.
|
|
112
|
+
- **`--out`/`-o` no longer accepts a flag-shaped value as a filename.** `--out -x` and
|
|
113
|
+
`--out=-x` previously wrote a file literally named `-x` (the dash-leading value was accepted
|
|
114
|
+
at face value); both forms now fail fast with `BAD_ARGS` ("-o/--out cannot start with '-':
|
|
115
|
+
got '-x'") instead. `-o -x` was already rejected before this change, via a separate internal
|
|
116
|
+
check — it still fails with the same code and exit status, now carrying the more accurate
|
|
117
|
+
message above in place of "-o/--out requires a value".
|
|
118
|
+
- **`{{project}}` template variable is now path-resolved** (absolute, normalized via
|
|
119
|
+
`path.resolve`), matching `{{artifact_path}}`'s existing behavior — it previously rendered the
|
|
120
|
+
raw `--cwd`/`process.cwd()` string verbatim. All three `TEMPLATE_RENDER` error paths also gain a
|
|
121
|
+
real, followable `hint` instead of `hint: null`.
|
|
122
|
+
- **MCP-launched council runs now record `run.template` provenance**, closing the one remaining
|
|
123
|
+
gap after Wave 1's D1 forwarded it on fanout/start — `mcp-council-run.js`'s template path no
|
|
124
|
+
longer discards `promptMeta`, so `run.json` carries `{name,hash}` the same way the CLI path
|
|
125
|
+
already did.
|
|
126
|
+
|
|
127
|
+
### Fixed
|
|
128
|
+
|
|
129
|
+
- **`amicus list --all` now actually lists every project.** The flag has been documented since
|
|
130
|
+
before v4.7 (`--all` / "Show all projects" in `amicus list`'s help text) but `listSidecars`
|
|
131
|
+
never read it, so it silently behaved exactly like a bare `amicus list`. It now enumerates
|
|
132
|
+
every project the global sessions-index knows about (an advisory navigation aid, not
|
|
133
|
+
authoritative — a stale entry pointing at a missing or unreadable project is skipped, not
|
|
134
|
+
surfaced as an error), deduped by canonical project identity.
|
|
135
|
+
- **`amicus list --search` was accepted and silently ignored.** The generic CLI arg parser took
|
|
136
|
+
any `--search <value>`, but nothing downstream read it, so the flag — whose sibling convention,
|
|
137
|
+
`amicus models --search`, was already a repo-wide pattern — quietly did nothing. It's now
|
|
138
|
+
implemented; see Added, above.
|
|
139
|
+
- **`amicus fanout --quiet` was accepted and silently ignored.** `quiet` is a repo-wide known
|
|
140
|
+
flag, so the command parsed and exited 0 — but `handleFanout` never forwarded it into
|
|
141
|
+
`runFanout`, which printed the launch banner and per-leg lines anyway. Same
|
|
142
|
+
accepted-but-ignored shape as `list --search` above.
|
|
143
|
+
- **`amicus pack save --version <semver>` was accepted and silently ignored — it wrote no pack at
|
|
144
|
+
all.** `version` is a global boolean flag, so `parseArgs` set `args.version = true`, stranded the
|
|
145
|
+
semver in positionals, and `bin/amicus.js` printed the amicus version banner *before* command
|
|
146
|
+
dispatch — `handlePack` never ran, and the command exited 0 having saved nothing.
|
|
147
|
+
`--version=2.0.0` failed identically. Meanwhile the handler read `args.version` for a value it
|
|
148
|
+
could never receive, and both the help text and `docs/usage.md` documented `--version <semver>`
|
|
149
|
+
as a real option. The pack's own version is now spelled **`--pack-version <semver>`** (honored on
|
|
150
|
+
both the flags and `--from-run` paths), and `pack save --version` fails fast with `BAD_ARGS`
|
|
151
|
+
naming the right spelling. Every other `--version` still prints the banner. Third instance of the
|
|
152
|
+
accepted-but-ignored shape, after `list --search` and `fanout --quiet` above.
|
|
153
|
+
- **A fanout whose server fails to start no longer drops its pack.** `errorWave` — the third
|
|
154
|
+
`buildWaveResult` call site — inherited a pre-seeded `tag` from `metadata.json` but not a
|
|
155
|
+
pre-seeded `pack`, so an MCP-spawned wave that died at server start persisted a `wave.json`
|
|
156
|
+
missing the pack it was launched with (and `amicus read --json` prefers `wave.json`). The two
|
|
157
|
+
other call sites already inherited both; this was the lone holdout.
|
|
158
|
+
- **The test suite no longer writes session directories outside its sandbox.** Several suites
|
|
159
|
+
passed the literal `'/tmp'` as a project cwd — on Windows that resolves to `C:\tmp`, a real
|
|
160
|
+
directory — so every run leaked real session dirs onto the developer's filesystem and into the
|
|
161
|
+
global sessions-index. They now sandbox under `os.tmpdir()`, pinned by
|
|
162
|
+
`tests/hermetic-tmp-guard.test.js`. This residue was what made `--all` an 8-second, 21k-row
|
|
163
|
+
dump on a developer machine.
|
|
164
|
+
- **`pack list` warnings now print to stderr, not stdout.** They previously shared stdout with
|
|
165
|
+
`pack list`'s data output — unlike `pack save`, which already used stderr for the same
|
|
166
|
+
"Warning:" text — so `pack list | grep` mixed diagnostics into data. `--json` output is
|
|
167
|
+
unaffected.
|
|
168
|
+
- **A council pack combining `critic` and `lenses` with a by-name (string) bench is now rejected
|
|
169
|
+
at validate-time (`PACK_INVALID`), matching the array-bench form.** It previously survived
|
|
170
|
+
run-mode validation and could later surface a mutual-exclusion error naming a flag the user
|
|
171
|
+
never typed. One consequence: a string-bench pack naming both `critic` and `lenses` — even
|
|
172
|
+
invoked with an explicit flag — now hard-fails `PACK_INVALID` instead of running; array-bench
|
|
173
|
+
packs already behaved this way, so this closes a bench-shape-dependent inconsistency rather
|
|
174
|
+
than introducing a new restriction.
|
|
175
|
+
- **The `{{var.}}` (empty variable key) template error now has a followable message.** It
|
|
176
|
+
previously told the user to run `--var =<value>` — a form the CLI's own `--var` parser rejects,
|
|
177
|
+
making the remedy unfollowable by construction; it now correctly explains that
|
|
178
|
+
`{{var.<key>}}` requires a key and lists the known variables.
|
|
179
|
+
- **`doctor`'s tmp-sweep checks no longer report a name-shaped directory as an unremovable
|
|
180
|
+
orphan.** A directory whose name happened to match the tmp-file pattern (e.g.
|
|
181
|
+
`.metadata.json.<pid>.<rand>.tmp`) was picked up by the orphan scan, then permanently failed to
|
|
182
|
+
unlink — parking the check at `warn` forever ("swept 0, N remaining (too fresh or
|
|
183
|
+
unremovable)") even after every real orphan was cleared. Directories are now excluded from
|
|
184
|
+
both sweeps (the metadata sweep, which never follows symlinks, also excludes
|
|
185
|
+
symlinks/sockets/FIFOs) before the scan ever returns them, so the check reports `ok` once
|
|
186
|
+
nothing real is left.
|
|
187
|
+
|
|
188
|
+
### Added (follow-up)
|
|
189
|
+
|
|
190
|
+
- **`amicus list --limit <n>`**: show only the *n* newest rows (`0` = unlimited, and absent
|
|
191
|
+
behaves exactly as before). When the cap elides rows it says so, naming the real total; in
|
|
192
|
+
`--json` mode that notice goes to stderr so stdout stays a single parseable document. Caps
|
|
193
|
+
output only — `--all` still enumerates every project, since capping the walk would rank rows it
|
|
194
|
+
never saw.
|
|
195
|
+
|
|
196
|
+
### CI
|
|
197
|
+
|
|
198
|
+
- **The MCP-Registry skip-check's version match is no longer a BRE with unescaped dots.**
|
|
199
|
+
`$VERSION` (a semver like `4.7.0`) was interpolated directly into the grep pattern, where an
|
|
200
|
+
unescaped `.` matches any character; the fail direction is fail-toward-skip (a false match
|
|
201
|
+
would silently drop a publish), so the dots are now backslash-escaped before matching. Not
|
|
202
|
+
exploitable in practice, but tightens the same idempotency check the v4.6.3 CI fix below
|
|
203
|
+
hardened.
|
|
204
|
+
|
|
205
|
+
### Fixed
|
|
206
|
+
|
|
207
|
+
- A pack file whose JSON body is not an object (`null`, an array, a bare number or string) used to
|
|
208
|
+
read as a *successful* load and then crash with an uncaught `TypeError` — `council run --pack` and
|
|
209
|
+
`pack show` both died, and `pack show --json` exited 0 with `"pack": null`. It is now a clean
|
|
210
|
+
`PACK_NOT_FOUND`.
|
|
211
|
+
- **The MCP `amicus_start` shared-server path skipped the budget gate entirely unless a pack set
|
|
212
|
+
`maxCost`.** It now gates unconditionally with the same `maxCost`/`maxCostPerMtok` config fallback
|
|
213
|
+
the CLI has always used. Runs that previously proceeded may now be refused — that is the fix.
|
|
214
|
+
- Budget refusal text is now surface-aware on the MCP `amicus_start` (shared-server) path: it no
|
|
215
|
+
longer names `--max-cost`/`--no-cost-gate`, flags that do not exist there. Other MCP-visible
|
|
216
|
+
refusals — the `amicus_start` spawn fallback and the fanout/council reservation hint recorded in
|
|
217
|
+
run docs — still carry CLI-flavoured text; that remainder is filed, not fixed here. On BOTH
|
|
218
|
+
surfaces the remedy now names only levers that can actually clear the branch that fired: raising
|
|
219
|
+
the ceiling was previously suggested for a per-$/Mtok refusal, which it could never clear.
|
|
220
|
+
- A council pack could set `options.timeout` to `true` or to a non-numeric string and have it reach
|
|
221
|
+
the engine — `validatePack` checks option key names, never value types, and the old post-merge
|
|
222
|
+
check was `timeout <= 0`, which `true` passes by coercing to `1`. Such a pack now exits 1.
|
|
223
|
+
- `--cwd` typed without a value parsed as boolean `true` and reached 16 consumer sites — crashing
|
|
224
|
+
`council run` with a raw `TypeError` and silently resolving templates against `<cwd>/true`. It now
|
|
225
|
+
exits 1 at the entry point. Same treatment for `council run`'s `--out-dir`, `--claude-review`,
|
|
226
|
+
`--run-id`, and `--timeout` (which also accepted `NaN`).
|
|
227
|
+
- **`council run --out-dir` could write outside the project.** The MCP path has been fenced since
|
|
228
|
+
v4.5; the CLI now applies the same containment check.
|
|
229
|
+
- A council member whose model name collides with an `Object.prototype` key (`toString`,
|
|
230
|
+
`constructor`, …) crashed the Workspace seats repaint and every live tick after it.
|
|
231
|
+
|
|
232
|
+
### Added (v4.7 PR7)
|
|
233
|
+
|
|
234
|
+
- **The seats table's trailing flag column marks a seat that was retried and stayed failed**
|
|
235
|
+
(PR1F-4): `↻ retried once`, on the errored seat's own primary cost row. Previously that
|
|
236
|
+
information only existed on a dead-seat row the v4.7 CA-4 convergence now suppresses, so it had
|
|
237
|
+
no home at all; a status-cell suffix was rejected because a dead seat's row can legitimately
|
|
238
|
+
carry `status: 'complete'`, and `complete — retried once` reads as "it finished, twice." Terminal
|
|
239
|
+
path only (`seatsFromRunStats`) — a seat retried while its run is still live shows no marker
|
|
240
|
+
until the run finishes.
|
|
241
|
+
|
|
242
|
+
### Fixed (v4.7 PR7)
|
|
243
|
+
|
|
244
|
+
- **Four stale-paint paths in the workspace prose panels, plus three unhandled-rejection sites,
|
|
245
|
+
closed together (T19-m1/T19-m2).** A panel could repaint stale content after a
|
|
246
|
+
close/flip-blind/reopen sequence, after two loads landed out of order, after the same run's
|
|
247
|
+
artifact manifest grew mid-flight, or after being collapsed mid-flight and reopened; separately,
|
|
248
|
+
three fire-and-forget panel-load promises could reject uncaught. Fixed behind a new
|
|
249
|
+
`workspace-lazy.js` extraction: an unconditional panel-cache drop on every issue, a monotonic
|
|
250
|
+
per-panel issue token so only the newest in-flight load can paint, two-argument
|
|
251
|
+
`.then(ok, fail)` termination on every load promise (with an announced eviction and a self-check
|
|
252
|
+
against a stale cache write), and a sync-safe wrap around the matrix drill-in call so a
|
|
253
|
+
synchronous throw still surfaces instead of escaping uncaught. Worth recording honestly: the
|
|
254
|
+
collapse-mid-flight path was not closed by the cache-drop half — that half *converted* it from a
|
|
255
|
+
deterministic stale paint into a race, by orphaning a still-in-flight load that no longer had a
|
|
256
|
+
cache entry to fence it. The issue token is what actually closes it. Both land in the same commit
|
|
257
|
+
series, so no released state ever carried the race.
|
|
258
|
+
- **`amicus_fanout`'s wave briefing is now the rendered prompt, not the raw one** (W1-M4),
|
|
259
|
+
matching the parity the `amicus_start` in-process path already had. Previously a spawned child
|
|
260
|
+
that aborted before rendering its own copy left `briefing.md` — the file
|
|
261
|
+
`amicus list --search`/`amicus read` treat as the wave's search corpus — permanently holding
|
|
262
|
+
unrendered template markup. **Behaviour change:** a wave launched from a pack that forwards a
|
|
263
|
+
`template` now writes a second file into the wave dir, `briefing-input.md` (the raw prompt handed
|
|
264
|
+
to the spawned child so its own render still drives `promptMeta.template` provenance), and
|
|
265
|
+
`--search` now matches the rendered text even for a wave whose MCP-spawned child aborted early —
|
|
266
|
+
previously it matched nothing meaningful in that case; the same rendered excerpt (first 200
|
|
267
|
+
characters) is also seeded into `metadata.json` at creation for every MCP fan-out wave, pack or
|
|
268
|
+
not, so `amicus list`'s BRIEFING column is populated for an aborted wave too, not just a
|
|
269
|
+
completed one. `amicus_start`'s identical divergence
|
|
270
|
+
(`mcp-server.js:669`) is unchanged; nobody has driven that path end to end yet, so it is filed in
|
|
271
|
+
`BACKLOG.md`, not fixed here.
|
|
272
|
+
- **`amicus_fanout` now rejects an empty prompt or a non-positive timeout before creating anything
|
|
273
|
+
on disk**, closing the one remaining pid-less `status: 'running'` orphan-wave class the schema
|
|
274
|
+
didn't already cover. **Behaviour change:** a request shaped like `{prompt: '', ...}` or
|
|
275
|
+
`{timeout: -1, ...}` previously created a wave directory and spawned a child that then failed on
|
|
276
|
+
its own terms; it now returns a plain-text error and creates nothing. The Zod schema closes this
|
|
277
|
+
for one entry point (`prompt: z.string().min(1, …)`, `timeout: z.number().positive(…)`); a second,
|
|
278
|
+
identical check lives in the handler itself, after pack merge, because a pack can push the same
|
|
279
|
+
invalid values through a door the schema never sees (`validatePack` checks option key names, not
|
|
280
|
+
value types).
|
|
281
|
+
|
|
282
|
+
### Changed (v4.7 PR7)
|
|
283
|
+
|
|
284
|
+
- **The budget-refusal text recorded in a run/wave doc's degrade record is now surface-neutral**
|
|
285
|
+
(PR6F-1), since that doc is read by both the CLI and MCP: "the $N cost ceiling for this run
|
|
286
|
+
refused it" / "Raise this run's cost ceiling, or turn the cost gate off, to seat them," in place
|
|
287
|
+
of CLI-flavoured `--max-cost`/`--no-cost-gate` wording that named flags an MCP caller cannot type.
|
|
288
|
+
A separate, structurally-unreachable copy of the same CLI-flavoured trailer (nothing ever renders
|
|
289
|
+
its `hint` on that path) was removed rather than reworded.
|
|
290
|
+
|
|
291
|
+
## [4.6.3] - 2026-08-05
|
|
292
|
+
|
|
293
|
+
### Added
|
|
294
|
+
|
|
295
|
+
- **`fable` now carries an authored direct-Anthropic route** (`anthropic/claude-fable-5`,
|
|
296
|
+
verified live: Anthropic's `/v1/models` lists it and a direct leg serves). With an
|
|
297
|
+
Anthropic key present, `fable` routes direct-first like the other Anthropic aliases;
|
|
298
|
+
the `ANTHROPIC_MODELS` floor gains a matching row so keyless installs validate it.
|
|
299
|
+
- **`doctor` gains a `session-metadata-tmp` check; `--fix` sweeps the orphans.** A kill
|
|
300
|
+
between an atomic write's tmp-file and rename leaves `.metadata.json.*.tmp` orphans in
|
|
301
|
+
per-session directories (the B09 class — ~30 write sites). Plain `doctor` reports them;
|
|
302
|
+
`--fix` removes orphans older than 60 s from the current project's sessions root and
|
|
303
|
+
announces the heal in the one voice (`Recovered: …`).
|
|
304
|
+
- **`council save` announces when it shadows a built-in bench.** Saving a council named
|
|
305
|
+
`free`/`budget`/`frontier` previously printed no notice at all (the overwrite marker only
|
|
306
|
+
tracked user-config names); the save now reports `shadowsBuiltin` (`--json`) and prints
|
|
307
|
+
the shadow notice.
|
|
308
|
+
|
|
309
|
+
### Fixed
|
|
310
|
+
|
|
311
|
+
- **`models --check` no longer false-flags deliberate gateway-only routes.** A curated
|
|
312
|
+
alias whose direct form is derived (not authored) from its OpenRouter route is no
|
|
313
|
+
longer reported STALE — flat row, `GATEWAY STALE` row, candidates, and the
|
|
314
|
+
`fix: --add-alias` retarget suggestion all suppressed together — when the OpenRouter
|
|
315
|
+
route still serves. Deliberately gateway-only entries (`gpt-pro`) are annotated in
|
|
316
|
+
the curated data and never audited for a direct sibling. Kills the v4.6.2
|
|
317
|
+
release-gate false positive whose suggested "fix" was a silent tier downgrade.
|
|
318
|
+
- **The Workspace seats panel's dead-seat rows are now role-aware and old-run
|
|
319
|
+
resilient.** A model that died as critic but succeeded as chair no longer has
|
|
320
|
+
its dead row hidden by the chair's cost row (only a live reviewing leg —
|
|
321
|
+
seat/critic/lens — suppresses, and a dead critic only by a live critic leg);
|
|
322
|
+
the dead critic's row names its role. Pre-v4.6 runs render their losses too:
|
|
323
|
+
`verdict.seatLoss.deadBenchSeats` feeds rows, and `verdict.json`'s
|
|
324
|
+
`degrades[]` backstops a `run.json` that lost its checkpoint. A stale
|
|
325
|
+
`get-run` reply from a run you navigated away from can no longer repaint the
|
|
326
|
+
run now open.
|
|
327
|
+
- **A valueless `-o`/`--out` on `council verdict` now errors** (`BAD_ARGS`, flag named,
|
|
328
|
+
exit 1) instead of crashing mid-write (renameSync `TypeError`) and orphaning a
|
|
329
|
+
`true.tmp-<pid>` temp file. Behavior change, per the v4.6.3 R1 ruling.
|
|
330
|
+
- **README corrections from the v4.6.3 accuracy review**: the Node.js floor is
|
|
331
|
+
22.12 (required since v3.0 — the README, install scripts, landing page, and
|
|
332
|
+
`amicus doctor`'s node check still said 18), and the optional-council-elements
|
|
333
|
+
list now matches the shipped skill (four opt-ins; the chair's verdict scale
|
|
334
|
+
has been standard, not opt-in). The doctor's `node` row now errors below
|
|
335
|
+
22.12 (it previously passed anything ≥ 18).
|
|
336
|
+
|
|
337
|
+
### CI
|
|
338
|
+
|
|
339
|
+
- **The MCP-Registry skip-check now verifies the version it trusts.** The
|
|
340
|
+
release workflow's idempotency pre-check previously skipped registry publish
|
|
341
|
+
on a bare HTTP 200; it now also requires the response body to both name the
|
|
342
|
+
exact version and report it as `active`, so preview-API schema churn — or a
|
|
343
|
+
stale/deprecated registry entry — can no longer produce a false skip. Every
|
|
344
|
+
new failure mode still routes toward publishing.
|
|
345
|
+
|
|
8
346
|
## [4.6.2] - 2026-08-05
|
|
9
347
|
|
|
10
348
|
### Added
|
|
@@ -91,6 +429,17 @@ All notable changes to Amicus are documented here. Format follows
|
|
|
91
429
|
with replacement suggestions by `models --check` / `doctor`. This was the pin that made
|
|
92
430
|
`models --check` exit 1 — the v4.6.2 release-gate risk.
|
|
93
431
|
|
|
432
|
+
### CI
|
|
433
|
+
|
|
434
|
+
- **The macOS/node-24 unit leg now runs jest with `--workerIdleMemoryLimit=1GB`.** That leg —
|
|
435
|
+
and only that leg — intermittently lost a worker to a native SIGSEGV ("A jest worker process
|
|
436
|
+
was terminated by another process"), which fails whichever suite occupied the worker with
|
|
437
|
+
zero assertion failures and a green rerun. Three confirmed hits (2026-07-31
|
|
438
|
+
run-cost-unknown, 2026-08-04 PR #100 update-notice, 2026-08-05 PR #105 — 6466 passed, the
|
|
439
|
+
dead worker alone failed 1 suite) tripped the standing third-occurrence rule. The limit
|
|
440
|
+
makes jest recycle an idle worker before the leak reaches segfault territory; the flag is
|
|
441
|
+
injected via a matrix `include`, so the other five legs still run a bare `npm test`.
|
|
442
|
+
|
|
94
443
|
## [4.6.1] - 2026-08-03
|
|
95
444
|
|
|
96
445
|
### Added
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**A multi-model LLM Council for Claude — with a parallel AI window underneath.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<p align="center"><img src="./docs/cards/council-hero.svg" width="560" alt="The Amicus council ritual across three convenings: independent review spokes, anonymous cross-review, and a non-Claude chair synthesizing the verdict — the third convening seats a local Qwen2.5-Coder on-device alongside cloud peers"></p>
|
|
8
8
|
|
|
9
9
|
Hand Claude a plan, a design, a diff, an architecture decision, a manuscript — anything — and say *council review this*: Amicus routes it through several models from different families, has them anonymously cross-review each other, and a non-Claude chair synthesizes a verdict you turn into accept/deny edits. Or skip the ceremony and **fork** a single conversation to Gemini, GPT, DeepSeek, or any other model — it works in parallel with full context, and you **fold** the result back when you're ready. Claude orchestrates throughout; you stay in your editor.
|
|
10
10
|
|
|
@@ -12,7 +12,7 @@ Hand Claude a plan, a design, a diff, an architecture decision, a manuscript —
|
|
|
12
12
|
|
|
13
13
|
[](https://www.npmjs.com/package/amicus)
|
|
14
14
|
[](./LICENSE)
|
|
15
|
-
[](https://nodejs.org)
|
|
16
16
|
[](./CONTRIBUTING.md)
|
|
17
17
|
|
|
18
18
|
**[Quick start ↓](#quick-start)** · [Commands](#commands) · [Documentation](#documentation) · [Troubleshooting](#troubleshooting)
|
|
@@ -62,7 +62,7 @@ One install delivers six things that work together:
|
|
|
62
62
|
|
|
63
63
|
Claude is the orchestrator. The council and chat skills run *on top of* the engine; you talk to Claude, and Claude drives Amicus.
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
<p align="center"><img src="./docs/cards/what-is-amicus.svg" alt="One install: the second-opinion council and sidecar skills riding the amicus CLI + MCP engine, with the live model catalog, watch/spend, and Council Workspace fed off it"></p>
|
|
66
66
|
|
|
67
67
|
---
|
|
68
68
|
|
|
@@ -89,6 +89,8 @@ flowchart LR
|
|
|
89
89
|
E --> F["Reviewed copy<br/>+ run folder"]
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
+
<p align="center"><img src="./docs/cards/blind-ballots.svg" width="520" alt="Anonymized cross-review: reviews are relabeled A, B, C before the bench ranks them — one model disputes its own review"></p>
|
|
93
|
+
|
|
92
94
|
**What a run produces** (in `output/<stem>-council/`):
|
|
93
95
|
|
|
94
96
|
- `review-<model>.md` × N — each model's independent review.
|
|
@@ -99,14 +101,15 @@ flowchart LR
|
|
|
99
101
|
findings-by-tier, cost — no chair prose). This is the default artifact handed to the user.
|
|
100
102
|
- For an **editable source**, the accepted edits land in `<stem>-reviewed.<ext>` next to the original.
|
|
101
103
|
|
|
102
|
-
**Optional council elements** (v2.2.0, all default off):
|
|
104
|
+
**Optional council elements** (v2.2.0, all default off): four 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. **Chair verdict scale** *(standard since v2.2.0's follow-ups — no longer opt-in)*: the chair always closes with 3–5 hard questions and one parseable `VERDICT: Ship it | Fix these first | Fundamental rethink` line.
|
|
103
105
|
|
|
104
106
|
- **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
107
|
- **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
108
|
- **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
109
|
- **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
|
|
|
111
|
+
<p align="center"><img src="./docs/cards/dial-it-up.svg" alt="The four opt-in council elements as toggles — critic seat and debate on, expert lenses and Claude-in-the-council off — with the up-front run-shape disclosure"></p>
|
|
112
|
+
|
|
110
113
|
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
114
|
|
|
112
115
|
**Cost is disclosed up front.** Before any model launches, you see the run shape — including any enabled optional elements — for example:
|
|
@@ -115,6 +118,8 @@ The critic and lens methodologies are adapted from the `/critic` and `/debate` a
|
|
|
115
118
|
|
|
116
119
|
Then the council waits for your confirmation.
|
|
117
120
|
|
|
121
|
+
<p align="center"><img src="./docs/cards/priced-up-front.svg" width="520" alt="The budget gate: a $0.42 run passes, a $31.80 bench is blocked, and the receipt matches the estimate"></p>
|
|
122
|
+
|
|
118
123
|
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
124
|
|
|
120
125
|
---
|
|
@@ -128,10 +133,14 @@ The council is the hero — start with the everyday way, and reach for the more
|
|
|
128
133
|
- **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)
|
|
129
134
|
- **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)
|
|
130
135
|
|
|
136
|
+
<p align="center"><img src="./docs/cards/same-table.svg" width="520" alt="A local Ollama model seated as an equal council member at $0.00 — a member, not a mode"></p>
|
|
137
|
+
|
|
131
138
|
### Headless council (CI)
|
|
132
139
|
|
|
133
140
|
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
141
|
|
|
142
|
+
<p align="center"><img src="./docs/cards/ship-gate.svg" alt="A council gating a release pipeline: exit 0 ships it, exit 1 sends it back"></p>
|
|
143
|
+
|
|
135
144
|
### Free council (zero-cost)
|
|
136
145
|
|
|
137
146
|
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`.
|
|
@@ -192,7 +201,7 @@ Every path delivers the MCP server and both skills. They differ in what else you
|
|
|
192
201
|
|
|
193
202
|
#### With npm — recommended
|
|
194
203
|
|
|
195
|
-
The canonical path, and the one that gets you the full interactive experience (needs [Node.js](https://nodejs.org) ≥
|
|
204
|
+
The canonical path, and the one that gets you the full interactive experience (needs [Node.js](https://nodejs.org) ≥ 22.12):
|
|
196
205
|
|
|
197
206
|
```bash
|
|
198
207
|
npm install -g amicus
|
|
@@ -202,7 +211,7 @@ This is the path to pick unless you specifically want the plugin's slash command
|
|
|
202
211
|
|
|
203
212
|
#### With the install script
|
|
204
213
|
|
|
205
|
-
Same result as npm, one command — macOS, Linux, or Windows (needs [Node.js](https://nodejs.org) ≥
|
|
214
|
+
Same result as npm, one command — macOS, Linux, or Windows (needs [Node.js](https://nodejs.org) ≥ 22.12):
|
|
206
215
|
|
|
207
216
|
```bash
|
|
208
217
|
# macOS / Linux
|
|
@@ -333,7 +342,7 @@ Everything you need before your first run, and what's optional.
|
|
|
333
342
|
|
|
334
343
|
**Runtime**
|
|
335
344
|
|
|
336
|
-
- **Node.js ≥
|
|
345
|
+
- **Node.js ≥ 22.12** — `node --version` to check. This is the only hard runtime prerequisite.
|
|
337
346
|
- **An active Claude Code or Cowork session** — Amicus is orchestrated by Claude; it is not a standalone chatbot.
|
|
338
347
|
|
|
339
348
|
**Install path & the git toolchain**
|
|
@@ -398,7 +407,7 @@ When you don't need a full council — just one other model's take — fork a co
|
|
|
398
407
|
|---------|--------------|
|
|
399
408
|
| `amicus start` | Launch a new session (interactive or `--no-ui`). |
|
|
400
409
|
| `amicus fanout` | Run N models on the same prompt in parallel (headless). |
|
|
401
|
-
| `amicus list` | Show previous sessions. |
|
|
410
|
+
| `amicus list` | Show previous sessions — shows the `--tag <t>` set at launch, `--search <q>` filters, `--limit <n>` caps the rows, `--all` spans every known project. |
|
|
402
411
|
| `amicus resume` | Reopen a previous session with full history. |
|
|
403
412
|
| `amicus continue` | Start a new session building on a previous one. |
|
|
404
413
|
| `amicus read` | Output a session's summary / conversation / metadata. |
|
|
@@ -441,13 +450,13 @@ $ amicus status demo123 --json
|
|
|
441
450
|
"taskId": "demo123",
|
|
442
451
|
"status": "complete",
|
|
443
452
|
"elapsed": "5m 0s",
|
|
444
|
-
"version": "4.
|
|
453
|
+
"version": "4.7.0",
|
|
445
454
|
"model": "google/gemini-2.5-flash",
|
|
446
455
|
"phase": "terminal"
|
|
447
456
|
}
|
|
448
457
|
```
|
|
449
458
|
|
|
450
|
-
`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).
|
|
459
|
+
`amicus list --status` accepts `running`, `complete`, `error`, `timed-out`, `aborted`, `crashed`, `idle-timeout`. Rows carry a `TAG` column (set at launch with `--tag <t>`); `--search <q>` filters by id/tag/briefing substring, `--limit <n>` caps the row count (0 = unlimited), and `--all` lists across every known project. 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).
|
|
451
460
|
|
|
452
461
|
---
|
|
453
462
|
|
|
@@ -462,6 +471,8 @@ amicus models --search gemini # filter by substring
|
|
|
462
471
|
|
|
463
472
|
`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 model ID directly — bare `provider/model` (canonical) or `openrouter/provider/model` (explicit override); see Routing below. Catalog internals, alias management, and the full-id passthrough table are in **[docs/usage.md § Models](./docs/usage.md#amicus-models--the-model-catalog)**.
|
|
464
473
|
|
|
474
|
+
<p align="center"><img src="./docs/cards/build-the-bench.svg" alt="Direct keys, one OpenRouter key, or local runtimes seat a mixed bench — different families, different blind spots"></p>
|
|
475
|
+
|
|
465
476
|
### Routing
|
|
466
477
|
|
|
467
478
|
- **Bare `provider/model`** (e.g. `openai/gpt-5.5`, `anthropic/claude-opus-4-8`, `google/gemini-3.6-flash`) is the canonical, policy-routed form — Amicus routes it **direct-first**: your direct provider key when one is configured, falling back to OpenRouter automatically when only an OpenRouter key exists.
|
|
@@ -475,7 +486,7 @@ Full details, the API-key/prefix table, and the migration notice are in **[docs/
|
|
|
475
486
|
|
|
476
487
|
## MCP integration
|
|
477
488
|
|
|
478
|
-
The MCP server is auto-registered on install (Claude Code and Claude Desktop / Cowork). It exposes
|
|
489
|
+
The MCP server is auto-registered on install (Claude Code and Claude Desktop / Cowork). It exposes these tools:
|
|
479
490
|
|
|
480
491
|
| Tool | What it does |
|
|
481
492
|
|------|--------------|
|
|
@@ -483,7 +494,7 @@ The MCP server is auto-registered on install (Claude Code and Claude Desktop / C
|
|
|
483
494
|
| `amicus_status` | Poll a task (or a fanout wave) for completion. |
|
|
484
495
|
| `amicus_wait` | Block inside one tool call until a session/wave finishes or the wait window closes. |
|
|
485
496
|
| `amicus_read` | Read results: summary, conversation, metadata, or JSON. |
|
|
486
|
-
| `amicus_list` | List past sessions. |
|
|
497
|
+
| `amicus_list` | List past sessions (`tag` field; `search` filters by id/tag/briefing substring). |
|
|
487
498
|
| `amicus_resume` | Reopen a session. |
|
|
488
499
|
| `amicus_continue` | New session building on a previous one. |
|
|
489
500
|
| `amicus_abort` | Stop a running session. |
|
package/bin/amicus.js
CHANGED
|
@@ -23,6 +23,8 @@ const { handleResume, handleContinue } = require('../src/cli-handlers-resume-con
|
|
|
23
23
|
const { isOneShotCommand, armExitWatchdog } = require('../src/utils/lifecycle');
|
|
24
24
|
const { suggestCommand } = require('../src/utils/input-validators');
|
|
25
25
|
const { unknownFlags, getKnownFlags } = require('../src/utils/known-flags');
|
|
26
|
+
const { packSaveVersionConflict } = require('../src/utils/cli-preflight');
|
|
27
|
+
const { failJson } = require('../src/utils/error-doc');
|
|
26
28
|
const { logger } = require('../src/utils/logger');
|
|
27
29
|
|
|
28
30
|
const VERSION = require('../package.json').version;
|
|
@@ -53,6 +55,23 @@ async function main() {
|
|
|
53
55
|
process.exit(1);
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
// `--cwd` typed with no value parses as boolean `true` (src/cli.js:101) and
|
|
59
|
+
// `--cwd=` as '' (src/cli.js:72). DEFAULTS (src/cli.js:28) always seeds a
|
|
60
|
+
// real absolute string, so a non-string or empty cwd can ONLY mean "typed
|
|
61
|
+
// without a value" — which makes this guard provably free of false
|
|
62
|
+
// positives. Left unguarded it reached 16 `args.cwd || process.cwd()`
|
|
63
|
+
// sites across 9 handlers: council run threw a raw TypeError, template
|
|
64
|
+
// silently resolved <cwd>/true.
|
|
65
|
+
// No dash check here: absolute paths never start with '-', and
|
|
66
|
+
// `--cwd ./x` is legitimate.
|
|
67
|
+
if (typeof args.cwd !== 'string' || args.cwd === '') {
|
|
68
|
+
console.error('Error: --cwd requires a value');
|
|
69
|
+
console.error(command
|
|
70
|
+
? `Run \`amicus ${command} --help\` to see valid options.`
|
|
71
|
+
: 'Run `amicus --help` to see valid options.');
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
56
75
|
// Install crash handler for MCP-spawned processes (have --task-id)
|
|
57
76
|
if (args['task-id'] && (command === 'start' || command === 'continue')) {
|
|
58
77
|
const { installCrashHandler } = require('../src/sidecar/crash-handler');
|
|
@@ -86,6 +105,16 @@ async function main() {
|
|
|
86
105
|
}
|
|
87
106
|
}
|
|
88
107
|
|
|
108
|
+
// `pack save` documents a per-pack `--pack-version <semver>`. `--version` is a
|
|
109
|
+
// global BOOLEAN_FLAG, so `pack save … --version 2.0.0` used to fall straight
|
|
110
|
+
// into the banner below: exit 0, no pack written, the semver stranded in
|
|
111
|
+
// positionals. Reject that one combination by name instead of silently doing
|
|
112
|
+
// something else; every other --version still prints the banner.
|
|
113
|
+
const versionConflict = packSaveVersionConflict(args);
|
|
114
|
+
if (versionConflict) {
|
|
115
|
+
process.exit(failJson(!!args.json, versionConflict));
|
|
116
|
+
}
|
|
117
|
+
|
|
89
118
|
// Handle --version
|
|
90
119
|
if (args.version) {
|
|
91
120
|
console.log(`amicus v${VERSION}`);
|
|
@@ -221,6 +250,8 @@ async function handleList(args) {
|
|
|
221
250
|
status: args.status,
|
|
222
251
|
all: args.all,
|
|
223
252
|
json: args.json,
|
|
253
|
+
search: args.search,
|
|
254
|
+
limit: args.limit,
|
|
224
255
|
project: args.cwd
|
|
225
256
|
});
|
|
226
257
|
}
|