amicus 4.3.0 → 4.4.1
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 +64 -0
- package/README.md +6 -3
- package/docs/DISTRIBUTION.md +234 -0
- package/docs/ROADMAP.md +200 -0
- package/docs/SHIMS.md +62 -0
- package/docs/architecture.md +104 -0
- package/docs/configuration.md +371 -0
- package/docs/council.md +911 -0
- package/docs/doc-system.md +92 -0
- package/docs/electron-testing.md +471 -0
- package/docs/jsdoc-setup.md +75 -0
- package/docs/opencode-integration.md +114 -0
- package/docs/publishing.md +60 -0
- package/docs/schemas.md +55 -0
- package/docs/testing.md +589 -0
- package/docs/troubleshooting.md +298 -0
- package/docs/usage.md +699 -0
- package/electron/fold.js +1 -1
- package/electron/ipc-workspace.js +283 -0
- package/electron/main.js +31 -1
- package/electron/preload-workspace.js +40 -0
- package/electron/setup-ui-aliases.js +6 -6
- package/electron/workspace-shell.js +85 -0
- package/electron/workspace-ui/index.html +111 -0
- package/electron/workspace-ui/live-model.js +112 -0
- package/electron/workspace-ui/md-lite.js +163 -0
- package/electron/workspace-ui/workspace-app.js +240 -0
- package/electron/workspace-ui/workspace-matrix.js +249 -0
- package/electron/workspace-ui/workspace-panels.js +237 -0
- package/electron/workspace-ui/workspace-render.js +277 -0
- package/electron/workspace-ui/workspace-verbs.js +293 -0
- package/electron/workspace-ui/workspace.css +172 -0
- package/package.json +8 -3
- package/schemas/council-run-live.schema.json +25 -1
- package/schemas/council-run.schema.json +34 -0
- package/schemas/progress.schema.json +26 -1
- package/schemas/spend.schema.json +52 -4
- package/skills/second-opinion/MODEL-NOTES.md +53 -5
- package/src/cli-handlers-council-run.js +25 -3
- package/src/cli-handlers-spend.js +50 -5
- package/src/cli-handlers-watch.js +48 -10
- package/src/cli.js +4 -2
- package/src/council/briefings-debate.js +27 -7
- package/src/council/briefings-stage2.js +155 -25
- package/src/council/briefings.js +59 -3
- package/src/council/findings.js +236 -9
- package/src/council/parse-stage2.js +10 -2
- package/src/council/report.js +19 -8
- package/src/council/run-assemble.js +42 -1
- package/src/council/run-budget.js +277 -0
- package/src/council/run-chair.js +4 -1
- package/src/council/run-debate.js +4 -2
- package/src/council/run-finalize.js +102 -0
- package/src/council/run-launch.js +73 -7
- package/src/council/run-server.js +248 -0
- package/src/council/run-stage2.js +118 -0
- package/src/council/run-stages.js +148 -113
- package/src/council/run-state.js +23 -1
- package/src/council/run.js +52 -53
- package/src/council/tally.js +10 -0
- package/src/headless.js +519 -17
- package/src/mcp-council-awareness.js +53 -3
- package/src/observe/council-legs.js +240 -0
- package/src/observe/live-doc.js +39 -4
- package/src/observe/watch-render.js +23 -1
- package/src/opencode-client.js +15 -3
- package/src/sidecar/child-sessions.js +197 -0
- package/src/sidecar/conversation-mirror.js +111 -37
- package/src/sidecar/fanout-budget.js +71 -0
- package/src/sidecar/fanout-leg-fallback.js +69 -21
- package/src/sidecar/fanout-leg.js +29 -1
- package/src/sidecar/fanout-signals.js +61 -0
- package/src/sidecar/fanout-wave-io.js +75 -0
- package/src/sidecar/fanout.js +65 -81
- package/src/sidecar/progress-fields.js +26 -4
- package/src/sidecar/progress.js +8 -1
- package/src/sidecar/session-utils.js +23 -14
- package/src/sidecar/tool-part.js +196 -0
- package/src/sidecar/workspace-window.js +62 -0
- package/src/spend-query.js +33 -6
- package/src/utils/env-num.js +42 -0
- package/src/utils/lifecycle.js +37 -1
- package/src/utils/path-fence.js +120 -0
- package/src/utils/pricing.js +114 -9
- package/src/utils/server-setup.js +79 -1
- package/src/utils/spend-ledger.js +24 -3
- package/src/workspace/artifact-guard.js +208 -0
- package/src/workspace/blind-mode.js +32 -0
- package/src/workspace/fold-format.js +124 -0
- package/src/workspace/live-normalize.js +169 -0
- package/src/workspace/matrix-model.js +94 -0
- package/src/workspace/run-detail.js +229 -0
- package/src/workspace/run-scan.js +148 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amicus",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.1",
|
|
4
4
|
"description": "Multi-model LLM Council + parallel AI window for Claude Code. Run structured council reviews across Gemini, GPT, DeepSeek and more — or fork a conversation to any model and fold the results back.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Christian Wagner"
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,70 @@
|
|
|
3
3
|
All notable changes to Amicus are documented here. Format follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow semver.
|
|
5
5
|
|
|
6
|
+
## [4.4.1] - 2026-07-27
|
|
7
|
+
|
|
8
|
+
A fast-follow patch on 4.4.0. Every item is a correction to something already shipped, and almost all of it was measured against real paid council runs rather than reasoned about — the five gate councils that certified the Council Workspace are also what found these. Five behaviour changes ride along and are called out under **Changed**, because a user upgrading a patch should not discover them by surprise.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **The repair path is whole for the first time.** 4.4.0 gave the Stage-1 findings repair the review it was repairing; the judge, chair, defense and re-vote repair prompts carried the identical omission, and `buildChairRepairPrompt` took no arguments at all. A repair leg is a *fresh* session with no memory of the turn it is repairing, so shipping only the validation errors asked a model to correct something it had never seen. **Three of the five paid gate councils burned a seat on it:** `wsgate02`'s `qwen` and `wsgate04`'s `glm` each refused twice ("I don't have a previous review to correct"), so a 4-model bench silently adjudicated on 3 while still paying for the fourth; `costgate01`'s `grok` complied instead — by **inventing a self-referential finding about its own empty output**, which entered `tally.json`, the street-cred rankings, the chair synthesis, and a human's decision. Every repair call site now embeds the text that actually failed, verbatim and uncapped, tracked across attempts so the errors and the artifact always describe the same generation. Separately, a repair that **silently changes the finding count is now refused** rather than adjudicated: the repair contract is "the same findings, fixed", and a count change is exactly the fabrication shape above. Where the original block was absent or unparseable there is no count to compare, so the repair is accepted but marked `findingsUnverified` rather than implying a check happened. A repair's output never replaces the review's prose — that would hand the judges a narrative-free review and put a JSON dump in the Stage-2 bundle.
|
|
13
|
+
- **Three of four seats on a paid council were silently truncated by the fence extractor.** The closing-fence pattern was unanchored, so the **first triple-backtick anywhere inside a JSON body ended the match** — and a review *of markdown* inevitably quotes a fence. On the $1.95 renderer-review council, `glm`, `opus` and `minimax` all came back `NOT_PARSEABLE` and collapsed to `conformance: unstructured`; replayed against the same artifacts after the fix they yield 6, 5 and 4 findings respectively. **15 of 17 findings were lost or left to a paid repair wave to rescue, and the chair synthesised from the two that survived without knowing the rest existed.** The extractor now enumerates every fenced opener independently, reads each one both ways (close-at-line-start primary, same-line close as fallback), and lets **`JSON.parse` arbitrate** — the last opener whose body actually parses wins. This is the repo's only fence extractor and all five consumers funnel through it, so judge, debate-defense and re-vote parsing carried the identical defect and are fixed by the same change; each now has its own test so a future re-implementation cannot regress one silently. The malformed-versus-absent distinction is preserved deliberately: a cut-off emit that never closed at all is still *absent*, because the repair path answers "no findings block" and "a broken findings block" differently.
|
|
14
|
+
- **A council run no longer races itself for OpenCode's database.** A run started a fresh OpenCode server for the Stage-1 seat wave, the critic solo, each findings repair, the Stage-2 judge wave, each judge repair, each debate wave and the chair chain — 10+ spawns, each one a fresh chance to lose OpenCode's SQLite startup race. Stage 1 launches its seat wave and its critic solo under one `Promise.all`, so two of those starts are ~140 ms apart *by construction*: one run **lost four of five seats in 736 ms** to `database is locked` and failed quorum, which is what made `--critic` a coin flip. A run now acquires **one** server and forwards it into every launch, closed once on the single path every terminal outcome already funnels through. It never fails closed — a shared server that will not start is a notice, and the run falls back to one server per wave exactly as before. The Stage-2 anonymization boundary was verified rather than assumed: judges run in the run's `_scratch` directory and scoping is per-call, so nothing about it ever lived in the server process. Separately, a **lock-class** start failure (`database is locked`, `database table is locked`, `SQLITE_BUSY` — and nothing else) is now retried 3 times over ≤750 ms, which covers the races a single process cannot remove: two amicus processes, or a CLI run beside a live MCP server. A missing binary, an auth failure, a port conflict and a failed health check are deterministic and fall straight through rather than tripling the latency before the same error.
|
|
15
|
+
- **`amicus spend` stopped reporting a total that `council run` calls inexact.** A leg whose spawned subagent could not be accounted for wrote a **priced** ledger row, so `unpricedRows` never caught it and the product's two truthfulness surfaces disagreed about the same dollars. Such a row now carries the flag and is counted as `unattributedSubtreeRows` **beside — never instead of —** `unpricedRows`, since a row can be both; the human table gains a second, distinctly worded line, because "we could not see this leg at all" and "we saw this leg but not what it spawned" are different facts. The MCP `amicus_spend` tool inherits it unchanged. And the unknown-spend notice is no longer **sticky**: it guarded on a boolean, so the first unknown leg was announced and every one created afterwards — Stage 2, repairs, debate, chair — was silently swallowed. It now re-announces on a growing count, and says "so far this run" rather than repeating a cumulative number as if it were new.
|
|
16
|
+
- **A leg observed only through cache tokens reports `unknown`, not a falsely free `$0`.** The observation gate accepted `cacheRead`/`cacheWrite`/`reasoning`, but the estimate prices `input`/`output` only — so a leg observed in neither passed the gate and resolved to `estimated $0.0000`, the same authoritative false zero 4.4.0 exists to eliminate, in the one corner its predicate did not cover. The v4.2 free-local `$0` tier is untouched: a real local seat reports genuine token counts and still resolves to `estimated ~$0.0000`.
|
|
17
|
+
- **A leg that both fell back to another model and left an unattributable subtree no longer reports `costExact: true`.** Folding a leg's attempts together returned a bare `{tokens, cost}` and dropped the subtree flag, so `run.json` claimed a complete total for a number that was a floor. The fold now preserves every key: the flag ORs across attempts (a gap admitted once cannot be erased by a later clean attempt) and a measured subtree sums rather than last-wins. Separately, the spend reader promised to skip corrupt ledger lines but let a valid-JSON *scalar* through as a row, inflating both `runs` and `unpricedRows`.
|
|
18
|
+
- **A failed leg no longer renders as complete in the Council Workspace.** A seat that errored or timed out could show a green check, because `timed-out` was missing from the terminal-state lists the mirror consults. Alongside it: the leg-role guard is now symmetric, a leg that throws writes a terminal progress record instead of leaving its last live one as the final word, and swallowed read failures are logged rather than discarded.
|
|
19
|
+
- **A permission failure is no longer reported as "not written yet".** An unreadable run artifact was indistinguishable from one the run had not produced yet, which had been producing a **silent chairless fold reporting `{ok: true}`** — the fold said it succeeded and carried no verdict. Three dead fallbacks and an unwired `legsTotal`/`legsComplete` pair were deleted in the same pass: a documented field that is never populated is worse than no field.
|
|
20
|
+
- **A Stage-1 wave that dies before its legs start no longer leaves the run looking healthy.** Such a wave wrote no `wave.json` at all, so nothing downstream could tell "the wave failed" from "the wave has not reported yet"; it now degrades the run loudly. A shared-server acquisition that fails likewise degrades loudly instead of silently, and its **success** is recorded too — previously only the failure was.
|
|
21
|
+
- **The `haiku` alias was never broken.** It hard-404'd 3 of 3 times across two paid councils — as chair (twice, including the fallback retry) and as a bench seat, ~2 s and zero tokens each — and the standing diagnosis was a rotten model id. It is not: the cause is an `ANTHROPIC_BASE_URL` without its `/v1` suffix, an **environment** misconfiguration. Documented as such, because the prescribed "fix or remove the alias" would have deleted a working route. The more useful half of the lesson stands unchanged from 4.4.0: a dead alias does not stop a council, it shrinks one.
|
|
22
|
+
- **Renderer and markdown robustness.** The workspace's markdown renderer no longer re-slices its input on every inline token (identical output on 219,543 verified inputs — exhaustive to length 6 plus 200,000 fuzz cases — removing a dependence on a V8 string-representation detail nothing stated or tested); heading text is trimmed rather than baking trailing blanks into a text node; and an unreachable heading-level clamp is gone, pinned so a future widening fails loudly instead of silently emitting an `<h7>`.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- **A review that honestly finds nothing is now a valid review.** An empty finding set was a hard error, which structurally pressured a model to invent a finding — directly contradicting the anti-sycophancy clause shipped in every Stage-1 briefing, and `costgate01`'s `grok` did exactly that, reaching a human's decision. A **present-but-empty** `findings` array with a non-empty `overall` now validates. The lines that already existed are preserved: a broken emit keeps its own codes, an empty set with a blank or missing `overall` is still an error, and a *missing* `findings` key is still an error — only an array that is present and empty means "I read it and found nothing". The briefing now says what the validator enforces, which also makes the repair prompt's "emit an empty findings array and say so" branch describe an answer that can actually pass rather than a trap costing two paid legs. Downstream, an all-clean bench degrades gracefully: Stage 2 still runs (peer ranking, and therefore street-cred, is unaffected by an empty findings pool), and the judge bundle and chair packet **state** the empty index instead of rendering a heading over nothing under an order to adjudicate ids that do not exist — an instruction a judge obeying it answers by inventing an id, which buys up to two paid repair solos per judge. The debate stage is genuinely skipped and already records its reason. **This changes what a council means when every seat comes back clean.**
|
|
27
|
+
- **A leg that exceeds the tool-settle grace ceiling now has its OpenCode session aborted.** 4.4.0 bounded the wait and completed the leg anyway; it left the underlying session running and **billing** for output nobody would read. The leg's completion and partial output are unchanged — only the session is stopped, after the child-session walk so subtree attribution survives, and before the server closes, since on a shared server (i.e. every council run) the server is not closed here at all — which is precisely the pathological case. Whether the abort landed rides the result, the terminal `progress.json` and the leg's `metadata.json` as `toolSettleAborted`, and it is recorded as `false` when the abort was attempted and failed rather than omitted: "we tried to stop it and could not; it may still be billing" is the useful half of that signal. A failed or hung abort can never alter a leg that already succeeded.
|
|
28
|
+
- **A run under a `--max-cost` ceiling now exits `2` when its own total is inexact.** A fully-unpriced council could never trip the ceiling, so a ceiling silently bounded nothing while the run exited `0` — an unqualified success for a number the run itself was reporting as a floor. When a ceiling is set *and* the total is inexact, the run now exits `2`, through the same degraded path a budget-refused wave already uses; a signal and a real error are never re-labelled. **The ceiling still never blocks a run** and still trips on **known** spend only — a fully-unpriced bench under a $0.01 ceiling runs every stage to completion. The docs now say "`--max-cost` bounds **known** spend", which is what it has always done. Anything gating on `council run`'s exit status should expect `2` where it previously saw `0` on an inexact run.
|
|
29
|
+
- **`amicus watch <id> --ui` now validates the run id.** A malformed id skipped validation entirely and surfaced whatever the run lookup produced — a vaguer error than the identical typo gets on the terminal path. It now **exits `1` with the validator's message instead of launching the workspace**. Bare `amicus watch --ui` still opens the project run-list landing; the check applies only when an id is actually supplied.
|
|
30
|
+
- **`npm i -g amicus` now installs the documentation.** The package's `files[]` excluded `docs/` entirely, so every word of documentation was unreachable from an install — and the moment a user most needs troubleshooting text already on disk is an opaque `Not Found` with zero tokens, which is exactly when they have no reason to trust a browser tab instead. The 15 top-level `docs/*.md` pages now ship (**+15 files, 285 → 300; +93 KB packed, +8.8%**). Images and the plan/spec archive deliberately do not — ~425 KB with no offline value. A handful of roadmap references point at repo working files that still do not ship; they are now labelled as such rather than reading as broken paths.
|
|
31
|
+
- **The fold's `Cost:` line stops saying the same thing twice.** It appended the source name on top of a glyph that already encoded the same fact, printing `~$0.0100 (estimated)` and `? (unknown)`. Those two words are gone — `~` already means inexact and a bare `?` already means unknown. Two sources keep their word because the glyph vocabulary cannot express them: **`reported`**, since a plain `$0.4321` is also what an unrecognised source renders as, so the absence of a glyph cannot mean "exact"; and **`mixed`**, since `~` says *inexact* without saying *which kind* — collapsing `mixed` to a bare `~$…` makes it indistinguishable from `estimated`, and the two are not the same claim. `mixed` asserts that part of the number is genuinely measured.
|
|
32
|
+
|
|
33
|
+
### Security
|
|
34
|
+
|
|
35
|
+
- **The Council Workspace's markdown renderer has finally been reviewed by a bench.** The component that turns **another model's prose into DOM** was in none of the five gate councils' review sets and shipped in 4.4.0 uncertified; one chair called that out explicitly and rated it blocking, while another cleared the same file by reading its *consumers* rather than the file. A paid council was run against the file itself. **It found nothing exploitable** — no DOM injection (`textContent`/`createTextNode` only, fixed tag names, no HTML parsing of model-controlled content) and no prototype pollution — and the findings it did raise are architectural, fixed above under **Fixed**. The certification is recorded here rather than in a working note because the disagreement it settles was a public one. Its adversarial coverage is now pinned: prototype-pollution inertness, `javascript:`/`data:` URL inertness, malformed and unmatched inline backticks, the resource budget at exactly the artifact-size cap under both pathological shapes, and a widened attribute-sink guard — the previous banned-token scan covered four HTML-string APIs and would **not** have caught `setAttribute('href', userText)`, with a negative control proving the guard is not vacuous. Two rendering-fidelity findings were surfaced and deliberately not fixed; neither is a security property.
|
|
36
|
+
- **The Council Workspace's read-only posture is now enforced rather than asserted.** That the workspace never writes into a run directory was checked nowhere. It now is, by a guard that **parses** rather than greps: these files are dense with prose *about* writes, and a text scan that goes red for a comment gets weakened rather than fixed, so the guard builds an AST (comments are structurally absent from it) and matches string literals by exact equality. It pins that no write API appears in the workspace source, that the registered IPC channel set is **exactly** the seven known channels — so a new channel cannot be added without being classified — and that the one verb which legitimately writes, Abort, **delegates** to the engine's own abort path rather than writing itself. A positive control scans the engine's own writer and requires it to come back dirty, so a broken scan cannot pass by finding nothing. The Workspace's CSP likewise gains a real regression guard: "no violations" is also what a *loosened* policy produces, so the check now appends an inline `<script>` and requires the refusal to appear.
|
|
37
|
+
|
|
38
|
+
## [4.4.0] - 2026-07-26
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- **Council Workspace (GUI)** — third Electron mode `council-workspace`, opened via `amicus watch <councilRunId> --ui` (bare `--ui` opens the project run list). Renders live and historical council runs: stage rail, live per-seat status/tokens/cost (v4.3 data layer, 1.5s/5s poll depending on window focus/visibility), verbatim anonymized Stage-2 packet, tier-colored adjudication matrix with basis counts/thin/override badges, dissent drill-in with prose highlight, chair verdict + street-cred + Stage-4 decisions, cost-by-seat with `--max-cost` gauge. Blind-mode toggle (labels vs models; ON while live, OFF once terminal — a reading aid against anchoring bias, not a security control: the label map is plaintext in `run.json`). Two verbs: confirm-gated Abort (delegates to the engine's own council-aware abort path) and nonced Fold (chair verdict to the launching terminal; no model call). Fully sandboxed first-party page (CSP with no network directive at all, `contextIsolation`, textContent-only rendering of model prose, enforced by a static source scan); read-only against run directories **apart from the Abort verb, which checkpoints the run through the engine's own in-process abort path** — not a direct write from the workspace code itself. `--ui` is interactive-only (`--json` is rejected, not silently ignored).
|
|
43
|
+
- `CdpClient.workspace(port)` e2e factory (`file://` target, port 9225) + a fixture-driven workspace CDP suite.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **Zero-cost reporting no longer lies about spend.** A leg whose captured token totals were *all zero* used to be priced as `0 × catalog price` and labelled `estimated $0.0000` — an authoritative "this seat was free" for work that had genuinely been billed. Diagnosed against four real paid council runs plus OpenCode's own session database: `council-wsgate02` spent **$0.9859 against a `--max-cost` ceiling of $0.75 (131%)** while Amicus believed $0.3720 and never emitted `COST_EXCEEDED`. Four separate defects, all fixed here:
|
|
48
|
+
- `resolveLegCost` now gates the estimate on **observed tokens**, not on the mere existence of a price, so a zero-token leg resolves to `{amount: null, source: 'unknown'}`. The v4.2 free-local-provider `$0` tier is unaffected — a local seat still reports real token counts, so it keeps resolving to `estimated ~$0.0000`.
|
|
49
|
+
- The headless poll loop's fast-path exits (trailing fold marker, SDK `idle`) could break *before* OpenCode stamps `info.tokens`/`info.cost` — measured losing by 155 ms and 29 ms on real paid legs. A bounded, best-effort **post-loop usage re-poll** (≤3 reads, ~1.2 s worst case, usage capture only — never re-mirrors text) now closes that window.
|
|
50
|
+
- `progress.json`'s usage snapshot was only ever written on `receiving` flushes, i.e. always before finalization — 31 of 35 real legs ended with an all-zero snapshot while `metadata.json` held thousands of tokens, and that snapshot is what the live GUI reads. A **terminal `complete` progress record** now carries the settled usage, and the reader prefers `metadata.json` for any terminal leg.
|
|
51
|
+
- `amicus spend` and the spend ledger no longer coerce a null cost into a measured-looking `$0.0000`: a model whose rows are all unpriced renders `?`, and `unpricedRows` is reported on `total`, `byModel`, every `group`, and `wasted`.
|
|
52
|
+
- **A leg is no longer declared `complete` while its OpenCode session is still working and billing.** Measured on a real paid run: `council-wsgate02`'s `wsgate02-s1-3` was declared complete on **166 characters** of reasoning preamble, 129 s before its `task` tool call finished, and its session then billed $0.14279 of further parent spend plus a $0.47105 child session — 166 characters were adjudicated as a finished peer review. Root cause was a shape drift, not a logic slip: the mirror modelled a tool call as an Anthropic-style `tool_use` part cleared by a matching `tool_result`, and **OpenCode emits neither** (36 `tool_use` records and 0 `tool_result` records across 35 recorded legs; 5,129 persisted parts resolve to six type names, none of them `tool_result`). So `pendingToolCalls` never cleared for any real leg, tool names never reached `conversation.jsonl`, and the `Task`-subagent log was permanently empty. Tool-call liveness is now keyed on the SDK's real `state.status` vocabulary (`pending`/`running`/`completed`/`error`; terminal = `completed`|`error`), and the completion gates that lack an explicit done-signal defer while a call is still executing. The wait is **bounded** by `AMICUS_TOOL_SETTLE_GRACE_MS` (default 300 s, `0` disables): on exceeding it the leg **completes anyway** — never fails — carrying `toolSettleTimedOut` on its result, its `metadata.json` and its terminal `progress.json` record, plus an error-level log line. A tool part whose status cannot be observed at all is deliberately *not* treated as live, so an unknown shape can never hang a finished leg.
|
|
53
|
+
- **`costExact: true` no longer claims a total is complete when it is not.** `council-wsgate01` reported `costExact: true` while **$0.0215 short** of OpenCode's ledger. Reconciled leg-by-leg: all 7 legs were `source: 'reported'` with real tokens, and **100% of the gap was one unattributed `explore` child session** ($0.021460, parent `wsgate01-s1-2`) — not rounding, not partial usage, not float drift. The predicate was wrong: `costExact` was computed as `unknownLegs === 0`, which asks "did every leg report tokens" — a statement about each leg's *own* session, not about whether the total is the whole bill. A leg that spawns a subagent now carries `subtreeUnknown` on its usage block, `sumWaveUsage` reports `subtreeUnknownLegs`, and `costExact` requires **both** every leg observed *and* no unattributed subtree. Surfaced on `run.json`, the `Notice:` line, the human summary, the workspace total and the `--max-cost` gauge (which goes indeterminate). Subtree-unknown spend still does not trip the ceiling — fail loud, not closed.
|
|
54
|
+
- **`--max-cost` is now threaded into the council pre-flight estimate.** `src/council/run-launch.js` never passed `maxCost` to the transport, so `src/sidecar/fanout.js` fell back to a `cfg.maxCost` key that does not exist and the `budget.js` soft ceiling was inert for every council run — the post-hoc check in `run.js` was the only ceiling, and it can only refuse *after* the money is spent. Each wave is now measured against the **remaining** allowance (ceiling − known spend − outstanding reservations).
|
|
55
|
+
- **The council pre-flight ceiling is now concurrency-safe.** Stage 1 launches its seat wave and its critic wave together under one `Promise.all`, and each launcher read the remaining allowance *before either wave's legs had been recorded* — so both saw the full, unreduced ceiling and both could pass a gate that only one of them fit under. A read is not a claim. The transport now takes an optional `reserveBudget(estimate)` seam (`src/sidecar/fanout-budget.js`, extracted from `runFanout` §1b) which the council answers with a **synchronous** read-and-claim against the allowance no sibling wave has taken — synchronicity is the guarantee, since the event loop cannot interleave two callers inside it. A fixed quota split was rejected as strictly more refusing than the ceiling requires. **When a wave is refused the run continues with a partial bench** — it never rolls back launched waves and never aborts (fail loud, not closed) — but the refusal is announced on stderr, recorded on `run.json` as `budgetRefusals[]`, and degrades the run's exit code to `2`. Stage 1's existing quorum gate still refuses to call a bench of fewer than two reviews a council.
|
|
56
|
+
- **The best-effort usage-settle re-poll can no longer discard a finished leg.** Its `try/catch` covered only the network read; the snapshot inspection that followed it (`mirrorUsageOnly`, `allAssistantUsagePresent`) ran outside the boundary, so a throw there escaped `runHeadless` and destroyed a leg whose answer had already been captured and paid for — the most expensive possible outcome for a path whose whole job is an optional usage top-up. The boundary now covers the entire loop body; a failure stops settling, keeps every dollar already mirrored, and leaves the completion verdict untouched.
|
|
57
|
+
- **`AMICUS_USAGE_SETTLE_POLLS=0` (and friends) now actually disable the feature.** All four v4.4 settle knobs parsed their environment override as `Number(process.env.X) || DEFAULT`, which silently rewrites an explicit `0` — the documented "off" value — back into the default. `AMICUS_USAGE_SETTLE_POLLS`, `AMICUS_USAGE_SETTLE_INTERVAL_MS`, `AMICUS_USAGE_SETTLE_CALL_TIMEOUT_MS` and `AMICUS_TOOL_SETTLE_GRACE_MS` now go through `src/utils/env-num.js`, which honors an explicit numeric value including `0` and falls back only for unset / blank / non-finite. Older knobs (`AMICUS_POLL_INTERVAL_MS`, `AMICUS_STABLE_*_POLLS`, `AMICUS_TOOL_CALL_STALL_MS`, …) deliberately keep the old form: `0` is not a documented escape hatch for any of them and honoring it would busy-loop a poller or disable a stall guard.
|
|
58
|
+
- **Subagent (child-session) spend is now attributed to the leg that spawned it.** A leg that calls the `task` tool spawns a *child* OpenCode session; OpenCode bills it separately, does **not** roll it into the parent session's cost, and amicus never enumerated it — so it was invisible to every total the product prints. Measured across the four recorded paid runs: **$0.492506** ($0.021460 in `wsgate01`, $0.471046 in `wsgate02`). `wsgate01` was the honest limit case — all 7 legs `source: 'reported'`, `unpricedLegs: 0`, `costExact: true`, and the run still 7.1% short, with 100% of the gap in one `explore` child session. `runHeadless` now walks each leg's child sessions at finalization (bounded, cycle-proof, directory-scoped) and the measured spend rolls into the run total, reported separately as `cost.subtreeCost` / `cost.subtreeSessions`. Replayed against the OpenCode oracle, `wsgate01` reconciles **exactly**. A child's price comes from OpenCode's own billing and is never estimated from a catalog — the SDK's session record carries no model id, so an estimate would be a guess. What the walk cannot account for still reports as `subtreeUnknown`, never as zero; conversely, a subtree that WAS fully walked now clears that flag, which the previous `task`-name proxy could never do. A failed walk with no evidence of a subagent at all flags nothing, so an OpenCode build without the `children` endpoint does not mark every leg of every run inexact.
|
|
59
|
+
- **A Stage-1 repair re-prompt now carries the review it is repairing.** When a review's trailing findings JSON failed validation the engine launched a repair solo — a *fresh* session with no memory of the review turn — and handed it the validation **errors without the review those errors were about**. Three of the five paid councils burned a seat on it: `wsgate02`'s `qwen` and `wsgate04`'s `glm` both refused, twice each ("I don't have a previous review to correct"; "the previous review's content was excluded by the caller… I will not fabricate findings"), so a 4-model bench silently adjudicated on 3 while still paying for the fourth's tokens; `costgate01`'s `grok` complied instead, by **inventing a self-referential finding about its own empty output**, which entered `tally.json`, the street-cred rankings and the chair synthesis as `C1` and reached a human's decision. The prompt now embeds, verbatim and uncapped, the text that actually failed — the original review on the first attempt, the previous repair's output on the second, so the errors and the artifact they describe are always the same thing. When there genuinely is no prior text the prompt **says so** and instructs the model to emit an empty `findings` array rather than leaving it to guess.
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- **Unknown cost fails LOUD, not CLOSED.** A leg whose cost cannot be determined does **not** halt a run and does **not** by itself trip `--max-cost` — the ceiling still trips on known spend only. Instead the uncertainty is made impossible to miss: `run.json`'s `usage` block gains `unknownLegs` + `costExact`, the council run emits a `Notice:` naming the count and stating that real spend is higher, the human summary appends `+ N leg(s) unknown — real spend is at least this much`, `amicus spend` adds an explicit unpriced-rows line, and the workspace's budget gauge switches to an indeterminate (hatched) band with a `≥` readout rather than claiming a percentage it cannot know. Nothing converts uncertainty into a fabricated number in either direction.
|
|
64
|
+
- **`amicus watch <councilRunId>` now prints per-seat rows in the terminal**, not just the stage checklist — each seat's model, status, message count, tokens, cost and stall state, refreshed on the same poll as the stage rail. This is a **behavior change to an existing command**: a plain terminal `amicus watch` on a council run shows materially more than it did on 4.3.0, with no new flag. The Council Workspace GUI and the terminal renderer now read the same per-leg data.
|
|
65
|
+
|
|
66
|
+
### Security
|
|
67
|
+
|
|
68
|
+
- **A council pointer file can no longer redirect reads — or writes — outside the project.** A `council-<runId>.json` pointer's `{runId, runDir}` JSON is validated only for truthiness (`src/council/run-state.js`), so a tampered or stale pointer could name any `runDir` on disk. The v4.4 Council Workspace already fenced all four of its pointer-consuming reads against the run dir's realpath; the older CLI/MCP surface behind `amicus_status` / `amicus_abort` / `amicus_list` / `amicus watch` did not, and two of its call sites are worse than a read leak — both crash detection and abort `checkpoint()` **into** `ptr.runDir`, making an unfenced pointer a write primitive at an attacker-chosen path. All of them now resolve and check containment **before touching the filesystem at all**, sharing the one fence implementation (`src/utils/path-fence.js`). A fenced-out pointer resolves to the existing "not a council run" outcome — the same `Session <id> not found in project <cwd>` error `amicus_status`/`amicus_abort` already return for an absent pointer, a skipped row in `amicus_list`, and `kind: 'unknown'` (→ `BAD_SESSION`) for `watch` — so no new error shape, and nothing is read or written from the escaping directory. Nothing legitimate is refused: a real `runDir` is always nested inside the project, enforced at creation time.
|
|
69
|
+
|
|
6
70
|
## [4.3.0] - 2026-07-24
|
|
7
71
|
|
|
8
72
|
### Added
|
package/README.md
CHANGED
|
@@ -45,13 +45,14 @@ Hand Claude a plan, a design, a diff, an architecture decision, a manuscript —
|
|
|
45
45
|
|
|
46
46
|
## What is Amicus
|
|
47
47
|
|
|
48
|
-
One install delivers
|
|
48
|
+
One install delivers six things that work together:
|
|
49
49
|
|
|
50
50
|
- **The `second-opinion` LLM Council skill.** Structured multi-model review: independent reviews → anonymized peer cross-review → a non-Claude chair verdict → tiered accept/deny decisions. This is the hero.
|
|
51
51
|
- **The `sidecar` chat skill.** Ad-hoc fork/work/fold — spin up one other model in a real window (or headless), work alongside it, fold the summary back.
|
|
52
52
|
- **The `amicus` CLI (with an `am` alias) and an MCP server.** The engine underneath both skills: launches sessions, shares context, runs parallel waves, and exposes the same surface to Claude as MCP tools.
|
|
53
53
|
- **A self-updating model catalog.** Aliases and validation resolve against a live catalog fetched from provider APIs (cached locally), so model names stay current without a hard-coded table.
|
|
54
54
|
- **Observability.** `amicus watch <id>` renders any live or finished run (fan-out or council) from any terminal; `--follow` streams milestones as they happen; `--on-complete` fires a hook when a run lands; `--retry-failed` plus opt-in cheaper-model fallbacks recover dead legs without relaunching the whole wave; `amicus spend` answers "what did this cost, and where" with per-run attribution.
|
|
55
|
+
- **Council Workspace.** `amicus watch <runId> --ui`: a window that shows a council *thinking* — live seats, the anonymized judge packet, the adjudication matrix, dissent drill-in, chair verdict, and cost-by-seat — for both live and historical runs.
|
|
55
56
|
|
|
56
57
|
Claude is the orchestrator. The council and chat skills run *on top of* the engine; you talk to Claude, and Claude drives Amicus.
|
|
57
58
|
|
|
@@ -314,7 +315,7 @@ amicus update
|
|
|
314
315
|
| `amicus continue` | Start a new session building on a previous one. |
|
|
315
316
|
| `amicus read` | Output a session's summary / conversation / metadata. |
|
|
316
317
|
| `amicus status <id>` | One-shot status for a session or fan-out wave (human or `--json`; `--wave <id>` alternative spelling). |
|
|
317
|
-
| `amicus watch <id>` | Live-render a fan-out wave, council run, or session from any terminal until it finishes — in-place table on a TTY, `--plain` milestone lines, or `--json` NDJSON; exit code maps the terminal state. |
|
|
318
|
+
| `amicus watch <id>` | Live-render a fan-out wave, council run, or session from any terminal until it finishes — in-place table on a TTY, `--plain` milestone lines, or `--json` NDJSON; exit code maps the terminal state. `--ui` opens the [Council Workspace](./docs/council.md#council-workspace-gui) window instead (interactive-only, no `--json`). |
|
|
318
319
|
| `amicus models` | List, search, refresh the catalog, or audit aliases. |
|
|
319
320
|
| `amicus doctor` | Diagnose your setup — keys, default model, catalog, aliases, OpenCode binary, Electron, skills, MCP registration, OpenRouter credit (`--json`; `--fix` self-heals what it can). |
|
|
320
321
|
| `amicus spend` | Cross-run cost rollup from the spend ledger, with per-run attribution — total + per-model spend, tokens, and source mix, most-expensive first (`--wave`/`--council`/`--project`/`--model`/`--op`/`--failed` filter it, `--group-by` buckets it, `--since 7d` windows it; `--json` for a versioned doc; shows remaining OpenRouter credit when a key is configured). |
|
|
@@ -350,7 +351,7 @@ $ amicus status demo123 --json
|
|
|
350
351
|
"taskId": "demo123",
|
|
351
352
|
"status": "complete",
|
|
352
353
|
"elapsed": "5m 0s",
|
|
353
|
-
"version": "4.
|
|
354
|
+
"version": "4.4.1",
|
|
354
355
|
"model": "google/gemini-2.5-flash",
|
|
355
356
|
"phase": "terminal"
|
|
356
357
|
}
|
|
@@ -461,6 +462,8 @@ Run `amicus doctor` first — it checks keys, catalog, OpenCode binary, Electron
|
|
|
461
462
|
| 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`. |
|
|
462
463
|
| `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). |
|
|
463
464
|
| `402` / "Payment Required" on first council review / `start` / `fanout` call | Your OpenRouter key is real but has no credit. Key save (`amicus key openrouter <key>` or the setup wizard's key step) only checks that the key **authenticates** — it doesn't check balance, so a zero-credit key saves cleanly and only fails later, on the first real model call. (The `amicus council` subcommand itself is deterministic math and never calls a model.) | Add credit at [openrouter.ai/credits](https://openrouter.ai/credits), **or** switch to a zero-cost council: `amicus setup` → option 2 (Free OpenRouter council) builds one from live `:free`-suffixed models and saves it as `councils.free` — then run `amicus fanout --council free …`. See "Free council (zero-cost)" under [The Council](#the-council) above. |
|
|
465
|
+
| Every direct `anthropic/…` model (`haiku`, `sonnet`, `opus`, `claude`) errors `Not Found` in ~2 s at zero tokens, but the same model works via `openrouter/anthropic/…` | An inherited `ANTHROPIC_BASE_URL` missing its `/v1` path segment. The engine appends only `/messages`, so requests hit `https://api.anthropic.com/messages` → HTTP 404 with an empty body → the bare status text. A shell spawned by Claude Code sets the `/v1`-less form for you. The model id, alias, and key are all fine. | `export ANTHROPIC_BASE_URL=https://api.anthropic.com/v1`, or unset it entirely, or pass `--gateway openrouter`. In a council a dead seat **degrades the run instead of failing it** — smoke-test each seat with one throwaway `amicus start` before paying for a council. See [docs/troubleshooting.md](./docs/troubleshooting.md#every-direct-anthropic-model-fails-with-not-found). |
|
|
466
|
+
| `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). |
|
|
464
467
|
| Session not found | No session matches the given ID | Run `amicus list`, or omit `--session-id` to use the most recent. |
|
|
465
468
|
| No conversation history found | Project-path encoding | Check `~/.claude/projects/`; `/` and `_` in the project path are encoded as `-` in the directory name. |
|
|
466
469
|
| Headless run never finishes | Task is bigger than the default timeout | Raise it: `--timeout 30`. |
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Distribution channels
|
|
2
|
+
|
|
3
|
+
Amicus ships through three channels. This doc is the runbook for each — what's
|
|
4
|
+
live today, what the submission/publish steps are, and what to check before
|
|
5
|
+
pulling the trigger on a release-facing action.
|
|
6
|
+
|
|
7
|
+
## 1. npm (existing)
|
|
8
|
+
|
|
9
|
+
**Status: live.** Tag `v*` on `main` → `.github/workflows/publish.yml` → npm
|
|
10
|
+
**Trusted Publishing** (GitHub OIDC, no long-lived npm token in CI) →
|
|
11
|
+
`npm publish --access public --provenance`. The workflow also cuts a GitHub
|
|
12
|
+
Release and asks Claude to draft categorized release notes from the commit
|
|
13
|
+
log + diff since the previous tag.
|
|
14
|
+
|
|
15
|
+
Postinstall (`scripts/postinstall.js`) registers the MCP server in Claude
|
|
16
|
+
Code / Claude Desktop / Cowork and copies both skills (`sidecar`,
|
|
17
|
+
`second-opinion`) into `~/.claude/skills/`. It does **not** copy
|
|
18
|
+
`commands/council.md` — that only ships via the plugin channel below. This
|
|
19
|
+
is a known, accepted gap for npm/install-script users (slash commands are
|
|
20
|
+
plugin-channel-only by design; see the npm-vs-plugin note at the top of the
|
|
21
|
+
CHANGELOG's Unreleased section).
|
|
22
|
+
|
|
23
|
+
## 2. Claude Code community marketplace (claude-community)
|
|
24
|
+
|
|
25
|
+
**Status: submitted 2026-07-01 — awaiting Anthropic review.** (Update this
|
|
26
|
+
line as the process advances: `submitted <date> / approved <date> / listed <date>`.
|
|
27
|
+
Note: the submission predates the Phase-9 polish on `main` — reviewers pulling
|
|
28
|
+
the repo see the current surface, including `commands/` and a clean
|
|
29
|
+
`claude plugin validate . --strict`.)
|
|
30
|
+
|
|
31
|
+
Two Anthropic-run marketplaces exist:
|
|
32
|
+
- **`claude-plugins-official`** — curated by Anthropic, no application process.
|
|
33
|
+
- **`claude-community`** — third-party plugins, submitted for review. This is
|
|
34
|
+
the one amicus targets.
|
|
35
|
+
|
|
36
|
+
Approved plugins are pinned to a commit SHA in
|
|
37
|
+
`anthropics/claude-plugins-community/.claude-plugin/marketplace.json`. CI in
|
|
38
|
+
that repo auto-bumps the pin as we push to `main`, and the public catalog
|
|
39
|
+
syncs from it nightly (a delay after any push is normal, not a bug). **PRs
|
|
40
|
+
opened directly against `anthropics/claude-plugins-community` are closed
|
|
41
|
+
automatically** — the only way in is the submission form below.
|
|
42
|
+
|
|
43
|
+
Because the pin auto-bumps on every push to `main`, every push after listing
|
|
44
|
+
reaches marketplace users on their next sync. `plugin.json` already pins an
|
|
45
|
+
explicit `version` synced to `package.json` (enforced by
|
|
46
|
+
`tests/plugin-manifest.test.js`), so this is the existing safe behavior:
|
|
47
|
+
users only see a version bump when we bump it, not on every commit. Treat
|
|
48
|
+
`main` as release-quality once listed.
|
|
49
|
+
|
|
50
|
+
### Preflight (run before every submission or major post-listing update)
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
claude plugin validate . --strict
|
|
54
|
+
claude --plugin-dir . # smoke: /amicus:council, /amicus:sidecar, /amicus:second-opinion, MCP tools
|
|
55
|
+
npm test
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- `claude plugin validate . --strict` is the same structural check the
|
|
59
|
+
review pipeline runs; `--strict` promotes unrecognized-field warnings to
|
|
60
|
+
errors so nothing slips through that CI would later flag. It needs the
|
|
61
|
+
Claude Code CLI installed locally — it is **not** wired into this repo's
|
|
62
|
+
CI (runners have no `claude` auth), so `tests/plugin-manifest.test.js` is
|
|
63
|
+
the CI-side proxy for manifest completeness.
|
|
64
|
+
- `claude --plugin-dir .` loads the plugin from the working tree so you can
|
|
65
|
+
manually confirm `/amicus:council`, `/amicus:sidecar`, and
|
|
66
|
+
`/amicus:second-opinion` all appear in the command picker exactly once,
|
|
67
|
+
and that the `amicus` MCP server connects (tools list populates).
|
|
68
|
+
- `npm test` must be green, specifically `tests/plugin-manifest.test.js`
|
|
69
|
+
and `tests/plugin-commands.test.js`.
|
|
70
|
+
|
|
71
|
+
**Known current-tree preflight result (checked 2026-07-02, `p9/distribution`
|
|
72
|
+
at a1bea3c):** `claude plugin validate . --strict` passes clean, exit 0.
|
|
73
|
+
(History: `--strict` previously flagged an unknown `plugin.json → bugs`
|
|
74
|
+
field; that field was removed in commit `4207485`, so the warning is gone.)
|
|
75
|
+
|
|
76
|
+
### Submit
|
|
77
|
+
|
|
78
|
+
- **Individual-author route:** https://platform.claude.com/plugins/submit
|
|
79
|
+
(Console form). This is the route for us — Christian has no Team/Enterprise
|
|
80
|
+
org, so the directory-management admin route below doesn't apply.
|
|
81
|
+
- **Team/Enterprise route:** https://claude.ai/admin-settings/directory/submissions/plugins/new
|
|
82
|
+
(requires Team/Enterprise org + directory management permissions — not
|
|
83
|
+
applicable here, listed for completeness).
|
|
84
|
+
- **Metadata to enter in the form:**
|
|
85
|
+
- Repository: `https://github.com/BourbonDog/amicus` (public, MIT)
|
|
86
|
+
- Plugin name: `amicus`
|
|
87
|
+
- Description: pulled from `.claude-plugin/plugin.json` → `description`
|
|
88
|
+
- Contact: `sendtowags@outlook.com`
|
|
89
|
+
- **Timing:** submit only after Task 9a (`commands/council.md` + the sidecar
|
|
90
|
+
argument surface) has merged to `main`, so the SHA the reviewer evaluates
|
|
91
|
+
and the SHA that eventually gets pinned both include the slash commands.
|
|
92
|
+
Submitting before 9a merges means the reviewed surface is incomplete.
|
|
93
|
+
- Never open a PR against `anthropics/claude-plugins-community` — it's a
|
|
94
|
+
read-only mirror for the public catalog; PRs there are auto-closed.
|
|
95
|
+
|
|
96
|
+
### What review checks (and what it might ask about)
|
|
97
|
+
|
|
98
|
+
The pipeline runs `claude plugin validate` plus automated safety screening.
|
|
99
|
+
There's no published SLA for turnaround — **budget this as unscheduled** and
|
|
100
|
+
don't put any downstream work on the critical path of approval.
|
|
101
|
+
|
|
102
|
+
Anticipated reviewer question: the npm package runs a postinstall
|
|
103
|
+
(`scripts/postinstall.js`) and the repo ships `install.sh` / `install.ps1`.
|
|
104
|
+
The **plugin channel itself never triggers postinstall** —
|
|
105
|
+
`.claude-plugin/plugin.json`'s `mcpServers.amicus.env` sets
|
|
106
|
+
`AMICUS_SKIP_POSTINSTALL=1`, so a plugin install only ever runs
|
|
107
|
+
`npx -y amicus@latest mcp` with that guard set, not the interactive
|
|
108
|
+
setup/registration flow. This paragraph is the answer if a reviewer asks.
|
|
109
|
+
|
|
110
|
+
### After approval
|
|
111
|
+
|
|
112
|
+
1. Search `"amicus"` in
|
|
113
|
+
https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/marketplace.json
|
|
114
|
+
to confirm the listing synced (nightly delay after approval is normal).
|
|
115
|
+
2. End-to-end verify:
|
|
116
|
+
```bash
|
|
117
|
+
claude plugin marketplace add anthropics/claude-plugins-community
|
|
118
|
+
claude plugin install amicus@claude-community
|
|
119
|
+
```
|
|
120
|
+
3. Update the Status line at the top of this section with the
|
|
121
|
+
submitted/approved/listed dates.
|
|
122
|
+
4. Optionally add an "Install as a Claude Code plugin" section to
|
|
123
|
+
`README.md` referencing `@claude-community` (not done as part of this
|
|
124
|
+
task — premature before approval, since the listing doesn't exist yet).
|
|
125
|
+
|
|
126
|
+
*(Everything in this subsection past "search 'amicus' in
|
|
127
|
+
`marketplace.json`" is unverified as of 2026-07-02 in the sense that we
|
|
128
|
+
haven't been through it yet — it's the documented expected flow per
|
|
129
|
+
Anthropic's published docs, not something we've personally exercised
|
|
130
|
+
end-to-end against the real submission.)*
|
|
131
|
+
|
|
132
|
+
## 3. MCP Registry
|
|
133
|
+
|
|
134
|
+
**Status: wired, not yet published (Phase 9c).** `server.json` (repo root)
|
|
135
|
+
and the `mcpName` field in `package.json` now exist, and
|
|
136
|
+
`.github/workflows/publish.yml` publishes to the MCP Registry
|
|
137
|
+
(`registry.modelcontextprotocol.io`) as the last three steps before the GitHub
|
|
138
|
+
Release, on every `v*` tag push. This has not fired yet — the first tag
|
|
139
|
+
push after this merge is the first real publish attempt.
|
|
140
|
+
|
|
141
|
+
**Namespace:** `io.github.BourbonDog/amicus` (case-sensitive — the registry
|
|
142
|
+
grants `io.github.<Login>/*` using the exact-case GitHub login/repository
|
|
143
|
+
owner). Confirmed unclaimed via
|
|
144
|
+
`https://registry.modelcontextprotocol.io/v0/servers?search=amicus`
|
|
145
|
+
(0 results, checked 2026-07-02).
|
|
146
|
+
|
|
147
|
+
**Flow:** tag↔`package.json` version lockstep is verified first (fails fast
|
|
148
|
+
with `::error::` on a mis-tag) → npm publish (existing, OIDC), itself guarded
|
|
149
|
+
by a version-exists check so a re-run does not re-attempt a version already
|
|
150
|
+
live on npm → `mcp-publisher` binary installed → `server.json` version
|
|
151
|
+
synced from the tag via `jq` (belt-and-braces; the in-repo
|
|
152
|
+
`server.json`/`package.json`/`packages[0]` versions are also kept in
|
|
153
|
+
lockstep by hand at release time and enforced by
|
|
154
|
+
`tests/scripts/package-manifest.test.js`) → MCP Registry publish, itself
|
|
155
|
+
pre-checked against the registry API so a re-run does not double-publish →
|
|
156
|
+
`mcp-publisher login github-oidc` (no secret needed, uses the same
|
|
157
|
+
`id-token: write` OIDC permission as the npm Trusted Publishing step),
|
|
158
|
+
retried up to 5 times on transient OIDC token-exchange failures → `mcp-publisher
|
|
159
|
+
publish`, retried up to 5 times (npm propagation lag) before hard-failing the
|
|
160
|
+
job → GitHub Release creation, guarded by an existence check so a re-run
|
|
161
|
+
does not fail on a release that already exists. The registry steps run
|
|
162
|
+
strictly after `npm publish` because npm-side ownership validation reads
|
|
163
|
+
`mcpName` from the *published* `package.json`.
|
|
164
|
+
|
|
165
|
+
**Release-order dependency (historical — satisfied before the first registry
|
|
166
|
+
publish):** the first post-merge `v*` tag had to wait for the Phase 4
|
|
167
|
+
tool-surface de-bloat, because the server still registered 13 deprecated
|
|
168
|
+
`sidecar_*` aliases alongside the real tools and the first registry publish
|
|
169
|
+
snapshots whatever surface exists at that time. Both have long since landed.
|
|
170
|
+
The rule that outlives the episode: **a registry publish snapshots the tool
|
|
171
|
+
surface, so land any tool-surface change before you cut the tag.** For the
|
|
172
|
+
current tool count, see the MCP table in [README.md](../README.md) — it is the
|
|
173
|
+
single source of truth and moves with each release (v4.0 added
|
|
174
|
+
`amicus_council_run`).
|
|
175
|
+
|
|
176
|
+
**Registry preview caveat:** the MCP Registry is still in preview per its
|
|
177
|
+
own docs (breaking changes/data resets possible before general
|
|
178
|
+
availability). The publish steps are additive to the existing npm/GitHub
|
|
179
|
+
Release flow and do not touch it; a registry publish failure after 5 retries
|
|
180
|
+
does fail the workflow job (hard `exit 1`), which means the 'Create GitHub
|
|
181
|
+
Release' step does not run on that path. If that trade-off proves unwanted
|
|
182
|
+
in practice, add `continue-on-error: true` to the 'Publish to MCP Registry'
|
|
183
|
+
step.
|
|
184
|
+
|
|
185
|
+
**First-publish de-risk:** before relying on CI for the first real publish,
|
|
186
|
+
run once locally: download `mcp-publisher` (Windows: the tarball flow from
|
|
187
|
+
the quickstart docs), `mcp-publisher login github` (device-flow auth as
|
|
188
|
+
BourbonDog), then `mcp-publisher publish` — to fail fast on any
|
|
189
|
+
namespace/validation error outside of CI. If publish returns "You do not
|
|
190
|
+
have permission…", the error message states the granted pattern; align
|
|
191
|
+
`server.json`'s `name` casing to it exactly.
|
|
192
|
+
|
|
193
|
+
**If the registry publish fails in CI (Phase 11 hardening):** re-running the
|
|
194
|
+
workflow is now the primary recovery path. Every publish-ish step in
|
|
195
|
+
`publish.yml` is idempotency-guarded, so a re-run skips whatever already
|
|
196
|
+
succeeded and only retries the step that actually failed:
|
|
197
|
+
- **npm publish** checks `npm view amicus@<version>` first and skips with a
|
|
198
|
+
`::notice::` if that version is already on the registry (instead of
|
|
199
|
+
hitting `EPUBLISHCONFLICT`).
|
|
200
|
+
- **MCP Registry publish** pre-checks
|
|
201
|
+
`registry.modelcontextprotocol.io/v0/servers/io.github.BourbonDog%2Famicus/versions/<version>`
|
|
202
|
+
(HTTP 200 = already published, 404 = not yet) and skips with a
|
|
203
|
+
`::notice::` if present, before attempting login or publish.
|
|
204
|
+
- **`mcp-publisher login github-oidc`** now retries up to 5 times (20s
|
|
205
|
+
apart) on transient OIDC token-exchange failures, same pattern as the
|
|
206
|
+
publish retry.
|
|
207
|
+
- **GitHub Release creation** checks `gh release view <tag>` first and skips
|
|
208
|
+
with a `::notice::` if the release already exists.
|
|
209
|
+
|
|
210
|
+
So: fix whatever caused the failure (registry outage, OIDC hiccup, etc.),
|
|
211
|
+
then re-run the failed job from the Actions tab (or `gh run rerun
|
|
212
|
+
--failed`). Do not delete and re-push the tag — the existing job re-run is
|
|
213
|
+
sufficient, and steps that already succeeded (npm publish, an earlier
|
|
214
|
+
registry publish, an existing release) are detected and skipped rather than
|
|
215
|
+
re-attempted or double-published.
|
|
216
|
+
|
|
217
|
+
**Caveat — content-level 422s are NOT re-run-recoverable.** A workflow
|
|
218
|
+
re-run checks out the tag, so a `server.json` validation error (the registry
|
|
219
|
+
returns HTTP 422 naming the failing field) reproduces identically on re-run.
|
|
220
|
+
Fix `server.json` on main and recover via the manual path below, or let the
|
|
221
|
+
fix ride the next tag. Known registry constraint (learned live): the
|
|
222
|
+
top-level `description` is capped at **100 characters** — v1.9.0's first
|
|
223
|
+
publish attempt 422'd on a 199-char description (2026-07-03); now pinned by
|
|
224
|
+
`tests/scripts/package-manifest.test.js`.
|
|
225
|
+
|
|
226
|
+
**Manual recovery (fallback, if re-run is not viable):**
|
|
227
|
+
1. **Registry publish:** run the same local de-risk flow above for real —
|
|
228
|
+
`mcp-publisher login github` (device-flow login as BourbonDog), sync
|
|
229
|
+
`server.json`'s `.version` and `.packages[0].version` to the tag that
|
|
230
|
+
already published to npm, then `mcp-publisher publish`.
|
|
231
|
+
2. **GitHub Release:** cut it by hand:
|
|
232
|
+
`gh release create <tag> --generate-notes --latest`. The "Generate release
|
|
233
|
+
notes with Claude" step is optional polish — skip it or run it manually
|
|
234
|
+
against the API.
|
package/docs/ROADMAP.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Amicus — reprioritized roadmap
|
|
2
|
+
|
|
3
|
+
**Reprioritization guidance (Christian, 2026-07-18):** engine-first is locked; the near-term work
|
|
4
|
+
ships as an incremental **4.x point-release line**, each rev delivering a **behavioral / feature
|
|
5
|
+
benefit users feel**; **enterprise-readiness is a venture unto itself** — the deliberate **5.0**
|
|
6
|
+
major jump, gated on funding/cofounder. The observability arc is split so the **data layer ships
|
|
7
|
+
first (v4.3)** and the **Electron "Council Workspace" (v4.4)** rides on top of it. `--dry-run` cost
|
|
8
|
+
preview dropped to the backlog.
|
|
9
|
+
|
|
10
|
+
Amicus is at **v4.4.1** (2026-07-27), the fast-follow patch on v4.4.0 (tagged 2026-07-26). Each
|
|
11
|
+
4.x rev below leads with the benefit, not the plumbing.
|
|
12
|
+
|
|
13
|
+
**Status:** v4.0 through **v4.4.1** have **shipped** — everything down to the v4.5 heading is a
|
|
14
|
+
record of what landed, not a plan. **v4.5 (policy packs + composition) is the next rev.** v5.0
|
|
15
|
+
remains forward-looking.
|
|
16
|
+
|
|
17
|
+
> 📁 **Reading this from an npm install?** Some references below point at working documents that
|
|
18
|
+
> live in the git repository and are deliberately **not** in the published package — anything under
|
|
19
|
+
> `.superpowers/` (the SDD working area, gitignored) and the root `BACKLOG.md`. The npm tarball
|
|
20
|
+
> ships `docs/*.md` only. Read those files at
|
|
21
|
+
> [github.com/BourbonDog/amicus](https://github.com/BourbonDog/amicus); the `.superpowers/` ones are
|
|
22
|
+
> local-only working notes and are not published anywhere. Every claim this roadmap makes is
|
|
23
|
+
> summarized here — the pointers are provenance, not prerequisites.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## v4.0 — "Councils become a command you can trust" *(foundation — engine-first)* — ✅ SHIPPED v4.0.0, 2026-07-20
|
|
28
|
+
**Benefit:** the flagship council stops being a manual 6-stage ritual — run a real adjudicated
|
|
29
|
+
council headlessly and in CI, and trust the output enough to gate on it.
|
|
30
|
+
- **Headless council orchestration engine** + `council run --headless` + `amicus_council_run` MCP — B1/A2/D2/F1 *(L)*
|
|
31
|
+
- **Council Review GitHub Action v2** (real adjudicated verdict on PRs) — B2 *(M)*
|
|
32
|
+
- **Versioned JSON envelope + published schema**, all failures routed through it — D3/C3 *(M)* — the engine's trustable contract
|
|
33
|
+
- **Prompt-injection fencing on JSON MCP tools** (H9) — A5/C6/D5 *(S)* — required before councils chew on untrusted CI content
|
|
34
|
+
- **Per-run fold nonce** (BL-7) — C5/D4 *(S)* — correctness/safety
|
|
35
|
+
> Why here: the engine is the moat and everything downstream (CI, automation, dashboards) needs it. The 3 cheap trust fixes ride along because a council you can't trust in automation isn't automatable.
|
|
36
|
+
|
|
37
|
+
## v4.1 — "The skill sheds the ritual" *(skill-on-engine fast path)* — ✅ SHIPPED v4.1.0, 2026-07-21
|
|
38
|
+
**Benefit:** the daily interactive council stops being a manual 6-stage ritual too — the
|
|
39
|
+
second-opinion skill delegates Stages 1–3+5 to `council run` and keeps only the human stages
|
|
40
|
+
(0 intake, 4 decisions, 6 lessons).
|
|
41
|
+
- **Skill fast path** — SKILL.md orchestration rewired onto `amicus council run` *(M)*
|
|
42
|
+
- **Debate mode headless** (Stage 2.5 rebuttal round in the engine; here or v4.2 at the latest) *(M)*
|
|
43
|
+
- **README + docs update** — skill fast path and headless debate mode reflected in `README.md` and `docs/council.md` *(S)*
|
|
44
|
+
> Why here: locked during the v4.0 design (2026-07-19) — the engine proves itself in CI first
|
|
45
|
+
> (v4.0), then the flagship interactive UX adopts it before any new feature front opens.
|
|
46
|
+
|
|
47
|
+
## v4.2 — "Bring your own models — $0, private, offline" — ✅ SHIPPED v4.2.0, 2026-07-23
|
|
48
|
+
**Benefit:** run sidecars and councils on local / OpenAI-compatible models (Ollama, LM Studio, vLLM)
|
|
49
|
+
— free marginal cost, private, air-gapped. The single biggest adoption + cost unlock (5 of 6 lenses' #1).
|
|
50
|
+
- **Local / OpenAI-compatible provider support** — `baseURL`/`type` discriminator, `$0`/offline pricing tier, setup-wizard support — A1/B3/C1/D1/E1 *(L)*
|
|
51
|
+
- **Adoption polish** (rides the "easy to start" story): `amicus init --claude` (C2), `doctor` at end of setup wizard (C8), docs for `spend`/`doctor`/`key` (C10) *(S)*
|
|
52
|
+
- **README + docs update** — local / OpenAI-compatible provider setup + `$0` pricing tier in `README.md` and `docs/configuration.md` *(S)*
|
|
53
|
+
> Why here (not enterprise): local models are a broad user benefit — cost, privacy, offline — not an enterprise-only feature. Comes right after the engine so councils can run on free/local seats.
|
|
54
|
+
|
|
55
|
+
## v4.3 — "See runs live in the terminal — and never waste one" *(observability data layer, first)* — ✅ SHIPPED v4.3.0, 2026-07-24
|
|
56
|
+
**Benefit:** watch runs in real time in the terminal, recover from dead legs, and see where every dollar went.
|
|
57
|
+
- **Live wave observability data layer** + CLI/TUI `amicus watch <waveId>` + `--follow` streaming + `--on-complete <exec|mcp-notify>` hook — F3/D6 *(M)* — the shared data layer v4.4 builds on
|
|
58
|
+
- **Failed-leg retry** `fanout --retry-failed <waveId>` + **cheaper-model fallback chains** + failed-leg partial-spend tracking — F2/E10/E8 *(M)*
|
|
59
|
+
- **Spend visibility & attribution (basic):** fix continue/resume zero-spend rows, attribute waveId/council/project on every row, queryable `spend query` — A4(basic)/E3/E4/E9/D7/C9 *(M)*
|
|
60
|
+
- **README + docs update** — `watch`/`--follow`, failed-leg retry, and `spend query` documented in `README.md` and `docs/usage.md` *(S)*
|
|
61
|
+
> Why here / why first: this is the observability data layer + terminal surface. It ships **before** the GUI (v4.4) because the desktop workspace is a front-end on exactly this data. All M-effort, so it lands fast.
|
|
62
|
+
|
|
63
|
+
## v4.4 — "The Council Workspace" *(desktop GUI on the v4.3 data layer)* — ✅ SHIPPED v4.4.0, 2026-07-26
|
|
64
|
+
**Benefit:** the same live data as a rich desktop app — watch a council *think*, not just tail a log.
|
|
65
|
+
- **★ Electron "Council Workspace" GUI** — live reviewer progress, anonymized peer packets, adjudication tiers, dissent, cost-by-seat, one-click fold into Claude Code — **B9** *(L)*
|
|
66
|
+
- **README + docs update** — Council Workspace walkthrough + screenshots in `README.md` and `docs/` *(S)*
|
|
67
|
+
> Why here: a GUI layer on top of v4.3's data layer. Split into its own point release because it's the one **L-effort** build in the observability arc — keeping v4.3 small and shippable.
|
|
68
|
+
>
|
|
69
|
+
> The five paid gate councils run against it (`wsgate01`–`wsgate04`, `costgate01`) are also what
|
|
70
|
+
> produced the 4.4.1 backlog below: the GUI shipped, and running real money through it is what
|
|
71
|
+
> surfaced the cost-attribution and repair-path defects that patch closes.
|
|
72
|
+
|
|
73
|
+
## v4.4.1 — "What the gate councils found" *(fast-follow patch on 4.4.0)* — ✅ SHIPPED v4.4.1, 2026-07-27
|
|
74
|
+
**Benefit:** the product stops mis-stating its own spend, a repair leg stops fabricating findings,
|
|
75
|
+
and a review that honestly finds nothing stops being an error.
|
|
76
|
+
- **Cost truthfulness** — subtree-unknown spend carried into the ledger, the sticky unknown-spend notice unstuck, a cache-only leg reported `unknown` rather than falsely free, and `--max-cost` degraded to exit `2` when the total is inexact rather than claiming a percentage it cannot know — CA-2/CA-3/CA-6/CA-7 *(M)*
|
|
77
|
+
- **The repair path, whole** — all four remaining repair-prompt builders now carry the artifact they are repairing, and a repaired review no longer splices two generations together — LC-12/LC-11 *(M)*
|
|
78
|
+
- **A clean review is a valid review** — `EMPTY_FINDINGS` accepts a well-formed empty set, and the tally, street-cred and chair degrade gracefully on an all-clean bench — LC-10 *(M)*
|
|
79
|
+
- **One OpenCode server per council run** — concurrent waves no longer race each other's SQLite open, which was making `--critic` a coin flip *(M)*
|
|
80
|
+
- Renderer, progress and leg-row robustness; `electron/` under the lint gate; the read-only-workspace invariant test; live rails green as documented *(S each)*
|
|
81
|
+
> Why a patch and not a rev: every item is a correction to something already shipped, all of it
|
|
82
|
+
> measured against real paid runs. Two behaviour changes ride along (LC-2's session abort at the
|
|
83
|
+
> tool-settle ceiling, LC-10's acceptance of an empty finding set) — both owner-ruled, both
|
|
84
|
+
> corrections rather than new capability. Scope, rulings and the full 61-item inventory live in the
|
|
85
|
+
> repo's working notes (`.superpowers/sdd/v441/backlog-and-proposal.md`, local-only) and in the
|
|
86
|
+
> repo's root `BACKLOG.md` — neither ships in the npm package; see the note at the top.
|
|
87
|
+
|
|
88
|
+
## v4.5 — "Save, share, and compose your councils"
|
|
89
|
+
**Benefit:** complex councils become one-command, repeatable, and chainable.
|
|
90
|
+
- **★ Auto-open the Council Workspace on a council run (Christian, 2026-07-26)** — when a council is
|
|
91
|
+
invoked from Claude Desktop and Electron is already present, the Workspace window opens by
|
|
92
|
+
default instead of requiring a separate `amicus watch <runId> --ui`. Today the GUI is opt-in and
|
|
93
|
+
discoverable only from `watch --help`, so the flagship v4.4 surface goes unseen on the very
|
|
94
|
+
client best able to show it. *(S–M; the pieces exist — see the design notes below.)*
|
|
95
|
+
- **Council policy packs + full run-profiles** (bench + lenses + options + briefing template, invoke by name) — B7/F5 *(M)*
|
|
96
|
+
- **Composable/chained waves** (`--input-from <waveId>` / pipe) for generate→critique→refine — F6 *(M)*
|
|
97
|
+
- **Briefing templates + library** (F9), **session/wave tagging + `--search` + grouped history** (F8), **GUI power ergonomics** (F10) *(S–M)*
|
|
98
|
+
- **README + docs update** — policy packs, chained waves, and the briefing-template library in `README.md` and `docs/` *(S)*
|
|
99
|
+
> Why here: velocity multipliers that only pay off once councils are a command (v4.0) and observable (v4.3/v4.4).
|
|
100
|
+
|
|
101
|
+
### Deferred out of v4.4.1 into v4.5 (2026-07-27)
|
|
102
|
+
|
|
103
|
+
Each is `M`+, or needs data or a design decision — the bar a patch on a published release cannot
|
|
104
|
+
carry. The table below is self-contained; the full write-ups (what, where, what breaks if it stays)
|
|
105
|
+
live in the repo's local-only working notes — `.superpowers/sdd/v44/v4.4.1-backlog.md`, with the
|
|
106
|
+
disposition that put them here in `.superpowers/sdd/v441/backlog-and-proposal.md`. **If you have
|
|
107
|
+
those notes, read that backlog's Appendix A (settled decisions) and Appendix B (known false
|
|
108
|
+
positives) before re-filing anything from this list.**
|
|
109
|
+
|
|
110
|
+
| ID | What | Why not 4.4.1 |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| **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 |
|
|
113
|
+
| **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 |
|
|
114
|
+
| **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 |
|
|
115
|
+
| **LC-5** | A chair fallback leaves no trace in `run.json` (`wsgate02`'s haiku failed twice; only `"chair":"minimax"` was recorded) | `M` — a run-record schema addition |
|
|
116
|
+
| **RN-1** | `sanitizeName` collisions surface as a banner rather than a refusal | `S` + a product decision that was already argued once |
|
|
117
|
+
| **RN-2** | `renderRunList` blind masking is best-effort — only the open run resolves labels | `M` |
|
|
118
|
+
| **RN-5** | A blind-mode flip closes every open prose panel and repaints twice | `S–M` |
|
|
119
|
+
| **RN-11** | `renderSeats` never reorders existing rows | `S`, cosmetic, no consequence yet |
|
|
120
|
+
| **REL-2** | `mcp-repomix-e2e` skips, so plugin-chain MCP discovery is exercised nowhere | `M` — needs `AMICUS_REPOMIX_E2E_PROJECT` pointed at a real project *and* `repomix` on PATH |
|
|
121
|
+
| **TST-1 / TST-2** | No real `--debate` fixture; the `lens:<slug>` role branch has zero coverage | `M` each, and they want doing together |
|
|
122
|
+
| **TST-3** | Abort confirm→status-flip is proven only against the fake DOM | `M` — needs a real CDP pass |
|
|
123
|
+
| **TST-7** | Six render functions have no unit coverage | `M` |
|
|
124
|
+
| *(new)* | **Residual integration-suite handle leaks** — a NAMED leak with evidence, filed 2026-07-27 after 4.4.1 fixed ENV-6 and the live rail still warned from *different* suites | `S–M`. Full evidence, including why `--detectOpenHandles` cannot diagnose this class, is in the repo's root `BACKLOG.md` (not in the npm package — read it on GitHub) — start there rather than re-deriving it |
|
|
125
|
+
|
|
126
|
+
**ENV-6 is NOT on this list** — it was pulled into 4.4.1 by owner ruling and fixed at the source
|
|
127
|
+
(the CDP e2e suite's SIGKILL escalation timer). **ENV-1** is not on it either: it is a decision
|
|
128
|
+
record ("eleven `Number(env) || default` sites"), not a task — a blanket migration would introduce
|
|
129
|
+
six new defects to fix one, and `src/utils/env-num.js`'s docblock records which knobs deliberately
|
|
130
|
+
keep the old form.
|
|
131
|
+
|
|
132
|
+
## v5.0 — Enterprise-readiness *(the deliberate major jump — a venture unto itself, gated on funding / cofounder)*
|
|
133
|
+
**Benefit:** team/org deployment — but a distinct product + go-to-market motion (SOC2, SLAs, sales, support), not a feature drop. Parked as the 5.0 major per the chair's hard-question #5: a solo dev can't credibly ship or support this alone.
|
|
134
|
+
- Secret-store backends + env-var-only mode (A3); org allowlists/blocklists, per-team cost ceilings, read-only enforcement (A6); RBAC
|
|
135
|
+
- Audit & compliance: reproducibility manifests + replay (B11), seed/temp/version pinning (A7), spend export to SIEM/warehouse (A10), `/health` + metrics + structured logging (A8)
|
|
136
|
+
- Team config `.amicusrc` (A9); spend **governance** (per-team caps/enforcement) — the governance half of A4
|
|
137
|
+
- Learning loops that need scale anyway: reliability-aware seat selection (B4), calibration benchmarks (B5), decision-outcome feedback (B10), adaptive strategy planner (B8), evidence provenance (B6)
|
|
138
|
+
- README + docs update: deployment/admin documentation for the above, in `README.md` and `docs/`
|
|
139
|
+
> These cluster because they share one prerequisite you don't have yet: an org buyer + the org to support. Revisit as a funded track.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### Design notes — auto-open the Council Workspace
|
|
144
|
+
|
|
145
|
+
Recorded 2026-07-26 from a read of the shipped code, so the v4.5 implementer starts from facts
|
|
146
|
+
rather than re-deriving them.
|
|
147
|
+
|
|
148
|
+
**The pieces already exist.**
|
|
149
|
+
|
|
150
|
+
| Need | Where it lives today |
|
|
151
|
+
|---|---|
|
|
152
|
+
| Launch the window | `src/sidecar/workspace-window.js` `launchWorkspaceWindow({project, runId})` |
|
|
153
|
+
| Detect the client | `src/utils/client-detect.js` `detectClient(mcpServer)` → `code-local` \| `code-web` \| `cowork` |
|
|
154
|
+
| Is Electron usable | `src/sidecar/electron-install.js` `isElectronUsable` / `resolveElectronBinary` |
|
|
155
|
+
| Current entry point | `amicus watch <runId> --ui` (`src/cli-handlers-watch.js:87`) |
|
|
156
|
+
|
|
157
|
+
**"Claude Desktop" maps to `code-local`.** ⚠️ But `detectClient` reads the MCP client's
|
|
158
|
+
`getClientVersion().name`, so it **only works on the MCP path** — `amicus_council_run`, which is
|
|
159
|
+
exactly the Claude Desktop case. A `council run` typed into a terminal has no MCP server, so
|
|
160
|
+
detection there falls through to the env override or the `cowork` status-quo default. Do not build
|
|
161
|
+
this on the CLI path expecting detection to work; either gate it on the MCP entry point or thread
|
|
162
|
+
an explicit client tag through. (Related: the Phase 12 backlog item about persisting the client tag
|
|
163
|
+
into shared-server `metadata.json` is the same seam.)
|
|
164
|
+
|
|
165
|
+
**Four guards, all load-bearing:**
|
|
166
|
+
|
|
167
|
+
1. **Never under `--json`.** `--ui` already rejects `--json` (interactive-only); an implicit default
|
|
168
|
+
must not create the combination the explicit flag refuses.
|
|
169
|
+
2. **Never in CI or headless.** `council run` is the engine behind the Council Review GitHub Action
|
|
170
|
+
and every headless fanout. A popped window on a runner is a hang, not a feature. Gate on the same
|
|
171
|
+
display check the e2e suite uses (`HAS_DISPLAY`).
|
|
172
|
+
3. **Never trigger an install.** Requirement is *"where Electron is installed"* — check
|
|
173
|
+
`isElectronUsable`, and if it is absent, do nothing silently. An implicit ~100 MB Electron
|
|
174
|
+
download on someone's first council run is a hostile surprise.
|
|
175
|
+
4. **Must be opt-out.** A `--no-ui` (or config key) that suppresses it, because this changes default
|
|
176
|
+
behaviour for an existing command.
|
|
177
|
+
|
|
178
|
+
**Why not v4.4.1.** It is a new default behaviour — a feature — and 4.4.1 is a patch on a shipped
|
|
179
|
+
release whose scope was explicitly locked. The patch already carries two behaviour changes (LC-2,
|
|
180
|
+
LC-10) that stretch the definition; a third that pops a GUI window would not be defensible as a
|
|
181
|
+
patch. Sits naturally beside v4.5's existing **GUI power ergonomics (F10)** line.
|
|
182
|
+
|
|
183
|
+
## Backlog (tracked, not scheduled)
|
|
184
|
+
- **`--dry-run` / cost & route preview** across start/fanout/council — E2/C7/F4 *(M)* — "know the cost/route before you commit"; useful, not essential to the near-term line.
|
|
185
|
+
- **F7** — Parallel council panels + super-chair (opt-in `--panels N` high-assurance; niche).
|
|
186
|
+
- **E7** — Prompt dedup cache (exact-dup, opt-in, excludes council/fanout) — minor cost optimization.
|
|
187
|
+
- **E6** — Cost-per-quality metric (withdrawn in debate; revisit if street-cred stabilizes).
|
|
188
|
+
- **`amicus key --local` picker** *(S)* — a default local-provider picker so `amicus key` sets/clears a bearer without naming the provider id: auto-select (and announce) when exactly one local provider is configured, a numbered prompt when several, and a hard error under `--json`/non-interactive rather than guessing a secret's destination. Register `--local` as a boolean flag. Deferred out of v4.2.1 as feature material (a new CLI surface, not a patch fix).
|
|
189
|
+
- **Headless no-output fast-fail backstop** *(M)* — fail a headless run fast (env-tunable `AMICUS_NO_OUTPUT_BACKSTOP_MS`, ~120s default) when a misconfigured local model produces zero output, reasoning, and tool-calls, instead of polling to the request/overall timeout. Disarms permanently on the first token/reasoning/tool_use, so a legit slow cold-prefill local model (30–90s is normal) is never affected. Deferred out of v4.2.1 as new runtime behavior.
|
|
190
|
+
|
|
191
|
+
## What changed vs. the council's flat top-10
|
|
192
|
+
- Split the flat list into a **benefit-themed 4.x point-release line** (v4.0 → v4.2 → v4.3 → v4.4 → v4.5).
|
|
193
|
+
- **v4.1 inserted post-design (2026-07-19):** skill-on-engine fast path + headless debate mode,
|
|
194
|
+
between the engine (v4.0) and local providers (v4.2). Spec: `docs/superpowers/specs/2026-07-19-v4.0-headless-council-engine-design.md`.
|
|
195
|
+
- **Local providers stays near-term** (v4.2) — a broad cost/privacy benefit, not enterprise.
|
|
196
|
+
- **Observability arc split:** v4.3 = the data layer + terminal surface + resilience + spend (ships first); **v4.4 = the Electron Council Workspace (B9)** as a GUI on that data.
|
|
197
|
+
- **`--dry-run` cost preview → backlog** (was in the observability rev).
|
|
198
|
+
- **Enterprise/governance/audit/compliance/learning-loops → v5.0**, reframed as the deliberate *major-version venture* gated on funding.
|
|
199
|
+
- The **cheap trust fixes** (envelope, injection fencing, fold nonce) pulled into **v4.0** because the engine needs them to be trustworthy in automation.
|
|
200
|
+
- **Docs are part of the rev (2026-07-20):** every rev from v4.1 onward closes with a **README + docs update** line item, so each release ships its own documentation rather than deferring it.
|