amicus 4.4.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 +32 -0
- package/README.md +3 -1
- 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/main.js +4 -1
- package/electron/setup-ui-aliases.js +6 -6
- package/electron/workspace-ui/live-model.js +12 -1
- package/electron/workspace-ui/md-lite.js +52 -8
- package/electron/workspace-ui/workspace-matrix.js +46 -9
- package/electron/workspace-ui/workspace-panels.js +14 -3
- package/electron/workspace-ui/workspace-render.js +7 -1
- package/electron/workspace-ui/workspace-verbs.js +48 -2
- package/package.json +8 -3
- package/schemas/council-run.schema.json +20 -0
- package/schemas/progress.schema.json +12 -0
- package/schemas/spend.schema.json +52 -4
- package/src/cli-handlers-spend.js +20 -2
- package/src/cli-handlers-watch.js +11 -0
- 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 +24 -1
- 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 +64 -11
- 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 +29 -1
- package/src/council/run-server.js +248 -0
- package/src/council/run-stage2.js +118 -0
- package/src/council/run-stages.js +132 -111
- package/src/council/run-state.js +23 -1
- package/src/council/run.js +44 -46
- package/src/council/tally.js +10 -0
- package/src/headless.js +175 -6
- package/src/observe/council-legs.js +60 -3
- package/src/observe/live-doc.js +18 -1
- package/src/observe/watch-render.js +4 -1
- package/src/sidecar/child-sessions.js +1 -2
- package/src/sidecar/fanout-leg-fallback.js +69 -21
- package/src/sidecar/fanout-leg.js +6 -0
- package/src/sidecar/fanout-signals.js +61 -0
- package/src/sidecar/fanout-wave-io.js +75 -0
- package/src/sidecar/fanout.js +61 -70
- 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/spend-query.js +17 -5
- package/src/utils/lifecycle.js +37 -1
- package/src/utils/path-fence.js +39 -1
- package/src/utils/pricing.js +26 -10
- package/src/utils/server-setup.js +79 -1
- package/src/utils/spend-ledger.js +24 -3
- package/src/workspace/artifact-guard.js +22 -1
- package/src/workspace/fold-format.js +33 -4
- package/src/workspace/live-normalize.js +28 -15
- package/src/workspace/run-detail.js +7 -1
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Architecture Details
|
|
2
|
+
|
|
3
|
+
## Data Flow
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
User: amicus start --model google/gemini-2.5 --briefing "Debug auth issue"
|
|
7
|
+
↓
|
|
8
|
+
CLI parses args (cli.js)
|
|
9
|
+
↓
|
|
10
|
+
buildContext() extracts from ~/.claude/projects/[project]/[session].jsonl
|
|
11
|
+
↓
|
|
12
|
+
buildPrompts() creates system prompt + user message
|
|
13
|
+
Interactive: context in system prompt (hidden from UI)
|
|
14
|
+
Headless: context in user message (no UI)
|
|
15
|
+
↓
|
|
16
|
+
startOpenCodeServer() → createSession() → sendPromptAsync()
|
|
17
|
+
↓
|
|
18
|
+
[Interactive] [Headless]
|
|
19
|
+
Electron BrowserView opens OpenCode async API (promptAsync)
|
|
20
|
+
User converses with model Agent works autonomously
|
|
21
|
+
FOLD clicked → Polls for [SIDECAR_FOLD:<nonce>] marker
|
|
22
|
+
Model generates summary ↓
|
|
23
|
+
(SUMMARY_TEMPLATE prompt) extractSummary() captures output
|
|
24
|
+
↓ ↓
|
|
25
|
+
Summary output to stdout → Claude Code receives in context
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Fold Mechanism
|
|
29
|
+
|
|
30
|
+
When the user clicks **Fold** (or presses `Cmd+Shift+F`) in interactive mode:
|
|
31
|
+
|
|
32
|
+
1. UI shows overlay with spinner ("Generating summary...")
|
|
33
|
+
2. `SUMMARY_TEMPLATE` is sent to the model via OpenCode HTTP API (`prompt_async`)
|
|
34
|
+
3. Electron polls `/session/:id/message` for the model's response
|
|
35
|
+
4. Model generates a structured summary with: Task, Findings, Attempted Approaches, Recommendations, Code Changes, Files Modified, Assumptions, Open Questions
|
|
36
|
+
5. Summary is written to stdout with a `[SIDECAR_FOLD:<nonce>]` metadata header
|
|
37
|
+
6. Electron window closes, `start.js` captures stdout and finalizes session
|
|
38
|
+
|
|
39
|
+
In headless mode, the agent outputs `[SIDECAR_FOLD:<nonce>]` autonomously when done, and `headless.js` extracts everything before the marker.
|
|
40
|
+
|
|
41
|
+
**Wire-format token:** The wire-format token emitted by the model in headless mode is `[SIDECAR_FOLD:<nonce>]` — a per-run random nonce, generated once per run before prompt construction (`src/utils/fold-marker.js`), embedded in headless mode instructions by `src/prompt-builder.js`, and required by `src/headless.js`'s detector (`findTrailingFoldMarker`, final-non-empty-line match on the exact nonced marker). This closes a hardening gap (#BL-7): a static, public marker meant model output that merely echoed it (prior instructions, a scraped doc, another run's transcript) could force a premature completion; requiring the run's own nonce means only a model that actually finished can produce it. The bare `[SIDECAR_FOLD]` literal (no `:<nonce>`) is kept only as a legacy/back-compat constant (`FOLD_MARKER` in `src/headless.js`) for callers with no nonce context — it is never accepted by the detector. Tracked in `docs/SHIMS.md`.
|
|
42
|
+
|
|
43
|
+
## Shared Server Architecture
|
|
44
|
+
|
|
45
|
+
Multiple Amicus invocations share a single OpenCode Go binary when `AMICUS_SHARED_SERVER=1` (the default). This eliminates per-invocation cold-start latency and reduces memory overhead.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Before (per-process): After (shared server):
|
|
49
|
+
MCP Server MCP Server
|
|
50
|
+
+-- amicus CLI (port 4096) +-- Shared OpenCode Server (port 4096)
|
|
51
|
+
| +-- OpenCode Go binary +-- Session A
|
|
52
|
+
+-- amicus CLI (port 4097) +-- Session B
|
|
53
|
+
| +-- OpenCode Go binary +-- Session C
|
|
54
|
+
+-- amicus CLI (port 4098)
|
|
55
|
+
+-- OpenCode Go binary
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The shared server restarts automatically on crash, up to 3 times within any 5-minute window. After 3 restarts the server is considered unstable and will not restart again; use `AMICUS_SHARED_SERVER=0` to fall back to per-process mode.
|
|
59
|
+
|
|
60
|
+
## Fanout Wave Architecture
|
|
61
|
+
|
|
62
|
+
`amicus fanout` runs N models on the same prompt concurrently using **one shared OpenCode server** (external-server mode). Key design properties, each traceable to source:
|
|
63
|
+
|
|
64
|
+
- **One server, N legs.** A single OpenCode server is started once (`src/sidecar/fanout.js` line 170–175) and passed via `options.client` / `options.server` to every `runHeadless` call.
|
|
65
|
+
- **Context built once.** `buildContext()` and `buildPrompts()` are called once before the leg loop (fanout.js lines 153–162); the resulting `systemPrompt` and `userMessage` are reused by all legs without per-leg re-serialisation.
|
|
66
|
+
- **Legs are ordinary sessions.** Each leg is an independent `runHeadless` session. Leg IDs follow the pattern `<waveId>-1`, `<waveId>-N` derived by `deriveLegIds()` (fanout.js line 37–39). Leg metadata carries `parentWave: waveId` (fanout-leg.js line 52).
|
|
67
|
+
- **Atomic wave document.** After all legs settle, `wave.json` is written atomically via a `.tmp` + rename sequence in the wave session directory (fanout.js lines 222–224). If the file is absent (e.g. hard kill), `buildWaveResultFromSession()` rebuilds it live from per-leg metadata.json files (`src/utils/result-schema.js` lines 179–217).
|
|
68
|
+
- **Per-leg watchdog backstop.** Each leg runs its own `IdleWatchdog` set to `timeoutMs + 60s` (fanout-leg.js lines 59–70). On timeout it marks only that leg aborted; it never calls `server.close()` or `process.exit()` — shared server safety.
|
|
69
|
+
- **Dead-server fast-exit.** Consecutive poll failures against a dead server exit immediately instead of burning the full timeout. The threshold is `AMICUS_MAX_CONSECUTIVE_POLL_FAILURES` (default 15, ≈ 30 s at 2 s polls), defined at `src/headless.js` line 33.
|
|
70
|
+
- **Signal handling.** On SIGINT or SIGTERM, the wave marks itself and all leg directories aborted, closes the server, then arms an exit watchdog. A second signal causes an immediate `process.exit(130/143)`. The control flow then proceeds through step 7 (aggregate + write `wave.json` + emit), so even an aborted wave produces a parseable JSON document (fanout.js lines 183–195, 227–229).
|
|
71
|
+
- **Wave status aggregation** (`src/utils/result-schema.js` lines 83–90):
|
|
72
|
+
- Any leg still running → `running`
|
|
73
|
+
- All legs complete → `complete`
|
|
74
|
+
- ≥ 1 complete, others failed → `partial`
|
|
75
|
+
- 0 complete, ≥ 1 aborted → `aborted`
|
|
76
|
+
- All failed (no complete, no aborted) → `error`
|
|
77
|
+
- **Exit codes** (result-schema.js lines 97–101): `complete` → 0, `partial` → 2, all other statuses → 1.
|
|
78
|
+
|
|
79
|
+
## IdleWatchdog State Machine
|
|
80
|
+
|
|
81
|
+
Each Amicus process runs an `IdleWatchdog` that transitions between two states:
|
|
82
|
+
|
|
83
|
+
- **BUSY**: A prompt is in flight or a session was recently active. Idle timer is paused.
|
|
84
|
+
- **IDLE**: No active requests for the configured idle period. Process (or shared server) self-terminates.
|
|
85
|
+
|
|
86
|
+
Transitions: `BUSY → IDLE` when the last active session goes quiet; `IDLE → BUSY` on any new incoming request. The idle clock resets on each BUSY→IDLE transition.
|
|
87
|
+
|
|
88
|
+
Timeout resolution priority (highest wins):
|
|
89
|
+
1. Per-mode env var: `AMICUS_IDLE_TIMEOUT_HEADLESS`, `AMICUS_IDLE_TIMEOUT_INTERACTIVE`, `AMICUS_IDLE_TIMEOUT_SERVER` (in minutes; the legacy `SIDECAR_IDLE_TIMEOUT_*` env-compat shim was removed in v2.0.0 — see `docs/SHIMS.md`)
|
|
90
|
+
2. Blanket env var `AMICUS_IDLE_TIMEOUT` in minutes
|
|
91
|
+
3. Constructor `timeout` option in milliseconds
|
|
92
|
+
4. Mode defaults: headless=15 m, interactive=60 m, server=30 m
|
|
93
|
+
|
|
94
|
+
Set the appropriate per-mode env var to `0` to disable self-termination for that mode entirely.
|
|
95
|
+
|
|
96
|
+
## Electron BrowserView Architecture
|
|
97
|
+
|
|
98
|
+
The Electron shell (`electron/main.js`) uses a **BrowserView** to avoid CSS conflicts between the OpenCode SPA and the Amicus toolbar:
|
|
99
|
+
|
|
100
|
+
- **BrowserView** (top): Loads the OpenCode web UI at `http://localhost:<port>`. Gets its own physical viewport, no CSS interference with the host window.
|
|
101
|
+
- **Main window** (bottom 40px): Renders the Amicus toolbar (branding, task ID, timer, Fold button) via a `data:` URL.
|
|
102
|
+
- On resize, `updateContentBounds()` adjusts the BrowserView to fill `height - 40px`.
|
|
103
|
+
|
|
104
|
+
This replaced earlier CSS-based approaches (`padding-bottom`, `calc(100dvh - 40px)`) which failed because OpenCode's Tailwind `h-dvh` class resolves to the actual browser viewport and ignores parent element overrides.
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# Configuration Reference
|
|
2
|
+
|
|
3
|
+
`amicus setup` is the recommended way to configure Amicus. It opens a graphical wizard that validates your API keys live, lets you pick a default model from the live catalog, and saves everything to `~/.config/amicus/.env` (permissions `0600`). The environment variables below are for overrides and advanced tuning — most users only need the API keys section.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## API Keys
|
|
8
|
+
|
|
9
|
+
Amicus reads API keys from `~/.config/amicus/.env` and from `process.env`. Environment variables already set in your shell win; the `.env` file fills in anything unset; `auth.json` is the last fallback. Keys written by `amicus setup` are never silently overridden by something with higher priority.
|
|
10
|
+
|
|
11
|
+
| Variable | Purpose |
|
|
12
|
+
|----------|---------|
|
|
13
|
+
| `OPENROUTER_API_KEY` | OpenRouter — routes to any provider from a single key. |
|
|
14
|
+
| `GOOGLE_GENERATIVE_AI_API_KEY` | Direct Google Gemini access (bypasses OpenRouter). |
|
|
15
|
+
| `OPENAI_API_KEY` | Direct OpenAI access. |
|
|
16
|
+
| `ANTHROPIC_API_KEY` | Direct Anthropic access. |
|
|
17
|
+
| `DEEPSEEK_API_KEY` | Direct DeepSeek access. |
|
|
18
|
+
|
|
19
|
+
**Running models locally?** None of the above are required — `amicus provider` configures Ollama, LM Studio, vLLM, or any other OpenAI-compatible endpoint as an additional provider at $0 marginal cost, no entry in this table needed. See [docs/usage.md § `amicus provider`](./usage.md#amicus-provider) and the `providers` key under [Config file format](#config-file-format) below. Local models also need to be loaded with enough context to fit Amicus's ~26k-token agent prompt (~32k is a safe target) — see **Running local models** in the same `amicus provider` section for the exact commands.
|
|
20
|
+
|
|
21
|
+
**Bare `provider/model` is the canonical, policy-routed form.** Amicus routes it **direct-first**:
|
|
22
|
+
your direct provider key when one is configured, falling back to `OPENROUTER_API_KEY`
|
|
23
|
+
automatically when it isn't. `openrouter/provider/model` is an **explicit override** that always
|
|
24
|
+
forces OpenRouter, even when a direct key exists — reach for it deliberately, or for gateway-only
|
|
25
|
+
vendors with no direct integration (Qwen, Grok, Mistral, GLM, …), which require this form. See
|
|
26
|
+
[Routing](#routing) below for the full picture (`routing.prefer`, `--gateway`, the migration
|
|
27
|
+
notice).
|
|
28
|
+
|
|
29
|
+
| Model prefix | Credential consumed |
|
|
30
|
+
|-------------|-------------------|
|
|
31
|
+
| `provider/model` (bare, canonical) | Direct key for that vendor if configured, else `OPENROUTER_API_KEY` |
|
|
32
|
+
| `openrouter/provider/model` | `OPENROUTER_API_KEY`, always |
|
|
33
|
+
|
|
34
|
+
Per vendor, the bare form's direct key is: `google/...` → `GOOGLE_GENERATIVE_AI_API_KEY`,
|
|
35
|
+
`openai/...` → `OPENAI_API_KEY`, `anthropic/...` → `ANTHROPIC_API_KEY`, `deepseek/...` →
|
|
36
|
+
`DEEPSEEK_API_KEY`.
|
|
37
|
+
|
|
38
|
+
**Inherited provider base URLs.** Amicus does not define or read `*_BASE_URL` variables for the
|
|
39
|
+
hosted vendors above, but it does pass the whole environment through to the OpenCode engine, which
|
|
40
|
+
hands them to the underlying provider SDK. `ANTHROPIC_BASE_URL` is the one that bites: the SDK
|
|
41
|
+
appends only `/messages` to it, so it must include the `/v1` path segment. A value of
|
|
42
|
+
`https://api.anthropic.com` (**no** `/v1`) makes every direct `anthropic/…` model fail with a bare
|
|
43
|
+
`Not Found` at zero tokens, while the same models still work through OpenRouter. Some hosts set
|
|
44
|
+
this for you — a shell spawned by Claude Code inherits the `/v1`-less form. Either export
|
|
45
|
+
`https://api.anthropic.com/v1` or unset the variable. See
|
|
46
|
+
[troubleshooting § Every Direct Anthropic Model Fails with `"Not Found"`](./troubleshooting.md#every-direct-anthropic-model-fails-with-not-found).
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Routing
|
|
51
|
+
|
|
52
|
+
`routing.prefer` in `config.json` sets the global default gateway policy; `--gateway` (CLI) or the
|
|
53
|
+
MCP `gateway` param overrides it per call.
|
|
54
|
+
|
|
55
|
+
| Setting | Values | Default | Effect |
|
|
56
|
+
|---------|--------|---------|--------|
|
|
57
|
+
| `routing.prefer` (config.json) | `"direct"` \| `"openrouter"` | `"direct"` | Global default: prefer the direct provider key when one exists, or always prefer OpenRouter. |
|
|
58
|
+
| `--gateway <mode>` (CLI, all commands that resolve a model) | `auto` \| `direct` \| `openrouter` | `auto` | Per-call override. `auto` means direct-first (honors `routing.prefer`); `direct`/`openrouter` force a specific gateway for this call and error if the required key is missing. |
|
|
59
|
+
| `gateway` (MCP: `amicus_start`, `amicus_continue`, `amicus_fanout`) | `"auto"` \| `"direct"` \| `"openrouter"` | `"auto"` | Same semantics as `--gateway`, for MCP callers. |
|
|
60
|
+
|
|
61
|
+
There is no `amicus setup` wizard step for `routing.prefer` yet — set it by hand-editing
|
|
62
|
+
`~/.config/amicus/config.json`'s top-level `routing.prefer` field (see the config.json example
|
|
63
|
+
below).
|
|
64
|
+
|
|
65
|
+
**One-time migration notice.** If you hold both an OpenRouter key and a direct key for a vendor,
|
|
66
|
+
the first launch that resolves a bare canonical id to that vendor via direct-first auto-routing
|
|
67
|
+
prints a one-time notice, e.g.:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Routing openai via direct API (previously OpenRouter).
|
|
71
|
+
Set routing.prefer: "openrouter" (or use --gateway openrouter) to restore.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The notice fires once per vendor (tracked in `config.json`'s `routing.migration_notified` map) —
|
|
75
|
+
not on every launch, and not when you explicitly chose the gateway with `--gateway`. Set
|
|
76
|
+
`routing.prefer: "openrouter"` (or pass `--gateway openrouter` per call) to keep routing everything
|
|
77
|
+
through OpenRouter as before.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Behavior
|
|
82
|
+
|
|
83
|
+
| Variable | Purpose | Default |
|
|
84
|
+
|----------|---------|---------|
|
|
85
|
+
| `LOG_LEVEL` | Log verbosity: `error` \| `warn` \| `info` \| `debug`. Keep `error` (the default) for clean LLM consumption; use `debug` to diagnose poll issues. | `error` |
|
|
86
|
+
| `AMICUS_CONFIG_DIR` | Override the entire config directory — keys, model catalog, session index. Useful for isolated test environments. | `~/.config/amicus` |
|
|
87
|
+
| `AMICUS_ENV_DIR` | Override just the `.env` file directory (keys only). The legacy `SIDECAR_ENV_DIR` name was removed in v2.0.0 — only `AMICUS_ENV_DIR` is read now. | `~/.config/amicus` (the config dir) |
|
|
88
|
+
| `AMICUS_FANOUT_MAX_LEGS` | Cap the number of concurrent legs in a single fanout wave. Protects against accidental runaway costs when `--models` is a long list. Non-positive or non-integer values fall back to the default. | `10` |
|
|
89
|
+
| `AMICUS_MCP_CLIENT` | Force the MCP server's `--client` value (`code-local`, `code-web`, or `cowork`) instead of auto-detecting it from the caller's MCP `initialize` handshake (`clientInfo.name`). Invalid values are ignored (with a warning) and detection proceeds normally. Note: `code-web` requires an explicit `--session-dir` and is not usable for MCP-spawned sessions. | auto-detected |
|
|
90
|
+
| `AMICUS_MAX_SESSIONS` | Maximum number of concurrent sessions the shared OpenCode server (`src/utils/shared-server.js`) will track before rejecting new ones. Renamed from `SIDECAR_MAX_SESSIONS` in v2.0.0. | `20` |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Headless Poller Tuning
|
|
95
|
+
|
|
96
|
+
These variables control the polling loop that drives headless sessions. The defaults are conservative and work for almost all workloads. You only need them if you are running against unusually slow or fast model endpoints, or if you are building tooling on top of Amicus and need tighter completion detection.
|
|
97
|
+
|
|
98
|
+
**Which of these accept `0`, and which ignore it.** The four `SETTLE` knobs in this table (`AMICUS_USAGE_SETTLE_POLLS`, `AMICUS_USAGE_SETTLE_INTERVAL_MS`, `AMICUS_USAGE_SETTLE_CALL_TIMEOUT_MS`, `AMICUS_TOOL_SETTLE_GRACE_MS`) read through `envNumber()` (`src/utils/env-num.js`), which honours an explicit, finite `0` — for those, `0` is a documented escape hatch and each row below says what it switches off. **Every other variable in this table reads through `Number(env) || default`, so `0` is falsy and silently falls back to the default** — there is no way to set them to zero, and that is deliberate: a `0` poll interval would busy-loop and a `0` stall threshold would kill every leg on its first poll. In both families a blank, missing or non-finite value falls back to the default.
|
|
99
|
+
|
|
100
|
+
| Variable | Purpose | Default |
|
|
101
|
+
|----------|---------|---------|
|
|
102
|
+
| `AMICUS_POLL_INTERVAL_MS` | Delay between poll cycles in milliseconds. Lower values detect completion faster but add more API calls; raise it if you see rate-limit warnings from the OpenCode server. | `2000` |
|
|
103
|
+
| `AMICUS_POLL_CALL_TIMEOUT_MS` | Per-poll `getMessages` call timeout in milliseconds. If a poll call hangs longer than this, it is abandoned and counted as a consecutive failure. | `30000` |
|
|
104
|
+
| `AMICUS_STABLE_FINISHED_POLLS` | Number of consecutive idle polls required after the SDK reports the session as `completed` before the headless runner exits. A small number (2) guards against a race where the assistant message is flagged complete but trailing content is still streaming. | `2` |
|
|
105
|
+
| `AMICUS_STABLE_IDLE_POLLS` | Number of consecutive idle polls required when no explicit completion signal is received (approximately 60 s at the 2 s default). This is the fallback heuristic for models or SDK versions that don't emit a clean completion event. | `30` |
|
|
106
|
+
| `AMICUS_MAX_CONSECUTIVE_POLL_FAILURES` | Consecutive poll failures before the headless runner bails. At the 2 s interval this is approximately 30 s. Prevents a dead server from burning the full session timeout on futile polls. | `15` |
|
|
107
|
+
| `AMICUS_TOOL_CALL_STALL_MS` | How long a tool call may sit pending with **no** result and no output growth before the leg is failed with `Tool call stalled: <tool>` and its OpenCode session aborted. This is the wedge guard: it targets a leg producing nothing at all, and it is skipped while a tool-settle deferral is active (`AMICUS_TOOL_SETTLE_GRACE_MS` owns that decision instead, and ends in a completion rather than a failure). **`0` is ignored** — it falls back to the default rather than disabling the guard, because a `0` threshold would kill every leg on its first poll. There is no way to switch this off; raise it if you legitimately run very long single tool calls. | `180000` |
|
|
108
|
+
| `AMICUS_USAGE_SETTLE_POLLS` | How many extra `getMessages` reads run **after** a leg has already finished, to catch provider usage/cost that lands milliseconds after the completion signal (measured: real paid legs losing their cost by 29 ms and 155 ms). The loop breaks early as soon as every assistant message carries usage, so the common case is one extra read. **Set to `0` to disable the reconciliation entirely** — legs then report whatever usage was present at completion, which can be `$0` on a leg that really did cost money. | `3` |
|
|
109
|
+
| `AMICUS_USAGE_SETTLE_INTERVAL_MS` | Delay between those settle reads. **`0` is honoured and means no delay** — the reads run back to back. It does **not** disable the reconciliation (that is `AMICUS_USAGE_SETTLE_POLLS=0`); it only removes the gap between attempts. | `400` |
|
|
110
|
+
| `AMICUS_USAGE_SETTLE_CALL_TIMEOUT_MS` | Per-call deadline for a settle read and for the child-session (subagent) spend walk. Deliberately much tighter than `AMICUS_POLL_CALL_TIMEOUT_MS`: the leg is already finished, so a hung read must not add 30 s × 3 to a run's wall time. The effective value is the **smaller** of this and `AMICUS_POLL_CALL_TIMEOUT_MS`, so raising it above that has no effect. **`0` is honoured and means no timer is armed at all** — a hung settle read or subtree walk would then wait indefinitely. | `5000` |
|
|
111
|
+
| `AMICUS_TOOL_SETTLE_GRACE_MS` | How long a completion signal may be deferred while a tool call has not reached a terminal status, so a leg is not declared complete while its session is still working and billing. On exceeding the grace the leg **completes anyway** — its partial output is kept and it is never failed — carrying `toolSettleTimedOut` on its result, its `metadata.json` and its terminal `progress.json`; its OpenCode session is then **aborted** so it stops billing for output nobody will read, and whether that abort landed is recorded as `toolSettleAborted`. Set to `0` to disable the deferral entirely (and with it the abort) — pre-v4.4 behaviour. | `300000` |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## GUI and Debug
|
|
116
|
+
|
|
117
|
+
| Variable | Purpose | Default |
|
|
118
|
+
|----------|---------|---------|
|
|
119
|
+
| `AMICUS_GUI_LOAD_TIMEOUT_MS` | Maximum wait in milliseconds for the Electron UI to load before the load-failsafe fires. If the OpenCode web UI fails to respond within this window, Amicus shows a load-error page instead of hanging invisibly. | `15000` |
|
|
120
|
+
| `AMICUS_DEBUG_PORT` | Chrome DevTools Protocol port for the Electron window. Increment (e.g. `9223`) to avoid conflicts with a running Chrome or another Amicus window. | `9222` |
|
|
121
|
+
| `AMICUS_MOCK_UPDATE` | Mock the update-notification state for UI development. Values: `available` \| `updating` \| `success` \| `error`. Has no effect outside development. | *(unset)* |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Process Lifecycle
|
|
126
|
+
|
|
127
|
+
Amicus processes self-terminate after a configurable idle period. The idle watchdog is active in all modes — headless, interactive, and shared-server.
|
|
128
|
+
|
|
129
|
+
| Variable | Purpose | Default |
|
|
130
|
+
|----------|---------|---------|
|
|
131
|
+
| `AMICUS_IDLE_TIMEOUT` | Blanket override for all modes (minutes; `0` = disabled). | *(mode default)* |
|
|
132
|
+
| `AMICUS_IDLE_TIMEOUT_HEADLESS` | Per-mode override for headless sessions (minutes). | `15` |
|
|
133
|
+
| `AMICUS_IDLE_TIMEOUT_INTERACTIVE` | Per-mode override for interactive sessions (minutes). | `60` |
|
|
134
|
+
| `AMICUS_IDLE_TIMEOUT_SERVER` | Per-mode override for shared-server sessions (minutes). | `30` |
|
|
135
|
+
|
|
136
|
+
Legacy `SIDECAR_IDLE_TIMEOUT*` names were removed in v2.0.0 — rename to the `AMICUS_IDLE_TIMEOUT*` forms above. See [docs/SHIMS.md](./SHIMS.md).
|
|
137
|
+
|
|
138
|
+
Set `AMICUS_IDLE_TIMEOUT=0` to disable self-termination entirely.
|
|
139
|
+
|
|
140
|
+
### Shared server
|
|
141
|
+
|
|
142
|
+
The shared-server mode (`AMICUS_SHARED_SERVER=1`, which is the default) lets multiple Amicus sessions reuse a single OpenCode Go binary process rather than spawning one per invocation, eliminating cold-start latency on the second and subsequent calls. Disable it with `AMICUS_SHARED_SERVER=0` if you need per-process isolation or are diagnosing a crash loop.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Model Names Reference
|
|
147
|
+
|
|
148
|
+
Amicus does **not** ship a frozen model list. Aliases and validation resolve against a live catalog fetched from provider APIs and cached at `~/.config/amicus/model-catalog.json`.
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
amicus models # list the full catalog
|
|
152
|
+
amicus models --search gemini # filter by substring (id + display name)
|
|
153
|
+
amicus models --refresh # force-fetch from provider APIs (bypasses the 24h TTL)
|
|
154
|
+
amicus models --check # audit your configured aliases against the catalog
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**Catalog mechanics:**
|
|
158
|
+
|
|
159
|
+
- **24-hour TTL.** The catalog is fetched at most once per 24 hours. `amicus models --refresh` bypasses the TTL immediately.
|
|
160
|
+
- **Keyless fetch.** The initial catalog fetch works without an API key — provider model lists are public. Keys are only needed when you actually launch a session.
|
|
161
|
+
- **Floor-only refresh guard.** A background or offline `--refresh` can never clobber a good cache with an empty or truncated response. If the fresh fetch returns fewer models than the cached catalog, Amicus keeps the existing cache and logs a warning. This protects against transient network errors.
|
|
162
|
+
- **Catalog location.** `~/.config/amicus/model-catalog.json` — human-readable JSON; safe to inspect or delete (it rebuilds on next use).
|
|
163
|
+
|
|
164
|
+
**Spend ledger.** Every completed run/leg appends one row to `~/.config/amicus/spend-ledger.jsonl` (tokens + resolved cost). `amicus spend` reads it for a cross-run rollup; safe to delete (starts fresh, loses history only).
|
|
165
|
+
|
|
166
|
+
**Validation on launch.** `amicus start` and `amicus fanout` validate the model against the catalog before launching. For an explicit `--model` this is **blocking** (a typo'd model name fails fast with same-vendor suggestions); for a model inherited from a previous session via `continue`/`resume` it is **advisory** (a warning is printed but the session still starts). Skip catalog validation with `--no-validate-model`, or refresh the catalog with `amicus models --refresh`.
|
|
167
|
+
|
|
168
|
+
**`amicus models --check` in CI.** The command exits with the **number of stale aliases** (capped at 100) and prints replacement suggestions for each, so it integrates cleanly into a CI gate:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
amicus models --check && echo "aliases ok"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Model Aliases
|
|
177
|
+
|
|
178
|
+
Aliases are short names that resolve to full provider-prefixed model IDs. `amicus setup` seeds a curated default set (e.g. `gemini`, `gpt`, `opus`, `deepseek`) to the bare canonical form for direct-capable vendors. You add or override aliases with:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
amicus setup --add-alias fast=google/gemini-3.1-flash-lite-preview
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Aliases are stored in `~/.config/amicus/config.json`. The source of truth for what resolves on your machine is `amicus models`, not this document.
|
|
185
|
+
|
|
186
|
+
**Full-id passthrough.** You can always bypass aliases and specify a model by its full ID — bare `provider/model` (canonical, direct-first) or `openrouter/provider/model` (explicit force-OpenRouter override):
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
amicus start --model google/gemini-3-pro-preview --prompt "..." # bare canonical, direct-first
|
|
190
|
+
amicus start --model anthropic/claude-opus-4 --prompt "..." # bare canonical, direct-first
|
|
191
|
+
amicus start --model openrouter/google/gemini-3.1-flash-lite-preview --prompt "..." # explicit override
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Where things live
|
|
197
|
+
|
|
198
|
+
New to Amicus's disk footprint? This section maps everything it reads and writes, verified against
|
|
199
|
+
the source that actually writes it — not aspirational. If a claim here and the code ever disagree,
|
|
200
|
+
the code wins; file an issue.
|
|
201
|
+
|
|
202
|
+
### The config tree
|
|
203
|
+
|
|
204
|
+
Everything lives under `~/.config/amicus/` (`getConfigDir()` in `src/utils/config.js`):
|
|
205
|
+
|
|
206
|
+
- **Override:** set `AMICUS_CONFIG_DIR` to relocate the entire tree — keys, catalog, session index,
|
|
207
|
+
both ledgers. Useful for isolated test environments.
|
|
208
|
+
- **Legacy fallback — removed in v2.0.0:** `getConfigDir()` no longer falls back to
|
|
209
|
+
`~/.config/sidecar/` at all. Through v1.x, config data was auto-migrated forward on every run
|
|
210
|
+
(a one-time, non-destructive copy into `~/.config/amicus/` the first time it didn't exist yet),
|
|
211
|
+
so most installs already have everything in the new location. If you jumped straight from a
|
|
212
|
+
pre-rebrand install to v2.0.0 without ever running a v1.x build, copy `~/.config/sidecar/` to
|
|
213
|
+
`~/.config/amicus/` by hand. See [docs/SHIMS.md](./SHIMS.md).
|
|
214
|
+
|
|
215
|
+
| File | Written by | Contains |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `config.json` | `amicus setup` / `saveConfig()` (`src/utils/config.js`) | Top-level keys: `default` (your default model alias), `aliases` (your alias → `provider/model` map), `councils` (saved council presets, e.g. `councils.free`), `providers` (user-defined local / OpenAI-compatible providers added via `amicus provider add`, or by hand — id → `{type, baseURL, flavor, name?, apiKeyEnv?, pricing}`; see [`amicus provider`](./usage.md#amicus-provider)), `routing` (`prefer`: `"direct"` \| `"openrouter"`; `migration_notified`: per-vendor flags for the one-time direct-migration notice — see [Routing](#routing)). `0600` permissions. |
|
|
218
|
+
| `.env` | `amicus setup` / `amicus key` | API keys (`OPENROUTER_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `DEEPSEEK_API_KEY`). `0600` permissions. |
|
|
219
|
+
| `model-catalog.json` | `refreshCatalog()` (`src/utils/model-catalog.js`) | The cached provider model list, schema-versioned, with a **24-hour TTL**. Also carries refresh-outcome fields — `lastRefreshAttempt` and `lastRefreshError` — stamped on a *failed* refresh without touching the last-good `models`/`fetchedAt` (a bad fetch never clobbers a good cache). Human-readable JSON; safe to delete, it rebuilds on next use. |
|
|
220
|
+
| `sessions-index.json` | `session-index.js` (`recordSession`, written at session start) | A **global** map of `taskId → project path`, consulted only when a per-project session lookup misses (e.g. an MCP server whose cwd differs from where the session was created). Navigation aid only, never authoritative — a corrupt index degrades to "no entry," never a crash. |
|
|
221
|
+
| `council-ledger.jsonl` | `src/council/ledger.js` (`appendRun`), on every `council tally` | One row per council model per run — findings raised, severity breakdown, street-cred, conformance. Read back by `amicus council stats`. |
|
|
222
|
+
| `spend-ledger.jsonl` | `src/utils/spend-ledger.js` (`appendSpend`), new in Phase 16 | One row per completed run/leg — tokens + resolved cost. Read back by `amicus spend` for the cross-run rollup. Append is best-effort and can never fail the run it's recording; safe to delete (starts fresh, loses history only). |
|
|
223
|
+
|
|
224
|
+
**Tmp-file pattern.** Several writers (`model-catalog.json`, `sessions-index.json`, session
|
|
225
|
+
metadata) use an atomic write: a temp file named `.<target>.<pid>.<random>.tmp` is written
|
|
226
|
+
alongside the target, then renamed into place. A process killed between the write and the rename
|
|
227
|
+
leaves an orphaned `.tmp` file behind forever — harmless, but it accumulates. `amicus doctor --fix`
|
|
228
|
+
sweeps orphaned `sessions-index.json.*.tmp` files (only ones older than 60 seconds, so a live
|
|
229
|
+
writer's in-flight tmp file is never touched); `amicus doctor` (without `--fix`) just reports the
|
|
230
|
+
count.
|
|
231
|
+
|
|
232
|
+
### Session storage
|
|
233
|
+
|
|
234
|
+
Session data is split across two different roots — don't confuse them:
|
|
235
|
+
|
|
236
|
+
**1. The session root** (`getSessionRoot()` in `src/environment.js`) — resolved per client, mostly
|
|
237
|
+
relevant for how Claude Code/Cowork discovers *your current conversation's* context to share:
|
|
238
|
+
|
|
239
|
+
| Client | Root |
|
|
240
|
+
|---|---|
|
|
241
|
+
| `code-local` (default on macOS, or when a `DISPLAY`/`WAYLAND_DISPLAY` is present) | `~/.claude/projects/<encoded-cwd>` — the cwd is encoded by replacing `/`, `\`, the drive-letter colon, and `_` with `-` (matches Claude Code's own scheme). |
|
|
242
|
+
| `cowork` | Platform-specific: macOS `~/Library/Application Support/Claude/local-agent-mode-sessions`, Windows `%APPDATA%\Claude\local-agent-mode-sessions`, Linux `~/.config/Claude/local-agent-mode-sessions`. |
|
|
243
|
+
| `code-web` | No default — `--session-dir` is **required**; there's nothing to resolve. |
|
|
244
|
+
|
|
245
|
+
**2. Amicus's own per-session directories** — where the actual session data (metadata, conversation,
|
|
246
|
+
summaries) is written. These live **project-scoped**, under `.claude/amicus_sessions/<taskId>/` in
|
|
247
|
+
the project directory (`SESSIONS_DIR` in `src/session-manager.js`; not under the session root
|
|
248
|
+
above). The legacy `.claude/sidecar_sessions/` dual-read was removed in v2.0.0 — that directory is
|
|
249
|
+
no longer read at all. If you have session history there, rename `.claude/sidecar_sessions/` to
|
|
250
|
+
`.claude/amicus_sessions/` to make it visible to `amicus list`/`amicus read` again. See
|
|
251
|
+
[docs/SHIMS.md](./SHIMS.md).
|
|
252
|
+
|
|
253
|
+
Per-session directory contents:
|
|
254
|
+
|
|
255
|
+
| File | Written by | Notes |
|
|
256
|
+
|---|---|---|
|
|
257
|
+
| `metadata.json` | `createSession()` | Model, project, briefing, mode, thinking level, status. Atomic write. |
|
|
258
|
+
| `conversation.jsonl` | Appended as the session runs | One JSON line per message. |
|
|
259
|
+
| `progress.json` | Headless polling | Live progress snapshot (message count, latest activity, stage) — read by `amicus status` and the fanout wave heartbeat. |
|
|
260
|
+
| `summary.md` | `saveSummary()`, on fold/completion | The fold output — what `amicus read <id>` returns by default. |
|
|
261
|
+
| `subagents/<subagentId>/` | Sub-agent sessions | Same shape as a top-level session (its own `metadata.json` + `conversation.jsonl`). |
|
|
262
|
+
|
|
263
|
+
**Fanout waves.** A wave (`amicus fanout`) gets its own session dir at `<waveId>` (same
|
|
264
|
+
`amicus_sessions/` root); each leg is a full sibling session dir named `<waveId>-1` through
|
|
265
|
+
`<waveId>-N` (`deriveLegIds()` in `src/sidecar/fanout.js`). The wave-heartbeat display reads each
|
|
266
|
+
leg's `progress.json`/`conversation.jsonl` directly — nothing wave-specific is stored beyond the
|
|
267
|
+
per-leg session dirs themselves plus the wave's own `metadata.json` (type `wave`, `legs: [...]`).
|
|
268
|
+
|
|
269
|
+
### Log location + LOG_LEVEL
|
|
270
|
+
|
|
271
|
+
**Logs go to stderr only — there is no log file, anywhere, ever.** `src/utils/logger.js` writes every
|
|
272
|
+
entry as one JSON line via `console.error(...)`; stdout is reserved for command output (summaries,
|
|
273
|
+
`--json` documents). Setting `LOG_LEVEL=debug` does **not** create a file or a new destination — it
|
|
274
|
+
only lowers the filter threshold so `debug`-level entries (which are dropped by default) start
|
|
275
|
+
printing to the same stderr stream. If you want debug output captured, redirect it yourself:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
LOG_LEVEL=debug amicus start --model gemini --prompt "test" --no-ui 2> debug.log
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Levels, in order of decreasing verbosity: `debug` > `info` > `warn` > `error` (the default). Each
|
|
282
|
+
level includes everything above it.
|
|
283
|
+
|
|
284
|
+
### Config file format
|
|
285
|
+
|
|
286
|
+
`config.json`, commented (comments added for illustration — real JSON has none):
|
|
287
|
+
|
|
288
|
+
```jsonc
|
|
289
|
+
{
|
|
290
|
+
// Default alias, resolved via `aliases` below when --model is omitted.
|
|
291
|
+
"default": "gemini",
|
|
292
|
+
|
|
293
|
+
// Short name -> full model id. Bare `provider/model` (canonical) routes direct-first;
|
|
294
|
+
// `amicus setup` seeds direct-capable vendors this way automatically.
|
|
295
|
+
// `amicus setup --add-alias name=provider/model` adds more.
|
|
296
|
+
"aliases": {
|
|
297
|
+
"gemini": "google/gemini-3-pro-preview",
|
|
298
|
+
"gpt": "openai/gpt-5",
|
|
299
|
+
"opus": "anthropic/claude-opus-4",
|
|
300
|
+
"deepseek": "deepseek/deepseek-v3"
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
// Named council member lists, e.g. seeded by the Free OpenRouter council
|
|
304
|
+
// wizard step. Run with `amicus fanout --council <name>`.
|
|
305
|
+
"councils": {
|
|
306
|
+
"free": ["free-gemini", "free-deepseek", "free-llama"]
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
// Gateway routing policy (see Routing above). `prefer` defaults to "direct"
|
|
310
|
+
// when this key is absent entirely. `migration_notified` is written
|
|
311
|
+
// automatically the first time the one-time direct-migration notice fires
|
|
312
|
+
// for a vendor — don't hand-edit it.
|
|
313
|
+
"routing": {
|
|
314
|
+
"prefer": "direct",
|
|
315
|
+
"migration_notified": { "openai": true }
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
// User-defined local / OpenAI-compatible providers (v4.2) — written by
|
|
319
|
+
// `amicus provider add`, or hand-edited. id -> normalized entry; `pricing`
|
|
320
|
+
// defaults to {prompt: 0, completion: 0} (the $0 tier) when omitted.
|
|
321
|
+
"providers": {
|
|
322
|
+
"lmstudio": { "type": "openai-compatible", "baseURL": "http://127.0.0.1:1234/v1", "flavor": "lmstudio" },
|
|
323
|
+
"ollama": { "type": "openai-compatible", "baseURL": "http://127.0.0.1:11434/v1", "flavor": "ollama" },
|
|
324
|
+
"vllm-lab": {
|
|
325
|
+
"type": "openai-compatible",
|
|
326
|
+
"baseURL": "http://127.0.0.1:8000/v1",
|
|
327
|
+
"flavor": "vllm",
|
|
328
|
+
"apiKeyEnv": "VLLM_LAB_API_KEY",
|
|
329
|
+
"pricing": { "prompt": 0.0000005, "completion": 0.0000015 }
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
A provider id may not shadow one of the five built-in vendors — `openrouter`, `google`, `openai`, `anthropic`, `deepseek` are rejected. `apiKeyEnv` names an env var — the token itself is never written to `config.json`, only to `.env` (`0600`), by `amicus provider add --bearer` or `amicus key <id> <token>`.
|
|
336
|
+
|
|
337
|
+
An alias whose value is missing, `null`, or not a string is stripped on the next `saveConfig()`
|
|
338
|
+
call, with a notice printed to stderr — `config.json` never accumulates dead aliases silently.
|
|
339
|
+
|
|
340
|
+
### Uninstall instructions
|
|
341
|
+
|
|
342
|
+
`npm uninstall -g amicus` removes the package and its bin shims. It does **not** clean up everything
|
|
343
|
+
`amicus` and its postinstall left behind — remove these by hand if you want a full uninstall:
|
|
344
|
+
|
|
345
|
+
| What | Where | Left behind because |
|
|
346
|
+
|---|---|---|
|
|
347
|
+
| MCP registration in Claude Code | `~/.claude.json` → `mcpServers.amicus` | Written by `scripts/postinstall.js`'s `registerClaudeCode()`; npm has no hook into another app's config file. Remove the `amicus` key under `mcpServers`, or run `claude mcp remove amicus`. |
|
|
348
|
+
| MCP registration in Claude Desktop / Cowork | `claude_desktop_config.json` → `mcpServers.amicus` (macOS: `~/Library/Application Support/Claude/`; Windows: `%APPDATA%\Claude\`; Linux: `~/.config/claude/`) | Written by `registerClaudeDesktop()`, same reasoning. Remove the `amicus` key under `mcpServers` by hand. |
|
|
349
|
+
| The chat skill | `~/.claude/skills/sidecar/` | Copied by `installSkill()`. Delete the directory. |
|
|
350
|
+
| The council skill | `~/.claude/skills/second-opinion/` | Copied by `installCouncilSkill()`. Delete the directory — note `MODEL-NOTES.md` inside it is **your** reviewer-reliability data (seeded once, never overwritten by updates), so back it up first if you want to keep it. |
|
|
351
|
+
| The entire config tree | `~/.config/amicus/` (keys, config, catalog cache, both ledgers, session index) | Never touched by npm at all — it's outside the package's install footprint by design (so an uninstall doesn't silently delete your API keys or history). Delete the directory yourself: `rm -rf ~/.config/amicus` (macOS/Linux) or `Remove-Item -Recurse -Force $HOME\.config\amicus` (PowerShell). |
|
|
352
|
+
| Per-project session data | `<project>/.claude/amicus_sessions/` in every project you ran Amicus from | Also outside npm's footprint — it lives inside *your* project directories, not the package. Delete per-project if you want it gone. |
|
|
353
|
+
|
|
354
|
+
If you plan to reinstall later, leaving `~/.config/amicus/` in place is the point — your keys,
|
|
355
|
+
aliases, and council presets carry over untouched.
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Dependencies
|
|
360
|
+
|
|
361
|
+
| Package | Purpose |
|
|
362
|
+
|---------|---------|
|
|
363
|
+
| `electron` ^43.1.1 | Interactive Amicus window |
|
|
364
|
+
| `tiktoken` ^1.0.0 | Declared for future exact tokenization; **currently unused** — token sizing uses a length/4 heuristic (see `src/context.js`, `src/context-compression.js`). |
|
|
365
|
+
| `jest` ^29.0.0 | Testing framework |
|
|
366
|
+
| `eslint` ^8.0.0 | Code linting |
|
|
367
|
+
| `lint-staged` ^16.3.2 | Run linters on staged files |
|
|
368
|
+
|
|
369
|
+
`opencode-ai` (>=1.0.0) is the bundled LLM conversation engine — it is installed automatically as a postinstall step and does not need a separate `npm install`.
|
|
370
|
+
|
|
371
|
+
> **Legacy names.** Pre-rebrand `SIDECAR_*` environment variables were removed entirely in v2.0.0 — they are no longer read, with no warning. Rename to the `AMICUS_*` equivalents documented above. See [docs/SHIMS.md](./SHIMS.md) for the full removal record and rename table.
|