opencode-swarm-plugin 0.23.6 → 0.25.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.
@@ -905,8 +905,345 @@ export class DecompositionError extends SwarmError {
905
905
  }
906
906
  }
907
907
 
908
+ /**
909
+ * Planning phase state machine for Socratic planning
910
+ */
911
+ type PlanningPhase = "questioning" | "alternatives" | "recommendation" | "ready";
912
+
913
+ /**
914
+ * Planning mode that determines interaction level
915
+ */
916
+ type PlanningMode = "socratic" | "fast" | "auto" | "confirm-only";
917
+
918
+ /**
919
+ * Socratic planning output structure
920
+ */
921
+ interface SocraticPlanOutput {
922
+ mode: PlanningMode;
923
+ phase: PlanningPhase;
924
+ questions?: Array<{ question: string; options?: string[] }>;
925
+ alternatives?: Array<{
926
+ name: string;
927
+ description: string;
928
+ tradeoffs: string;
929
+ }>;
930
+ recommendation?: { approach: string; reasoning: string };
931
+ memory_context?: string;
932
+ codebase_context?: {
933
+ git_status?: string;
934
+ relevant_files?: string[];
935
+ };
936
+ ready_to_decompose: boolean;
937
+ next_action?: string;
938
+ }
939
+
940
+ /**
941
+ * Interactive planning tool with Socratic questioning
942
+ *
943
+ * Implements a planning phase BEFORE decomposition that:
944
+ * 1. Gathers context (git, files, semantic memory)
945
+ * 2. Asks clarifying questions (socratic mode)
946
+ * 3. Explores alternatives with tradeoffs
947
+ * 4. Recommends an approach with reasoning
948
+ * 5. Confirms before proceeding to decomposition
949
+ *
950
+ * Modes:
951
+ * - socratic: Full interactive planning with questions, alternatives, recommendations
952
+ * - fast: Skip brainstorming, go straight to decomposition with memory context
953
+ * - auto: Auto-select best approach based on task keywords, minimal interaction
954
+ * - confirm-only: Show decomposition, wait for yes/no confirmation
955
+ *
956
+ * Based on the Socratic Planner Pattern from obra/superpowers.
957
+ *
958
+ * @see docs/analysis-socratic-planner-pattern.md
959
+ */
960
+ export const swarm_plan_interactive = tool({
961
+ description:
962
+ "Interactive planning phase with Socratic questioning before decomposition. Supports multiple modes from full interactive to auto-proceed.",
963
+ args: {
964
+ task: tool.schema.string().min(1).describe("The task to plan"),
965
+ mode: tool.schema
966
+ .enum(["socratic", "fast", "auto", "confirm-only"])
967
+ .default("socratic")
968
+ .describe("Planning mode: socratic (full), fast (skip questions), auto (minimal), confirm-only (single yes/no)"),
969
+ context: tool.schema
970
+ .string()
971
+ .optional()
972
+ .describe("Optional additional context about the task"),
973
+ user_response: tool.schema
974
+ .string()
975
+ .optional()
976
+ .describe("User's response to a previous question (for multi-turn socratic mode)"),
977
+ phase: tool.schema
978
+ .enum(["questioning", "alternatives", "recommendation", "ready"])
979
+ .optional()
980
+ .describe("Current planning phase (for resuming multi-turn interaction)"),
981
+ },
982
+ async execute(args): Promise<string> {
983
+ // Import needed modules
984
+ const { selectStrategy, formatStrategyGuidelines, STRATEGIES } =
985
+ await import("./swarm-strategies");
986
+ const { formatMemoryQueryForDecomposition } = await import("./learning");
987
+
988
+ // Determine current phase
989
+ const currentPhase: PlanningPhase = args.phase || "questioning";
990
+ const mode: PlanningMode = args.mode || "socratic";
991
+
992
+ // Gather context - always do this regardless of mode
993
+ let memoryContext = "";
994
+ let codebaseContext: { git_status?: string; relevant_files?: string[] } = {};
995
+
996
+ // Generate semantic memory query instruction
997
+ // Note: Semantic memory is accessed via OpenCode's global tools, not as a direct import
998
+ // The coordinator should call semantic-memory_find before calling this tool
999
+ // and pass results in the context parameter
1000
+ try {
1001
+ const memoryQuery = formatMemoryQueryForDecomposition(args.task, 3);
1002
+ memoryContext = `[Memory Query Instruction]\n${memoryQuery.instruction}\nQuery: "${memoryQuery.query}"\nLimit: ${memoryQuery.limit}`;
1003
+ } catch (error) {
1004
+ console.warn("[swarm_plan_interactive] Memory query formatting failed:", error);
1005
+ }
1006
+
1007
+ // Get git context for codebase awareness
1008
+ try {
1009
+ const gitResult = await Bun.$`git status --short`.quiet().nothrow();
1010
+ if (gitResult.exitCode === 0) {
1011
+ codebaseContext.git_status = gitResult.stdout.toString().trim();
1012
+ }
1013
+ } catch (error) {
1014
+ // Git not available or not in a git repo - continue without it
1015
+ }
1016
+
1017
+ // Fast mode: Skip to recommendation
1018
+ if (mode === "fast") {
1019
+ const strategyResult = selectStrategy(args.task);
1020
+ const guidelines = formatStrategyGuidelines(strategyResult.strategy);
1021
+
1022
+ const output: SocraticPlanOutput = {
1023
+ mode: "fast",
1024
+ phase: "ready",
1025
+ recommendation: {
1026
+ approach: strategyResult.strategy,
1027
+ reasoning: `${strategyResult.reasoning}\n\n${guidelines}`,
1028
+ },
1029
+ memory_context: memoryContext || undefined,
1030
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1031
+ ready_to_decompose: true,
1032
+ next_action: "Proceed to swarm_decompose or swarm_delegate_planning",
1033
+ };
1034
+
1035
+ return JSON.stringify(output, null, 2);
1036
+ }
1037
+
1038
+ // Auto mode: Auto-select and proceed
1039
+ if (mode === "auto") {
1040
+ const strategyResult = selectStrategy(args.task);
1041
+
1042
+ const output: SocraticPlanOutput = {
1043
+ mode: "auto",
1044
+ phase: "ready",
1045
+ recommendation: {
1046
+ approach: strategyResult.strategy,
1047
+ reasoning: `Auto-selected based on task keywords: ${strategyResult.reasoning}`,
1048
+ },
1049
+ memory_context: memoryContext || undefined,
1050
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1051
+ ready_to_decompose: true,
1052
+ next_action: "Auto-proceeding to decomposition",
1053
+ };
1054
+
1055
+ return JSON.stringify(output, null, 2);
1056
+ }
1057
+
1058
+ // Confirm-only mode: Generate decomposition, show it, wait for yes/no
1059
+ if (mode === "confirm-only") {
1060
+ // This mode will be handled by calling swarm_delegate_planning
1061
+ // and then asking for confirmation on the result
1062
+ const output: SocraticPlanOutput = {
1063
+ mode: "confirm-only",
1064
+ phase: "ready",
1065
+ recommendation: {
1066
+ approach: "Will generate decomposition for your review",
1067
+ reasoning: "Use swarm_delegate_planning to generate the plan, then present it for yes/no confirmation",
1068
+ },
1069
+ memory_context: memoryContext || undefined,
1070
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1071
+ ready_to_decompose: false,
1072
+ next_action: "Call swarm_delegate_planning, then show result and ask for confirmation",
1073
+ };
1074
+
1075
+ return JSON.stringify(output, null, 2);
1076
+ }
1077
+
1078
+ // Socratic mode: Full interactive planning
1079
+ // Phase 1: Questioning
1080
+ if (currentPhase === "questioning") {
1081
+ // Analyze task to identify what needs clarification
1082
+ const taskLower = args.task.toLowerCase();
1083
+ const questions: Array<{ question: string; options?: string[] }> = [];
1084
+
1085
+ // Check for vague task signals from skill
1086
+ const isVague = {
1087
+ noFiles: !taskLower.includes("src/") && !taskLower.includes("file"),
1088
+ vagueVerb:
1089
+ taskLower.includes("improve") ||
1090
+ taskLower.includes("fix") ||
1091
+ taskLower.includes("update") ||
1092
+ taskLower.includes("make better"),
1093
+ noSuccessCriteria: !taskLower.includes("test") && !taskLower.includes("verify"),
1094
+ };
1095
+
1096
+ // Generate clarifying questions (one at a time)
1097
+ if (isVague.noFiles) {
1098
+ questions.push({
1099
+ question: "Which part of the codebase should this change affect?",
1100
+ options: [
1101
+ "Core functionality (src/)",
1102
+ "UI components (components/)",
1103
+ "API routes (app/api/)",
1104
+ "Configuration and tooling",
1105
+ "Tests",
1106
+ ],
1107
+ });
1108
+ } else if (isVague.vagueVerb) {
1109
+ questions.push({
1110
+ question: "What specific change are you looking for?",
1111
+ options: [
1112
+ "Add new functionality",
1113
+ "Modify existing behavior",
1114
+ "Remove/deprecate something",
1115
+ "Refactor without behavior change",
1116
+ "Fix a bug",
1117
+ ],
1118
+ });
1119
+ } else if (isVague.noSuccessCriteria) {
1120
+ questions.push({
1121
+ question: "How will we know this task is complete?",
1122
+ options: [
1123
+ "All tests pass",
1124
+ "Feature works as demonstrated",
1125
+ "Code review approved",
1126
+ "Documentation updated",
1127
+ "Performance target met",
1128
+ ],
1129
+ });
1130
+ }
1131
+
1132
+ // If task seems clear, move to alternatives phase
1133
+ if (questions.length === 0) {
1134
+ const output: SocraticPlanOutput = {
1135
+ mode: "socratic",
1136
+ phase: "alternatives",
1137
+ memory_context: memoryContext || undefined,
1138
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1139
+ ready_to_decompose: false,
1140
+ next_action: "Task is clear. Call again with phase=alternatives to explore approaches",
1141
+ };
1142
+ return JSON.stringify(output, null, 2);
1143
+ }
1144
+
1145
+ // Return first question only (Socratic principle: one at a time)
1146
+ const output: SocraticPlanOutput = {
1147
+ mode: "socratic",
1148
+ phase: "questioning",
1149
+ questions: [questions[0]],
1150
+ memory_context: memoryContext || undefined,
1151
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1152
+ ready_to_decompose: false,
1153
+ next_action: "User should answer this question, then call again with user_response",
1154
+ };
1155
+
1156
+ return JSON.stringify(output, null, 2);
1157
+ }
1158
+
1159
+ // Phase 2: Alternatives
1160
+ if (currentPhase === "alternatives") {
1161
+ const strategyResult = selectStrategy(args.task);
1162
+
1163
+ // Build 2-3 alternative approaches
1164
+ const alternatives: Array<{
1165
+ name: string;
1166
+ description: string;
1167
+ tradeoffs: string;
1168
+ }> = [];
1169
+
1170
+ // Primary recommendation
1171
+ alternatives.push({
1172
+ name: strategyResult.strategy,
1173
+ description: strategyResult.reasoning,
1174
+ tradeoffs: `Confidence: ${(strategyResult.confidence * 100).toFixed(0)}%. ${STRATEGIES[strategyResult.strategy].description}`,
1175
+ });
1176
+
1177
+ // Add top 2 alternatives
1178
+ for (let i = 0; i < Math.min(2, strategyResult.alternatives.length); i++) {
1179
+ const alt = strategyResult.alternatives[i];
1180
+ alternatives.push({
1181
+ name: alt.strategy,
1182
+ description: STRATEGIES[alt.strategy].description,
1183
+ tradeoffs: `Match score: ${alt.score}. ${STRATEGIES[alt.strategy].antiPatterns[0] || "Consider trade-offs carefully"}`,
1184
+ });
1185
+ }
1186
+
1187
+ const output: SocraticPlanOutput = {
1188
+ mode: "socratic",
1189
+ phase: "alternatives",
1190
+ alternatives,
1191
+ memory_context: memoryContext || undefined,
1192
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1193
+ ready_to_decompose: false,
1194
+ next_action: "User should choose an approach, then call again with phase=recommendation",
1195
+ };
1196
+
1197
+ return JSON.stringify(output, null, 2);
1198
+ }
1199
+
1200
+ // Phase 3: Recommendation
1201
+ if (currentPhase === "recommendation") {
1202
+ const strategyResult = selectStrategy(args.task);
1203
+ const guidelines = formatStrategyGuidelines(strategyResult.strategy);
1204
+
1205
+ const output: SocraticPlanOutput = {
1206
+ mode: "socratic",
1207
+ phase: "recommendation",
1208
+ recommendation: {
1209
+ approach: strategyResult.strategy,
1210
+ reasoning: `Based on your input and task analysis:\n\n${strategyResult.reasoning}\n\n${guidelines}`,
1211
+ },
1212
+ memory_context: memoryContext || undefined,
1213
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1214
+ ready_to_decompose: false,
1215
+ next_action: "User should confirm to proceed. Then call again with phase=ready",
1216
+ };
1217
+
1218
+ return JSON.stringify(output, null, 2);
1219
+ }
1220
+
1221
+ // Phase 4: Ready
1222
+ if (currentPhase === "ready") {
1223
+ const output: SocraticPlanOutput = {
1224
+ mode: "socratic",
1225
+ phase: "ready",
1226
+ recommendation: {
1227
+ approach: "Confirmed by user",
1228
+ reasoning: "Ready to proceed with decomposition",
1229
+ },
1230
+ memory_context: memoryContext || undefined,
1231
+ codebase_context: Object.keys(codebaseContext).length > 0 ? codebaseContext : undefined,
1232
+ ready_to_decompose: true,
1233
+ next_action: "Proceed to swarm_decompose or swarm_delegate_planning",
1234
+ };
1235
+
1236
+ return JSON.stringify(output, null, 2);
1237
+ }
1238
+
1239
+ // Should never reach here
1240
+ throw new Error(`Invalid planning phase: ${currentPhase}`);
1241
+ },
1242
+ });
1243
+
908
1244
  export const decomposeTools = {
909
1245
  swarm_decompose,
910
1246
  swarm_validate_decomposition,
911
1247
  swarm_delegate_planning,
1248
+ swarm_plan_interactive,
912
1249
  };
