amicus 4.6.1 → 4.6.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 +152 -0
- package/README.md +7 -8
- package/docs/ROADMAP.md +38 -4
- package/docs/configuration.md +18 -12
- package/docs/council.md +7 -2
- package/docs/troubleshooting.md +49 -20
- package/docs/usage.md +30 -3
- package/electron/setup-ui-aliases.js +2 -2
- package/electron/workspace-ui/index.html +3 -0
- package/electron/workspace-ui/live-model.js +146 -2
- package/electron/workspace-ui/workspace-app.js +8 -3
- package/electron/workspace-ui/workspace-panels.js +9 -10
- package/electron/workspace-ui/workspace-render.js +9 -3
- package/electron/workspace-ui/workspace-seats.js +132 -0
- package/electron/workspace-ui/workspace-verbs.js +2 -1
- package/electron/workspace-ui/workspace.css +6 -0
- package/package.json +1 -1
- package/schemas/alias-audit.schema.json +6 -1
- package/schemas/council-run.schema.json +14 -0
- package/src/cli-handlers-council.js +9 -0
- package/src/cli-handlers-doctor.js +25 -7
- package/src/cli.js +4 -0
- package/src/council/presets-cli.js +6 -2
- package/src/council/run-chair.js +55 -6
- package/src/headless.js +119 -9
- package/src/mcp-council-awareness.js +1 -0
- package/src/opencode-client.js +21 -0
- package/src/session-manager.js +6 -2
- package/src/sidecar/fanout-leg.js +2 -2
- package/src/sidecar/fanout.js +1 -1
- package/src/sidecar/models-probe.js +119 -0
- package/src/sidecar/models.js +81 -6
- package/src/utils/alias-audit.js +71 -1
- package/src/utils/base-url-classify.js +74 -0
- package/src/utils/council-presets.js +6 -2
- package/src/utils/curated-models.js +71 -16
- package/src/utils/doctor-base-url-check.js +41 -0
- package/src/utils/gateway-route-audit.js +16 -3
- package/src/utils/model-fetcher.js +9 -6
- package/src/utils/model-tiers.js +28 -7
- package/src/utils/no-output-backstop.js +48 -0
- package/src/utils/remediation-hints.js +14 -0
- package/src/utils/result-schema.js +29 -2
- package/src/utils/session-metadata-tmp-sweep.js +136 -0
- package/src/workspace/live-normalize.js +1 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amicus",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.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
|
@@ -5,6 +5,158 @@ All notable changes to Amicus are documented here. Format follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [4.6.3] - 2026-08-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`fable` now carries an authored direct-Anthropic route** (`anthropic/claude-fable-5`,
|
|
13
|
+
verified live: Anthropic's `/v1/models` lists it and a direct leg serves). With an
|
|
14
|
+
Anthropic key present, `fable` routes direct-first like the other Anthropic aliases;
|
|
15
|
+
the `ANTHROPIC_MODELS` floor gains a matching row so keyless installs validate it.
|
|
16
|
+
- **`doctor` gains a `session-metadata-tmp` check; `--fix` sweeps the orphans.** A kill
|
|
17
|
+
between an atomic write's tmp-file and rename leaves `.metadata.json.*.tmp` orphans in
|
|
18
|
+
per-session directories (the B09 class — ~30 write sites). Plain `doctor` reports them;
|
|
19
|
+
`--fix` removes orphans older than 60 s from the current project's sessions root and
|
|
20
|
+
announces the heal in the one voice (`Recovered: …`).
|
|
21
|
+
- **`council save` announces when it shadows a built-in bench.** Saving a council named
|
|
22
|
+
`free`/`budget`/`frontier` previously printed no notice at all (the overwrite marker only
|
|
23
|
+
tracked user-config names); the save now reports `shadowsBuiltin` (`--json`) and prints
|
|
24
|
+
the shadow notice.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **`models --check` no longer false-flags deliberate gateway-only routes.** A curated
|
|
29
|
+
alias whose direct form is derived (not authored) from its OpenRouter route is no
|
|
30
|
+
longer reported STALE — flat row, `GATEWAY STALE` row, candidates, and the
|
|
31
|
+
`fix: --add-alias` retarget suggestion all suppressed together — when the OpenRouter
|
|
32
|
+
route still serves. Deliberately gateway-only entries (`gpt-pro`) are annotated in
|
|
33
|
+
the curated data and never audited for a direct sibling. Kills the v4.6.2
|
|
34
|
+
release-gate false positive whose suggested "fix" was a silent tier downgrade.
|
|
35
|
+
- **The Workspace seats panel's dead-seat rows are now role-aware and old-run
|
|
36
|
+
resilient.** A model that died as critic but succeeded as chair no longer has
|
|
37
|
+
its dead row hidden by the chair's cost row (only a live reviewing leg —
|
|
38
|
+
seat/critic/lens — suppresses, and a dead critic only by a live critic leg);
|
|
39
|
+
the dead critic's row names its role. Pre-v4.6 runs render their losses too:
|
|
40
|
+
`verdict.seatLoss.deadBenchSeats` feeds rows, and `verdict.json`'s
|
|
41
|
+
`degrades[]` backstops a `run.json` that lost its checkpoint. A stale
|
|
42
|
+
`get-run` reply from a run you navigated away from can no longer repaint the
|
|
43
|
+
run now open.
|
|
44
|
+
- **A valueless `-o`/`--out` on `council verdict` now errors** (`BAD_ARGS`, flag named,
|
|
45
|
+
exit 1) instead of crashing mid-write (renameSync `TypeError`) and orphaning a
|
|
46
|
+
`true.tmp-<pid>` temp file. Behavior change, per the v4.6.3 R1 ruling.
|
|
47
|
+
- **README corrections from the v4.6.3 accuracy review**: the Node.js floor is
|
|
48
|
+
22.12 (required since v3.0 — the README, install scripts, landing page, and
|
|
49
|
+
`amicus doctor`'s node check still said 18), and the optional-council-elements
|
|
50
|
+
list now matches the shipped skill (four opt-ins; the chair's verdict scale
|
|
51
|
+
has been standard, not opt-in). The doctor's `node` row now errors below
|
|
52
|
+
22.12 (it previously passed anything ≥ 18).
|
|
53
|
+
|
|
54
|
+
### CI
|
|
55
|
+
|
|
56
|
+
- **The MCP-Registry skip-check now verifies the version it trusts.** The
|
|
57
|
+
release workflow's idempotency pre-check previously skipped registry publish
|
|
58
|
+
on a bare HTTP 200; it now also requires the response body to both name the
|
|
59
|
+
exact version and report it as `active`, so preview-API schema churn — or a
|
|
60
|
+
stale/deprecated registry entry — can no longer produce a false skip. Every
|
|
61
|
+
new failure mode still routes toward publishing.
|
|
62
|
+
|
|
63
|
+
## [4.6.2] - 2026-08-05
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
- **Headless legs now fail fast when a model produces nothing.** A leg that produces zero
|
|
68
|
+
output, reasoning, or tool calls for `AMICUS_NO_OUTPUT_BACKSTOP_MS` (120 s default,
|
|
69
|
+
env-tunable) is failed with `NO_OUTPUT_BACKSTOP: …` instead of burning the full `--timeout`
|
|
70
|
+
to learn nothing — the "accepted but not serving" class. Disarms permanently on the first
|
|
71
|
+
sign of activity, so slow cold-prefill local models are unaffected; `0` (or negative)
|
|
72
|
+
disables it.
|
|
73
|
+
- **`doctor` gains a new `anthropic-base-url` row.** Prints the exact `ANTHROPIC_BASE_URL` the
|
|
74
|
+
process sees and how it will be treated — the host-form value can live only in a parent
|
|
75
|
+
process's environment, so the seen value is the only diagnostic there is.
|
|
76
|
+
- **Host-form `ANTHROPIC_BASE_URL` is now carried into the engine as `<value>/v1` by default**
|
|
77
|
+
(a provider-config override — zero env vars written; announced once per process).
|
|
78
|
+
Host-form is the Anthropic-SDK convention (the SDK appends `/v1` itself), but OpenCode's
|
|
79
|
+
provider layer treats the value as the full prefix, so unnormalized host-form previously
|
|
80
|
+
404'd every direct-Anthropic leg. `AMICUS_BASE_URL_NORMALIZE=0` disables normalization
|
|
81
|
+
entirely.
|
|
82
|
+
- **`models --check` and the `doctor` aliases row now flag stored-alias drift**: a stored alias
|
|
83
|
+
that's still catalog-listed but no longer matches any route its family currently resolves to
|
|
84
|
+
(the v4.6.1 `gemini` release-gate class), with the exact `setup --add-alias` refresh command.
|
|
85
|
+
- **`models --check` gains an opt-in `--live` probe.** `--check --live` sends one real, tiny
|
|
86
|
+
request to every *stored* alias (curated defaults are out of scope) on a single quiet fan-out
|
|
87
|
+
wave and reports `SERVED` / `SILENT` (`accepted-but-silent`) / `ERROR` per alias — the
|
|
88
|
+
on-demand version of the check that would have caught the v4.6.1 `gemini` incident (a
|
|
89
|
+
catalog-listed model no longer actually served). Spends real money: one tiny leg per stored
|
|
90
|
+
alias. Non-served outcomes fold into the existing exit code; a stored-alias count above the
|
|
91
|
+
fan-out leg cap (`AMICUS_FANOUT_MAX_LEGS`) fails fast before anything is probed. When the
|
|
92
|
+
probe can't run (catalog unavailable, or `--refresh` also passed), Amicus announces the skip
|
|
93
|
+
instead of silently dropping the flag.
|
|
94
|
+
- **The Council Workspace seats panel now shows seats a run announced dead.** The **Seats**
|
|
95
|
+
table appends a row for every seat with zero usable legs — derived from `run.json`'s
|
|
96
|
+
`degrades[]` (dead-leg/dead-wave records) and the critic's `verdict.seatLoss` — with a
|
|
97
|
+
blind-maskable model name (a dead seat has no anonymity label, so blind mode renders
|
|
98
|
+
`(masked)` rather than leak the raw id), `did not review — retried once` (the degrade
|
|
99
|
+
recorded a `retryWaveId`) or plain `did not review`, no cost cell, and muted seat-dead
|
|
100
|
+
styling. Dead rows appear live, mid-poll: as soon as the run checkpoints the loss — always
|
|
101
|
+
post-retry, so a row never lands before the seat's one shot at recovery is spent — it paints
|
|
102
|
+
and stays through every tick after (immediately for a dead-wave seat; at that stage's
|
|
103
|
+
boundary for a dead-leg seat, since the panel keeps suppressing the row while the seat's own
|
|
104
|
+
errored-leg entry is still listed live); the run's terminal refresh then additionally unions
|
|
105
|
+
the critic's `seatLoss` on top, for any loss the live payload alone didn't carry.
|
|
106
|
+
- **The chair fallback walk now records every attempt on `run.json`.** Each leg it tries — `ch1`
|
|
107
|
+
(the requested chair), `ch2` (a same-chair retry), `ch3` (the ledger-promoted fallback) —
|
|
108
|
+
appends an entry to an additive `chairAttempts[]` array (`{waveId, model, outcome, reason}`,
|
|
109
|
+
`outcome ∈ completed|error|timeout|no-output`), checkpointed after every attempt so a mid-walk
|
|
110
|
+
kill never loses what already ran. When no chair leg completes at all, the `chair-failed`
|
|
111
|
+
degrade's "What was lost" `why` now names each attempt's cause instead of one flat sentence —
|
|
112
|
+
`ch1 <model>: <reason> · ch2 <model>: <reason> · ...` — while a chair that ran but produced no
|
|
113
|
+
parseable VERDICT line keeps its original flat why (the walk didn't fail). The `ch4`
|
|
114
|
+
VERDICT-line repair re-prompt is deliberately not counted as an attempt — its chair leg already
|
|
115
|
+
completed; only the verdict line gets re-prompted.
|
|
116
|
+
|
|
117
|
+
### Fixed
|
|
118
|
+
|
|
119
|
+
- **The `gpt` quick-pick family stopped resolving once OpenAI split 5.6 into
|
|
120
|
+
tiers.** `idPattern` only matched bare numeric ids (`gpt-5.5`), so it missed
|
|
121
|
+
5.6 entirely — `gpt-5.6-sol` (premium), `gpt-5.6-terra` (mid), `gpt-5.6-luna`
|
|
122
|
+
(economy), and their `-pro` siblings all fell outside it, leaving the family
|
|
123
|
+
pinned to the older `gpt-5.5` and the owner's stored `gpt` alias reported as
|
|
124
|
+
DRIFTED. Per owner ruling, `gpt` now tracks the TERRA (mid) tier: the
|
|
125
|
+
pattern additionally matches `-terra` while still excluding `-terra-pro`,
|
|
126
|
+
`-sol*`, `-luna*`, and the unrelated `-codex` family; the pinned fallback
|
|
127
|
+
moves to `openrouter/openai/gpt-5.6-terra`. Bare numeric ids stay matched as
|
|
128
|
+
a within-family fallback.
|
|
129
|
+
- **The curated `opus` pin fell behind the live catalog.** Both routes move from Claude
|
|
130
|
+
Opus 4.8 to Claude Opus 5: `openrouter/anthropic/claude-opus-5` plus the authored
|
|
131
|
+
direct `anthropic/claude-opus-5` (verified against the live catalog and Anthropic docs
|
|
132
|
+
2026-08-04 — authored, never derived; anthropic stays in `DIVERGENT_VENDORS`). Same
|
|
133
|
+
live price, so the `frontier` bench's pricing evidence is unchanged. The offline
|
|
134
|
+
`ANTHROPIC_MODELS` floor gains a matching `anthropic/claude-opus-5` row so keyless and
|
|
135
|
+
offline installs never report the shipped default stale. Opus 5's two gateway forms
|
|
136
|
+
coincide (no dotted version segment), so the dot-vs-dash regression guards now ride
|
|
137
|
+
`haiku`, the surviving divergent-form alias.
|
|
138
|
+
|
|
139
|
+
### Removed
|
|
140
|
+
|
|
141
|
+
- **The `devstral` alias** (owner ruling 2026-08-04). OpenRouter delisted the entire
|
|
142
|
+
devstral family — zero matches across the live catalog, any vendor — and the alias had
|
|
143
|
+
no other route. No served model is a devstral successor, so the alias was dropped
|
|
144
|
+
rather than retargeted ("no pinned guess is better than a wrong one"); `mistral`
|
|
145
|
+
remains the vendor's alias, and a stored `devstral` alias in user config is flagged
|
|
146
|
+
with replacement suggestions by `models --check` / `doctor`. This was the pin that made
|
|
147
|
+
`models --check` exit 1 — the v4.6.2 release-gate risk.
|
|
148
|
+
|
|
149
|
+
### CI
|
|
150
|
+
|
|
151
|
+
- **The macOS/node-24 unit leg now runs jest with `--workerIdleMemoryLimit=1GB`.** That leg —
|
|
152
|
+
and only that leg — intermittently lost a worker to a native SIGSEGV ("A jest worker process
|
|
153
|
+
was terminated by another process"), which fails whichever suite occupied the worker with
|
|
154
|
+
zero assertion failures and a green rerun. Three confirmed hits (2026-07-31
|
|
155
|
+
run-cost-unknown, 2026-08-04 PR #100 update-notice, 2026-08-05 PR #105 — 6466 passed, the
|
|
156
|
+
dead worker alone failed 1 suite) tripped the standing third-occurrence rule. The limit
|
|
157
|
+
makes jest recycle an idle worker before the leak reaches segfault territory; the flag is
|
|
158
|
+
injected via a matrix `include`, so the other five legs still run a bare `npm test`.
|
|
159
|
+
|
|
8
160
|
## [4.6.1] - 2026-08-03
|
|
9
161
|
|
|
10
162
|
### Added
|
package/README.md
CHANGED
|
@@ -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)
|
|
@@ -99,12 +99,11 @@ flowchart LR
|
|
|
99
99
|
findings-by-tier, cost — no chair prose). This is the default artifact handed to the user.
|
|
100
100
|
- For an **editable source**, the accepted edits land in `<stem>-reviewed.<ext>` next to the original.
|
|
101
101
|
|
|
102
|
-
**Optional council elements** (v2.2.0, all default off):
|
|
102
|
+
**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
103
|
|
|
104
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
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
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
107
|
- **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
108
|
|
|
110
109
|
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).
|
|
@@ -192,7 +191,7 @@ Every path delivers the MCP server and both skills. They differ in what else you
|
|
|
192
191
|
|
|
193
192
|
#### With npm — recommended
|
|
194
193
|
|
|
195
|
-
The canonical path, and the one that gets you the full interactive experience (needs [Node.js](https://nodejs.org) ≥
|
|
194
|
+
The canonical path, and the one that gets you the full interactive experience (needs [Node.js](https://nodejs.org) ≥ 22.12):
|
|
196
195
|
|
|
197
196
|
```bash
|
|
198
197
|
npm install -g amicus
|
|
@@ -202,7 +201,7 @@ This is the path to pick unless you specifically want the plugin's slash command
|
|
|
202
201
|
|
|
203
202
|
#### With the install script
|
|
204
203
|
|
|
205
|
-
Same result as npm, one command — macOS, Linux, or Windows (needs [Node.js](https://nodejs.org) ≥
|
|
204
|
+
Same result as npm, one command — macOS, Linux, or Windows (needs [Node.js](https://nodejs.org) ≥ 22.12):
|
|
206
205
|
|
|
207
206
|
```bash
|
|
208
207
|
# macOS / Linux
|
|
@@ -333,7 +332,7 @@ Everything you need before your first run, and what's optional.
|
|
|
333
332
|
|
|
334
333
|
**Runtime**
|
|
335
334
|
|
|
336
|
-
- **Node.js ≥
|
|
335
|
+
- **Node.js ≥ 22.12** — `node --version` to check. This is the only hard runtime prerequisite.
|
|
337
336
|
- **An active Claude Code or Cowork session** — Amicus is orchestrated by Claude; it is not a standalone chatbot.
|
|
338
337
|
|
|
339
338
|
**Install path & the git toolchain**
|
|
@@ -441,7 +440,7 @@ $ amicus status demo123 --json
|
|
|
441
440
|
"taskId": "demo123",
|
|
442
441
|
"status": "complete",
|
|
443
442
|
"elapsed": "5m 0s",
|
|
444
|
-
"version": "4.6.
|
|
443
|
+
"version": "4.6.3",
|
|
445
444
|
"model": "google/gemini-2.5-flash",
|
|
446
445
|
"phase": "terminal"
|
|
447
446
|
}
|
|
@@ -552,7 +551,7 @@ Run `amicus doctor` first — it checks keys, catalog, OpenCode binary, Electron
|
|
|
552
551
|
| 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`. |
|
|
553
552
|
| `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). |
|
|
554
553
|
| `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. |
|
|
555
|
-
| 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
|
|
554
|
+
| 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 host-form `ANTHROPIC_BASE_URL` (missing `/v1`) — the Anthropic-SDK convention, not OpenCode's; a shell spawned by Claude Code sets it for you. **Since v4.6.2 amicus normalizes this to `<value>/v1` automatically** (a provider-config override, announced once on stderr) — the model id, alias, and key were never the problem, and now neither is the URL, unless `AMICUS_BASE_URL_NORMALIZE=0` is set or the path is nonstandard. | Should now self-heal — confirm with `amicus doctor`'s `anthropic-base-url` row (shows the value seen + its treatment). Still failing: unset `AMICUS_BASE_URL_NORMALIZE` if you set it, or `export ANTHROPIC_BASE_URL=https://api.anthropic.com/v1` / unset the var entirely / 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). |
|
|
556
555
|
| `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). |
|
|
557
556
|
| Session not found | No session matches the given ID | Run `amicus list`, or omit `--session-id` to use the most recent. |
|
|
558
557
|
| No conversation history found | Project-path encoding | Check `~/.claude/projects/`; `/` and `_` in the project path are encoded as `-` in the directory name. |
|
package/docs/ROADMAP.md
CHANGED
|
@@ -7,10 +7,10 @@ major jump, gated on funding/cofounder. The observability arc is split so the **
|
|
|
7
7
|
first (v4.3)** and the **Electron "Council Workspace" (v4.4)** rides on top of it. `--dry-run` cost
|
|
8
8
|
preview dropped to the backlog.
|
|
9
9
|
|
|
10
|
-
Amicus is at **v4.6.
|
|
10
|
+
Amicus is at **v4.6.2** (tagged 2026-08-05). Each 4.x rev below leads with the benefit, not the
|
|
11
11
|
plumbing.
|
|
12
12
|
|
|
13
|
-
**Status:** v4.0 through **v4.6.
|
|
13
|
+
**Status:** v4.0 through **v4.6.2** have **shipped** — everything down to the v4.7 heading is a
|
|
14
14
|
record of what landed, not a plan. **v4.7 (composition + tagging + GUI ergonomics) is the next
|
|
15
15
|
planned rev** — that scope carried the number v4.6 here until the degrade-announcement-invariant
|
|
16
16
|
milestone took the v4.6.0 release (2026-08-02); renumbered, not descoped. v5.0 remains
|
|
@@ -135,6 +135,40 @@ as hard as a crash.
|
|
|
135
135
|
> the user which one. That silent-degrade class was ruled a north-star violation and took the rev
|
|
136
136
|
> number; the composition scope below moved to v4.7.
|
|
137
137
|
|
|
138
|
+
**v4.6.1 (shipped 2026-08-03):** the follow-on point release — **SL-2** ("a lost seat gets one
|
|
139
|
+
more chance": the once-only Stage-1 retry with `Recovered:` heals, ruled heal-first off SL-3),
|
|
140
|
+
the **MCP update notice**, the `rebuildElectron` hint deletion, and the **fold-back-corrected
|
|
141
|
+
MODEL-NOTES seed** (PR #93). Ninth consecutive first-attempt publish.
|
|
142
|
+
|
|
143
|
+
### v4.6.1 / v4.6.2 — the field-report five *(patch train)* — ✅ SHIPPED v4.6.2, 2026-08-05
|
|
144
|
+
Field-report-driven hardening in five sequential PRs plus one ruling follow-up: the
|
|
145
|
+
`ANTHROPIC_BASE_URL` diagnosis pair (doctor row + host-form normalization) and stored-alias
|
|
146
|
+
drift warning (#95); doctor-suite hermeticity (#96); the no-output backstop —
|
|
147
|
+
`AMICUS_NO_OUTPUT_BACKSTOP_MS`, legs that produce nothing fail fast with a real reason (#99);
|
|
148
|
+
`models --check --live` — one quiet paid wave proves stored aliases actually SERVE (#100);
|
|
149
|
+
Workspace dead-seat rows — an announced-dead seat renders on the seats panel, live mid-poll
|
|
150
|
+
after the owner's ruling, blind-masked (#102, #103); chair-attempt records — the fallback walk
|
|
151
|
+
is diagnosable from `run.json` (`chairAttempts[]`, #105). The v4.6 announcement invariant now
|
|
152
|
+
reaches the surface users watch and the artifact they keep.
|
|
153
|
+
|
|
154
|
+
### v4.6.3 — the post-train sweep *(patch)* — ✅ SHIPPED v4.6.3, 2026-08-05
|
|
155
|
+
A four-PR correction patch: the models audit stops crying wolf, the seats panel stops being
|
|
156
|
+
fooled, and a handful of proven small defects land with tests.
|
|
157
|
+
- **Audit routing-choice + fable direct route** — `models --check` stops flagging deliberate
|
|
158
|
+
gateway-only routes like `gpt-pro` STALE (no more harmful downgrade suggestion); fable gains an
|
|
159
|
+
authored `anthropic/claude-fable-5` route and routes direct-first with an Anthropic key — #107
|
|
160
|
+
- **Role-aware, old-run-resilient dead-seat rows + openRun guard** — a model dead as critic but
|
|
161
|
+
alive as chair now renders its dead row; pre-v4.6 runs render dead rows from
|
|
162
|
+
`verdict.degrades`/`seatLoss.deadBenchSeats`; the third F09-class stale-reply hole
|
|
163
|
+
(`openRun`'s `get-run` reply) closes — #108
|
|
164
|
+
- **Valueless `-o` + save-shadow notice + metadata tmp sweep** — a trailing bare `-o`/`--out`
|
|
165
|
+
now errors instead of orphaning a tmp file; `council save` announces when it shadows a
|
|
166
|
+
built-in bench; `doctor --fix` sweeps orphaned `metadata.json` tmp files — #109
|
|
167
|
+
- **Registry body assert + Node-floor truth sweep + `makeBaseDeps()`** — the MCP-Registry
|
|
168
|
+
skip-check verifies the version *and* status it trusts, fail-toward-publish on every other
|
|
169
|
+
path; the README/install scripts/doctor all agree on the real Node ≥22.12 floor; eleven
|
|
170
|
+
duplicated doctor test fixtures consolidate into one factory — #110
|
|
171
|
+
|
|
138
172
|
## v4.7 — "Compose your councils" *(renumbered from v4.6, 2026-08-02 — spec + fresh plan at kickoff per the anti-rot rule)*
|
|
139
173
|
**Benefit:** councils chain — generate → critique → refine with no manual copy-paste — and history
|
|
140
174
|
becomes navigable.
|
|
@@ -143,8 +177,8 @@ becomes navigable.
|
|
|
143
177
|
- **Session/wave tagging + `--search` + grouped history** (F8) *(S–M)*
|
|
144
178
|
- **GUI power ergonomics** (F10: focus-follows fold hotkey, distinguishable window titles, tiling
|
|
145
179
|
presets) *(S each)*
|
|
146
|
-
- Deferred-item candidates per the v4.5 design doc's §8: RN-2, TST-1/TST-2, REL-2, CA-4
|
|
147
|
-
remainder of TST-7
|
|
180
|
+
- Deferred-item candidates per the v4.5 design doc's §8: RN-2, TST-1/TST-2, REL-2, CA-4
|
|
181
|
+
(repair-solos half — the failed-chair half shipped v4.6.2), remainder of TST-7
|
|
148
182
|
- **README + docs update** *(S)*
|
|
149
183
|
> The 2026-07-19 combined spec (`2026-07-19-v4.5-policy-packs-composition-design.md`) holds the
|
|
150
184
|
> approved chaining/tagging/F10 design detail and is the primary input to the v4.7 brainstorm; it
|
package/docs/configuration.md
CHANGED
|
@@ -36,14 +36,16 @@ Per vendor, the bare form's direct key is: `google/...` → `GOOGLE_GENERATIVE_A
|
|
|
36
36
|
`DEEPSEEK_API_KEY`.
|
|
37
37
|
|
|
38
38
|
**Inherited provider base URLs.** Amicus does not define or read `*_BASE_URL` variables for the
|
|
39
|
-
hosted vendors above,
|
|
40
|
-
hands them to the underlying provider SDK. `ANTHROPIC_BASE_URL`
|
|
41
|
-
appends only `/messages` to it, so it must include the `/v1` path segment
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
`
|
|
46
|
-
|
|
39
|
+
hosted vendors above, and it still passes the whole environment through to the OpenCode engine,
|
|
40
|
+
which hands them to the underlying provider SDK. `ANTHROPIC_BASE_URL` gets one extra treatment:
|
|
41
|
+
the SDK appends only `/messages` to it, so it must include the `/v1` path segment, and some hosts
|
|
42
|
+
set the `/v1`-less host-form for you — a shell spawned by Claude Code inherits it. **Since v4.6.2,
|
|
43
|
+
amicus detects that host-form value and carries a normalized `<value>/v1` into the engine as a
|
|
44
|
+
provider-config override by default** (no env var is rewritten) — see `AMICUS_BASE_URL_NORMALIZE`
|
|
45
|
+
above to disable it, and `amicus doctor`'s `anthropic-base-url` row to see how your current value
|
|
46
|
+
is being treated. Any other path (including an already-correct `/v1`) passes through unchanged.
|
|
47
|
+
See [troubleshooting § Every Direct Anthropic Model Fails with `"Not Found"`](./troubleshooting.md#every-direct-anthropic-model-fails-with-not-found)
|
|
48
|
+
for the pre-normalization failure mode and the manual fix if you've disabled the knob.
|
|
47
49
|
|
|
48
50
|
---
|
|
49
51
|
|
|
@@ -88,6 +90,7 @@ through OpenRouter as before.
|
|
|
88
90
|
| `AMICUS_FANOUT_MAX_LEGS` | Cap the number of concurrent legs in a single fanout wave. Protects against accidental runaway costs when `--models` is a long list. Non-positive or non-integer values fall back to the default. | `10` |
|
|
89
91
|
| `AMICUS_MCP_CLIENT` | Force the MCP server's `--client` value (`code-local`, `code-web`, or `cowork`) instead of auto-detecting it from the caller's MCP `initialize` handshake (`clientInfo.name`). Invalid values are ignored (with a warning) and detection proceeds normally. Note: `code-web` requires an explicit `--session-dir` and is not usable for MCP-spawned sessions. | auto-detected |
|
|
90
92
|
| `AMICUS_MAX_SESSIONS` | Maximum number of concurrent sessions the shared OpenCode server (`src/utils/shared-server.js`) will track before rejecting new ones. Renamed from `SIDECAR_MAX_SESSIONS` in v2.0.0. | `20` |
|
|
93
|
+
| `AMICUS_BASE_URL_NORMALIZE` | Set `0` to stop amicus from carrying a host-form `ANTHROPIC_BASE_URL` into the engine as `<value>/v1`. Host-form is the Anthropic-SDK convention (the SDK appends `/v1`); OpenCode treats the value as a full prefix, so unnormalized host-form 404s every direct-Anthropic leg. | `1` |
|
|
91
94
|
|
|
92
95
|
---
|
|
93
96
|
|
|
@@ -95,7 +98,7 @@ through OpenRouter as before.
|
|
|
95
98
|
|
|
96
99
|
These variables control the polling loop that drives headless sessions. The defaults are conservative and work for almost all workloads. You only need them if you are running against unusually slow or fast model endpoints, or if you are building tooling on top of Amicus and need tighter completion detection.
|
|
97
100
|
|
|
98
|
-
**Which of these accept `0`, and which ignore it.**
|
|
101
|
+
**Which of these accept `0`, and which ignore it.** Five knobs in this table — the four `SETTLE` knobs (`AMICUS_USAGE_SETTLE_POLLS`, `AMICUS_USAGE_SETTLE_INTERVAL_MS`, `AMICUS_USAGE_SETTLE_CALL_TIMEOUT_MS`, `AMICUS_TOOL_SETTLE_GRACE_MS`) plus `AMICUS_NO_OUTPUT_BACKSTOP_MS` — read through `envNumber()` (`src/utils/env-num.js`), which honours an explicit, finite `0` — for those, `0` is a documented escape hatch and each row below says what it switches off (`AMICUS_NO_OUTPUT_BACKSTOP_MS` treats any negative value the same as `0`). **Every other variable in this table reads through `Number(env) || default`, so `0` is falsy and silently falls back to the default** — there is no way to set them to zero, and that is deliberate: a `0` poll interval would busy-loop and a `0` stall threshold would kill every leg on its first poll. In both families a blank, missing or non-finite value falls back to the default.
|
|
99
102
|
|
|
100
103
|
| Variable | Purpose | Default |
|
|
101
104
|
|----------|---------|---------|
|
|
@@ -105,6 +108,7 @@ These variables control the polling loop that drives headless sessions. The defa
|
|
|
105
108
|
| `AMICUS_STABLE_IDLE_POLLS` | Number of consecutive idle polls required when no explicit completion signal is received (approximately 60 s at the 2 s default). This is the fallback heuristic for models or SDK versions that don't emit a clean completion event. | `30` |
|
|
106
109
|
| `AMICUS_MAX_CONSECUTIVE_POLL_FAILURES` | Consecutive poll failures before the headless runner bails. At the 2 s interval this is approximately 30 s. Prevents a dead server from burning the full session timeout on futile polls. | `15` |
|
|
107
110
|
| `AMICUS_TOOL_CALL_STALL_MS` | How long a tool call may sit pending with **no** result and no output growth before the leg is failed with `Tool call stalled: <tool>` and its OpenCode session aborted. This is the wedge guard: it targets a leg producing nothing at all, and it is skipped while a tool-settle deferral is active (`AMICUS_TOOL_SETTLE_GRACE_MS` owns that decision instead, and ends in a completion rather than a failure). **`0` is ignored** — it falls back to the default rather than disabling the guard, because a `0` threshold would kill every leg on its first poll. There is no way to switch this off; raise it if you legitimately run very long single tool calls. | `180000` |
|
|
111
|
+
| `AMICUS_NO_OUTPUT_BACKSTOP_MS` | Fail a headless leg fast when the model has produced no output, reasoning, or tool calls for this long — the "accepted but not serving" class. Disarms permanently on the first sign of activity, so slow cold-prefill local models are unaffected. **Set `0` (or negative) to disable the backstop entirely** — silent legs then run to the ordinary timeout. | `120000` |
|
|
108
112
|
| `AMICUS_USAGE_SETTLE_POLLS` | How many extra `getMessages` reads run **after** a leg has already finished, to catch provider usage/cost that lands milliseconds after the completion signal (measured: real paid legs losing their cost by 29 ms and 155 ms). The loop breaks early as soon as every assistant message carries usage, so the common case is one extra read. **Set to `0` to disable the reconciliation entirely** — legs then report whatever usage was present at completion, which can be `$0` on a leg that really did cost money. | `3` |
|
|
109
113
|
| `AMICUS_USAGE_SETTLE_INTERVAL_MS` | Delay between those settle reads. **`0` is honoured and means no delay** — the reads run back to back. It does **not** disable the reconciliation (that is `AMICUS_USAGE_SETTLE_POLLS=0`); it only removes the gap between attempts. | `400` |
|
|
110
114
|
| `AMICUS_USAGE_SETTLE_CALL_TIMEOUT_MS` | Per-call deadline for a settle read and for the child-session (subagent) spend walk. Deliberately much tighter than `AMICUS_POLL_CALL_TIMEOUT_MS`: the leg is already finished, so a hung read must not add 30 s × 3 to a run's wall time. The effective value is the **smaller** of this and `AMICUS_POLL_CALL_TIMEOUT_MS`, so raising it above that has no effect. **`0` is honoured and means no timer is armed at all** — a hung settle read or subtree walk would then wait indefinitely. | `5000` |
|
|
@@ -243,9 +247,11 @@ Everything lives under `~/.config/amicus/` (`getConfigDir()` in `src/utils/confi
|
|
|
243
247
|
metadata) use an atomic write: a temp file named `.<target>.<pid>.<random>.tmp` is written
|
|
244
248
|
alongside the target, then renamed into place. A process killed between the write and the rename
|
|
245
249
|
leaves an orphaned `.tmp` file behind forever — harmless, but it accumulates. `amicus doctor --fix`
|
|
246
|
-
sweeps orphaned `sessions-index.json.*.tmp` files
|
|
247
|
-
|
|
248
|
-
|
|
250
|
+
sweeps orphaned `sessions-index.json.*.tmp` files and, per-session, orphaned `.metadata.json.*.tmp`
|
|
251
|
+
files (the B09 class, ~30 write sites — both `<taskId>/` and `<taskId>/subagents/<id>/` levels
|
|
252
|
+
under the current project's `.claude/amicus_sessions/`); both sweeps only remove files older than
|
|
253
|
+
60 seconds, so a live writer's in-flight tmp file is never touched. `amicus doctor` (without
|
|
254
|
+
`--fix`) just reports the counts.
|
|
249
255
|
|
|
250
256
|
### Session storage
|
|
251
257
|
|
package/docs/council.md
CHANGED
|
@@ -176,7 +176,9 @@ Key semantics:
|
|
|
176
176
|
same per-member reason) as a preview, before you spend anything.
|
|
177
177
|
- Chair failure recovery: one retry of the same chair → promote the highest peers-only
|
|
178
178
|
street-cred model (from `amicus council stats`) that is not a bench seat → give up and write
|
|
179
|
-
the verdict with `overallVerdict: null`.
|
|
179
|
+
the verdict with `overallVerdict: null`. Each attempt in that walk is additionally recorded on
|
|
180
|
+
`run.json` as `chairAttempts[]` (`{waveId, model, outcome, reason}`), checkpointed after every
|
|
181
|
+
attempt so a mid-walk kill preserves what already happened.
|
|
180
182
|
- SIGINT/SIGTERM abort the active wave/solo, finalize `run.json` as `aborted`, exit 130/143.
|
|
181
183
|
`amicus abort <councilRunId>` (and the MCP tools via the sessions-dir pointer file
|
|
182
184
|
`council-<runId>.json`) work on council runs; `status`/`list` resolve them the same way.
|
|
@@ -329,7 +331,10 @@ launch:
|
|
|
329
331
|
the Stage-2 contract carries no structured reason field, so rationale lives in prose; on a
|
|
330
332
|
`--debate` run, a re-voted cell instead opens `revote-<model>.md` and also surfaces the
|
|
331
333
|
structured `reason` `debate.json` records for that re-vote), chair verdict + street-cred +
|
|
332
|
-
Stage-4 decisions, and a cost-by-seat table with a `--max-cost` ceiling gauge.
|
|
334
|
+
Stage-4 decisions, and a cost-by-seat table with a `--max-cost` ceiling gauge. The Seats table
|
|
335
|
+
also lists any seat the run announced dead as a muted, no-cost row, live — as soon as the run
|
|
336
|
+
checkpoints the loss, no terminal wait required (a seat whose errored legs still occupy the
|
|
337
|
+
active stage's roster paints once that stage completes).
|
|
333
338
|
|
|
334
339
|
**Historical runs** render entirely from the run directory — open any old `council-<runId>` at any
|
|
335
340
|
time; nothing here requires the run to still be live.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
## First: run `amicus doctor`
|
|
7
7
|
|
|
8
|
-
Before working through any symptom below, run `amicus doctor` (plugin-only installs: `npx -y amicus@latest doctor`). It checks, in order: Node version, config directory, API keys, default model, catalog freshness, alias staleness, the OpenCode binary, the OpenCode engine's MCP launch path, Electron, installed skills, MCP registration, the legacy sidecar MCP entry, session index tmp files, OpenRouter credit, local providers, and the project root — and prints a targeted fix hint for every failing check. `amicus doctor --fix` self-heals what it can (e.g. re-installs a broken Electron in place); `--json` gives machine-readable output.
|
|
8
|
+
Before working through any symptom below, run `amicus doctor` (plugin-only installs: `npx -y amicus@latest doctor`). It checks, in order: Node version, config directory, API keys, default model, catalog freshness, alias staleness and drift, the ANTHROPIC_BASE_URL form, the OpenCode binary, the OpenCode engine's MCP launch path, Electron, installed skills, MCP registration, the legacy sidecar MCP entry, session index tmp files, OpenRouter credit, local providers, and the project root — and prints a targeted fix hint for every failing check. `amicus doctor --fix` self-heals what it can (e.g. re-installs a broken Electron in place); `--json` gives machine-readable output.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -56,33 +56,50 @@ one.** The council degrades around the missing model — the chair silently fall
|
|
|
56
56
|
collapses from 3 seats to 2, and every finding comes back `confidence: "thin"` because it only ever
|
|
57
57
|
had one peer corroborator. Nothing in `verdict.json` records that the roster changed.
|
|
58
58
|
|
|
59
|
-
**Cause:** an `ANTHROPIC_BASE_URL` environment variable
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
**Cause:** an `ANTHROPIC_BASE_URL` environment variable in **host-form** — missing the `/v1` path
|
|
60
|
+
segment. That's the Anthropic-SDK convention (the SDK appends `/v1` itself), not OpenCode's — its
|
|
61
|
+
provider layer treats the value as the already-complete prefix and appends only `/messages`, so
|
|
62
|
+
`https://api.anthropic.com` (no `/v1`) posts to `https://api.anthropic.com/messages` instead of
|
|
63
63
|
`https://api.anthropic.com/v1/messages`. That URL returns HTTP **404 with an empty body**, so the AI
|
|
64
|
-
SDK has no error payload to report and surfaces the bare HTTP status text — `Not Found`.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
SDK has no error payload to report and surfaces the bare HTTP status text — `Not Found`. Some hosts
|
|
65
|
+
set this variable for you: notably, a shell spawned by Claude Code inherits
|
|
66
|
+
`ANTHROPIC_BASE_URL=https://api.anthropic.com` (no `/v1`) from the host process. The model id, the
|
|
67
|
+
alias, and the API key are never the problem; only the URL is wrong.
|
|
68
|
+
|
|
69
|
+
**Since v4.6.2, this self-heals by default.** Amicus classifies `ANTHROPIC_BASE_URL` on every
|
|
70
|
+
engine start; when it's host-form, it carries a normalized `<value>/v1` into the engine as a
|
|
71
|
+
provider-config override (no env var is rewritten) and prints one
|
|
72
|
+
`Notice: ANTHROPIC_BASE_URL is host-form (…); passing …/v1 to the engine …` line to stderr, once per
|
|
73
|
+
process. `amicus doctor` also gained an `anthropic-base-url` row that always prints the exact value
|
|
74
|
+
it sees and how it's being treated. So on a current install, this failure should be rare — if
|
|
75
|
+
you're seeing it anyway, it's one of:
|
|
76
|
+
- **`AMICUS_BASE_URL_NORMALIZE=0` is set**, the deliberate escape hatch — it disables the fix
|
|
77
|
+
entirely. Easy to hit by accident if you set it while chasing something unrelated.
|
|
78
|
+
- **`ANTHROPIC_BASE_URL` carries a nonstandard path** — anything other than blank/`/` (host-form)
|
|
79
|
+
or an already-correct `/v1` — which amicus passes through untouched rather than guessing (an
|
|
80
|
+
exotic proxy serving `/messages` at a custom root stays possible).
|
|
81
|
+
- You're running a **pre-v4.6.2** amicus, where none of the above exists yet.
|
|
82
|
+
|
|
83
|
+
**Confirm it in one command** (no key needed for the first three lines):
|
|
72
84
|
|
|
73
85
|
```bash
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
amicus doctor # anthropic-base-url row: the value seen + how it's treated
|
|
87
|
+
echo "$ANTHROPIC_BASE_URL" # host-form (no /v1 suffix) is the underlying condition
|
|
88
|
+
echo "$AMICUS_BASE_URL_NORMALIZE" # "0" here is what disables the automatic fix
|
|
89
|
+
amicus start --model haiku --prompt hi --no-ui # should complete; stderr shows the Notice line
|
|
90
|
+
# the first time normalization actually fires
|
|
77
91
|
```
|
|
78
92
|
|
|
79
93
|
**Fix** — pick one:
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
|
|
94
|
+
- Unset `AMICUS_BASE_URL_NORMALIZE` (or set it to anything other than `0`) to restore the default
|
|
95
|
+
self-heal.
|
|
96
|
+
- Still failing with normalization on? Add the missing segment yourself:
|
|
97
|
+
`export ANTHROPIC_BASE_URL=https://api.anthropic.com/v1` (PowerShell:
|
|
98
|
+
`$env:ANTHROPIC_BASE_URL = 'https://api.anthropic.com/v1'`), or unset the variable entirely:
|
|
99
|
+
`unset ANTHROPIC_BASE_URL` (PowerShell: `Remove-Item Env:\ANTHROPIC_BASE_URL`).
|
|
83
100
|
- Or route Anthropic models through OpenRouter for the run: `--gateway openrouter`.
|
|
84
101
|
|
|
85
|
-
|
|
102
|
+
Any of these gets `amicus start --model haiku …` completing normally again. **Before spending
|
|
86
103
|
money on a council, run one throwaway `amicus start` against each configured seat** — a
|
|
87
104
|
`Not Found` there costs nothing, whereas discovering it mid-council costs a degraded verdict.
|
|
88
105
|
|
|
@@ -188,6 +205,18 @@ For full headless configuration, see [docs/configuration.md](./configuration.md)
|
|
|
188
205
|
|
|
189
206
|
---
|
|
190
207
|
|
|
208
|
+
## Headless Leg Fails with `NO_OUTPUT_BACKSTOP`
|
|
209
|
+
|
|
210
|
+
**Symptom:** A headless leg (`amicus start --no-ui`, or one leg of a `fanout`/council run) fails with an error starting `NO_OUTPUT_BACKSTOP: model produced no output, reasoning, or tool calls in Ns`.
|
|
211
|
+
|
|
212
|
+
**Cause:** The model endpoint accepted the request but produced nothing — no output, reasoning, or tool calls — for the entire backstop window (120 s by default). This is the "accepted but not serving" class: usually a dead or misconfigured endpoint, or a catalog-listed model that's no longer actually being served upstream.
|
|
213
|
+
|
|
214
|
+
**Confirm:** `amicus models --check` — audits your configured aliases against the live catalog and flags drift/staleness. A model that still resolves locally but has quietly been retired upstream is exactly this failure mode, but a static audit only compares against the catalog's *listing* — it can't tell you whether a still-listed model actually answers. For that, run `amicus models --check --live` on demand: it sends one tiny real request to every stored alias and reports `SERVED` / `SILENT` / `ERROR` per alias, where `SILENT` (`accepted-but-silent`) is this exact `NO_OUTPUT_BACKSTOP` failure, caught deliberately instead of by accident. It spends real money (one tiny leg per stored alias) — see [docs/usage.md § `amicus models`](./usage.md#amicus-models--the-model-catalog) for cost, scope, and exit-code details.
|
|
215
|
+
|
|
216
|
+
**Fix:** Check the alias's target (`amicus models --search <term>` to find the current id, then re-point the alias) — this is the common case. Raise `AMICUS_NO_OUTPUT_BACKSTOP_MS` only if a model legitimately needs more than 120 s to produce its first token; see [docs/configuration.md § Headless Poller Tuning](./configuration.md#headless-poller-tuning).
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
191
220
|
## Multiple Active Sessions / Wrong Session Picked Up
|
|
192
221
|
|
|
193
222
|
**Symptom:** Amicus resumes or reads from the wrong session.
|
package/docs/usage.md
CHANGED
|
@@ -376,10 +376,35 @@ amicus models # List the catalog
|
|
|
376
376
|
amicus models --search gemini # Filter by substring over id and name
|
|
377
377
|
amicus models --refresh # Force-refresh from provider APIs
|
|
378
378
|
amicus models --check # Audit your aliases against the catalog
|
|
379
|
+
amicus models --check --live # + probe every stored alias with a real leg (spends)
|
|
379
380
|
```
|
|
380
381
|
|
|
381
382
|
`amicus models --check` exits with the **number of stale aliases** (capped at 100) and prints same-vendor replacement suggestions for each, so it drops cleanly into CI.
|
|
382
383
|
|
|
384
|
+
**Gateway-only routes.** A curated alias whose direct form is *derived* from its OpenRouter route (rather than
|
|
385
|
+
authored) is not reported STALE when that direct form is missing from the vendor's
|
|
386
|
+
direct namespace while the OpenRouter route still serves — a gateway-only route with
|
|
387
|
+
no direct sibling is a routing choice, not staleness. Deliberately gateway-only
|
|
388
|
+
entries (e.g. `gpt-pro`) are annotated as such and are never offered a retarget.
|
|
389
|
+
|
|
390
|
+
**Drifted aliases.** `--check` (and the `doctor` aliases row) also flags **`DRIFTED:`** stored aliases — a stored alias whose target is still catalog-listed but no longer matches any route its family currently resolves to (the v4.6.1 `gemini` release-gate class, where `doctor` stayed green while the model behind it had moved on). Each drift line prints the exact `amicus setup --add-alias <alias>=<current>` refresh command. Drift is informational only — unlike stale aliases, it never changes the exit code.
|
|
391
|
+
|
|
392
|
+
**Live probe (`--check --live`).** Presence in the catalog is not proof of service — a stored alias can point at a model id the catalog still lists but the provider has quietly stopped serving (the v4.6.1 `gemini` incident). `--check` alone can't see that; `--live` can, by actually asking. Scope is **stored aliases only** (`amicus setup --add-alias`) — curated defaults follow the catalog by construction and have no "was it actually served" question for a live probe to answer. **This spends real money — one tiny leg per stored alias** — every probed alias gets one ordinary engine leg on a single quiet fan-out wave, with a real session dir and a real spend-ledger row, exactly as if you'd run it yourself.
|
|
393
|
+
|
|
394
|
+
Each stored alias resolves to one of three outcomes:
|
|
395
|
+
|
|
396
|
+
| Outcome | Example line | Meaning |
|
|
397
|
+
|---------|--------------|---------|
|
|
398
|
+
| `SERVED` | `SERVED: gemini -> openrouter/google/gemini-3.6-flash ($0.0004)` | The model answered; cost shown in parens. |
|
|
399
|
+
| `SILENT` (`accepted-but-silent`) | `SILENT: probetest -> anthropic/claude-opus-4-8 — NO_OUTPUT_BACKSTOP: … (accepted but not serving)` | The endpoint accepted the request but produced nothing for the probe's 30 s backstop window (shorter than the ordinary 120 s default, and not tunable) — the exact "listed but not actually serving" failure this check exists to catch. |
|
|
400
|
+
| `ERROR` | `ERROR: gpt -> openai/gpt-5.6-terra — 402 Payment Required` | Routing, auth, or provider failure; the raw error is printed. |
|
|
401
|
+
|
|
402
|
+
**Exit code.** The probe's non-served count folds into the same exit code as the static audit — `max(existing exit, min(nonServedCount, 100))` — so a single `SILENT` or `ERROR` fails the check even when every alias is otherwise catalog-fresh. No stored aliases prints `Live probe: no stored aliases to probe` and never affects the exit code. `--json` adds `probe` (the per-alias array) and `probeCount` (its length) to the `alias-audit` document — both additive, `[]`/`0` when `--live` wasn't passed.
|
|
403
|
+
|
|
404
|
+
**Cap.** The probe is one fan-out leg per stored alias, so it's bound by the same fan-out leg cap as everything else — 10 by default, raise it with `AMICUS_FANOUT_MAX_LEGS`. More stored aliases than the cap fails fast with a one-line error and probes nothing, so a doomed wave never spends a token.
|
|
405
|
+
|
|
406
|
+
**When it doesn't run.** `--live` requires `--check` (a bare `--live` errors immediately). If the catalog itself is unavailable, or `--refresh` is also on the command line (which returns before `--check` ever runs), the probe is skipped — Amicus says so instead of silently dropping the flag: `--live skipped: <reason> — nothing was probed`. The `--json` signal differs by path: for catalog-unavailable, the `alias-audit` document carries an additive `probeSkipped` field (a reason slug, e.g. `"catalog-unavailable"`; `null` once the probe actually ran or wasn't requested); for the `--refresh` case, `--json`'s stdout document is a `model-catalog` doc instead, which never carries `probeSkipped` — the announcement goes to stderr there so stdout stays valid JSON.
|
|
407
|
+
|
|
383
408
|
**Validation on launch.** `start` and `fanout` validate the model against the catalog before launching. For an explicit `--model` on `continue`/`resume` this is **blocking** (a typo'd model fails fast with suggestions); for a model *inherited* from a prior session it's **advisory**. Skip it any time with `--no-validate-model`, or fix the catalog with `amicus models --refresh`.
|
|
384
409
|
|
|
385
410
|
**Aliases are a curated seed, not a fixed list.** `amicus setup` seeds a curated set of short aliases (e.g. `gemini`, `gpt`, `opus`, `deepseek`), and you add or override them with `amicus setup --add-alias name=provider/model`. To see exactly what resolves on *your* machine, run `amicus models` — that is the source of truth.
|
|
@@ -443,7 +468,7 @@ $ amicus status demo123 --json
|
|
|
443
468
|
"taskId": "demo123",
|
|
444
469
|
"status": "complete",
|
|
445
470
|
"elapsed": "5m 0s",
|
|
446
|
-
"version": "4.6.
|
|
471
|
+
"version": "4.6.3",
|
|
447
472
|
"model": "google/gemini-2.5-flash",
|
|
448
473
|
"phase": "terminal"
|
|
449
474
|
}
|
|
@@ -495,12 +520,13 @@ Runs every check below, in order, and prints a ✓/⚠/✗ line for each plus a
|
|
|
495
520
|
|
|
496
521
|
| Check | What it verifies | Can fail as |
|
|
497
522
|
|---|---|---|
|
|
498
|
-
| `node` | Node.js ≥
|
|
523
|
+
| `node` | Node.js ≥ 22.12 | error |
|
|
499
524
|
| `config-dir` | The resolved config directory | *(always ok)* |
|
|
500
525
|
| `keys` | At least one cloud-vendor key configured | error |
|
|
501
526
|
| `default-model` | Your default model alias resolves | error |
|
|
502
527
|
| `catalog` | Model-catalog cache present and within the 24h TTL | warn |
|
|
503
528
|
| `aliases` | Your configured aliases still resolve against the catalog | warn |
|
|
529
|
+
| `anthropic-base-url` | `ANTHROPIC_BASE_URL` isn't host-form (host-form 404s every direct-Anthropic leg unless normalized) | warn |
|
|
504
530
|
| `opencode-bin` | The OpenCode engine binary is on `PATH` | error |
|
|
505
531
|
| `engine-mcp` | The engine copy `npx -y amicus@latest mcp` would actually launch (catches a broken npx-cache copy a healthy local install would hide) | warn (error only if there's exactly one npx-cache copy and it's broken) |
|
|
506
532
|
| `electron` | Electron (the interactive GUI) is installed | warn — headless still works |
|
|
@@ -508,13 +534,14 @@ Runs every check below, in order, and prints a ✓/⚠/✗ line for each plus a
|
|
|
508
534
|
| `mcp` | Amicus is registered as an MCP server in Claude Code | warn |
|
|
509
535
|
| `mcp-legacy` | No duplicate legacy `sidecar` MCP entry survives alongside `amicus` | warn |
|
|
510
536
|
| `sessions-index-tmp` | No orphaned `sessions-index.json.*.tmp` files | warn |
|
|
537
|
+
| `session-metadata-tmp` | No orphaned per-session `.metadata.json.*.tmp` files (the B09 class) | warn |
|
|
511
538
|
| `openrouter-credit` | Remaining OpenRouter credit (skipped — reports `ok` — when no OpenRouter key is set) | warn |
|
|
512
539
|
| `local-providers` **(v4.2)** | Every provider in `config.providers` is reachable | warn |
|
|
513
540
|
| `project-root` | Your cwd looks like a real project, not an app/install dir | warn |
|
|
514
541
|
|
|
515
542
|
**`local-providers`** probes every configured local provider (2s timeout each) the same way `amicus provider test` does, and reports per-id reachability in one line, e.g. `ollama: 3 models @ http://127.0.0.1:11434/v1; my-vllm: unreachable @ http://127.0.0.1:8000/v1`. No providers configured at all is a plain `ok` ("none configured") — this check can never fail your doctor run outright, only warn: a napping `ollama serve` isn't treated as broken setup.
|
|
516
543
|
|
|
517
|
-
`--fix` self-heals
|
|
544
|
+
`--fix` self-heals five of the checks above in place: reprovisions Electron, copies the OpenCode engine into a broken npx-cache install, removes a duplicate legacy MCP entry, sweeps orphaned session-index tmp files, and sweeps orphaned per-session metadata tmp files (both tmp sweeps only ones older than 60s). It does **not** start a local server for you — `local-providers` stays a warning until you start the server yourself.
|
|
518
545
|
|
|
519
546
|
Exit code is `1` if anything is `error`, else `0` (same rule drives `--json`'s `ok` field).
|
|
520
547
|
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
* delete, and add functionality for the setup wizard Step 3.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
/** Grouping metadata for the
|
|
8
|
+
/** Grouping metadata for the 19 default aliases */
|
|
9
9
|
const ALIAS_GROUPS = [
|
|
10
10
|
{ name: 'Gemini', keys: ['gemini', 'gemini-pro'] },
|
|
11
11
|
{ name: 'GPT', keys: ['gpt', 'gpt-pro', 'codex'] },
|
|
12
12
|
{ name: 'Claude', keys: ['claude', 'sonnet', 'opus', 'haiku', 'fable'] },
|
|
13
13
|
{ name: 'DeepSeek', keys: ['deepseek'] },
|
|
14
14
|
{ name: 'Qwen', keys: ['qwen', 'qwen-coder', 'qwen-flash'] },
|
|
15
|
-
{ name: 'Mistral', keys: ['mistral'
|
|
15
|
+
{ name: 'Mistral', keys: ['mistral'] },
|
|
16
16
|
{ name: 'Other', keys: ['glm', 'minimax', 'grok', 'kimi', 'seed'] },
|
|
17
17
|
];
|
|
18
18
|
|