superpowers-opencode-fork-dev-test 1.0.2 → 1.1.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.
Files changed (37) hide show
  1. package/.opencode/plugins/superpowers.js +203 -129
  2. package/package.json +3 -2
  3. package/skills/brainstorming/SKILL.md +54 -0
  4. package/skills/dispatching-parallel-agents/SKILL.md +180 -0
  5. package/skills/executing-plans/SKILL.md +76 -0
  6. package/skills/finishing-a-development-branch/SKILL.md +200 -0
  7. package/skills/receiving-code-review/SKILL.md +213 -0
  8. package/skills/requesting-code-review/SKILL.md +105 -0
  9. package/skills/requesting-code-review/code-reviewer.md +146 -0
  10. package/skills/subagent-driven-development/SKILL.md +240 -0
  11. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
  12. package/skills/subagent-driven-development/implementer-prompt.md +78 -0
  13. package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  14. package/skills/systematic-debugging/CREATION-LOG.md +119 -0
  15. package/skills/systematic-debugging/SKILL.md +296 -0
  16. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  17. package/skills/systematic-debugging/condition-based-waiting.md +115 -0
  18. package/skills/systematic-debugging/defense-in-depth.md +122 -0
  19. package/skills/systematic-debugging/find-polluter.sh +63 -0
  20. package/skills/systematic-debugging/root-cause-tracing.md +169 -0
  21. package/skills/systematic-debugging/test-academic.md +14 -0
  22. package/skills/systematic-debugging/test-pressure-1.md +58 -0
  23. package/skills/systematic-debugging/test-pressure-2.md +68 -0
  24. package/skills/systematic-debugging/test-pressure-3.md +69 -0
  25. package/skills/test-driven-development/SKILL.md +371 -0
  26. package/skills/test-driven-development/testing-anti-patterns.md +299 -0
  27. package/skills/using-git-worktrees/SKILL.md +217 -0
  28. package/skills/using-superpowers/SKILL.md +87 -0
  29. package/skills/verification-before-completion/SKILL.md +139 -0
  30. package/skills/writing-plans/SKILL.md +116 -0
  31. package/skills/writing-skills/SKILL.md +655 -0
  32. package/skills/writing-skills/anthropic-best-practices.md +1150 -0
  33. package/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  34. package/skills/writing-skills/graphviz-conventions.dot +172 -0
  35. package/skills/writing-skills/persuasion-principles.md +187 -0
  36. package/skills/writing-skills/render-graphs.js +168 -0
  37. package/skills/writing-skills/testing-skills-with-subagents.md +384 -0
@@ -47,21 +47,38 @@ const normalizePath = (p, homeDir) => {
47
47
  };
48
48
 
49
49
  export const SuperpowersPlugin = async ({ client, directory }) => {
50
+ console.log('[superpowers DEBUG] Plugin loading...');
51
+ console.log('[superpowers DEBUG] __dirname:', __dirname);
52
+ console.log('[superpowers DEBUG] Platform:', os.platform());
53
+ console.log('[superpowers DEBUG] Client name:', client?.app?.name);
54
+ console.log('[superpowers DEBUG] Directory:', directory);
55
+
50
56
  const homeDir = os.homedir();
51
57
  const superpowersSkillsDir = path.resolve(__dirname, '../../skills');
52
58
  const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir);
53
59
  const configDir = envConfigDir || path.join(homeDir, '.config/opencode');
54
60
 
61
+ console.log('[superpowers DEBUG] Home dir:', homeDir);
62
+ console.log('[superpowers DEBUG] Config dir:', configDir);
63
+ console.log('[superpowers DEBUG] Skills dir:', superpowersSkillsDir);
64
+
55
65
  // Helper to generate bootstrap content