@@ -871,30 +871,8 @@ export const swarm_progress = tool({
871
871
  });
872
872
  await appendEvent(event, args.project_key);
873
873
 
874
- // Update swarm_contexts table
875
- const { getDatabase } = await import("swarm-mail");
876
- const db = await getDatabase(args.project_key);
877
- const now = Date.now();
878
- await db.query(
879
- `INSERT INTO swarm_contexts (id, epic_id, bead_id, strategy, files, dependencies, directives, recovery, created_at, updated_at)
880
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
881
- ON CONFLICT (id) DO UPDATE SET
882
- files = EXCLUDED.files,
883
- recovery = EXCLUDED.recovery,
884
- updated_at = EXCLUDED.updated_at`,
885
- [
886
- args.bead_id,
887
- epicId,
888
- args.bead_id,
889
- checkpoint.strategy,
890
- JSON.stringify(checkpoint.files),
891
- JSON.stringify(checkpoint.dependencies),
892
- JSON.stringify(checkpoint.directives),
893
- JSON.stringify(checkpoint.recovery),
894
- now,
895
- now,
896
- ],
897
- );
874
+ // NOTE: The event handler (handleSwarmCheckpointed in store.ts) updates
875
+ // the swarm_contexts table. We follow event sourcing pattern here.
898
876
  checkpointCreated = true;
