amicus 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/LICENSE +21 -0
- package/README.md +477 -0
- package/bin/amicus.js +382 -0
- package/electron/assets/icon.png +0 -0
- package/electron/assets/icon.svg +5 -0
- package/electron/fold.js +163 -0
- package/electron/ipc-setup.js +176 -0
- package/electron/load-failsafe.js +85 -0
- package/electron/main.js +468 -0
- package/electron/preload-setup.js +38 -0
- package/electron/preload.js +33 -0
- package/electron/setup-ui-alias-script.js +218 -0
- package/electron/setup-ui-aliases.js +85 -0
- package/electron/setup-ui-keys-script.js +115 -0
- package/electron/setup-ui-keys.js +97 -0
- package/electron/setup-ui-model.js +138 -0
- package/electron/setup-ui-styles.js +327 -0
- package/electron/setup-ui.js +465 -0
- package/electron/summary.js +118 -0
- package/electron/toolbar.js +229 -0
- package/electron/window-position.js +35 -0
- package/package.json +98 -0
- package/scripts/postinstall.js +193 -0
- package/scripts/setup-hooks.js +42 -0
- package/skill/SKILL.md +976 -0
- package/skills/second-opinion/COUNCIL-DESIGN.md +227 -0
- package/skills/second-opinion/MODEL-NOTES.md +104 -0
- package/skills/second-opinion/SKILL.md +389 -0
- package/src/cli-handlers.js +188 -0
- package/src/cli.js +400 -0
- package/src/conflict.js +144 -0
- package/src/context-compression.js +102 -0
- package/src/context.js +199 -0
- package/src/drift.js +144 -0
- package/src/environment.js +157 -0
- package/src/headless.js +742 -0
- package/src/index.js +106 -0
- package/src/jsonl-parser.js +180 -0
- package/src/mcp-server.js +625 -0
- package/src/mcp-tools.js +407 -0
- package/src/opencode-client.js +615 -0
- package/src/prompt-builder.js +355 -0
- package/src/prompts/cowork-agent-prompt.js +118 -0
- package/src/session-manager.js +414 -0
- package/src/session.js +180 -0
- package/src/sidecar/context-builder.js +297 -0
- package/src/sidecar/continue.js +212 -0
- package/src/sidecar/crash-handler.js +56 -0
- package/src/sidecar/fanout-leg.js +107 -0
- package/src/sidecar/fanout-output.js +46 -0
- package/src/sidecar/fanout.js +236 -0
- package/src/sidecar/interactive.js +217 -0
- package/src/sidecar/models.js +135 -0
- package/src/sidecar/progress.js +218 -0
- package/src/sidecar/read.js +183 -0
- package/src/sidecar/resume.js +221 -0
- package/src/sidecar/session-utils.js +288 -0
- package/src/sidecar/setup-window.js +79 -0
- package/src/sidecar/setup.js +280 -0
- package/src/sidecar/start.js +251 -0
- package/src/utils/agent-mapping.js +138 -0
- package/src/utils/alias-audit.js +98 -0
- package/src/utils/alias-resolver.js +77 -0
- package/src/utils/api-key-store.js +259 -0
- package/src/utils/api-key-validation.js +97 -0
- package/src/utils/auth-json.js +109 -0
- package/src/utils/config.js +291 -0
- package/src/utils/curated-models.js +82 -0
- package/src/utils/env-compat.js +38 -0
- package/src/utils/env-loader.js +54 -0
- package/src/utils/idle-watchdog.js +225 -0
- package/src/utils/input-validators.js +127 -0
- package/src/utils/lifecycle.js +43 -0
- package/src/utils/logger.js +84 -0
- package/src/utils/mcp-discovery.js +194 -0
- package/src/utils/mcp-validators.js +78 -0
- package/src/utils/model-catalog.js +103 -0
- package/src/utils/model-fetcher.js +179 -0
- package/src/utils/model-validator.js +207 -0
- package/src/utils/path-setup.js +41 -0
- package/src/utils/port-pid.js +39 -0
- package/src/utils/prompt-source.js +53 -0
- package/src/utils/result-schema.js +261 -0
- package/src/utils/server-setup.js +93 -0
- package/src/utils/session-abort.js +53 -0
- package/src/utils/session-lock.js +95 -0
- package/src/utils/shared-server.js +216 -0
- package/src/utils/start-helpers.js +76 -0
- package/src/utils/thinking-validators.js +92 -0
- package/src/utils/update-notifier-loader.js +18 -0
- package/src/utils/updater.js +157 -0
- package/src/utils/validators.js +300 -0
package/src/mcp-tools.js
ADDED
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool Definitions for Amicus
|
|
3
|
+
*
|
|
4
|
+
* Defines all tools exposed by the Amicus MCP server.
|
|
5
|
+
* Uses Zod schemas for input validation (converted to JSON Schema by MCP SDK).
|
|
6
|
+
*
|
|
7
|
+
* @module mcp-tools
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { z } = require('zod');
|
|
11
|
+
const { formatAliasNames } = require('./utils/config');
|
|
12
|
+
|
|
13
|
+
/** Zod pattern for safe task IDs (alphanumeric, hyphens, underscores only) */
|
|
14
|
+
const safeTaskId = z.string().regex(
|
|
15
|
+
/^[a-zA-Z0-9_-]{1,64}$/,
|
|
16
|
+
'Task ID must be 1-64 alphanumeric, hyphen, or underscore characters'
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
/** Zod pattern for safe model identifiers (must not start with -) */
|
|
20
|
+
const safeModel = z.string().regex(
|
|
21
|
+
/^[a-zA-Z0-9_/.@:][a-zA-Z0-9_/.@:-]{0,199}$/,
|
|
22
|
+
'Model must be 1-200 chars, start with alphanumeric, and contain only provider/model characters'
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Build all MCP tools with dynamic descriptions that include live alias names.
|
|
27
|
+
* @returns {Array<{name: string, description: string, inputSchema: object}>}
|
|
28
|
+
*/
|
|
29
|
+
function getTools() {
|
|
30
|
+
const aliasNames = formatAliasNames();
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
name: 'amicus_start',
|
|
34
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
35
|
+
description:
|
|
36
|
+
'Spawn an Amicus session with a different LLM. Returns a task ID immediately. ' +
|
|
37
|
+
'Mode selection: use INTERACTIVE (default, noUi: false) for research, ' +
|
|
38
|
+
'exploration, analysis, and any task where the user benefits from watching ' +
|
|
39
|
+
'progress live. It eliminates the polling problem entirely. ' +
|
|
40
|
+
'Use HEADLESS (noUi: true) only for background automation the user does NOT ' +
|
|
41
|
+
'need to monitor. When in doubt, use interactive. ' +
|
|
42
|
+
'EXCEPTION: When spawning multiple sessions simultaneously, ' +
|
|
43
|
+
'ALWAYS use HEADLESS (noUi: true) for all of them unless the user ' +
|
|
44
|
+
'explicitly requests interactive. Opening multiple Electron windows ' +
|
|
45
|
+
'at once is disruptive. ' +
|
|
46
|
+
'For headless mode, ALWAYS run `sleep 25` in your shell before each ' +
|
|
47
|
+
'amicus_status call to enforce the polling interval. ' +
|
|
48
|
+
'For interactive mode, do not poll. Wait for the user to tell you ' +
|
|
49
|
+
'they\'ve clicked Fold, then use amicus_read. ' +
|
|
50
|
+
'Call amicus_guide first if you need help choosing a model or writing a good briefing.' +
|
|
51
|
+
' Pass includeContext: false when the briefing is fully self-contained.',
|
|
52
|
+
inputSchema: {
|
|
53
|
+
model: safeModel.optional().describe(
|
|
54
|
+
`Short alias (${aliasNames}) or full provider/model ID. ` +
|
|
55
|
+
'If omitted, uses the configured default. Call amicus_guide to see all aliases.'
|
|
56
|
+
),
|
|
57
|
+
prompt: z.string().describe(
|
|
58
|
+
'Detailed task briefing. Include: objective, background, ' +
|
|
59
|
+
'files of interest, success criteria.'
|
|
60
|
+
),
|
|
61
|
+
agent: z.enum(['Chat', 'Plan', 'Build']).optional()
|
|
62
|
+
.default('Chat').describe(
|
|
63
|
+
'Agent mode. Chat (default): reads auto, writes ask ' +
|
|
64
|
+
'permission. Plan: read-only analysis. Build: full auto ' +
|
|
65
|
+
'(all operations approved).'
|
|
66
|
+
),
|
|
67
|
+
noUi: z.boolean().optional().default(false).describe(
|
|
68
|
+
'Run headless without GUI. Default false (opens Electron window).'
|
|
69
|
+
),
|
|
70
|
+
thinking: z.enum([
|
|
71
|
+
'none', 'minimal', 'low', 'medium', 'high', 'xhigh'
|
|
72
|
+
]).optional().describe(
|
|
73
|
+
'Reasoning effort level. Default: medium.'
|
|
74
|
+
),
|
|
75
|
+
timeout: z.number().optional().describe(
|
|
76
|
+
'Headless timeout in minutes. Default: 15. Only applies when noUi is true.'
|
|
77
|
+
),
|
|
78
|
+
contextTurns: z.number().optional().describe(
|
|
79
|
+
'Max conversation turns to include from your Claude session. Default: 50.'
|
|
80
|
+
),
|
|
81
|
+
contextSince: z.string().optional().describe(
|
|
82
|
+
'Time filter for context — include only turns from the last N minutes/hours/days. ' +
|
|
83
|
+
'Format: 30m, 2h, 1d. Overrides contextTurns when set.'
|
|
84
|
+
),
|
|
85
|
+
contextMaxTokens: z.number().optional().describe(
|
|
86
|
+
'Cap on context size in tokens. Default: 80000.'
|
|
87
|
+
),
|
|
88
|
+
summaryLength: z.enum(['brief', 'normal', 'verbose']).optional().describe(
|
|
89
|
+
'Fold summary verbosity. brief: key findings only. normal (default): full ' +
|
|
90
|
+
'structured output. verbose: maximum detail.'
|
|
91
|
+
),
|
|
92
|
+
includeContext: z.boolean().optional().default(true).describe(
|
|
93
|
+
'Whether to include parent conversation history as context. '
|
|
94
|
+
+ 'Default: true. Set to false when the briefing is self-contained '
|
|
95
|
+
+ 'and does not depend on prior conversation. See amicus_guide for guidance.'
|
|
96
|
+
),
|
|
97
|
+
coworkProcess: z.string().optional().describe(
|
|
98
|
+
'Cowork VM process name (e.g., "modest-laughing-goodall"). ' +
|
|
99
|
+
'Extract from CWD: /sessions/<name>/. Required for parent context loading.'
|
|
100
|
+
),
|
|
101
|
+
parentSession: z.string().optional().describe(
|
|
102
|
+
'Claude Code session UUID for exact context matching. ' +
|
|
103
|
+
'Prevents ambiguity when multiple sessions are active in the same project.'
|
|
104
|
+
),
|
|
105
|
+
windowPosition: z.enum(['right', 'left', 'center']).optional()
|
|
106
|
+
.default('right').describe(
|
|
107
|
+
'Where to place the Amicus window on screen. ' +
|
|
108
|
+
'right (default): flush against the right edge. ' +
|
|
109
|
+
'left: flush against the left edge. center: centered.'
|
|
110
|
+
),
|
|
111
|
+
project: z.string().optional().describe(
|
|
112
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
113
|
+
),
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: 'amicus_status',
|
|
118
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
119
|
+
description:
|
|
120
|
+
'Check the status of a running Amicus session. Returns status ' +
|
|
121
|
+
'(running/complete), elapsed time, and progress info. Primarily ' +
|
|
122
|
+
'for headless mode \u2014 in interactive mode, wait for the user to ' +
|
|
123
|
+
'tell you the session is done instead of polling.',
|
|
124
|
+
inputSchema: {
|
|
125
|
+
taskId: safeTaskId.describe(
|
|
126
|
+
'The task ID returned by amicus_start.'
|
|
127
|
+
),
|
|
128
|
+
project: z.string().optional().describe(
|
|
129
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
130
|
+
),
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'amicus_read',
|
|
135
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
136
|
+
description:
|
|
137
|
+
'Read the results of a completed Amicus session. Returns the summary ' +
|
|
138
|
+
'by default, or full conversation history, or session metadata.',
|
|
139
|
+
inputSchema: {
|
|
140
|
+
taskId: safeTaskId.describe('The task ID to read.'),
|
|
141
|
+
mode: z.enum(['summary', 'conversation', 'metadata']).optional()
|
|
142
|
+
.default('summary').describe(
|
|
143
|
+
'What to read. summary (default): the fold summary. ' +
|
|
144
|
+
'conversation: full message history. metadata: session info.'
|
|
145
|
+
),
|
|
146
|
+
project: z.string().optional().describe(
|
|
147
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
148
|
+
),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: 'amicus_list',
|
|
153
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
154
|
+
description:
|
|
155
|
+
'List all Amicus sessions for the current project. Shows task ID, ' +
|
|
156
|
+
'model, status, age, and briefing excerpt.',
|
|
157
|
+
inputSchema: {
|
|
158
|
+
status: z.enum(['all', 'running', 'complete']).optional().describe(
|
|
159
|
+
'Filter by status. Default: show all.'
|
|
160
|
+
),
|
|
161
|
+
project: z.string().optional().describe(
|
|
162
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
163
|
+
),
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'amicus_resume',
|
|
168
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
169
|
+
description:
|
|
170
|
+
'Reopen a previous Amicus session with full conversation history ' +
|
|
171
|
+
'preserved. The session continues in the same OpenCode session. ' +
|
|
172
|
+
'Returns a task ID immediately — use amicus_status to poll.',
|
|
173
|
+
inputSchema: {
|
|
174
|
+
taskId: safeTaskId.describe(
|
|
175
|
+
'The task ID of the session to resume.'
|
|
176
|
+
),
|
|
177
|
+
noUi: z.boolean().optional().default(false).describe(
|
|
178
|
+
'Resume in headless mode. Default false (opens Electron window).'
|
|
179
|
+
),
|
|
180
|
+
timeout: z.number().optional().describe(
|
|
181
|
+
'Headless timeout in minutes. Default: 15. Only applies when noUi is true.'
|
|
182
|
+
),
|
|
183
|
+
project: z.string().optional().describe(
|
|
184
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
185
|
+
),
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
name: 'amicus_continue',
|
|
190
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
191
|
+
description:
|
|
192
|
+
'Start a new Amicus session that inherits a previous session\'s ' +
|
|
193
|
+
'conversation as context. The previous session\'s messages become ' +
|
|
194
|
+
'read-only background for the new task. Returns a task ID ' +
|
|
195
|
+
'immediately — use amicus_status to poll.',
|
|
196
|
+
inputSchema: {
|
|
197
|
+
taskId: safeTaskId.describe(
|
|
198
|
+
'The task ID of the previous session to continue from.'
|
|
199
|
+
),
|
|
200
|
+
prompt: z.string().describe(
|
|
201
|
+
'New task description for the continuation.'
|
|
202
|
+
),
|
|
203
|
+
model: safeModel.optional().describe(
|
|
204
|
+
`Override model — short alias (${aliasNames}) or full provider/model ID. Defaults to the original session's model.`
|
|
205
|
+
),
|
|
206
|
+
noUi: z.boolean().optional().default(false).describe(
|
|
207
|
+
'Run headless. Default false (opens Electron window).'
|
|
208
|
+
),
|
|
209
|
+
timeout: z.number().optional().describe(
|
|
210
|
+
'Headless timeout in minutes. Default: 15. Only applies when noUi is true.'
|
|
211
|
+
),
|
|
212
|
+
contextTurns: z.number().optional().describe(
|
|
213
|
+
'Max turns from the previous session\'s conversation to include as context. Default: 80000 tokens.'
|
|
214
|
+
),
|
|
215
|
+
contextMaxTokens: z.number().optional().describe(
|
|
216
|
+
'Cap on previous session context size in tokens. Default: 80000.'
|
|
217
|
+
),
|
|
218
|
+
project: z.string().optional().describe(
|
|
219
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
220
|
+
),
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'amicus_setup',
|
|
225
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
226
|
+
description:
|
|
227
|
+
'Open the Amicus setup wizard to configure API keys and default ' +
|
|
228
|
+
'model. Launches an interactive Electron window for configuration.',
|
|
229
|
+
inputSchema: {},
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: 'amicus_abort',
|
|
233
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
234
|
+
description:
|
|
235
|
+
'Abort a running Amicus session. Stops the OpenCode agent ' +
|
|
236
|
+
'immediately. Use when a session is taking too long or is no ' +
|
|
237
|
+
'longer needed.',
|
|
238
|
+
inputSchema: {
|
|
239
|
+
taskId: safeTaskId.describe(
|
|
240
|
+
'The task ID of the running session to abort.'
|
|
241
|
+
),
|
|
242
|
+
project: z.string().optional().describe(
|
|
243
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
244
|
+
),
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: 'amicus_fanout',
|
|
249
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
250
|
+
description:
|
|
251
|
+
'Run N models on the SAME prompt in parallel (one shared engine) and ' +
|
|
252
|
+
'aggregate the results. Headless only. Returns {waveId, taskIds[]} ' +
|
|
253
|
+
'immediately. Poll amicus_status with the waveId (run `sleep 25` between ' +
|
|
254
|
+
'polls); when done, amicus_read the waveId for the aggregated JSON wave ' +
|
|
255
|
+
'document (per-leg summaries inside). Each leg is also an ordinary ' +
|
|
256
|
+
'session readable by taskId.',
|
|
257
|
+
inputSchema: {
|
|
258
|
+
models: z.array(safeModel).min(1).max(10).describe(
|
|
259
|
+
`1-10 models (2+ for genuine fan-out). Short aliases (${aliasNames}) or full provider/model IDs. Duplicates allowed.`
|
|
260
|
+
),
|
|
261
|
+
prompt: z.string().describe(
|
|
262
|
+
'The briefing sent to every model. Self-contained briefings work best (set includeContext false).'
|
|
263
|
+
),
|
|
264
|
+
agent: z.enum(['Plan', 'Build']).optional().describe(
|
|
265
|
+
'Agent mode for every leg. Build (default): full tool access. Plan: read-only analysis. Chat is not supported headless.'
|
|
266
|
+
),
|
|
267
|
+
thinking: z.enum(['none', 'minimal', 'low', 'medium', 'high', 'xhigh']).optional().describe(
|
|
268
|
+
'Reasoning effort for every leg. Default: medium.'
|
|
269
|
+
),
|
|
270
|
+
timeout: z.number().optional().describe(
|
|
271
|
+
'Per-leg timeout in minutes (wall-clock ≈ slowest leg). Default: 15.'
|
|
272
|
+
),
|
|
273
|
+
summaryLength: z.enum(['brief', 'normal', 'verbose']).optional().describe(
|
|
274
|
+
'Summary verbosity for every leg.'
|
|
275
|
+
),
|
|
276
|
+
includeContext: z.boolean().optional().default(true).describe(
|
|
277
|
+
'Include parent conversation context (built once, shared by all legs). Set false for self-contained briefings.'
|
|
278
|
+
),
|
|
279
|
+
project: z.string().optional().describe(
|
|
280
|
+
'Optional project directory path. Auto-detected from working directory if omitted.'
|
|
281
|
+
),
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: 'amicus_guide',
|
|
286
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
287
|
+
description:
|
|
288
|
+
'Get detailed usage instructions for Amicus — when to spawn ' +
|
|
289
|
+
'sessions, how to write good briefings, agent selection guidelines, ' +
|
|
290
|
+
'and the async workflow pattern. Call this first if you haven\'t ' +
|
|
291
|
+
'used Amicus before.',
|
|
292
|
+
inputSchema: {},
|
|
293
|
+
},
|
|
294
|
+
];
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Returns the guide text for the amicus_guide tool.
|
|
299
|
+
* Includes live alias table from user config.
|
|
300
|
+
* @returns {string} Markdown-formatted guide text
|
|
301
|
+
*/
|
|
302
|
+
function getGuideText() {
|
|
303
|
+
const { getEffectiveAliases } = require('./utils/config');
|
|
304
|
+
const aliases = getEffectiveAliases();
|
|
305
|
+
const aliasRows = Object.entries(aliases)
|
|
306
|
+
.map(([name, model]) => `| ${name} | ${model} |`)
|
|
307
|
+
.join('\n');
|
|
308
|
+
|
|
309
|
+
return `# Amicus Usage Guide
|
|
310
|
+
|
|
311
|
+
## What Is Amicus?
|
|
312
|
+
Amicus spawns parallel conversations with different LLMs and folds results back into your context.
|
|
313
|
+
|
|
314
|
+
## When to Use Amicus
|
|
315
|
+
**DO:** Different model's strengths needed, deep exploration, parallel investigation.
|
|
316
|
+
**DON'T:** Simple tasks you can handle directly.
|
|
317
|
+
|
|
318
|
+
## Async Workflow
|
|
319
|
+
|
|
320
|
+
### Headless Mode (noUi: true)
|
|
321
|
+
1. amicus_start with model + prompt + noUi: true -> get task ID
|
|
322
|
+
2. Run \`sleep 25\` in your shell (this enforces the polling interval)
|
|
323
|
+
3. amicus_status to check progress
|
|
324
|
+
4. If still running, run \`sleep 25\` again before each subsequent amicus_status call
|
|
325
|
+
5. amicus_read to get the summary once complete
|
|
326
|
+
6. Act on findings
|
|
327
|
+
|
|
328
|
+
**IMPORTANT:** Always run \`sleep 25\` before every amicus_status call. This is not optional. Each premature poll wastes context tokens for zero benefit. The sleep command enforces the wait mechanically.
|
|
329
|
+
|
|
330
|
+
### Interactive Mode (noUi: false, default)
|
|
331
|
+
1. amicus_start with model + prompt -> get task ID
|
|
332
|
+
2. Tell the user: "Let me know when you're done with the session and have clicked Fold."
|
|
333
|
+
3. Do NOT poll amicus_status. Wait for the user to tell you it's done.
|
|
334
|
+
4. If the user starts a new message without mentioning the session, ask if they're done or just call amicus_read
|
|
335
|
+
5. Act on findings
|
|
336
|
+
|
|
337
|
+
### Fan-Out (amicus_fanout)
|
|
338
|
+
Run the SAME prompt across 1-10 models in parallel (one shared engine):
|
|
339
|
+
1. amicus_fanout with models + prompt -> {waveId, taskIds[]}
|
|
340
|
+
2. sleep 25, then amicus_status with the waveId (repeat until done)
|
|
341
|
+
3. amicus_read the waveId -> aggregated JSON wave document (per-leg summaries inside)
|
|
342
|
+
Each leg is an ordinary session: read/resume/continue it by taskId.
|
|
343
|
+
|
|
344
|
+
## Agent Selection
|
|
345
|
+
| Agent | Reads | Writes | Bash | Use When |
|
|
346
|
+
|-------|-------|--------|------|----------|
|
|
347
|
+
| Chat (default) | auto | asks | asks | Questions, analysis |
|
|
348
|
+
| Plan | auto | denied | denied | Read-only analysis |
|
|
349
|
+
| Build | auto | auto | auto | Implementation tasks |
|
|
350
|
+
|
|
351
|
+
## Writing Good Briefings
|
|
352
|
+
Include: Objective, Background, Files of interest, Success criteria, Constraints.
|
|
353
|
+
|
|
354
|
+
## Available Model Aliases
|
|
355
|
+
| Alias | Model |
|
|
356
|
+
|-------|-------|
|
|
357
|
+
${aliasRows}
|
|
358
|
+
|
|
359
|
+
Or use full IDs in provider/model format (e.g., openrouter/provider/model-id).
|
|
360
|
+
Run amicus_setup to configure defaults and add custom aliases.
|
|
361
|
+
|
|
362
|
+
## Session Matching
|
|
363
|
+
Cowork: pass coworkProcess (extract from CWD: /sessions/<name>/).
|
|
364
|
+
Claude Code CLI: pass parentSession with your session UUID.
|
|
365
|
+
|
|
366
|
+
## Context Control (includeContext)
|
|
367
|
+
|
|
368
|
+
By default, Amicus includes your parent conversation history as context. Set \`includeContext: false\` to skip this and save tokens when the briefing is self-contained.
|
|
369
|
+
|
|
370
|
+
### MUST Include Context (Red Flags)
|
|
371
|
+
- Task references prior conversation ("the code we discussed", "that bug", "the approach you suggested")
|
|
372
|
+
- Fact checking or second opinions on recent work
|
|
373
|
+
- Code review of changes made in this session
|
|
374
|
+
- "Does this look right?" or validation requests
|
|
375
|
+
- Continuing a debugging thread
|
|
376
|
+
- Any task where the session needs to understand what happened before
|
|
377
|
+
|
|
378
|
+
### Safe to Skip Context
|
|
379
|
+
- Greenfield tasks with explicit file paths and instructions
|
|
380
|
+
- General knowledge or research questions
|
|
381
|
+
- Tasks fully scoped in the briefing (files, criteria, constraints all specified)
|
|
382
|
+
- Independent analysis unrelated to current conversation
|
|
383
|
+
|
|
384
|
+
### Self-Contained Briefing Template
|
|
385
|
+
When setting \`includeContext: false\`, write a richer briefing:
|
|
386
|
+
|
|
387
|
+
\`\`\`
|
|
388
|
+
**Objective:** [Specific goal]
|
|
389
|
+
**Files to read:** [Exact paths]
|
|
390
|
+
**Relevant code:** [Paste key snippets if needed]
|
|
391
|
+
**Success criteria:** [How to know when done]
|
|
392
|
+
**Constraints:** [Scope limits, things to avoid]
|
|
393
|
+
\`\`\`
|
|
394
|
+
|
|
395
|
+
The session has NO other context. Everything it needs must be in the briefing.
|
|
396
|
+
|
|
397
|
+
## Existing Sessions
|
|
398
|
+
Call amicus_list before spawning. Use amicus_resume to reopen or amicus_continue to build on previous findings.
|
|
399
|
+
`;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
module.exports = {
|
|
403
|
+
getTools,
|
|
404
|
+
getGuideText,
|
|
405
|
+
safeTaskId,
|
|
406
|
+
safeModel,
|
|
407
|
+
};
|