amicus 4.8.0 → 4.9.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 +355 -0
- package/README.md +10 -5
- package/docs/CITATIONS.md +13 -5
- package/docs/ROADMAP.md +101 -10
- package/docs/configuration.md +55 -5
- package/docs/council.md +102 -14
- package/docs/troubleshooting.md +9 -2
- package/docs/usage.md +128 -12
- package/electron/ipc-setup.js +39 -2
- package/electron/main.js +46 -3
- package/electron/offer-session.js +51 -0
- package/electron/setup-ui-model.js +99 -9
- package/electron/setup-ui-styles.js +22 -0
- package/electron/setup-ui.js +244 -32
- package/electron/workspace-ui/live-dead-seats.js +163 -91
- package/electron/workspace-ui/live-seats.js +4 -4
- package/electron/workspace-ui/workspace-banners.js +30 -7
- package/electron/workspace-ui/workspace-matrix.js +23 -3
- package/electron/workspace-ui/workspace-seats.js +95 -79
- package/package.json +2 -1
- package/schemas/council-run.schema.json +2 -2
- package/schemas/council-tally.schema.json +17 -1
- package/schemas/council-verdict.schema.json +12 -4
- package/schemas/run.schema.json +6 -1
- package/skills/second-opinion/COUNCIL-DESIGN.md +1 -1
- package/skills/second-opinion/MANUAL-ORCHESTRATION.md +1 -1
- package/skills/second-opinion/MODEL-NOTES.md +88 -9
- package/skills/second-opinion/SEAT-BRIEFS.md +36 -4
- package/skills/second-opinion/SKILL.md +151 -36
- package/src/cli-council-run-bench.js +98 -6
- package/src/cli-handlers-council-run.js +18 -6
- package/src/cli-handlers-council.js +57 -7
- package/src/cli-handlers-doctor.js +12 -15
- package/src/cli.js +3 -1
- package/src/council/anonymize.js +2 -1
- package/src/council/briefings-chair-task.js +161 -0
- package/src/council/briefings-chair.js +33 -8
- package/src/council/briefings-debate.js +79 -13
- package/src/council/briefings-stage2-task.js +236 -0
- package/src/council/briefings-stage2.js +103 -26
- package/src/council/briefings-task.js +167 -0
- package/src/council/briefings.js +41 -4
- package/src/council/chair-fallback.js +95 -0
- package/src/council/debate.js +38 -21
- package/src/council/findings.js +3 -2
- package/src/council/ledger.js +2 -2
- package/src/council/parse-stage2.js +64 -16
- package/src/council/report-cost.js +61 -0
- package/src/council/report-html.js +26 -4
- package/src/council/report-md.js +30 -2
- package/src/council/report.js +40 -37
- package/src/council/run-assemble.js +21 -6
- package/src/council/run-chair.js +44 -95
- package/src/council/run-debate-revote.js +81 -49
- package/src/council/run-debate.js +51 -34
- package/src/council/run-finish.js +5 -3
- package/src/council/run-retry-keys.js +4 -4
- package/src/council/run-retry-launch.js +4 -4
- package/src/council/run-retry-notes.js +72 -15
- package/src/council/run-stage1-launch.js +4 -4
- package/src/council/run-stage1-rows.js +9 -6
- package/src/council/run-stage2.js +81 -47
- package/src/council/run-stages.js +9 -21
- package/src/council/run-stats-entry.js +46 -1
- package/src/council/run.js +28 -13
- package/src/council/seats.js +2 -2
- package/src/council/stage1-bind.js +3 -2
- package/src/council/verdict-seat-loss.js +124 -0
- package/src/council/verdict.js +108 -99
- package/src/headless.js +256 -49
- package/src/mcp-council-bench.js +64 -3
- package/src/mcp-council-run.js +10 -3
- package/src/mcp-server.js +52 -12
- package/src/mcp-tools.js +41 -5
- package/src/observe/council-legs.js +2 -2
- package/src/opencode-client.js +19 -1
- package/src/pack/pack-forward.js +15 -12
- package/src/pack/pack-resolve.js +1 -1
- package/src/prompt-builder.js +17 -1
- package/src/sidecar/fanout-leg.js +26 -0
- package/src/sidecar/fanout.js +1 -1
- package/src/sidecar/list-council.js +178 -0
- package/src/sidecar/list-limit.js +3 -1
- package/src/sidecar/list-search.js +2 -1
- package/src/sidecar/models.js +8 -1
- package/src/sidecar/read.js +34 -10
- package/src/sidecar/setup.js +124 -0
- package/src/template/render.js +16 -7
- package/src/utils/alias-audit.js +81 -3
- package/src/utils/alias-shadow-writer.js +220 -0
- package/src/utils/alias-shadow.js +294 -0
- package/src/utils/config.js +1 -1
- package/src/utils/curated-models.js +16 -8
- package/src/utils/degrade.js +12 -5
- package/src/utils/doctor-alias-check.js +149 -0
- package/src/utils/engine-log-parse.js +289 -0
- package/src/utils/engine-log-tail.js +114 -0
- package/src/utils/engine-log.js +250 -0
- package/src/utils/engine-skew-records.js +146 -0
- package/src/utils/engine-skew.js +300 -0
- package/src/utils/gateway-router.js +10 -2
- package/src/utils/model-canonicalization.js +64 -0
- package/src/utils/model-catalog.js +1 -1
- package/src/utils/model-shortlist.js +100 -0
- package/src/utils/provider-default-picker.js +93 -45
- package/src/utils/provider-default-prompt.js +1 -1
- package/src/utils/quick-picks.js +2 -2
- package/src/utils/remediation-hints.js +24 -0
- package/src/utils/result-schema.js +10 -0
- package/src/utils/text-sanitize.js +81 -0
- package/src/utils/ttft.js +57 -0
- package/src/utils/untrusted-fence.js +111 -1
- package/src/workspace/fold-format.js +28 -7
- package/src/workspace/live-normalize.js +2 -1
- package/src/workspace/matrix-model.js +6 -2
- package/src/workspace/run-detail.js +35 -9
- package/src/workspace/seat-space.js +10 -6
package/docs/ROADMAP.md
CHANGED
|
@@ -13,10 +13,10 @@ lives under **Backlog (tracked, not scheduled)** with everything else that is re
|
|
|
13
13
|
Nothing about the content changed and no judgment about its value is implied; only its status. When
|
|
14
14
|
an org buyer and the org to support them exist, it earns a number then.
|
|
15
15
|
|
|
16
|
-
Amicus is at **v4.
|
|
16
|
+
Amicus is at **v4.9.0** (2026-08-26). Each 4.x rev below leads with the benefit, not the
|
|
17
17
|
plumbing.
|
|
18
18
|
|
|
19
|
-
**Status:** v4.0 through **v4.
|
|
19
|
+
**Status:** v4.0 through **v4.9.0** have **shipped** — everything on this page is a record of what
|
|
20
20
|
landed, not a plan. Composition — the scope that
|
|
21
21
|
carried the number v4.6 here until the degrade-announcement-invariant milestone took the v4.6.0
|
|
22
22
|
release (2026-08-02) — is now an unscheduled candidate for the next rev, tabled in its own section
|
|
@@ -206,7 +206,8 @@ list. Two findings drove it:
|
|
|
206
206
|
An earlier draft of this note said *"all three had already rotted"*; that universal is false and
|
|
207
207
|
is corrected here. The other two HAD already rotted before T2.4 began (`report.js:79` and
|
|
208
208
|
`ledger.js:24` are comments at `ed5c0c02`), so their drift is pre-existing, not this release's.
|
|
209
|
-
The report fallback is now at `src/council/report.js ::
|
|
209
|
+
The report fallback is now at `src/council/report-cost.js :: buildCostModel`'s `total` (it was
|
|
210
|
+
`report.js :: toModel`'s until v4.9 W8 extracted the cost table); all three claims
|
|
210
211
|
themselves still hold. So CA-4's omissions are not a schema nicety — they under-report spend on the
|
|
211
212
|
surface the owner relies on, which collides with the cost-truth principle (*reported > estimated
|
|
212
213
|
> unknown; never fabricate $0*). An omitted leg is not "unknown" — it renders as money never
|
|
@@ -222,9 +223,9 @@ list. Two findings drove it:
|
|
|
222
223
|
(`run-assemble.js:180-184`) and one `repair` row per `-q<N>` solo, failed ones included
|
|
223
224
|
(`run-stage2.js:122`).
|
|
224
225
|
⚠️ **Scope correction:** the failed-chair third of the original CA-4 is **closed** — v4.6.2's
|
|
225
|
-
`chairAttempts[]` records every attempt on `run.json` (`run-chair.js:
|
|
226
|
+
`chairAttempts[]` records every attempt on `run.json` (`run-chair.js:71` cites LC-5 by name), and
|
|
226
227
|
failed-chair cost already reaches `runStats` too: a failed ch1–ch3 attempt gets its own
|
|
227
|
-
`chair-attempt` row there carrying that leg's real `usage` (`run-chair.js:
|
|
228
|
+
`chair-attempt` row there carrying that leg's real `usage` (`run-chair.js:91-95`), so no third
|
|
228
229
|
row class was needed.
|
|
229
230
|
- **GOA-7 prerequisite — segment the ledger by RESOLVED model, not alias** *(S–M)*: **shipped.**
|
|
230
231
|
`ledger.js:124` now keys on `row.resolvedModel || row.model` and `LEDGER_SCHEMA_VERSION` is 2.
|
|
@@ -256,7 +257,9 @@ list. Two findings drove it:
|
|
|
256
257
|
> *Next-rev hard gates*: the tight-file extraction pass (`cli-handlers-council-run.js` is at
|
|
257
258
|
> **299/300 exactly**, `run-debate.js` at 299, two files **at 300**), and KNOWN_VARIABLES
|
|
258
259
|
> single-sourcing **only if** `{{input}}` is ever scoped — it is not in this rev, so that gate
|
|
259
|
-
> travels with composition rather than blocking here.
|
|
260
|
+
> travels with composition rather than blocking here. *(Update 2026-08-25: the KNOWN_VARIABLES
|
|
261
|
+
> gate is now satisfied — landed in v4.9 W1 ahead of any composition work. The tight-file
|
|
262
|
+
> numbers in this note are a dated snapshot; re-measure with `npm run check:sizes`.)*
|
|
260
263
|
|
|
261
264
|
### Deferred out of v4.4.1 into v4.5 (2026-07-27)
|
|
262
265
|
|
|
@@ -276,7 +279,7 @@ a proposed disposition — v4.5 ride-along / v4.6 / backlog — tabled for rulin
|
|
|
276
279
|
| **CA-4** | `tally.json`'s `runStats` omits Stage-2 judges, repair solos and failed chair attempts (5 rows for 11 real legs in `wsgate04`) | `M` — a schema question, not a fix |
|
|
277
280
|
| **CA-5** | `isSubagentToolCall` is still a `name === 'task'` string proxy | `M`, and **reduced** by v4.4.0: it is now only the fallback when the real subtree walk finds nothing |
|
|
278
281
|
| **LC-1** | B53's stall kill is skipped while a tool-settle deferral is active | `S–M` — shipped deliberately; the author wants a second opinion, which needs data from real runs |
|
|
279
|
-
| ~~**LC-5**~~ | ~~A chair fallback leaves no trace in `run.json`~~ — ✅ **CLOSED by v4.6.2**: `chairAttempts[]` records every attempt (`{waveId, model, outcome, reason}`), checkpointed after each; `run-chair.js:113` cites LC-5 by name. **Do not re-file.** | — |
|
|
282
|
+
| ~~**LC-5**~~ | ~~A chair fallback leaves no trace in `run.json`~~ — ✅ **CLOSED by v4.6.2**: `chairAttempts[]` records every attempt (`{waveId, model, outcome, reason}`), checkpointed after each; `run-chair.js@v4.6.2:113` cites LC-5 by name. **Do not re-file.** | — |
|
|
280
283
|
| **RN-1** | `sanitizeName` collisions surface as a banner rather than a refusal | `S` + a product decision that was already argued once |
|
|
281
284
|
| **RN-2** | `renderRunList` blind masking is best-effort — only the open run resolves labels | `M` |
|
|
282
285
|
| **RN-5** | A blind-mode flip closes every open prose panel and repaints twice | `S–M` |
|
|
@@ -354,6 +357,93 @@ behaviour changes.
|
|
|
354
357
|
CI off 1.2.20. First release whose suite ran against the engine users actually get
|
|
355
358
|
- Plus a `sidecar/reopen-spend.js` extraction, a dead-code deletion, and three documentation gates
|
|
356
359
|
|
|
360
|
+
## v4.8 — "Every seat counts as itself" *(seat identity)* — ✅ SHIPPED v4.8.0, 2026-08-23
|
|
361
|
+
**Benefit:** seat a model twice and the council finally treats the two seats as two reviewers —
|
|
362
|
+
each with its own vote, its own row, its own file and its own dead-seat badge. Before this rev a
|
|
363
|
+
repeated alias was a bench that quietly disagreed with itself about how many reviewers were in the
|
|
364
|
+
room.
|
|
365
|
+
|
|
366
|
+
**Scope note.** The design spec behind this number
|
|
367
|
+
(`docs/superpowers/specs/2026-08-10-v4.8-ask-anything-count-everyone-design.md`) carried two halves,
|
|
368
|
+
*ask anything* and *count everyone*. v4.8.0 shipped **count everyone** — the seat-identity spine —
|
|
369
|
+
across the `v48-*` PR train; **ask anything** (task mode, #134/#130, with #146 folded in) was sized
|
|
370
|
+
and moved whole to v4.9 rather than carried half-done. That is the ruling, not a slip.
|
|
371
|
+
|
|
372
|
+
- **Seats are first-class.** A seat id *is* its alias on every bench with no repeated `--models`
|
|
373
|
+
entry; where an alias occupies more than one position the seats are `<alias>#1`, `<alias>#2`, and
|
|
374
|
+
the artifacts follow (`review-<alias>-1.md`, and the same rule for `judge-`/`rebuttal-`/`revote-`).
|
|
375
|
+
`meta.seats` rides the tally/verdict documents index-parallel with `meta.models` *(L)*
|
|
376
|
+
- **⚠️ The peers-only filter excludes the raiser by SEAT, and findings on a repeated-alias bench
|
|
377
|
+
change tier in BOTH directions** — a genuine twin's corroboration is no longer discarded, and a
|
|
378
|
+
twin's *dispute* now demotes. Deliberate, measured case-by-case, and disclosed with its permanent
|
|
379
|
+
cost: `Disputed` feeds the append-only ledger's `factErrorRate`, which is never migrated.
|
|
380
|
+
Distinct-alias benches are byte-for-byte unaffected *(M)*
|
|
381
|
+
- **Two new honesty marks on `tally.json`/`verdict.json`** — `findings[].sameModelCorroboration`
|
|
382
|
+
(corroboration that came from another seat of the same model, so it is not independent) and
|
|
383
|
+
`findings[].unattributedPeerDrops` (a count of votes excluded from `basis` that the engine could
|
|
384
|
+
not attribute to anyone). Both emit-when-set; both shipped with their own wrong-in-two-directions
|
|
385
|
+
disclosures rather than as clean wins *(M)*
|
|
386
|
+
- **Prototype pollution closed across the alias tables** — a member literally named `toString`,
|
|
387
|
+
`constructor`, `valueOf` or `hasOwnProperty` is no longer a valid alias at any of five gates, and
|
|
388
|
+
`resolveModel('toString')` throws instead of returning the function itself. One table was not
|
|
389
|
+
enough: a spread into a plain `{}` re-creates the inherited prototype, so all three builders are
|
|
390
|
+
seeded *(M)*
|
|
391
|
+
- **A finding with no named raiser stops corroborating itself**, on one principle applied in order —
|
|
392
|
+
*attribute when you can, mark only when you cannot* — with seat ids deciding first *(M)*
|
|
393
|
+
- **The Workspace stops collapsing dead seats**, and a live seat no longer erases its dead twin;
|
|
394
|
+
dead rows, retry badges and DOM keys are keyed on the seat, with the producer emitting `null`
|
|
395
|
+
rather than the alias for a seat it could not identify. Residuals pinned by tests asserting the
|
|
396
|
+
known-wrong behaviour so they cannot rot silently *(M)*
|
|
397
|
+
- **`streetCred[]` stops dropping or inventing rows** when a hand-assembled `meta.seats` disagrees
|
|
398
|
+
with `meta.models`, and a mixed reliability-ledger pair group stops reading narrower than one with
|
|
399
|
+
no seat information at all *(S–M)*
|
|
400
|
+
> Why here: seat identity is a prerequisite, not a feature. Every surface that says *which model
|
|
401
|
+
> said what* — the peer split, street-cred, the ledger join, the Workspace panels, the artifact
|
|
402
|
+
> filenames — was keyed on the alias, so all of them told the same lie on the same bench shape.
|
|
403
|
+
> Fixing them one at a time would have been six half-fixes; the spine makes all six the same fix.
|
|
404
|
+
>
|
|
405
|
+
> **Lineage.** v4.6 made a loss announce itself, v4.7 made the accounting match reality, v4.8 makes
|
|
406
|
+
> the *attribution* match reality. Same invariant family, applied to identity.
|
|
407
|
+
|
|
408
|
+
**v4.8.1 (shipped 2026-08-25):** the fast-follow patch — setup Step 2 offered one card per curated
|
|
409
|
+
model *family* with no way to choose within it, and the route pill it wrote stored a **provider** id
|
|
410
|
+
rather than a model id, so nothing downstream could tell two models of one family apart either
|
|
411
|
+
(#138). Both wizard surfaces now offer a vendor-scoped drill-down on a new pure `model-shortlist.js`.
|
|
412
|
+
|
|
413
|
+
## v4.9 — "The council does new work" *(task mode)* — ✅ SHIPPED v4.9.0, 2026-08-26
|
|
414
|
+
**Benefit:** the council stops being able only to critique. Point it at open-ended work with
|
|
415
|
+
`--intent task` and every seat *produces* the deliverable, the judges rank which response best does
|
|
416
|
+
the work, and the chair synthesizes an **answer** — `Converged | Split | Insufficient` — instead of
|
|
417
|
+
a verdict about a review that never happened.
|
|
418
|
+
|
|
419
|
+
- **★ Task mode** — the *ask anything* half deferred out of v4.8, shipped whole: intent plumbing,
|
|
420
|
+
Stage-1 task frames at every dispatch site, task judging and the task chair, honest renderers on
|
|
421
|
+
every surface, and zero reliability rows written by a task run. **Closes #134, #130 and #146** —
|
|
422
|
+
`--intent task` on the CLI, `intent: 'task'` over MCP, and a review run that is byte-identical
|
|
423
|
+
everywhere *(L)*
|
|
424
|
+
- **The engine speaks for itself** — a `NO_OUTPUT_BACKSTOP` death report now quotes the engine's own
|
|
425
|
+
newest ERROR line for that session, and names a server-vs-install engine skew when there is one,
|
|
426
|
+
with a remedy that says why `doctor` cannot see this class. **Closes #133** *(M)*
|
|
427
|
+
- **Bench signals** — the `ttftMs` probe (measured off the backstop's own substantive-activity
|
|
428
|
+
predicate, never derived), and a one-per-run warning when a local alias shadows a curated one with
|
|
429
|
+
a different id, surfaced on the CLI, over MCP and in `models --check` *(M)*
|
|
430
|
+
- **The dead-seat surface finishes the v4.8 job** — an unbound seat stops being invisible in the
|
|
431
|
+
Workspace, and the critic path keys on seat identity, closing the dead-bench-twin-beside-live-critic
|
|
432
|
+
erasure v4.8 disclosed as a residual *(M)*
|
|
433
|
+
- **`amicus list` shows council runs on the CLI**, as `amicus_list` has over MCP since v4.0, with
|
|
434
|
+
the current-project-only scope stated out loud rather than left silent *(S–M)*
|
|
435
|
+
- **Docs update** — task mode in `README.md`, `docs/council.md` and `docs/usage.md`; the `runStats`
|
|
436
|
+
builder unification, the SI-16 splits and the `seatKey` consolidation carry the internal half *(S)*
|
|
437
|
+
> Why here: #130 and #134 are the same problem from two directions — #130 is the bug report of what
|
|
438
|
+
> happens when a generative brief meets a review-shaped pipeline, #134 is the request to support
|
|
439
|
+
> generative briefs properly — and both trace to one hard-coded frame telling every seat it was a
|
|
440
|
+
> reviewer. One declaration serves both, which is why they were designed together and shipped
|
|
441
|
+
> together rather than as a detector and a feature.
|
|
442
|
+
>
|
|
443
|
+
> **Lineage.** v4.6 through v4.8 each made the council *more honest about a run it already knew how
|
|
444
|
+
> to do* — announcing losses, counting money, attributing seats. v4.9 changes what a council can be
|
|
445
|
+
> asked for in the first place, which is a different kind of rev and is scoped as one.
|
|
446
|
+
|
|
357
447
|
## Backlog (tracked, not scheduled)
|
|
358
448
|
|
|
359
449
|
### Enterprise-readiness *(unscheduled — gated on funding / cofounder)*
|
|
@@ -388,9 +478,10 @@ consumer today (the Council Review GitHub Action) runs a single review per PR, n
|
|
|
388
478
|
agent driving it, or the `critique`/`refine` built-ins are wanted on their own — those are a much
|
|
389
479
|
smaller slice than the chaining machinery and could ship independently of F6.
|
|
390
480
|
|
|
391
|
-
⚠️ **
|
|
392
|
-
|
|
393
|
-
`
|
|
481
|
+
⚠️ **Its hard gate is already satisfied:** KNOWN_VARIABLES single-sourcing landed in v4.9 W1
|
|
482
|
+
(2026-08-25) — `src/template/render.js` now derives both validation and rendering from
|
|
483
|
+
`KNOWN_VARIABLES`, drift-tested, so `{{input}}` no longer waits on it. See `BACKLOG.md`
|
|
484
|
+
*Next-rev hard gates* (ticked).
|
|
394
485
|
|
|
395
486
|
### GUI power ergonomics (F10) *(unscheduled — dropped from v4.7, 2026-08-05)*
|
|
396
487
|
Focus-follows-fold hotkey, distinguishable window titles, tiling presets *(S each)*.
|
package/docs/configuration.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Configuration Reference
|
|
2
2
|
|
|
3
|
-
`amicus setup` is the recommended way to configure Amicus. It opens a graphical wizard that validates your API keys live, lets you pick a default model from the live catalog, and saves everything to `~/.config/amicus/.env` (permissions `0600`). The environment variables below are for overrides and advanced tuning — most users only need the API keys section.
|
|
3
|
+
`amicus setup` is the recommended way to configure Amicus. It opens a graphical wizard that validates your API keys live, lets you pick a default model from the live catalog — down to a specific model per provider, not just the family default — and saves everything to `~/.config/amicus/.env` (permissions `0600`). The environment variables below are for overrides and advanced tuning — most users only need the API keys section.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -78,6 +78,52 @@ not on every launch, and not when you explicitly chose the gateway with `--gatew
|
|
|
78
78
|
`routing.prefer: "openrouter"` (or pass `--gateway openrouter` per call) to keep routing everything
|
|
79
79
|
through OpenRouter as before.
|
|
80
80
|
|
|
81
|
+
### Cost tier
|
|
82
|
+
|
|
83
|
+
`routing.tier` is your standing answer to "when a vendor offers several models, which end of its
|
|
84
|
+
range do you want by default?" It lives under `routing` for filing reasons only — **it does not
|
|
85
|
+
change how a call is routed**, and it is not a gateway knob. Its one and only effect is which row
|
|
86
|
+
the **cost-aware default picker** preselects (`src/utils/provider-default-picker.js`).
|
|
87
|
+
|
|
88
|
+
| Tier | Means | Example (Anthropic) |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `"frontier"` | the most capable / most expensive of the vendor's line | `claude-opus-*` |
|
|
91
|
+
| `"balanced"` | the middle of the range — **the default** | `claude-sonnet-*` |
|
|
92
|
+
| `"economy"` | the cheapest of the line | `claude-haiku-*` |
|
|
93
|
+
|
|
94
|
+
Absent, misspelled or set to anything outside those three, the tier **coerces silently to
|
|
95
|
+
`"balanced"`** — a junk value never errors and never blocks a launch. Per-vendor tier resolution
|
|
96
|
+
lives in `src/utils/model-tiers.js`; when a vendor's catalog has no model matching the tier, the
|
|
97
|
+
picker falls back to the cheapest priced row, then the first row.
|
|
98
|
+
|
|
99
|
+
**`routing.tier` is hand-edited only.** No wizard step, CLI command or GUI control writes it — set
|
|
100
|
+
it yourself in `~/.config/amicus/config.json` (the same rule as [`maxCostPerMtok`](#cost-gate)
|
|
101
|
+
below):
|
|
102
|
+
|
|
103
|
+
```jsonc
|
|
104
|
+
{ "routing": { "prefer": "direct", "tier": "economy" } }
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Where the picker actually runs.** It offers you that vendor's models, priced, with the tier's pick
|
|
108
|
+
flagged as recommended, and writes your choice to `aliases.<vendor>` (seeding `config.default` when
|
|
109
|
+
that is still unset). Three surfaces reach it:
|
|
110
|
+
|
|
111
|
+
- `amicus key <provider> <key>` — after a successful **cloud**-vendor key save (local-provider
|
|
112
|
+
bearer saves skip it).
|
|
113
|
+
- `amicus setup` — the readline wizard runs it once per keyed provider, in detection order.
|
|
114
|
+
- The **Electron setup window** — the same picker, with a family → model drill-down.
|
|
115
|
+
|
|
116
|
+
Non-interactively (`--json`, `--quiet`, or no TTY) the picker takes the recommended pick silently and
|
|
117
|
+
prints a one-line summary instead of prompting. It is also a graceful no-op for `openrouter`, which
|
|
118
|
+
is a gateway rather than a model vendor.
|
|
119
|
+
|
|
120
|
+
**`routing.tier_onboarded`** is bookkeeping, not a setting: a boolean written automatically the
|
|
121
|
+
first time `amicus start` prints the one-time tip pointing existing users at the picker
|
|
122
|
+
(`src/utils/start-helpers.js`). The tip only fires on an interactive run that already has a direct
|
|
123
|
+
provider key and has not used the picker yet, and the flag is set only when the line actually
|
|
124
|
+
printed — so a `--json` run never burns it. Don't hand-edit it; delete it if you want the tip once
|
|
125
|
+
more.
|
|
126
|
+
|
|
81
127
|
---
|
|
82
128
|
|
|
83
129
|
## Behavior
|
|
@@ -343,12 +389,16 @@ level includes everything above it.
|
|
|
343
389
|
},
|
|
344
390
|
|
|
345
391
|
// Gateway routing policy (see Routing above). `prefer` defaults to "direct"
|
|
346
|
-
// when this key is absent entirely. `
|
|
347
|
-
//
|
|
348
|
-
//
|
|
392
|
+
// when this key is absent entirely. `tier` is the cost-tier preference the
|
|
393
|
+
// model picker preselects on ("frontier" | "balanced" | "economy"; anything
|
|
394
|
+
// else coerces to "balanced") — hand-edited only, see Cost tier above.
|
|
395
|
+
// `migration_notified` and `tier_onboarded` are both written automatically
|
|
396
|
+
// when their one-time notices fire — don't hand-edit either.
|
|
349
397
|
"routing": {
|
|
350
398
|
"prefer": "direct",
|
|
351
|
-
"
|
|
399
|
+
"tier": "balanced",
|
|
400
|
+
"migration_notified": { "openai": true },
|
|
401
|
+
"tier_onboarded": true
|
|
352
402
|
},
|
|
353
403
|
|
|
354
404
|
// User-defined local / OpenAI-compatible providers (v4.2) — written by
|
package/docs/council.md
CHANGED
|
@@ -21,6 +21,7 @@ orchestration recipe. This page is the reference for the artifacts that recipe p
|
|
|
21
21
|
|
|
22
22
|
- [The pipeline, end to end](#the-pipeline-end-to-end)
|
|
23
23
|
- [`amicus council run`](#amicus-council-run)
|
|
24
|
+
- [Task mode (`--intent task`)](#task-mode---intent-task)
|
|
24
25
|
- [Debate mode](#debate-mode)
|
|
25
26
|
- [Council Workspace (GUI)](#council-workspace-gui)
|
|
26
27
|
- [Auto-open on `amicus_council_run` (v4.5)](#auto-open-on-amicus_council_run-v45)
|
|
@@ -112,6 +113,7 @@ amicus council run --prompt-file <briefing.md>
|
|
|
112
113
|
[--gateway auto|direct|openrouter] [--no-validate-model]
|
|
113
114
|
[--template <name|path>] [--artifact <file>] [--var k=v] # v4.5, see docs/usage.md#briefing-templates
|
|
114
115
|
[--pack <name|path>] # v4.5, see docs/usage.md#policy-packs
|
|
116
|
+
[--intent review|task] # v4.9, see Task mode below
|
|
115
117
|
```
|
|
116
118
|
|
|
117
119
|
**The headless engine (v4.0).** Everything the `second-opinion` skill orchestrates by hand in
|
|
@@ -258,7 +260,10 @@ cross-process lock.
|
|
|
258
260
|
`verdict.json` here is the **undecided** verdict — same schema as [`amicus council
|
|
259
261
|
verdict`](#amicus-council-verdict)'s output (council family v2) plus **`overallVerdict`**
|
|
260
262
|
(`"Ship it" | "Fix these first" | "Fundamental rethink" | null`), parsed from the chair's final
|
|
261
|
-
`VERDICT:` line.
|
|
263
|
+
`VERDICT:` line — or, on a task run (`--intent task`, v4.9), `"Converged" | "Split" |
|
|
264
|
+
"Insufficient" | null` parsed from its final `ANSWER:` line instead (both scales, and why they
|
|
265
|
+
are disjoint, are in the `overallVerdict` key note under [`amicus council
|
|
266
|
+
verdict`](#amicus-council-verdict)). Example excerpt:
|
|
262
267
|
|
|
263
268
|
```json
|
|
264
269
|
{
|
|
@@ -282,6 +287,82 @@ Consumers gate on **tiers + the chair verdict line** (`overallVerdict`), per the
|
|
|
282
287
|
report-only Stage-4 policy. Headless runs pin `meta.claudeInCouncil: false`,
|
|
283
288
|
`meta.runType: "headless"`, and the chair is excluded from the street-cred universe.
|
|
284
289
|
|
|
290
|
+
### Task mode (`--intent task`)
|
|
291
|
+
|
|
292
|
+
By default a council **reviews** the material it is given. `--intent task` (over MCP: the `intent`
|
|
293
|
+
parameter on `amicus_council_run`, spelled `'task'`) points the same pipeline at **open-ended work**
|
|
294
|
+
instead: the bench *produces* what the briefing asks for, and the chair synthesizes an **answer**
|
|
295
|
+
rather than a verdict about a review that never happened.
|
|
296
|
+
|
|
297
|
+
`review` is the default, and it is never stored: `--intent review` is accepted and normalized away
|
|
298
|
+
at every door, so nothing writes `intent: "review"` onto `run.json`, `tally.json` or `verdict.json`.
|
|
299
|
+
Only `"task"` is ever recorded — the same emit-when-set idiom as `--tag`. Any other value is a
|
|
300
|
+
pre-flight `BAD_ARGS` failure before any spend.
|
|
301
|
+
|
|
302
|
+
**What changes, stage by stage:**
|
|
303
|
+
|
|
304
|
+
| Stage | Review intent (default) | Task intent |
|
|
305
|
+
|---|---|---|
|
|
306
|
+
| Stage 1 | *"You are one reviewer… Review the material"* — each seat critiques the briefing | *"you are not reviewing the briefing, you are executing it"* — each seat produces the deliverable, then declares the load-bearing claims it rests on |
|
|
307
|
+
| Stage 2 rank | Order the reviews by how **accurate** each critique was | Order the responses from the one that **best does the work the briefing asked for** to the one that does it least well |
|
|
308
|
+
| Stage 2 adjudicate | For every finding id, `agree`/`dispute`/`neutral` on the **critique** | For every claim id, `agree`/`dispute`/`neutral` on whether **the claim holds** |
|
|
309
|
+
| Chair | `VERDICT: Ship it \| Fix these first \| Fundamental rethink` | `ANSWER: Converged \| Split \| Insufficient` |
|
|
310
|
+
| Reliability ledger | One row per (run × model) appended | **Nothing appended** |
|
|
311
|
+
|
|
312
|
+
**The two scales are disjoint on purpose.** They share no value and no keyword, which is what lets
|
|
313
|
+
each parser stay blind to the other's line: a task run can never report `"Ship it"`, and a review run
|
|
314
|
+
can never report `"Converged"`. The run's intent is what selects the parser — including on a Stage-5
|
|
315
|
+
`amicus council verdict` rebuild long after the run is over, where a carried `overallVerdict` from
|
|
316
|
+
the *wrong* scale is refused and the chair's prose is re-parsed instead. Full field semantics are in
|
|
317
|
+
the `overallVerdict` and `intent` key notes under
|
|
318
|
+
[`amicus council verdict`](#amicus-council-verdict).
|
|
319
|
+
|
|
320
|
+
**What does *not* change.** The Stage-1 output contract is identical — the same trailing fenced JSON
|
|
321
|
+
skeleton, the same `blocker | major | minor | nit` severity enum, the same required-non-empty
|
|
322
|
+
`location`, validated by the same validator and repaired by the same bounded repair loop. Only the
|
|
323
|
+
frame and the field *glosses* fork. In task mode `location` is the grounding discipline: it names
|
|
324
|
+
what the claim rests on — a source, a computation, or the literal word `assumption`. An empty
|
|
325
|
+
`findings[]` under a real `overall` is a valid task response, exactly as it is a valid review, and
|
|
326
|
+
the bench is told so rather than left to invent claims to fill the array.
|
|
327
|
+
|
|
328
|
+
Two things a task bundle carries that a review bundle never does: the Stage-2 judge packet ends with
|
|
329
|
+
a `--- THE BRIEFING (what every response was asked to do) ---` section — judges cannot rank *how well
|
|
330
|
+
the work was done* without the ask — and that section is fenced as reference material, because it is
|
|
331
|
+
the first time briefing text reaches a judge in band.
|
|
332
|
+
|
|
333
|
+
**Task runs write no reliability rows, and say so.** Two gates enforce it (the engine's own append
|
|
334
|
+
and `amicus council tally`'s), and `council tally` refuses a `meta.intent` that is neither spelling
|
|
335
|
+
rather than letting a near-miss slide into the ledger. Where the skip is **load-bearing** it is
|
|
336
|
+
**announced, and the announcement does not degrade the run** — a `Note:` record on the
|
|
337
|
+
`ledger-skipped` channel with `kind: "info"`, which the degrade sink cannot use to flip a run's
|
|
338
|
+
`degraded` state. ⚠️ It is emitted at one site, not on every task run: the chair-fallback promotion
|
|
339
|
+
arm, reached only after the chair's own attempts have all failed and the run still has budget,
|
|
340
|
+
because that arm is the one step that draws on ledger history a task run never fed. A task run whose
|
|
341
|
+
chair answers has no `ledger-skipped` note, and needs none. `info` records are announcements, not losses: the report gives
|
|
342
|
+
them their own **Notes:** list and keeps them out of `## What was lost`. Relatedly,
|
|
343
|
+
[`amicus council stats`](#amicus-council-stats) on an empty ledger now names where rows come from
|
|
344
|
+
instead of implying that no council ever ran.
|
|
345
|
+
|
|
346
|
+
**Read the tiers correctly.** A task run's report carries the line *"Tiers report peer concurrence,
|
|
347
|
+
never verification."* directly under the tier counts, and the chair's own packet carries the same
|
|
348
|
+
caveat beside the adjudications it is weighing. Peer agreement on a generative bench is correlation
|
|
349
|
+
between models trained on overlapping priors — a tier says *how many peers concurred*, never *that
|
|
350
|
+
the claim was checked*.
|
|
351
|
+
|
|
352
|
+
**Review runs are byte-identical.** Not "unchanged as far as we know": the review path composes
|
|
353
|
+
through the same dispatcher, and the shared packet — section headers, `Review by <model>` labels,
|
|
354
|
+
empty-section wordings — is used verbatim in both intents. One vocabulary, two instructions.
|
|
355
|
+
|
|
356
|
+
**Limitations, as of v4.9:**
|
|
357
|
+
|
|
358
|
+
- **One intent per run.** There is no mixed bench; the whole run is a task run or a review run.
|
|
359
|
+
- **Intent is not pack-settable.** A [policy pack](./usage.md#policy-packs) cannot carry it — pass
|
|
360
|
+
the flag (or the MCP parameter) explicitly.
|
|
361
|
+
- **`--claude-review` is refused with `--intent task`.** Entering a file as review N+1 is review
|
|
362
|
+
machinery and has no task-mode meaning.
|
|
363
|
+
- **Task runs build no reliability history**, so they never contribute to — and never benefit from —
|
|
364
|
+
`amicus council stats`, including the ledger-driven chair-fallback promotion.
|
|
365
|
+
|
|
285
366
|
### Debate mode
|
|
286
367
|
|
|
287
368
|
`--debate` adds a **Stage-2.5 rebuttal round** between cross-review and the final tally
|
|
@@ -757,7 +838,8 @@ named here. That is why the v4.8 keys below each needed their own line.
|
|
|
757
838
|
**Key notes:**
|
|
758
839
|
- `schemaVersion` — verdict-document schema version (currently `2`).
|
|
759
840
|
- `type` — document-type discriminator; always `"council-verdict"` (council family v2 envelope).
|
|
760
|
-
- `overallVerdict` — the chair's
|
|
841
|
+
- `overallVerdict` — the chair's terminal-line outcome, on **one of two disjoint scales, chosen by the run's intent**. A review run (no `intent` key) carries a verdict-scale value — `"Ship it"`, `"Fix these first"`, `"Fundamental rethink"` — parsed from the chair's `VERDICT:` line. A **task run** (`intent: "task"`, v4.9) carries an answer-scale value — `"Converged"`, `"Split"`, `"Insufficient"` — parsed from the chair's `ANSWER:` line. The two scales share no value and no keyword, which is what lets each parser be blind to the other's line; a task run therefore never reports `"Ship it"`, and a review run never reports `"Converged"`. `null` on either scale when no chair terminal line was produced (populated by the headless engine during Stage 3; `null` for a plain `council verdict` merge without engine integration).
|
|
842
|
+
- `intent` — **v4.9**, optional, `"task"` only. Present exactly when the run was launched with `--intent task`; absent means review — the engine never writes `"review"` (emit-when-task, the same idiom as `tag`). It is the key every renderer forks on: the report's concurrence qualifier and header word, the fold's and the Workspace chip's `ANSWER:`/`VERDICT:` label, and the chair's own packet/parser upstream of this document.
|
|
761
843
|
- `seats` — **v4.8**, optional. The tally record's `meta.seats` (same `{id, alias, role, lens, position}` shape), promoted to the top level next to `seatLoss`. Present only when the tally record carried one, i.e. only when the bench repeated an alias. It is what makes the `alias#N` ids on `findings[].raiserSeat`, `adjudications[].seat` and `runStats[].seat` resolvable from the verdict **alone** — before v4.8 the verdict named seats it could not resolve. `council report` reads it to give each seat its own adjudication-matrix column; when it is absent, or is not an array of objects each carrying a string `id`, the **adjudication matrix** falls back to alias space whole and renders exactly as it did before v4.8. ⚠️ **That fallback is the matrix's alone — it is not a whole-document guarantee.** The street-cred table beside it labels each row from `streetCred[].seat` whenever the row carries one, a predicate independent of this key, so a verdict with seated `streetCred[]` rows and no usable `seats` renders seat ids in the street-cred table and aliases in the matrix (measured on an absent `seats`, a non-array `seats`, and an array-of-strings `seats`). In-process both fields come from the same twin bench and travel together; the split is reachable on a hand-assembled or externally-supplied record, which `buildVerdict`'s own docblock names. A verdict written before v4.8 carries no `streetCred[].seat` at all and is unaffected.
|
|
762
844
|
- `findings[].raiserSeat` — **v4.8**, optional. The raising seat's id, carried through from the tally record; absent unless the bench repeated an alias. `findings[].raiser` stays the alias.
|
|
763
845
|
- `findings[].sameModelCorroboration` — **v4.8**, optional, `true` only. Carried through from the tally record; see the tally-record notes above for the stamp's meaning **and for the two directions in which it is wrong** (it misses one model behind two aliases, and it fires falsely on one alias behind two executables).
|
|
@@ -802,7 +884,12 @@ wrapper over `buildReport()` (`src/council/report.js`, which builds the neutral
|
|
|
802
884
|
dispatches to `report-md.js` / `report-html.js` — the two renderers that own the string formats).
|
|
803
885
|
|
|
804
886
|
**What it renders**, in this order: a header (run type, id, date, chair, council members), a
|
|
805
|
-
|
|
887
|
+
tier-count summary table — headed **Verdict summary** on a review run and **Answer summary** on a
|
|
888
|
+
task run, since a task run produces an answer, not a verdict, and on a task run followed by the
|
|
889
|
+
one-line concurrence qualifier (*tiers report peer concurrence, never verification*) — a
|
|
890
|
+
**What was lost** section
|
|
891
|
+
when the run degraded (plus a **Notes** list for informational records, e.g. a task run's
|
|
892
|
+
ledger-skipped announcement), the **adjudication matrix** (finding × judge, `✓`/`✗`/`–` with
|
|
806
893
|
`*` marking the raiser's own vote), the **peers-only street-cred table**, **findings grouped by
|
|
807
894
|
tier** (Disputed first), and a **cost table** (per-model status/duration/cost + wave total,
|
|
808
895
|
sourced from `runStats[].usage`).
|
|
@@ -873,17 +960,18 @@ matrix does not carry — `` `†` `` marks a finding corroborated only by anoth
|
|
|
873
960
|
same model — so from v4.8.0 the two legends are no longer interchangeable. That line, and the `†`
|
|
874
961
|
itself, appear only on a run that actually raised such a finding, which is a twin bench only.
|
|
875
962
|
|
|
876
|
-
⚠️ **v4.8
|
|
877
|
-
sentence above is scoped to the **matrix**, and stays true.
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
963
|
+
⚠️ **v4.8 filed a SECOND report/Workspace divergence, in the street-cred table — CLOSED in v4.9.**
|
|
964
|
+
The sentence above is scoped to the **matrix**, and stays true. All three street-cred renderers now
|
|
965
|
+
label each row `seat || model`: `report-md.js` and `report-html.js` (v4.8), and the Workspace's own
|
|
966
|
+
(`electron/workspace-ui/workspace-matrix.js :: renderVerdict`, v4.9). A twin bench reads
|
|
967
|
+
`gemini#1` / `gemini#2` in every one of them, instead of the Workspace reading `gemini` twice with
|
|
968
|
+
different numbers under one identical name; on any bench with no repeated alias all three are
|
|
969
|
+
unchanged, because every seat id there *is* its alias. ⚠️ **Blind mode is the deliberate exception
|
|
970
|
+
and is unchanged**: the Workspace still shows the anonymised label, falls back to the model alias
|
|
971
|
+
when no label resolves, and renders a seat id in neither case — a seat id contains its alias, so
|
|
972
|
+
printing one would defeat blind mode (the same rule the matrix follows two paragraphs above).
|
|
973
|
+
`BACKLOG.md` filed this behind the gate *"`opts.labelOf` must accept a seat id"*, which the fix did
|
|
974
|
+
not need: `labelOf` stays alias-keyed, because the value blind mode has to show was never the seat.
|
|
887
975
|
|
|
888
976
|
This is the same renderer the `second-opinion` skill calls in Stage 5 to produce `report.html`.
|
|
889
977
|
**`report.md` and this renderer's output are two different files** — `report.md` is Claude-authored
|
package/docs/troubleshooting.md
CHANGED
|
@@ -237,11 +237,18 @@ For full headless configuration, see [docs/configuration.md](./configuration.md)
|
|
|
237
237
|
|
|
238
238
|
**Cause:** The mechanism only knows that the deadline passed with no substantive activity — no output, reasoning, or tool calls — for the backstop window (300 s by default for an ordinary leg). It does **not** know *why*. Do not read this as "the endpoint is dead" or "the model isn't being served" — the message deliberately stops short of that claim, because at one of its two firing sites the backstop can win the race before the prompt send even resolves, so acceptance itself was never observed. Treat `NO_OUTPUT_BACKSTOP` as "silence past the deadline," not a diagnosis.
|
|
239
239
|
|
|
240
|
-
|
|
240
|
+
Two trailing clauses are the exceptions, and neither is the mechanism's inference:
|
|
241
|
+
|
|
242
|
+
- ` — engine log: <excerpt>` (since v4.9) is the OpenCode engine's own ERROR line for this exact session, quoted verbatim from the engine's log. That clause is the engine speaking. "For this exact session" is strict: the line must name your session in one of the engine's own session fields (`session.id=`, `id=`, …), so a neighbouring session's failure is never quoted at you — and when nothing on disk meets that bar, the clause is simply absent rather than approximate.
|
|
243
|
+
- ` (engine skew: server <a> ≠ installed <b>)` (since v4.9) means the engine serving **this** run reported a different version than the `opencode-ai` sitting in the install that launched it — two facts, both published by the software itself, neither guessed. It names the server this leg actually talked to, as of this leg's most recent session: a skew seen on some other server in the same process, or one that was fixed part-way through, never rides along on a report it does not belong to. This is #133's own shape; see the Lesson below.
|
|
244
|
+
|
|
245
|
+
The two clauses are independent: either can appear without the other, and the skew clause is **not** conditional on the log read succeeding. With neither, the message is exactly what it was before v4.9. Everything before them is still only "silence past the deadline".
|
|
246
|
+
|
|
247
|
+
**Lesson from #133:** an earlier version of this message *did* guess a cause ("likely a listed-but-not-serving model or a dead endpoint"), and that guess sent 30 minutes of debugging at model ids and API keys on a real incident. The actual cause was an OpenCode engine version skew between the npx-cached copy and the global install — sitting in the engine's own log the whole time, at the exact timestamp of every dead session. **Both halves are now surfaced for you** (v4.9): the log line becomes the ` — engine log:` clause, and the skew itself is detected at session-create time — announced on stderr as `[amicus] engine version skew: …` (once per standing skew per server, not once per session) and repeated in the ` (engine skew: …)` clause above. The remedy is to make the two copies the same version — update whichever is behind (`npm i -g amicus`, or re-run the installer for the surface that failed). `amicus doctor` will **not** confirm this one: its engine check compares npx-cached copies against the global install and is structurally blind to the copy the running server loaded, so it can report clean while this notice is firing. One related line can also appear, once per process: `[amicus] server identity unavailable — skew attribution is process-wide; SDK shape may have changed`. It means amicus could not read which server a client is talking to, so skew records stop being kept per server and share one bucket — the skew detection still works, but a clause could in principle be attributed to the wrong server when a run talks to more than one. It is a report about amicus itself, not about your models; if you see it, the OpenCode SDK has probably changed shape and amicus needs an update. If neither clause is present, read the log yourself before chasing model/endpoint theories — see the fix below for where it lives.
|
|
241
248
|
|
|
242
249
|
**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 one possible explanation, 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.
|
|
243
250
|
|
|
244
|
-
**Fix:**
|
|
251
|
+
**Fix:** Read the ` — engine log: …` clause on the failure message first, if it has one — that is the engine's own account of this session (see #133 above). If it has none, look yourself: OpenCode writes its logs to `$XDG_DATA_HOME/opencode/log` when that variable is set, otherwise `~/.local/share/opencode/log` (that path holds on Windows too) — check **both** when `XDG_DATA_HOME` is set, since a leftover value can point at a directory the running engine never writes to (amicus searches all of them, newest file first, and answers from the most recently written line that both is an ERROR and names your session). Current engine builds write **one timestamped file per process** there, e.g. `2026-08-25T185532.log`; older ones append to a single `opencode.log` in the same directory, and both layouts turn up on real machines — so check the newest files by modification time, not one fixed filename. The session's `ses_…` id is the correlation key. Then check the alias's target (`amicus models --search <term>` to find the current id, then re-point the alias) — a stale alias is a common case, but not the only one. If the failing leg was a Stage-1 retry (the window read `600s`, or generally double your configured/default value), `AMICUS_NO_OUTPUT_BACKSTOP_MS` **is** the lever — raising it raises both the first attempt's window and the retry's doubled one, unless your `--timeout` is low enough that the doubled window is clamped to the leg timeout. On an ordinary (non-retry) leg, raise it only if a model legitimately needs more than 300 s to produce its first token. The live probe's fixed 30 s window is the one case the env var genuinely cannot touch. See [docs/configuration.md § Headless Poller Tuning](./configuration.md#headless-poller-tuning).
|
|
245
252
|
|
|
246
253
|
---
|
|
247
254
|
|