56
66
  const getBootstrapContent = () => {
57
- // Try to load using-superpowers skill
58
- const skillPath = path.join(superpowersSkillsDir, 'using-superpowers', 'SKILL.md');
59
- if (!fs.existsSync(skillPath)) return null;
67
+ try {
68
+ // Try to load using-superpowers skill
69
+ const skillPath = path.join(superpowersSkillsDir, 'using-superpowers', 'SKILL.md');
70
+ console.log('[superpowers DEBUG] Looking for bootstrap skill at:', skillPath);
60
71
 
61
- const fullContent = fs.readFileSync(skillPath, 'utf8');
62
- const { content } = extractAndStripFrontmatter(fullContent);
72
+ if (!fs.existsSync(skillPath)) {
73
+ console.log('[superpowers DEBUG] Bootstrap skill not found at:', skillPath);
74
+ return null;
75
+ }
63
76
 
64
- const toolMapping = `**Tool Mapping for OpenCode:**
77
+ console.log('[superpowers DEBUG] Found bootstrap skill, reading content...');
78
+ const fullContent = fs.readFileSync(skillPath, 'utf8');
79
+ const { content } = extractAndStripFrontmatter(fullContent);
80
+
81
+ const toolMapping = `**Tool Mapping for OpenCode:**
65
82
  When skills reference tools you don't have, substitute OpenCode equivalents:
66
83
  - \`TodoWrite\` → \`update_plan\`
67
84
  - \`Task\` tool with subagents → Use OpenCode's subagent system (@mention)
@@ -72,7 +89,8 @@ When skills reference tools you don't have, substitute OpenCode equivalents:
72
89
  Superpowers skills are in \`${configDir}/skills/superpowers/\`
73
90
  Use OpenCode's native \`skill\` tool to list and load skills.`;
74
91
 
75
- return `<EXTREMELY_IMPORTANT>
92
+ console.log('[superpowers DEBUG] Bootstrap content generated successfully');
93
+ return `<EXTREMELY_IMPORTANT>
76
94
  You have superpowers.
77
95
 
78
96
  **IMPORTANT: The using-superpowers skill content is included below. It is ALREADY LOADED - you are currently following it. Do NOT use the skill tool to load "using-superpowers" again - that would be redundant.**
@@ -81,6 +99,10 @@ ${content}
81
99
 
82
100
  ${toolMapping}
83
101
  </EXTREMELY_IMPORTANT>`;
102
+ } catch (error) {
103
+ console.error('[superpowers DEBUG] Error generating bootstrap content:', error);
104
+ return null;
105
+ }
84
106
  };
85
107
 
86
108
  // Platform detection: only run on Linux or macOS
@@ -150,156 +172,208 @@ ${toolMapping}
150
172
 
151
173
  // Autoinstall handler - entry point for all autoinstall logic
152
174
  const handleAutoinstall = async () => {
153
- // Exit early on unsupported platforms
154
- if (!isSupportedPlatform) {
155
- client.app.log('superpowers: Skipping autoinstall - unsupported platform:', platform);
156
- return;
157
- }
175
+ console.log('[superpowers DEBUG] handleAutoinstall called');
176
+ console.log('[superpowers DEBUG] Platform:', platform);
177
+ console.log('[superpowers DEBUG] isOpencode:', isOpencode);
178
+ console.log('[superpowers DEBUG] isSupportedPlatform:', isSupportedPlatform);
158
179
 
159
- // Exit early if not running in OpenCode
160
- if (!isOpencode) {
161
- client.app.log('superpowers: Skipping autoinstall - not running in OpenCode');
162
- return;
163
- }
180
+ try {
181
+ // Exit early on unsupported platforms
182
+ if (!isSupportedPlatform) {
183
+ console.log('[superpowers DEBUG] Skipping autoinstall - unsupported platform:', platform);
184
+ client.app.log('superpowers: Skipping autoinstall - unsupported platform:', platform);
185
+ return;
186
+ }
164
187
 
165
- // Read configuration from directory/opencode.json
166
- const config = readConfig();
167
-
168
- client.app.log('superpowers: Autoinstall starting...');
169
- client.app.log('superpowers: Config directory:', configDir);
170
-
171
- const superpowersDir = path.join(configDir, 'superpowers');
172
- const pluginSymlinkPath = path.join(configDir, 'plugins/superpowers.js');
173
- const skillsSymlinkPath = path.join(configDir, 'skills/superpowers');
174
- const targetPluginPath = path.join(superpowersDir, '.opencode/plugins/superpowers.js');
175
- const targetSkillsPath = path.join(superpowersDir, 'skills');
176
-
177
- // Task 4: Implement git clone if not exists
178
- if (!fs.existsSync(superpowersDir)) {
179
- client.app.log('superpowers: Superpowers directory not found, cloning repository...');
180
- try {
181
- await $`git clone git+https://github.com/obra/superpowers.git ${superpowersDir}`;
182
- client.app.log('superpowers: Successfully cloned superpowers repository');
183
- } catch (error) {
184
- if (error.message.includes('git')) {
185
- client.app.log('superpowers: Error: Git is not installed. Please install git to continue.');
186
- } else {
187
- client.app.log('superpowers: Failed to clone repository:', error.message);
188
- }
188
+ // Exit early if not running in OpenCode
189
+ if (!isOpencode) {
190
+ console.log('[superpowers DEBUG] Skipping autoinstall - not running in OpenCode');
191
+ client.app.log('superpowers: Skipping autoinstall - not running in OpenCode');
189
192
  return;
190
193
  }
191
- } else {
192
- client.app.log('superpowers: Superpowers directory exists at', superpowersDir);
193
- }
194
194
 
195
- // Task 5: Implement symlink creation/removal (idempotent)
196
- const createSymlink = (source, target) => {
197
- try {
198
- // Remove existing symlink or file if it exists
199
- if (fs.existsSync(target) || fs.lstatSync(target).isSymbolicLink()) {
200
- client.app.log('superpowers: Removing existing symlink at', target);
201
- fs.unlinkSync(target);
195
+ // Read configuration from directory/opencode.json
196
+ const config = readConfig();
197
+
198
+ console.log('[superpowers DEBUG] Autoinstall starting...');
199
+ console.log('[superpowers DEBUG] Config directory:', configDir);
200
+ client.app.log('superpowers: Autoinstall starting...');
201
+ client.app.log('superpowers: Config directory:', configDir);
202
+
203
+ const superpowersDir = path.join(configDir, 'superpowers');
204
+ const pluginSymlinkPath = path.join(configDir, 'plugins/superpowers.js');
205
+ const skillsSymlinkPath = path.join(configDir, 'skills/superpowers');
206
+ const targetPluginPath = path.join(superpowersDir, '.opencode/plugins/superpowers.js');
207
+ const targetSkillsPath = path.join(superpowersDir, 'skills');
208
+
209
+ console.log('[superpowers DEBUG] superpowersDir:', superpowersDir);
210
+ console.log('[superpowers DEBUG] Plugin symlink path:', pluginSymlinkPath);
211
+ console.log('[superpowers DEBUG] Skills symlink path:', skillsSymlinkPath);
212
+
213
+ // Task 4: Implement git clone if not exists
214
+ if (!fs.existsSync(superpowersDir)) {
215
+ console.log('[superpowers DEBUG] Superpowers directory not found, cloning...');
216
+ client.app.log('superpowers: Superpowers directory not found, cloning repository...');
217
+ try {
218
+ await $`git clone git+https://github.com/obra/superpowers.git ${superpowersDir}`;
219
+ console.log('[superpowers DEBUG] Successfully cloned repository');
220
+ client.app.log('superpowers: Successfully cloned superpowers repository');
221
+ } catch (error) {
222
+ console.error('[superpowers DEBUG] Clone error:', error);
223
+ if (error.message.includes('git')) {
224
+ client.app.log('superpowers: Error: Git is not installed. Please install git to continue.');
225
+ } else {
226
+ client.app.log('superpowers: Failed to clone repository:', error.message);
227
+ }
228
+ return;
202
229
  }
203
- } catch (error) {
204
- // Ignore errors if target doesn't exist
230
+ } else {
231
+ console.log('[superpowers DEBUG] Superpowers directory exists:', superpowersDir);
232
+ client.app.log('superpowers: Superpowers directory exists at', superpowersDir);
205
233
  }
206
234
 
207
- // Ensure parent directory exists
208
- const parentDir = path.dirname(target);
209
- if (!fs.existsSync(parentDir)) {
210
- client.app.log('superpowers: Creating parent directory', parentDir);
211
- fs.mkdirSync(parentDir, { recursive: true });
212
- }
235
+ // Task 5: Implement symlink creation/removal (idempotent)
236
+ const createSymlink = (source, target) => {
237
+ console.log('[superpowers DEBUG] Creating symlink:', target, '→', source);
238
+ try {
239
+ // Remove existing symlink or file if it exists
240
+ if (fs.existsSync(target) || fs.lstatSync(target).isSymbolicLink()) {
241
+ console.log('[superpowers DEBUG] Removing existing symlink at:', target);
242
+ client.app.log('superpowers: Removing existing symlink at', target);
243
+ fs.unlinkSync(target);
244
+ }
245
+ } catch (error) {
246
+ // Ignore errors if target doesn't exist
247
+ console.log('[superpowers DEBUG] Error checking/removing existing symlink:', error.message);
248
+ }
213
249
 
214
- // Create symlink
215
- try {
216
- fs.symlinkSync(source, target);
217
- client.app.log('superpowers: Created symlink', target, '→', source);
218
- } catch (error) {
219
- client.app.log('superpowers: Failed to create symlink', target, '→', source, ':', error.message);
220
- }
221
- };
250
+ // Ensure parent directory exists
251
+ const parentDir = path.dirname(target);
252
+ if (!fs.existsSync(parentDir)) {
253
+ console.log('[superpowers DEBUG] Creating parent directory:', parentDir);
254
+ client.app.log('superpowers: Creating parent directory', parentDir);
255
+ fs.mkdirSync(parentDir, { recursive: true });
256
+ }
222
257
 
223
- createSymlink(targetPluginPath, pluginSymlinkPath);
224
- createSymlink(targetSkillsPath, skillsSymlinkPath);
258
+ // Create symlink
259
+ try {
260
+ fs.symlinkSync(source, target);
261
+ console.log('[superpowers DEBUG] Successfully created symlink');
262
+ client.app.log('superpowers: Created symlink', target, '→', source);
263
+ } catch (error) {
264
+ console.error('[superpowers DEBUG] Symlink creation error:', error);
265
+ client.app.log('superpowers: Failed to create symlink', target, '→', source, ':', error.message);
266
+ }
267
+ };
225
268
 
226
- // Task 6: Implement update detection and pull
227
- const checkForUpdates = async () => {
228
- const gitDir = path.join(superpowersDir, '.git');
229
-
230
- if (!fs.existsSync(gitDir)) {
231
- client.app.log('superpowers: Not a git repository, skipping update check');
232
- return;
233
- }
269
+ console.log('[superpowers DEBUG] Creating plugin symlink...');
270
+ createSymlink(targetPluginPath, pluginSymlinkPath);
271
+ console.log('[superpowers DEBUG] Creating skills symlink...');
272
+ createSymlink(targetSkillsPath, skillsSymlinkPath);
234
273
 
235
- // Check for manual install
236
- if (isManualInstall(superpowersDir)) {
237
- client.app.log('superpowers: Manual installation detected, skipping auto-update');
238
- return;
239
- }
274
+ // Task 6: Implement update detection and pull
275
+ const checkForUpdates = async () => {
276
+ console.log('[superpowers DEBUG] Checking for updates...');
277
+ const gitDir = path.join(superpowersDir, '.git');
240
278
 
241
- // Check autoupdate config
242
- if (!config.superpowers.autoupdate) {
243
- return;
244
- }
279
+ if (!fs.existsSync(gitDir)) {
280
+ console.log('[superpowers DEBUG] Not a git repository, skipping update check');
281
+ client.app.log('superpowers: Not a git repository, skipping update check');
282
+ return;
283
+ }
245
284
 
246
- if (config.superpowers.autoupdate_notify) {
247
- client.app.log('superpowers: Checking for updates...');
248
- }
285
+ // Check for manual install
286
+ if (isManualInstall(superpowersDir)) {
287
+ console.log('[superpowers DEBUG] Manual install detected, skipping auto-update');
288
+ client.app.log('superpowers: Manual installation detected, skipping auto-update');
289
+ return;
290
+ }
249
291
 
250
- try {
251
- // Git fetch with timeout
252
- await Promise.race([
253
- $`git -C ${superpowersDir} fetch origin`,
254
- new Promise((_, reject) =>
255
- setTimeout(() => reject(new Error('Timeout')), 30000)
256
- )
257
- ]);
258
-
259
- // Check if local branch is behind remote
260
- const localRev = await $`git -C ${superpowersDir} rev-parse HEAD`;
261
- const remoteRev = await $`git -C ${superpowersDir} rev-parse @{u}`;
262
-
263
- if (localRev.stdout.trim() !== remoteRev.stdout.trim()) {
264
- if (config.superpowers.autoupdate_notify) {
265
- client.app.log('superpowers: Updates available, pulling changes...');
266
- }
267
- await $`git -C ${superpowersDir} pull`;
268
-
269
- // Get the current version/tag
270
- try {
271
- const tag = await $`git -C ${superpowersDir} describe --tags --abbrev=0 2>/dev/null`;
292
+ // Check autoupdate config
293
+ if (!config.superpowers.autoupdate) {
294
+ console.log('[superpowers DEBUG] Auto-update disabled in config');
295
+ return;
296
+ }
297
+
298
+ if (config.superpowers.autoupdate_notify) {
299
+ console.log('[superpowers DEBUG] Checking for updates...');
300
+ client.app.log('superpowers: Checking for updates...');
301
+ }
302
+
303
+ try {
304
+ // Git fetch with timeout
305
+ await Promise.race([
306
+ $`git -C ${superpowersDir} fetch origin`,
307
+ new Promise((_, reject) =>
308
+ setTimeout(() => reject(new Error('Timeout')), 30000)
309
+ )
310
+ ]);
311
+
312
+ // Check if local branch is behind remote
313
+ const localRev = await $`git -C ${superpowersDir} rev-parse HEAD`;
314
+ const remoteRev = await $`git -C ${superpowersDir} rev-parse @{u}`;
315
+
316
+ if (localRev.stdout.trim() !== remoteRev.stdout.trim()) {
272
317
  if (config.superpowers.autoupdate_notify) {
273
- client.app.log('superpowers: Updated to version:', tag.stdout.trim());
318
+ console.log('[superpowers DEBUG] Updates available, pulling...');
319
+ client.app.log('superpowers: Updates available, pulling changes...');
320
+ }
321
+ await $`git -C ${superpowersDir} pull`;
322
+
323
+ // Get the current version/tag
324
+ try {
325
+ const tag = await $`git -C ${superpowersDir} describe --tags --abbrev=0 2>/dev/null`;
326
+ if (config.superpowers.autoupdate_notify) {
327
+ console.log('[superpowers DEBUG] Updated to version:', tag.stdout.trim());
328
+ client.app.log('superpowers: Updated to version:', tag.stdout.trim());
329
+ }
330
+ } catch {
331
+ if (config.superpowers.autoupdate_notify) {
332
+ console.log('[superpowers DEBUG] Updated successfully (no tag)');
333
+ client.app.log('superpowers: Updated successfully (no tag available)');
334
+ }
274
335
  }
275
- } catch {
336
+ } else {
276
337
  if (config.superpowers.autoupdate_notify) {
277
- client.app.log('superpowers: Updated successfully (no tag available)');
338
+ console.log('[superpowers DEBUG] Already up to date');
339
+ client.app.log('superpowers: Already up to date');
278
340
  }
279
341
  }
280
- } else {
281
- if (config.superpowers.autoupdate_notify) {
282
- client.app.log('superpowers: Already up to date');
342
+ } catch (error) {
343
+ console.error('[superpowers DEBUG] Update check error:', error);
344
+ if (error.message === 'Timeout') {
345
+ client.app.log('superpowers: Update check timed out, continuing...');
346
+ } else {
347
+ client.app.log('superpowers: Update check failed:', error.message);
283
348
  }
284
349
  }
285
- } catch (error) {
286
- if (error.message === 'Timeout') {
287
- client.app.log('superpowers: Update check timed out, continuing...');
288
- } else {
289
- client.app.log('superpowers: Update check failed:', error.message);
290
- }
291
- }
292
- };
350
+ };
293
351
 
294
- // Run update check in background (non-blocking)
295
- setImmediate(() => {
296
- checkForUpdates();
297
- });
352
+ // Run update check in background (non-blocking)
353
+ console.log('[superpowers DEBUG] Scheduling update check...');
354
+ setImmediate(() => {
355
+ checkForUpdates();
356
+ });
357
+ console.log('[superpowers DEBUG] Autoinstall completed successfully');
358
+ } catch (error) {
359
+ console.error('[superpowers ERROR] Fatal error in handleAutoinstall:', error);
360
+ console.error('[superpowers ERROR] Stack:', error.stack);
361
+ if (client?.app?.log) {
362
+ client.app.log('superpowers: Fatal error:', error.message);
363
+ }
364
+ }
298
365
  };
299
366
 
300
367
  return {
301
368
  // Autoinstall entry point - triggers on new sessions
302
369
  'session.created': async () => {
370
+ console.log('[superpowers DEBUG] session.created hook fired');
371
+ await handleAutoinstall();
372
+ },
373
+
374
+ // Alternative hook - try session.start as well
375
+ 'session.start': async () => {
376
+ console.log('[superpowers DEBUG] session.start hook fired');
303
377
  await handleAutoinstall();
304
378
  },
305
379
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "superpowers-opencode-fork-dev-test",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Superpowers plugin for OpenCode.ai - Complete software development workflow with composable skills",
5
5
  "type": "module",
6
6
  "main": ".opencode/plugins/superpowers.js",
@@ -11,7 +11,8 @@
11
11
  }
12
12
  },
13
13
  "files": [
14
- ".opencode/plugins/superpowers.js"
14
+ ".opencode/plugins/superpowers.js",
15
+ "skills/**/*"
15
16
  ],
16
17
  "scripts": {
17
18
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: brainstorming
3
+ description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
4
+ ---
5
+
6
+ # Brainstorming Ideas Into Designs
7
+
8
+ ## Overview
9
+
10
+ Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
11
+
12
+ Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design in small sections (200-300 words), checking after each section whether it looks right so far.
13
+
14
+ ## The Process
15
+
16
+ **Understanding the idea:**
17
+ - Check out the current project state first (files, docs, recent commits)
18
+ - Ask questions one at a time to refine the idea
19
+ - Prefer multiple choice questions when possible, but open-ended is fine too
20
+ - Only one question per message - if a topic needs more exploration, break it into multiple questions
21
+ - Focus on understanding: purpose, constraints, success criteria
22
+
23
+ **Exploring approaches:**
24
+ - Propose 2-3 different approaches with trade-offs
25
+ - Present options conversationally with your recommendation and reasoning
26
+ - Lead with your recommended option and explain why
27
+
28
+ **Presenting the design:**
29
+ - Once you believe you understand what you're building, present the design
30
+ - Break it into sections of 200-300 words
31
+ - Ask after each section whether it looks right so far
32
+ - Cover: architecture, components, data flow, error handling, testing
33
+ - Be ready to go back and clarify if something doesn't make sense
34
+
35
+ ## After the Design
36
+
37
+ **Documentation:**
38
+ - Write the validated design to `docs/plans/YYYY-MM-DD-<topic>-design.md`
39
+ - Use elements-of-style:writing-clearly-and-concisely skill if available
40
+ - Commit the design document to git
41
+
42
+ **Implementation (if continuing):**
43
+ - Ask: "Ready to set up for implementation?"
44
+ - Use superpowers:using-git-worktrees to create isolated workspace
45
+ - Use superpowers:writing-plans to create detailed implementation plan
46
+
47
+ ## Key Principles
48
+
49
+ - **One question at a time** - Don't overwhelm with multiple questions
50
+ - **Multiple choice preferred** - Easier to answer than open-ended when possible
51
+ - **YAGNI ruthlessly** - Remove unnecessary features from all designs
52
+ - **Explore alternatives** - Always propose 2-3 approaches before settling
53
+ - **Incremental validation** - Present design in sections, validate each
54
+ - **Be flexible** - Go back and clarify when something doesn't make sense
@@ -0,0 +1,180 @@
1
+ ---
2
+ name: dispatching-parallel-agents
3
+ description: Use when facing 2+ independent tasks that can be worked on without shared state or sequential dependencies
4
+ ---
5
+
6
+ # Dispatching Parallel Agents
7
+
8
+ ## Overview
9
+
10
+ When you have multiple unrelated failures (different test files, different subsystems, different bugs), investigating them sequentially wastes time. Each investigation is independent and can happen in parallel.
11
+
12
+ **Core principle:** Dispatch one agent per independent problem domain. Let them work concurrently.
13
+
14
+ ## When to Use
15
+
16
+ ```dot
17
+ digraph when_to_use {
18
+ "Multiple failures?" [shape=diamond];
19
+ "Are they independent?" [shape=diamond];
20
+ "Single agent investigates all" [shape=box];
21
+ "One agent per problem domain" [shape=box];
22
+ "Can they work in parallel?" [shape=diamond];
23
+ "Sequential agents" [shape=box];
24
+ "Parallel dispatch" [shape=box];
25
+
26
+ "Multiple failures?" -> "Are they independent?" [label="yes"];
27
+ "Are they independent?" -> "Single agent investigates all" [label="no - related"];
28
+ "Are they independent?" -> "Can they work in parallel?" [label="yes"];
29
+ "Can they work in parallel?" -> "Parallel dispatch" [label="yes"];
30
+ "Can they work in parallel?" -> "Sequential agents" [label="no - shared state"];
31
+ }
32
+ ```
33
+
34
+ **Use when:**
35
+ - 3+ test files failing with different root causes
36
+ - Multiple subsystems broken independently
37
+ - Each problem can be understood without context from others
38
+ - No shared state between investigations
39
+
40
+ **Don't use when:**
41
+ - Failures are related (fix one might fix others)
42
+ - Need to understand full system state
43
+ - Agents would interfere with each other
44
+
45
+ ## The Pattern
46
+
47
+ ### 1. Identify Independent Domains
48
+
49
+ Group failures by what's broken:
50
+ - File A tests: Tool approval flow
51
+ - File B tests: Batch completion behavior
52
+ - File C tests: Abort functionality
53
+
54
+ Each domain is independent - fixing tool approval doesn't affect abort tests.
55
+
56
+ ### 2. Create Focused Agent Tasks
57
+
58
+ Each agent gets:
59
+ - **Specific scope:** One test file or subsystem
60
+ - **Clear goal:** Make these tests pass
61
+ - **Constraints:** Don't change other code
62
+ - **Expected output:** Summary of what you found and fixed
63
+
64
+ ### 3. Dispatch in Parallel
65
+
66
+ ```typescript
67
+ // In Claude Code / AI environment
68
+ Task("Fix agent-tool-abort.test.ts failures")
69
+ Task("Fix batch-completion-behavior.test.ts failures")
70
+ Task("Fix tool-approval-race-conditions.test.ts failures")
71
+ // All three run concurrently
72
+ ```
73
+
74
+ ### 4. Review and Integrate
75
+
76
+ When agents return:
77
+ - Read each summary
78
+ - Verify fixes don't conflict
79
+ - Run full test suite
80
+ - Integrate all changes
81
+
82
+ ## Agent Prompt Structure
83
+
84
+ Good agent prompts are:
85
+ 1. **Focused** - One clear problem domain
86
+ 2. **Self-contained** - All context needed to understand the problem
87
+ 3. **Specific about output** - What should the agent return?
88
+
89
+ ```markdown
90
+ Fix the 3 failing tests in src/agents/agent-tool-abort.test.ts:
91
+
92
+ 1. "should abort tool with partial output capture" - expects 'interrupted at' in message
93
+ 2. "should handle mixed completed and aborted tools" - fast tool aborted instead of completed
94
+ 3. "should properly track pendingToolCount" - expects 3 results but gets 0
95
+
96
+ These are timing/race condition issues. Your task:
97
+
98
+ 1. Read the test file and understand what each test verifies
99
+ 2. Identify root cause - timing issues or actual bugs?
100
+ 3. Fix by:
101
+ - Replacing arbitrary timeouts with event-based waiting
102
+ - Fixing bugs in abort implementation if found
103
+ - Adjusting test expectations if testing changed behavior
104
+
105
+ Do NOT just increase timeouts - find the real issue.
106
+
107
+ Return: Summary of what you found and what you fixed.
108
+ ```
109
+
110
+ ## Common Mistakes
111
+
112
+ **❌ Too broad:** "Fix all the tests" - agent gets lost
113
+ **✅ Specific:** "Fix agent-tool-abort.test.ts" - focused scope
114
+
115
+ **❌ No context:** "Fix the race condition" - agent doesn't know where
116
+ **✅ Context:** Paste the error messages and test names
117
+
118
+ **❌ No constraints:** Agent might refactor everything
119
+ **✅ Constraints:** "Do NOT change production code" or "Fix tests only"
120
+
121
+ **❌ Vague output:** "Fix it" - you don't know what changed
122
+ **✅ Specific:** "Return summary of root cause and changes"
123
+
124
+ ## When NOT to Use
125
+
126
+ **Related failures:** Fixing one might fix others - investigate together first
127
+ **Need full context:** Understanding requires seeing entire system
128
+ **Exploratory debugging:** You don't know what's broken yet
129
+ **Shared state:** Agents would interfere (editing same files, using same resources)
130
+
131
+ ## Real Example from Session
132
+
133
+ **Scenario:** 6 test failures across 3 files after major refactoring
134
+
135
+ **Failures:**
136
+ - agent-tool-abort.test.ts: 3 failures (timing issues)
137
+ - batch-completion-behavior.test.ts: 2 failures (tools not executing)
138
+ - tool-approval-race-conditions.test.ts: 1 failure (execution count = 0)
139
+
140
+ **Decision:** Independent domains - abort logic separate from batch completion separate from race conditions
141
+
142
+ **Dispatch:**
143
+ ```
144
+ Agent 1 → Fix agent-tool-abort.test.ts
145
+ Agent 2 → Fix batch-completion-behavior.test.ts
146
+ Agent 3 → Fix tool-approval-race-conditions.test.ts
147
+ ```
148
+
149
+ **Results:**
150
+ - Agent 1: Replaced timeouts with event-based waiting
151
+ - Agent 2: Fixed event structure bug (threadId in wrong place)
152
+ - Agent 3: Added wait for async tool execution to complete
153
+
154
+ **Integration:** All fixes independent, no conflicts, full suite green
155
+
156
+ **Time saved:** 3 problems solved in parallel vs sequentially
157
+
158
+ ## Key Benefits
159
+
160
+ 1. **Parallelization** - Multiple investigations happen simultaneously
161
+ 2. **Focus** - Each agent has narrow scope, less context to track
162
+ 3. **Independence** - Agents don't interfere with each other
163
+ 4. **Speed** - 3 problems solved in time of 1
164
+
165
+ ## Verification
166
+
167
+ After agents return:
168
+ 1. **Review each summary** - Understand what changed
169
+ 2. **Check for conflicts** - Did agents edit same code?
170
+ 3. **Run full suite** - Verify all fixes work together
171
+ 4. **Spot check** - Agents can make systematic errors
172
+
173
+ ## Real-World Impact
174
+
175
+ From debugging session (2025-10-03):
176
+ - 6 failures across 3 files
177
+ - 3 agents dispatched in parallel
178
+ - All investigations completed concurrently
179
+ - All fixes integrated successfully
180
+ - Zero conflicts between agent changes