899
877
  } catch (error) {
900
878
  // Non-fatal - log and continue
@@ -2114,31 +2092,11 @@ export const swarm_checkpoint = tool({
2114
2092
 
2115
2093
  await appendEvent(event, args.project_key);
2116
2094
 
2117
- // Update swarm_contexts table for fast recovery
2118
- const { getDatabase } = await import("swarm-mail");
2119
- const db = await getDatabase(args.project_key);
2095
+ // NOTE: The event handler (handleSwarmCheckpointed in store.ts) updates
2096
+ // the swarm_contexts table. We don't write directly here to follow
2097
+ // event sourcing pattern - single source of truth is the event log.
2120
2098
 
2121
2099
  const now = Date.now();
2122
- await db.query(
2123
- `INSERT INTO swarm_contexts (id, epic_id, bead_id, strategy, files, dependencies, directives, recovery, created_at, updated_at)
2124
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
2125
- ON CONFLICT (id) DO UPDATE SET
2126
- files = EXCLUDED.files,
2127
- recovery = EXCLUDED.recovery,
2128
- updated_at = EXCLUDED.updated_at`,
2129
- [
2130
- args.bead_id, // Use bead_id as unique ID
2131
- args.epic_id,
2132
- args.bead_id,
2133
- checkpoint.strategy,
2134
- JSON.stringify(checkpoint.files),
2135
- JSON.stringify(checkpoint.dependencies),
2136
- JSON.stringify(checkpoint.directives),
2137
- JSON.stringify(checkpoint.recovery),
2138
- now,
2139
- now,
2140
- ],
2141
- );
2142
2100
 
2143
2101
  return JSON.stringify(
2144
2102
  {
@@ -2227,15 +2185,21 @@ export const swarm_recover = tool({
2227
2185
  }
2228
2186
 
2229
2187
  const row = result.rows[0];
2188
+ // PGLite auto-parses JSON columns, so we need to handle both cases
2189
+ const parseIfString = <T>(val: unknown): T =>
2190
+ typeof val === "string" ? JSON.parse(val) : (val as T);
2191
+
2230
2192
  const context: SwarmBeadContext = {
2231
2193
  id: row.id,
2232
2194
  epic_id: row.epic_id,
2233
2195
  bead_id: row.bead_id,
2234
2196
  strategy: row.strategy as SwarmBeadContext["strategy"],
2235
- files: JSON.parse(row.files),
2236
- dependencies: JSON.parse(row.dependencies),
2237
- directives: JSON.parse(row.directives),
2238
- recovery: JSON.parse(row.recovery),
2197
+ files: parseIfString<string[]>(row.files),
2198
+ dependencies: parseIfString<string[]>(row.dependencies),
2199
+ directives: parseIfString<SwarmBeadContext["directives"]>(
2200
+ row.directives,
2201
+ ),
2202
+ recovery: parseIfString<SwarmBeadContext["recovery"]>(row.recovery),
2239
2203
  created_at: row.created_at,
2240
2204
  updated_at: row.updated_at,
2241
2205
  };
@@ -273,13 +273,11 @@ Only modify these files. Need others? Message the coordinator.
273
273
 
274
274
  {error_context}
275
275
 
276
- ## [MANDATORY: SWARM MAIL INITIALIZATION]
276
+ ## [MANDATORY SURVIVAL CHECKLIST]
277
277
 
278
- **CRITICAL: YOU MUST INITIALIZE SWARM MAIL BEFORE DOING ANY WORK.**
278
+ **CRITICAL: Follow this checklist IN ORDER. Each step builds on the previous.**
279
279
 
280
- This is your FIRST step - before reading files, before planning, before ANY other action.
281
-
282
- ### Step 1: Initialize (REQUIRED - DO THIS FIRST)
280
+ ### Step 1: Initialize Coordination (REQUIRED - DO THIS FIRST)
283
281
  \`\`\`
284
282
  swarmmail_init(project_path="{project_path}", task_description="{bead_id}: {subtask_title}")
285
283
  \`\`\`
@@ -292,26 +290,124 @@ swarmmail_init(project_path="{project_path}", task_description="{bead_id}: {subt
292
290
 
293
291
  **If you skip this step, your work will not be tracked and swarm_complete will fail.**
294
292
 
295
- ## [SWARM MAIL USAGE]
293
+ ### Step 2: Query Past Learnings (BEFORE starting work)
294
+ \`\`\`
295
+ semantic-memory_find(query="<keywords from your task>", limit=5)
296
+ \`\`\`
296
297
 
297
- After initialization, use Swarm Mail for coordination:
298
+ **Check if past agents solved similar problems.** Search for:
299
+ - Error messages if debugging
300
+ - Domain concepts (e.g., "authentication", "caching")
301
+ - Technology stack (e.g., "Next.js", "React")
302
+ - Patterns (e.g., "event sourcing", "validation")
298
303
 
299
- ### Check Inbox Regularly
304
+ **Past learnings save time and prevent repeating mistakes.**
305
+
306
+ ### Step 3: Load Relevant Skills (if available)
300
307
  \`\`\`
301
- swarmmail_inbox() # Check for coordinator messages
302
- swarmmail_read_message(message_id=N) # Read specific message
308
+ skills_list() # See what skills exist
309
+ skills_use(name="<relevant-skill>", context="<your task>") # Load skill
303
310
  \`\`\`
304
311
 
305
- ### Report Progress (REQUIRED - don't work silently)
312
+ **Common skill triggers:**
313
+ - Writing tests? → \`skills_use(name="testing-patterns")\`
314
+ - Breaking dependencies? → \`skills_use(name="testing-patterns")\`
315
+ - Multi-agent coordination? → \`skills_use(name="swarm-coordination")\`
316
+ - Building a CLI? → \`skills_use(name="cli-builder")\`
317
+
318
+ ### Step 4: Reserve Your Files (YOU reserve, not coordinator)
306
319
  \`\`\`
307
- swarmmail_send(
308
- to=["coordinator"],
309
- subject="Progress: {bead_id}",
310
- body="<what you did, blockers, questions>",
311
- thread_id="{epic_id}"
320
+ swarmmail_reserve(
321
+ paths=[{file_list}],
322
+ reason="{bead_id}: {subtask_title}",
323
+ exclusive=true
324
+ )
325
+ \`\`\`
326
+
327
+ **Workers reserve their own files.** This prevents edit conflicts with other agents.
328
+
329
+ ### Step 5: Do the Work
330
+ - Read your assigned files
331
+ - Implement changes
332
+ - Verify (typecheck if applicable)
333
+
334
+ ### Step 6: Report Progress at Milestones
335
+ \`\`\`
336
+ swarm_progress(
337
+ project_key="{project_path}",
338
+ agent_name="<your-agent-name>",
339
+ bead_id="{bead_id}",
340
+ status="in_progress",
341
+ progress_percent=25, # or 50, 75
342
+ message="<what you just completed>"
312
343
  )
313
344
  \`\`\`
314
345
 
346
+ **Report at 25%, 50%, 75% completion.** This:
347
+ - Triggers auto-checkpoint (saves context)
348
+ - Keeps coordinator informed
349
+ - Prevents silent failures
350
+
351
+ ### Step 7: Manual Checkpoint BEFORE Risky Operations
352
+ \`\`\`
353
+ swarm_checkpoint(
354
+ project_key="{project_path}",
355
+ agent_name="<your-agent-name>",
356
+ bead_id="{bead_id}"
357
+ )
358
+ \`\`\`
359
+
360
+ **Call BEFORE:**
361
+ - Large refactors
362
+ - File deletions
363
+ - Breaking API changes
364
+ - Anything that might fail catastrophically
365
+
366
+ **Checkpoints preserve context so you can recover if things go wrong.**
367
+
368
+ ### Step 8: Store Learnings (if you discovered something)
369
+ \`\`\`
370
+ semantic-memory_store(
371
+ information="<what you learned, WHY it matters, how to apply it>",
372
+ metadata="<tags: domain, tech-stack, pattern-type>"
373
+ )
374
+ \`\`\`
375
+
376
+ **Store:**
377
+ - Tricky bugs you solved (root cause + solution)
378
+ - Project-specific patterns or domain rules
379
+ - Tool/library gotchas and workarounds
380
+ - Failed approaches (anti-patterns to avoid)
381
+
382
+ **Don't store generic knowledge.** Store the WHY, not just the WHAT.
383
+
384
+ ### Step 9: Complete (REQUIRED - releases reservations)
385
+ \`\`\`
386
+ swarm_complete(
387
+ project_key="{project_path}",
388
+ agent_name="<your-agent-name>",
389
+ bead_id="{bead_id}",
390
+ summary="<what you accomplished>",
391
+ files_touched=["list", "of", "files"]
392
+ )
393
+ \`\`\`
394
+
395
+ **This automatically:**
396
+ - Runs UBS bug scan
397
+ - Releases file reservations
398
+ - Records learning signals
399
+ - Notifies coordinator
400
+
401
+ **DO NOT manually close the bead with beads_close.** Use swarm_complete.
402
+
403
+ ## [SWARM MAIL COMMUNICATION]
404
+
405
+ ### Check Inbox Regularly
406
+ \`\`\`
407
+ swarmmail_inbox() # Check for coordinator messages
408
+ swarmmail_read_message(message_id=N) # Read specific message
409
+ \`\`\`
410
+
315
411
  ### When Blocked
316
412
  \`\`\`
317
413
  swarmmail_send(
@@ -324,42 +420,48 @@ swarmmail_send(
324
420
  beads_update(id="{bead_id}", status="blocked")
325
421
  \`\`\`
326
422
 
327
- ### Release Files When Done
423
+ ### Report Issues to Other Agents
424
+ \`\`\`
425
+ swarmmail_send(
426
+ to=["OtherAgent", "coordinator"],
427
+ subject="Issue in {bead_id}",
428
+ body="<describe problem, don't fix their code>",
429
+ thread_id="{epic_id}"
430
+ )
431
+ \`\`\`
432
+
433
+ ### Manual Release (if needed)
328
434
  \`\`\`
329
- swarmmail_release() # Or let swarm_complete handle it
435
+ swarmmail_release() # Manually release reservations
330
436
  \`\`\`
331
437
 
438
+ **Note:** \`swarm_complete\` automatically releases reservations. Only use manual release if aborting work.
439
+
332
440
  ## [OTHER TOOLS]
333
441
  ### Beads
334
442
  - beads_update(id, status) - Mark blocked if stuck
335
443
  - beads_create(title, type) - Log new bugs found
336
444
 
337
- ### Skills (if available)
445
+ ### Skills
338
446
  - skills_list() - Discover available skills
339
447
  - skills_use(name) - Activate skill for specialized guidance
340
-
341
- ### Completion (REQUIRED)
342
- - swarm_complete(project_key, agent_name, bead_id, summary, files_touched)
343
-
344
- ## [LEARNING]
345
- As you work, note reusable patterns, best practices, or domain insights:
346
- - If you discover something that would help future agents, consider creating a skill
347
- - Use skills_create to codify patterns for the project
348
- - Good skills have clear "when to use" descriptions with actionable instructions
349
- - Skills make swarms smarter over time
350
-
351
- ## [WORKFLOW]
352
- 1. **swarmmail_init** - Initialize session (MANDATORY FIRST STEP)
353
- 2. Read assigned files
354
- 3. Implement changes
355
- 4. **swarmmail_send** - Report progress to coordinator
356
- 5. Verify (typecheck)
357
- 6. **swarm_complete** - Mark done, release reservations
358
-
359
- **CRITICAL REQUIREMENTS:**
360
- - Step 1 (swarmmail_init) is NON-NEGOTIABLE - do it before anything else
361
- - Never work silently - send progress updates via swarmmail_send every significant milestone
362
- - If you complete without initializing, swarm_complete will detect this and warn/fail
448
+ - skills_create(name) - Create new skill (if you found a reusable pattern)
449
+
450
+ ## [CRITICAL REQUIREMENTS]
451
+
452
+ **NON-NEGOTIABLE:**
453
+ 1. Step 1 (swarmmail_init) MUST be first - do it before anything else
454
+ 2. Step 2 (semantic-memory_find) MUST happen before starting work
455
+ 3. Step 4 (swarmmail_reserve) - YOU reserve files, not coordinator
456
+ 4. Step 6 (swarm_progress) - Report at milestones, don't work silently
457
+ 5. Step 9 (swarm_complete) - Use this to close, NOT beads_close
458
+
459
+ **If you skip these steps:**
460
+ - Your work won't be tracked (swarm_complete will fail)
461
+ - You'll waste time repeating solved problems (no semantic memory query)
462
+ - Edit conflicts with other agents (no file reservation)
463
+ - Lost work if you crash (no checkpoints)
464
+ - Future agents repeat your mistakes (no learnings stored)
363
465
 
364
466
  Begin now.`;
365
467