amicus 1.1.0 → 1.2.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/marketplace.json +14 -0
- package/.claude-plugin/plugin.json +19 -0
- package/CHANGELOG.md +63 -0
- package/LICENSE +22 -1
- package/README.md +12 -2
- package/bin/amicus.js +13 -161
- package/package.json +6 -4
- package/scripts/postinstall.js +16 -7
- package/skills/second-opinion/COUNCIL-DESIGN.md +34 -34
- package/skills/second-opinion/MODEL-NOTES.md +23 -17
- package/skills/second-opinion/SKILL.md +77 -45
- package/src/cli-handlers-council.js +59 -0
- package/src/cli-handlers-doctor.js +173 -0
- package/src/cli-handlers-run.js +196 -0
- package/src/cli-handlers.js +1 -1
- package/src/cli.js +11 -2
- package/src/council/findings.js +48 -0
- package/src/council/ledger.js +82 -0
- package/src/council/tally.js +108 -0
- package/src/council/verdict.js +48 -0
- package/src/headless.js +43 -149
- package/src/mcp-server.js +6 -0
- package/src/sidecar/budget.js +83 -0
- package/src/sidecar/conversation-mirror.js +128 -0
- package/src/sidecar/fanout-leg.js +4 -1
- package/src/sidecar/fanout.js +34 -7
- package/src/sidecar/interactive-mirror.js +66 -0
- package/src/sidecar/interactive.js +35 -21
- package/src/sidecar/models.js +10 -9
- package/src/sidecar/session-finalize.js +26 -0
- package/src/sidecar/session-utils.js +5 -5
- package/src/sidecar/setup.js +2 -2
- package/src/sidecar/start.js +19 -6
- package/src/utils/activity-poller.js +47 -0
- package/src/utils/alias-audit.js +17 -4
- package/src/utils/alias-resolver.js +1 -1
- package/src/utils/config.js +4 -4
- package/src/utils/curated-models.js +2 -2
- package/src/utils/error-doc.js +55 -0
- package/src/utils/lifecycle.js +1 -1
- package/src/utils/model-catalog.js +1 -1
- package/src/utils/pricing.js +93 -0
- package/src/utils/result-schema.js +21 -2
- package/src/utils/session-abort.js +40 -13
- package/src/utils/validators.js +17 -17
- /package/{skill → skills/sidecar}/SKILL.md +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bourbondog-amicus",
|
|
3
|
+
"owner": { "name": "Christian Wagner", "url": "https://github.com/BourbonDog" },
|
|
4
|
+
"metadata": { "description": "Amicus — multi-model LLM Council + parallel AI window for Claude Code." },
|
|
5
|
+
"plugins": [
|
|
6
|
+
{
|
|
7
|
+
"name": "amicus",
|
|
8
|
+
"source": "./",
|
|
9
|
+
"description": "Multi-model LLM Council + parallel AI window. Run structured council reviews across Gemini, GPT, DeepSeek and more — or fork a conversation to any model and fold the results back.",
|
|
10
|
+
"author": { "name": "Christian Wagner" },
|
|
11
|
+
"keywords": ["claude-code", "multi-model", "llm", "council", "second-opinion"]
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "amicus",
|
|
3
|
+
"version": "1.2.1",
|
|
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
|
+
"author": { "name": "Christian Wagner" },
|
|
6
|
+
"homepage": "https://bourbondog.github.io/amicus/",
|
|
7
|
+
"repository": "https://github.com/BourbonDog/amicus",
|
|
8
|
+
"bugs": "https://github.com/BourbonDog/amicus/issues",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": ["claude-code", "multi-model", "llm", "council", "second-opinion", "sidecar", "gemini", "gpt", "deepseek"],
|
|
11
|
+
"skills": ["./skills/sidecar", "./skills/second-opinion"],
|
|
12
|
+
"mcpServers": {
|
|
13
|
+
"amicus": {
|
|
14
|
+
"command": "npx",
|
|
15
|
+
"args": ["-y", "amicus@latest", "mcp"],
|
|
16
|
+
"env": { "AMICUS_SKIP_POSTINSTALL": "1" }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,69 @@ All notable changes to Amicus are documented here. Format follows
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [1.2.1] - 2026-06-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **`amicus models --check` / `amicus doctor` stale deepseek warning is now clearable**: the
|
|
12
|
+
built-in deepseek direct fallback (`deepseek/deepseek-chat`) has been updated to
|
|
13
|
+
`deepseek/deepseek-v4-pro`. Additionally, stale curated-route warnings are now suppressed when
|
|
14
|
+
the same alias already resolves live via any other source (default openrouter route or a
|
|
15
|
+
user-set alias), so the suggested `--add-alias` fix actually clears the warning instead of
|
|
16
|
+
leaving it permanently unresolvable.
|
|
17
|
+
|
|
18
|
+
## [1.2.0] - 2026-06-24
|
|
19
|
+
|
|
20
|
+
A post-launch enhancement program: reliability and cost made real, the council's
|
|
21
|
+
trust machinery turned from hand-math into deterministic code, plus first-run
|
|
22
|
+
diagnostics, a Claude Code plugin, and an observable interactive surface.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- **`amicus doctor`**: a one-screen first-run health check — configured providers, default-model
|
|
26
|
+
resolution vs. the live catalog, catalog freshness, the OpenCode binary, Electron, installed
|
|
27
|
+
skills, and MCP registration. Each red line carries the exact fix command; `--json` lets skills
|
|
28
|
+
self-diagnose.
|
|
29
|
+
- **Claude Code plugin**: Amicus is now installable from the marketplace —
|
|
30
|
+
`/plugin marketplace add BourbonDog/amicus` then `/plugin install amicus`. The plugin ships both
|
|
31
|
+
skills and the MCP server; npm stays the engine/CLI. (The plugin channel skips the global
|
|
32
|
+
postinstall via `AMICUS_SKIP_POSTINSTALL` so it can't double-register.)
|
|
33
|
+
- **Per-leg cost & token telemetry**: the run/wave schema (now `schemaVersion: 2`) carries a
|
|
34
|
+
`usage` block — input/output/reasoning tokens and a `$` cost tagged by source (reported >
|
|
35
|
+
estimated > unknown). Surfaced in `fanout --json` and council run-stats.
|
|
36
|
+
- **Enforced budget gate**: a per-`$/Mtok` threshold (on by default — blocks o3-pro-class models
|
|
37
|
+
before a wave launches) plus an optional `--max-cost` total ceiling. `--no-cost-gate` is the
|
|
38
|
+
explicit escape hatch.
|
|
39
|
+
- **`amicus council tally|stats`**: deterministic council scoring — a structured findings
|
|
40
|
+
contract, a peers-only tier cascade with self-vote-corrected street-cred, a compounding
|
|
41
|
+
reviewer-reliability ledger, and a machine-readable `verdict.json`. The council stays a skill;
|
|
42
|
+
the engine owns only the arithmetic and schemas.
|
|
43
|
+
- **Structured `--json` error envelope**: pre-flight failures now emit a typed
|
|
44
|
+
`{ ok: false, error: { code, message, hint } }` document on stdout (stable codes like
|
|
45
|
+
`MISSING_KEY`, `BAD_MODEL`, `BUDGET_EXCEEDED`) instead of bare text on stderr.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
- **Interactive GUI sessions now persist live**: `conversation.jsonl` and `progress.json` are
|
|
49
|
+
written as the session runs, so the CLI heartbeat, `amicus status`, and
|
|
50
|
+
`amicus read --conversation` work for GUI sessions — and **closing the window without folding no
|
|
51
|
+
longer loses the transcript**. Interactive runs also record token/cost usage. (Headless and
|
|
52
|
+
interactive now share one persistence transform.)
|
|
53
|
+
- **Reliability**: a single source of truth for terminal state (exit code and `metadata.status`
|
|
54
|
+
always agree; the idle backstop no longer exits 0 with `running` metadata), and an
|
|
55
|
+
activity-driven interactive watchdog that won't kill an actively-working-but-quiet GUI session.
|
|
56
|
+
- **CI**: a real matrix (Ubuntu / Windows / macOS × Node 18 / 20 / 22) plus lint, secret-scan, and
|
|
57
|
+
size-gate now gate every push and the publish.
|
|
58
|
+
- Repo layout: the chat skill moved to `skills/sidecar/` (both skills live under `skills/`); npm
|
|
59
|
+
`homepage` now points at the live site; README and the landing page gained a "Prerequisites &
|
|
60
|
+
cost" section.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
- **MCP stderr fd leak**: `spawnSidecarProcess` opened a `debug.log` descriptor for the child's
|
|
64
|
+
stderr but never closed the parent's copy — a descriptor leak that, on Windows, also held the
|
|
65
|
+
file open and blocked session-dir cleanup.
|
|
66
|
+
- Platform-correct missing-key guidance (PowerShell `$PROFILE`/`setx` on Windows; leads with
|
|
67
|
+
`amicus key`); the committed-secret scan now knows all five providers; `amicus models` marks
|
|
68
|
+
your **actual** aliases (not curated defaults); OpenRouter's `-1` "variable pricing" sentinel
|
|
69
|
+
renders as `—` instead of a nonsense negative price.
|
|
70
|
+
|
|
8
71
|
## [1.1.0] - 2026-06-11
|
|
9
72
|
|
|
10
73
|
### Added
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 John Renaldi
|
|
3
|
+
Copyright (c) 2025 John Renaldi Claude Sidecar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Copyright (c) 2026 Christian Wagner Amicus
|
|
4
25
|
|
|
5
26
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
27
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|

|
|
8
8
|
|
|
9
|
-
Hand Claude a
|
|
9
|
+
Hand Claude a plan, a design, a diff, an architecture decision, a manuscript — anything — and say *council review this*: Amicus routes it through several models from different families, has them anonymously cross-review each other, and a non-Claude chair synthesizes a verdict you turn into accept/deny edits. Or skip the ceremony and **fork** a single conversation to Gemini, GPT, DeepSeek, or any other model — it works in parallel with full context, and you **fold** the result back when you're ready. Claude orchestrates throughout; you stay in your editor.
|
|
10
10
|
|
|
11
11
|
[](https://www.npmjs.com/package/amicus)
|
|
12
12
|
[](./LICENSE)
|
|
@@ -67,6 +67,16 @@ The postinstall step auto-configures everything — no manual registration:
|
|
|
67
67
|
- Registers the **MCP server** in Claude Code and in Claude Desktop / Cowork, so the Amicus tools appear natively.
|
|
68
68
|
- Installs **both skills** into `~/.claude/skills/` — `second-opinion` (the council) and `sidecar` (the chat skill).
|
|
69
69
|
|
|
70
|
+
## Prerequisites & what it costs you
|
|
71
|
+
|
|
72
|
+
Before your first run:
|
|
73
|
+
|
|
74
|
+
- **Node.js ≥ 18** — `node --version` to check.
|
|
75
|
+
- **An active Claude Code or Cowork session** — Amicus is orchestrated by Claude; it is not a standalone chatbot.
|
|
76
|
+
- **At least one paid model API key** — OpenRouter (covers the most models) or a direct Google / OpenAI / Anthropic / DeepSeek key. Add one with `amicus setup` or `amicus key <provider> <key>`.
|
|
77
|
+
|
|
78
|
+
**What a run costs.** A sidecar is a single model call. A full council is typically **~5–8 paid model calls** (e.g. 3 reviewers across 2 fan-out waves + 1 chair). Amicus shows an estimate before each council and enforces a built-in budget gate that refuses ultra-expensive models (o3-pro class) unless you opt in with `--no-cost-gate`. You pay your providers directly for the tokens; Amicus itself is free and open-source.
|
|
79
|
+
|
|
70
80
|
**Configure:**
|
|
71
81
|
|
|
72
82
|
```bash
|
|
@@ -452,7 +462,7 @@ LOG_LEVEL=debug amicus start --model gemini --prompt "test" --no-ui
|
|
|
452
462
|
| [docs/publishing.md](./docs/publishing.md) | Release and publish process. |
|
|
453
463
|
| [docs/SHIMS.md](./docs/SHIMS.md) | Legacy `SIDECAR_*` → `AMICUS_*` compatibility shims. |
|
|
454
464
|
| [skills/second-opinion/SKILL.md](./skills/second-opinion/SKILL.md) | The LLM Council skill. |
|
|
455
|
-
| [
|
|
465
|
+
| [skills/sidecar/SKILL.md](./skills/sidecar/SKILL.md) | The `sidecar` chat skill. |
|
|
456
466
|
| [evals/README.md](./evals/README.md) | End-to-end eval harness for LLM interactions. |
|
|
457
467
|
|
|
458
468
|
---
|
package/bin/amicus.js
CHANGED
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
const { loadCredentials } = require('../src/utils/env-loader');
|
|
12
12
|
loadCredentials();
|
|
13
13
|
|
|
14
|
-
const { parseArgs,
|
|
14
|
+
const { parseArgs, getUsage } = require('../src/cli');
|
|
15
15
|
const { validateTaskId } = require('../src/utils/validators');
|
|
16
16
|
const { resolveModelFromArgs, validateFallbackModel } = require('../src/utils/start-helpers');
|
|
17
17
|
const { handleSetup, handleAbort, handleUpdate, handleMcp, handleKey } = require('../src/cli-handlers');
|
|
18
|
+
const { handleStart, handleFanout, handleRead } = require('../src/cli-handlers-run');
|
|
18
19
|
const { isOneShotCommand, armExitWatchdog } = require('../src/utils/lifecycle');
|
|
19
20
|
const { logger } = require('../src/utils/logger');
|
|
20
21
|
|
|
@@ -73,7 +74,7 @@ async function main() {
|
|
|
73
74
|
try {
|
|
74
75
|
switch (command) {
|
|
75
76
|
case 'start':
|
|
76
|
-
await handleStart(args);
|
|
77
|
+
exitCode = await handleStart(args);
|
|
77
78
|
break;
|
|
78
79
|
case 'fanout':
|
|
79
80
|
exitCode = await handleFanout(args);
|
|
@@ -95,6 +96,16 @@ async function main() {
|
|
|
95
96
|
exitCode = await handleModels(args);
|
|
96
97
|
break;
|
|
97
98
|
}
|
|
99
|
+
case 'council': {
|
|
100
|
+
const { handleCouncil } = require('../src/cli-handlers-council');
|
|
101
|
+
exitCode = await handleCouncil(args);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case 'doctor': {
|
|
105
|
+
const { handleDoctor } = require('../src/cli-handlers-doctor');
|
|
106
|
+
exitCode = await handleDoctor(args);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
98
109
|
case 'setup':
|
|
99
110
|
await handleSetup(args);
|
|
100
111
|
break;
|
|
@@ -129,135 +140,6 @@ async function main() {
|
|
|
129
140
|
}
|
|
130
141
|
}
|
|
131
142
|
|
|
132
|
-
/**
|
|
133
|
-
* Handle 'sidecar start' command
|
|
134
|
-
* Spec Reference: §4.1
|
|
135
|
-
*/
|
|
136
|
-
async function handleStart(args) {
|
|
137
|
-
// F4: --prompt-file support (XOR --prompt) and --json gating
|
|
138
|
-
if (args.prompt !== undefined || args['prompt-file'] !== undefined) {
|
|
139
|
-
const { resolvePromptSource } = require('../src/utils/prompt-source');
|
|
140
|
-
const promptRes = resolvePromptSource(args);
|
|
141
|
-
if (promptRes.error) {
|
|
142
|
-
console.error(promptRes.error);
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}
|
|
145
|
-
args.prompt = promptRes.prompt;
|
|
146
|
-
}
|
|
147
|
-
if (args.json && !args['no-ui']) {
|
|
148
|
-
console.error('Error: --json requires --no-ui');
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const { model, alias } = resolveModelFromArgs(args);
|
|
153
|
-
args.model = model;
|
|
154
|
-
args.model = await validateFallbackModel(args, alias);
|
|
155
|
-
|
|
156
|
-
// Normalize agent: --agent takes precedence, otherwise use --mode
|
|
157
|
-
args.agent = args.agent || args.mode;
|
|
158
|
-
|
|
159
|
-
const validation = validateStartArgs(args);
|
|
160
|
-
if (!validation.valid) {
|
|
161
|
-
console.error(validation.error);
|
|
162
|
-
process.exit(1);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const { startSidecar } = require('../src/index');
|
|
166
|
-
|
|
167
|
-
await startSidecar({
|
|
168
|
-
taskId: args['task-id'],
|
|
169
|
-
model: args.model,
|
|
170
|
-
prompt: args.prompt,
|
|
171
|
-
sessionId: args['session-id'],
|
|
172
|
-
cwd: args.cwd,
|
|
173
|
-
contextTurns: args['context-turns'],
|
|
174
|
-
contextSince: args['context-since'],
|
|
175
|
-
contextMaxTokens: args['context-max-tokens'],
|
|
176
|
-
noUi: args['no-ui'],
|
|
177
|
-
timeout: args.timeout,
|
|
178
|
-
agent: args.agent,
|
|
179
|
-
mcp: args.mcp,
|
|
180
|
-
mcpConfig: args['mcp-config'],
|
|
181
|
-
thinking: args.thinking,
|
|
182
|
-
summaryLength: args['summary-length'],
|
|
183
|
-
client: args.client,
|
|
184
|
-
sessionDir: args['session-dir'],
|
|
185
|
-
foldShortcut: args['fold-shortcut'],
|
|
186
|
-
opencodePort: args['opencode-port'],
|
|
187
|
-
noMcp: args['no-mcp'],
|
|
188
|
-
excludeMcp: args['exclude-mcp'],
|
|
189
|
-
coworkProcess: args['cowork-process'],
|
|
190
|
-
position: args.position,
|
|
191
|
-
json: !!args.json,
|
|
192
|
-
modelInput: alias || null,
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Handle 'amicus fanout' command (F4).
|
|
198
|
-
* Returns the wave exit code: 0 all complete, 2 partial, 1 none/hard failure,
|
|
199
|
-
* 130/143 when the wave was signal-aborted.
|
|
200
|
-
*/
|
|
201
|
-
async function handleFanout(args) {
|
|
202
|
-
const { resolvePromptSource } = require('../src/utils/prompt-source');
|
|
203
|
-
const promptRes = resolvePromptSource(args);
|
|
204
|
-
if (promptRes.error) {
|
|
205
|
-
console.error(promptRes.error);
|
|
206
|
-
process.exit(1);
|
|
207
|
-
}
|
|
208
|
-
if (typeof args.models !== 'string' || !args.models.trim()) {
|
|
209
|
-
console.error('Error: --models is required (comma-separated aliases or provider/model IDs)');
|
|
210
|
-
process.exit(1);
|
|
211
|
-
}
|
|
212
|
-
if (args['wave-id']) {
|
|
213
|
-
const check = validateTaskId(String(args['wave-id']));
|
|
214
|
-
if (!check.valid) {
|
|
215
|
-
console.error(check.error);
|
|
216
|
-
process.exit(1);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
if (args.agent && String(args.agent).toLowerCase() === 'chat') {
|
|
220
|
-
console.error('Error: --agent chat is interactive-only; fanout is headless');
|
|
221
|
-
process.exit(1);
|
|
222
|
-
}
|
|
223
|
-
if (args.timeout !== undefined && args.timeout <= 0) {
|
|
224
|
-
console.error('Error: --timeout must be a positive number');
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
227
|
-
const { parseModelsList } = require('../src/sidecar/fanout');
|
|
228
|
-
if (parseModelsList(args.models).length === 0) {
|
|
229
|
-
console.error('Error: --models must contain at least one non-empty entry');
|
|
230
|
-
process.exit(1);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Direct require — the src/index.js public re-export is added later (Task 13)
|
|
234
|
-
const { runFanout } = require('../src/sidecar/fanout');
|
|
235
|
-
const { exitCode } = await runFanout({
|
|
236
|
-
models: args.models,
|
|
237
|
-
prompt: promptRes.prompt,
|
|
238
|
-
promptMeta: promptRes.promptMeta,
|
|
239
|
-
waveId: args['wave-id'],
|
|
240
|
-
project: args.cwd || process.cwd(),
|
|
241
|
-
agent: args.agent || args.mode,
|
|
242
|
-
thinking: args.thinking,
|
|
243
|
-
timeout: args.timeout,
|
|
244
|
-
summaryLength: args['summary-length'],
|
|
245
|
-
includeContext: !args['no-context'],
|
|
246
|
-
sessionId: args['session-id'],
|
|
247
|
-
contextTurns: args['context-turns'],
|
|
248
|
-
contextSince: args['context-since'],
|
|
249
|
-
contextMaxTokens: args['context-max-tokens'],
|
|
250
|
-
mcp: args.mcp,
|
|
251
|
-
mcpConfig: args['mcp-config'],
|
|
252
|
-
noMcp: args['no-mcp'],
|
|
253
|
-
excludeMcp: args['exclude-mcp'],
|
|
254
|
-
noValidateModel: args['no-validate-model'],
|
|
255
|
-
json: !!args.json,
|
|
256
|
-
client: args.client,
|
|
257
|
-
});
|
|
258
|
-
return exitCode;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
143
|
/**
|
|
262
144
|
* Handle 'sidecar list' command
|
|
263
145
|
* Spec Reference: §4.2
|
|
@@ -348,36 +230,6 @@ async function handleContinue(args) {
|
|
|
348
230
|
});
|
|
349
231
|
}
|
|
350
232
|
|
|
351
|
-
/**
|
|
352
|
-
* Handle 'sidecar read' command
|
|
353
|
-
* Spec Reference: §4.5
|
|
354
|
-
*/
|
|
355
|
-
async function handleRead(args) {
|
|
356
|
-
const taskId = args._[1];
|
|
357
|
-
|
|
358
|
-
if (!taskId) {
|
|
359
|
-
console.error('Error: task_id is required for read');
|
|
360
|
-
console.error('Usage: sidecar read <task_id> [--summary|--conversation]');
|
|
361
|
-
process.exit(1);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const taskIdCheck = validateTaskId(taskId);
|
|
365
|
-
if (!taskIdCheck.valid) {
|
|
366
|
-
console.error(taskIdCheck.error);
|
|
367
|
-
process.exit(1);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const { readSidecar } = require('../src/index');
|
|
371
|
-
|
|
372
|
-
await readSidecar({
|
|
373
|
-
taskId,
|
|
374
|
-
conversation: args.conversation,
|
|
375
|
-
metadata: args.metadata,
|
|
376
|
-
json: args.json,
|
|
377
|
-
project: args.cwd
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
|
|
381
233
|
// Run main
|
|
382
234
|
main().catch(err => {
|
|
383
235
|
console.error(`Fatal error: ${err.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amicus",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.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
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"url": "git+https://github.com/BourbonDog/amicus.git"
|
|
25
25
|
},
|
|
26
26
|
"bugs": "https://github.com/BourbonDog/amicus/issues",
|
|
27
|
-
"homepage": "https://github.
|
|
27
|
+
"homepage": "https://bourbondog.github.io/amicus/",
|
|
28
28
|
"bin": {
|
|
29
29
|
"amicus": "./bin/amicus.js",
|
|
30
30
|
"am": "./bin/amicus.js",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"bin/",
|
|
40
40
|
"src/",
|
|
41
41
|
"electron/",
|
|
42
|
-
"skill/",
|
|
43
42
|
"skills/",
|
|
43
|
+
".claude-plugin/",
|
|
44
44
|
"CHANGELOG.md",
|
|
45
45
|
"scripts/postinstall.js",
|
|
46
46
|
"scripts/setup-hooks.js"
|
|
@@ -63,7 +63,9 @@
|
|
|
63
63
|
"generate-docs": "node scripts/generate-docs.js",
|
|
64
64
|
"generate-docs:check": "node scripts/generate-docs.js --check",
|
|
65
65
|
"validate-docs": "node scripts/validate-docs.js --full",
|
|
66
|
-
"prepare": "node scripts/setup-hooks.js"
|
|
66
|
+
"prepare": "node scripts/setup-hooks.js",
|
|
67
|
+
"check:secrets": "node scripts/check-secrets.js --all",
|
|
68
|
+
"check:sizes": "node scripts/check-file-sizes.js --all"
|
|
67
69
|
},
|
|
68
70
|
"dependencies": {
|
|
69
71
|
"@modelcontextprotocol/sdk": "^1.27.0",
|
package/scripts/postinstall.js
CHANGED
|
@@ -13,7 +13,7 @@ const path = require('path');
|
|
|
13
13
|
const os = require('os');
|
|
14
14
|
const { execFileSync } = require('child_process');
|
|
15
15
|
|
|
16
|
-
const SKILL_SOURCE = path.join(__dirname, '..', '
|
|
16
|
+
const SKILL_SOURCE = path.join(__dirname, '..', 'skills', 'sidecar', 'SKILL.md');
|
|
17
17
|
const COUNCIL_SOURCE_DIR = path.join(__dirname, '..', 'skills', 'second-opinion');
|
|
18
18
|
|
|
19
19
|
/** Council files + per-file install semantics: SKILL/COUNCIL-DESIGN are product code
|
|
@@ -172,12 +172,21 @@ function registerClaudeDesktop() {
|
|
|
172
172
|
addMcpToConfigFile(configPath, 'sidecar', MCP_CONFIG);
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
function main() {
|
|
175
|
+
function main(deps = {}) {
|
|
176
|
+
if (process.env.AMICUS_SKIP_POSTINSTALL === '1') {
|
|
177
|
+
console.log('[amicus] AMICUS_SKIP_POSTINSTALL set — skipping global setup (plugin channel handles registration).');
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const _installSkill = deps.installSkill || installSkill;
|
|
181
|
+
const _installCouncilSkill = deps.installCouncilSkill || installCouncilSkill;
|
|
182
|
+
const _registerClaudeCode = deps.registerClaudeCode || registerClaudeCode;
|
|
183
|
+
const _registerClaudeDesktop = deps.registerClaudeDesktop || registerClaudeDesktop;
|
|
184
|
+
|
|
176
185
|
console.log('[amicus] Installing...');
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
186
|
+
_installSkill();
|
|
187
|
+
_installCouncilSkill();
|
|
188
|
+
_registerClaudeCode();
|
|
189
|
+
_registerClaudeDesktop();
|
|
181
190
|
|
|
182
191
|
console.log('');
|
|
183
192
|
console.log('[amicus] Setup:');
|
|
@@ -190,4 +199,4 @@ if (require.main === module) {
|
|
|
190
199
|
main();
|
|
191
200
|
}
|
|
192
201
|
|
|
193
|
-
module.exports = { addMcpToConfigFile, installSkill, installCouncilSkill, COUNCIL_FILES };
|
|
202
|
+
module.exports = { main, addMcpToConfigFile, installSkill, installCouncilSkill, COUNCIL_FILES };
|
|
@@ -35,7 +35,7 @@ non-Claude chairman + per-model inspectable artifacts.
|
|
|
35
35
|
chair) is prose workflow Claude performs while driving the `amicus` CLI. v3 note: the *transport*
|
|
36
36
|
is now engine-native — each review wave is ONE `amicus fanout --json` call returning structured
|
|
37
37
|
run documents — but scoring, tallying, anonymization, and synthesis remain Claude's manual work.
|
|
38
|
-
No backend, no parsing code beyond reading JSON fields.
|
|
38
|
+
No backend, no parsing code beyond reading JSON fields. Deterministic arithmetic/formatting/schema helpers under `amicus council` (findings validation, tier tally, street-cred, ledger) are sanctioned; judgment, synthesis, anonymization, and de-anonymization remain Claude's inline work.
|
|
39
39
|
|
|
40
40
|
## 3. What changes vs. v1
|
|
41
41
|
|
|
@@ -44,7 +44,7 @@ non-Claude chairman + per-model inspectable artifacts.
|
|
|
44
44
|
| Independent reviews | ✅ Phase 2 parallel sidecars | ✅ Stage 1 — now emits a **structured findings list** |
|
|
45
45
|
| Cross-review | ❌ none | ⭐ **Stage 2** — anonymized peer ranking **+** per-finding adjudication |
|
|
46
46
|
| Synthesis | Claude synthesizes | ⭐ **Council-model chair** synthesizes; Claude only presents |
|
|
47
|
-
| Decision tiers | Claude's consensus/divergence read | ⭐ **Peer-validated** tiers (Confirmed / Contested / Singleton) |
|
|
47
|
+
| Decision tiers | Claude's consensus/divergence read | ⭐ **Peer-validated** tiers (Disputed / Confirmed / Contested / Singleton) |
|
|
48
48
|
| Scoring | none | ⭐ Reviewer **street-cred** + per-finding **peer-confidence** |
|
|
49
49
|
| Artifacts | reviewed copy + report | + per-model raw reviews, cross-review matrix, chair verdict (run folder) |
|
|
50
50
|
| MODEL-NOTES | per-model quirks | + **reviewer-reliability** rolling table feeding recommendations |
|
|
@@ -106,11 +106,9 @@ Run as ordered phases; track as todos. **Three sequential waves of model calls**
|
|
|
106
106
|
- Chair selection & fallback: §5.3.
|
|
107
107
|
|
|
108
108
|
### Stage 4 — Tiered decisions (peer-validated)
|
|
109
|
-
- **Consensus tier** = **Confirmed** findings (
|
|
110
|
-
|
|
111
|
-
-
|
|
112
|
-
findings → present **each individually**, showing the dissent and which model raised/disputed it.
|
|
113
|
-
- Record every decision (accepted / denied / modified).
|
|
109
|
+
- **Consensus tier** = **Confirmed** findings (≥ 2 peer agreements, agrees dominate) → offer one **bulk accept/deny** (user may name exceptions).
|
|
110
|
+
- **Judgment tier** = **Disputed** (strong peer pushback), **Contested** (live dispute), or **Singleton** (only the raiser) → present **each individually**, showing the adjudication data and which model raised/disputed it.
|
|
111
|
+
- Record every decision (accepted / denied / modified / deferred).
|
|
114
112
|
|
|
115
113
|
### Stage 5 — Outputs
|
|
116
114
|
- **Editable source** → write `<stem>-reviewed.<ext>` next to the original (accepted changes
|
|
@@ -119,8 +117,8 @@ Run as ordered phases; track as todos. **Three sequential waves of model calls**
|
|
|
119
117
|
|
|
120
118
|
### Stage 6 — Capture lessons (compounding)
|
|
121
119
|
- Reflect on failures/mitigations and briefing wording, as today.
|
|
122
|
-
- **
|
|
123
|
-
- **
|
|
120
|
+
- **Ledger auto-appends** — `ledger.appendRun(record)` writes one row per (run × model) to `council-ledger.jsonl` automatically at finalize (shown in the run summary). No manual reliability-table update needed.
|
|
121
|
+
- **Qualitative MODEL-NOTES update (approval-gated):** draft per-model quirk/conformance notes; write the proposed diff to `_tmp-proposed-model-notes-update.md`; present its path in the approval prompt; do not write until approved.
|
|
124
122
|
The approval prompt carries the diff file's path; chat text alone is not sufficient (an approval
|
|
125
123
|
dialog can hide the chat transcript). Keep it tight.
|
|
126
124
|
|
|
@@ -136,14 +134,23 @@ Run as ordered phases; track as todos. **Three sequential waves of model calls**
|
|
|
136
134
|
and judged blind by the council models. Claude never ranks/adjudicates (it holds the map) —
|
|
137
135
|
the asymmetry detailed in §5.4.
|
|
138
136
|
|
|
139
|
-
### 5.2 Scoring (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
- **
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
137
|
+
### 5.2 Scoring (`amicus council tally` computes; Claude may override at the margins)
|
|
138
|
+
|
|
139
|
+
**Street cred** — computed two ways by `amicus council tally`:
|
|
140
|
+
- **withSelf** = each model's mean rank position across **all** judges' `FINAL RANKING:` blocks (lower = better).
|
|
141
|
+
- **peersOnly** = mean rank across judges **other than** that model (self-vote excluded).
|
|
142
|
+
The cross-review matrix shows both; the ledger and Stage-0 bench recommendations consume **peersOnly** only.
|
|
143
|
+
|
|
144
|
+
**Per-finding peer-confidence tier** — determined by a **peers-only** cascade: for a finding raised by model R, peers are all judges except R (the raiser's own adjudication is excluded — consistent with the peers-only street-cred rule). Let `a` = peer agrees, `d` = peer disputes. The cascade is exhaustive and mutually exclusive:
|
|
145
|
+
|
|
146
|
+
| Priority | Tier | Rule | Meaning |
|
|
147
|
+
|---|---|---|---|
|
|
148
|
+
| 1 | **Disputed** | `d ≥ 2` and `d > a` | Strong peer pushback — the finding itself is likely wrong |
|
|
149
|
+
| 2 | **Confirmed** | `a ≥ 2` and `a > d` | ≥ 2 independent corroborations, agrees dominate |
|
|
150
|
+
| 3 | **Contested** | `d ≥ 1` (whatever remains) | At least one live dispute — in question |
|
|
151
|
+
| 4 | **Singleton** | else (`d = 0` and `a < 2`) | At most one endorsement, no pushback — thin |
|
|
152
|
+
|
|
153
|
+
`confidence` is `thin` when total engaged peers `a + d ≤ 1` — cells `(0,0)`, `(1,0)`, and `(0,1)`. **Claude may override the tier at `thin` margins** (recorded as `tierOverride: {from, to, reason}` and surfaced in the matrix and `verdict.json`). These four tiers drive Stage 4. `amicus council tally` assigns them deterministically; judgment at the margins remains Claude's.
|
|
147
154
|
|
|
148
155
|
### 5.3 Chair selection & fallback
|
|
149
156
|
- Default: Claude **recommends a non-Claude chair** from the council each run (often the
|
|
@@ -161,7 +168,7 @@ Lets you see how the bench judges Claude's *own* take.
|
|
|
161
168
|
- **Which review: always fresh** — Claude does a new structured Stage-1 review on the artifact
|
|
162
169
|
every time it's enabled (not a formalization of upstream feedback).
|
|
163
170
|
- **Readout — "How Claude's review fared":** Claude's street-cred rank among peers and the
|
|
164
|
-
Confirmed/Contested/Singleton split of its findings, reported in the matrix and report.
|
|
171
|
+
Disputed/Confirmed/Contested/Singleton split of its findings, reported in the matrix and report.
|
|
165
172
|
- **Integrity:** when Claude presents results, it reports the bench's verdict on its own review
|
|
166
173
|
at face value — no defending or re-litigating.
|
|
167
174
|
|
|
@@ -171,22 +178,16 @@ One tidy run folder: `output/<stem>-council/` (or `./second-opinion/<stem>-counc
|
|
|
171
178
|
- `review-<model>.md` ×N — raw Stage 1 reviews (plus `review-claude.md` when "Claude in the
|
|
172
179
|
council" is on)
|
|
173
180
|
- `crossreview-matrix.md` — adjudication grid + street-cred table (de-anonymized)
|
|
174
|
-
- `verdict.md` — the chair's synthesis
|
|
181
|
+
- `verdict.md` — the chair's synthesis (prose)
|
|
182
|
+
- `verdict.json` — schema-stamped machine-readable record: tally output + Stage-4 decisions, written via `buildVerdict(record, decisions)` at Stage 5
|
|
175
183
|
- `report.md` — synthesis + decision log + what was applied (+ the "How Claude's review fared"
|
|
176
184
|
readout when "Claude in the council" is on)
|
|
177
185
|
- `<stem>-reviewed.<ext>` — written **next to the original**, as today (editable sources only)
|
|
178
186
|
- Temp extracts get a clearly-temporary name and are cleaned up at the end.
|
|
179
187
|
|
|
180
188
|
## 7. MODEL-NOTES reviewer-reliability
|
|
181
|
-
Add a compact rolling table consulted in Stage 0 and updated (with approval) in Stage 6:
|
|
182
|
-
|
|
183
|
-
| model | runs | avg street-cred | confirm-rate | notes |
|
|
184
|
-
|---|---|---|---|---|
|
|
185
189
|
|
|
186
|
-
- **avg street-cred
|
|
187
|
-
- **confirm-rate** — share of this model's findings that ended up **Confirmed** by peers.
|
|
188
|
-
- Used to justify recommendations ("DeepSeek findings peer-confirm ~80% → strong default
|
|
189
|
-
reviewer"). Kept tight per the existing no-bloat rule; merge/prune rather than append.
|
|
190
|
+
The append-only `council-ledger.jsonl` (consumed via `amicus council stats`) is the **authoritative source of quantitative reviewer-reliability data** — runs, avg peers-only street-cred, confirm-rate, fact-error rate, conformance distribution. `MODEL-NOTES.md` keeps only *qualitative* per-model quirks and structural-conformance notes (`clean` / `repaired` / `unstructured`); it may embed a snapshot generated from `amicus council stats --json` but is no longer hand-edited for numbers. Stage-6 reliability updates are written by the ledger auto-append; the MODEL-NOTES prose update remains approval-gated.
|
|
190
191
|
|
|
191
192
|
## 8. Gating, cost, degradation & failure handling
|
|
192
193
|
|
|
@@ -207,23 +208,22 @@ Add a compact rolling table consulted in Stage 0 and updated (with approval) in
|
|
|
207
208
|
- **Stage 3:** chair failure uses the same fallback chain (re-run → promote next-best non-Claude
|
|
208
209
|
→ Claude chairs with explicit disclosure).
|
|
209
210
|
- **Run stats (v3):** `report.md` includes a per-leg table (model, status, durationMs) read from
|
|
210
|
-
the wave/run documents. The schema carries no cost data — never invent cost figures.
|
|
211
|
+
the wave/run documents. `durationMs` and `usage` are copied verbatim from the per-leg run docs; any leg with no run doc gets `durationMs: null` (and `usage: null`) — never invent a value. The schema carries no cost data — never invent cost figures.
|
|
211
212
|
- **Transient failures:** provider 502s etc. → re-run the affected leg (solo `start --json`) or
|
|
212
213
|
the wave; never present a half-finished run as an answer.
|
|
213
214
|
|
|
214
215
|
## 9. Non-goals (YAGNI)
|
|
215
216
|
- No web UI, API server, or persistent conversation store (LLM Council's app shell).
|
|
216
|
-
- No code/backend for scoring or parsing — Claude does it inline.
|
|
217
|
+
- No code/backend for scoring or parsing — Claude does it inline. Deterministic arithmetic/formatting/schema helpers under `amicus council` (findings validation, tier tally, street-cred, ledger) are sanctioned; judgment, synthesis, anonymization, and de-anonymization remain Claude's inline work.
|
|
217
218
|
- No automatic MODEL-NOTES writes — always approval-gated.
|
|
218
219
|
- Claude is **not** a council member by default; it joins only via the opt-in toggle (§5.4),
|
|
219
220
|
and even then it is judged-but-non-voting/non-chairing.
|
|
220
221
|
|
|
221
222
|
## 10. Open questions
|
|
222
223
|
- None blocking. Possible later refinement: a numeric peer-confidence score instead of the
|
|
223
|
-
|
|
224
|
+
four qualitative tiers, if tiers prove too coarse in practice.
|
|
224
225
|
|
|
225
226
|
## 11. Implementation surface
|
|
226
|
-
- `SKILL.md` — the Stage 0–6 council flow on the v3 transport.
|
|
227
|
-
- `MODEL-NOTES.md` —
|
|
228
|
-
|
|
229
|
-
- No other files.
|
|
227
|
+
- `SKILL.md` — the Stage 0–6 council flow on the v3 transport (WS-3: findings contract, tally assembly recipe, `amicus council tally/stats`, `verdict.json`, ledger auto-append).
|
|
228
|
+
- `MODEL-NOTES.md` — qualitative per-model quirks, structural-conformance notes, cost guardrail, Stage-2 briefing tips. Quantitative reliability data now generated by `amicus council stats` (ledger). Engine workarounds that F1/F2/F4 made obsolete were pruned at v3.
|
|
229
|
+
- `src/council/` — the deterministic helpers (`findings.js`, `tally.js`, `verdict.js`, `ledger.js`). No other files.
|