iriai-build 0.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 (80) hide show
  1. package/bin/iriai-build.js +78 -0
  2. package/bridge-v3.js +98 -0
  3. package/cli/bootstrap.js +83 -0
  4. package/cli/commands/implementation.js +64 -0
  5. package/cli/commands/index.js +46 -0
  6. package/cli/commands/launch.js +153 -0
  7. package/cli/commands/plan.js +117 -0
  8. package/cli/commands/setup.js +80 -0
  9. package/cli/commands/slack.js +97 -0
  10. package/cli/commands/transfer.js +111 -0
  11. package/cli/config.js +92 -0
  12. package/cli/display.js +121 -0
  13. package/cli/terminal-input.js +666 -0
  14. package/cli/wait.js +82 -0
  15. package/index.js +1488 -0
  16. package/lib/agent-process.js +170 -0
  17. package/lib/bridge-state.js +126 -0
  18. package/lib/constants.js +137 -0
  19. package/lib/health-monitor.js +113 -0
  20. package/lib/prompt-builder.js +565 -0
  21. package/lib/signal-watcher.js +215 -0
  22. package/lib/slack-helpers.js +224 -0
  23. package/lib/state-machines/feature-lead.js +408 -0
  24. package/lib/state-machines/operator-agent.js +173 -0
  25. package/lib/state-machines/planning-role.js +161 -0
  26. package/lib/state-machines/role-agent.js +186 -0
  27. package/lib/state-machines/team-orchestrator.js +160 -0
  28. package/package.json +31 -0
  29. package/v3/.handover-html-evidence.md +35 -0
  30. package/v3/KICKOFF-HTML-EVIDENCE.md +98 -0
  31. package/v3/PLAN-HTML-EVIDENCE-HARDENING.md +603 -0
  32. package/v3/adapters/desktop-adapter.js +78 -0
  33. package/v3/adapters/interface.js +146 -0
  34. package/v3/adapters/slack-adapter.js +608 -0
  35. package/v3/adapters/slack-helpers.js +179 -0
  36. package/v3/adapters/terminal-adapter.js +249 -0
  37. package/v3/agent-supervisor.js +320 -0
  38. package/v3/artifact-portal.js +1184 -0
  39. package/v3/bridge.db +0 -0
  40. package/v3/constants.js +170 -0
  41. package/v3/db.js +76 -0
  42. package/v3/file-io.js +216 -0
  43. package/v3/helpers.js +174 -0
  44. package/v3/operator.js +364 -0
  45. package/v3/orchestrator.js +2886 -0
  46. package/v3/plan-compiler.js +440 -0
  47. package/v3/prompt-builder.js +849 -0
  48. package/v3/queries.js +461 -0
  49. package/v3/recovery.js +508 -0
  50. package/v3/review-sessions.js +360 -0
  51. package/v3/roles/accessibility-auditor/CLAUDE.md +50 -0
  52. package/v3/roles/analytics-engineer/CLAUDE.md +40 -0
  53. package/v3/roles/architect/CLAUDE.md +809 -0
  54. package/v3/roles/backend-implementer/CLAUDE.md +97 -0
  55. package/v3/roles/code-reviewer/CLAUDE.md +89 -0
  56. package/v3/roles/database-implementer/CLAUDE.md +97 -0
  57. package/v3/roles/deployer/CLAUDE.md +42 -0
  58. package/v3/roles/designer/CLAUDE.md +386 -0
  59. package/v3/roles/documentation/CLAUDE.md +40 -0
  60. package/v3/roles/feature-lead/CLAUDE.md +233 -0
  61. package/v3/roles/frontend-implementer/CLAUDE.md +97 -0
  62. package/v3/roles/implementer/CLAUDE.md +97 -0
  63. package/v3/roles/integration-tester/CLAUDE.md +174 -0
  64. package/v3/roles/observability-engineer/CLAUDE.md +40 -0
  65. package/v3/roles/operator/CLAUDE.md +322 -0
  66. package/v3/roles/orchestrator/CLAUDE.md +288 -0
  67. package/v3/roles/package-implementer/CLAUDE.md +47 -0
  68. package/v3/roles/performance-analyst/CLAUDE.md +49 -0
  69. package/v3/roles/plan-compiler/CLAUDE.md +163 -0
  70. package/v3/roles/planning-lead/CLAUDE.md +41 -0
  71. package/v3/roles/pm/CLAUDE.md +806 -0
  72. package/v3/roles/regression-tester/CLAUDE.md +135 -0
  73. package/v3/roles/release-manager/CLAUDE.md +43 -0
  74. package/v3/roles/security-auditor/CLAUDE.md +90 -0
  75. package/v3/roles/smoke-tester/CLAUDE.md +97 -0
  76. package/v3/roles/test-author/CLAUDE.md +42 -0
  77. package/v3/roles/verifier/CLAUDE.md +90 -0
  78. package/v3/schema.sql +134 -0
  79. package/v3/slack-adapter.js +510 -0
  80. package/v3/slack-helpers.js +346 -0
@@ -0,0 +1,565 @@
1
+ // prompt-builder.js — All prompt templates ported from bash heredocs to JS.
2
+ // Source mappings:
3
+ // buildOperatorPrompt ← run-operator.sh L133-160
4
+ // buildRolePrompt ← run-role.sh L232-255
5
+ // buildOrchestratorPrompt ← run-team.sh L293-322
6
+ // buildPlanningRolePrompt ← run-planning-role.sh L158-198
7
+ // buildFeatureLeadInitPrompt ← run-feature-lead.sh L682-701
8
+ // buildFeatureLeadTriggerPrompt ← run-feature-lead.sh L920-1016
9
+
10
+ import { IRIAI_TEAM_DIR, IMPL_BASE } from "./constants.js";
11
+
12
+ // ─── Operator ────────────────────────────────────────────────────────────────
13
+
14
+ export function buildOperatorPrompt({ featureName, operatorDir, flDir, featureDir, history, userMessage }) {
15
+ return `You are the Operator for feature '${featureName}'.
16
+
17
+ ## Your Signal Directory
18
+ OPERATOR_DIR=${operatorDir}
19
+
20
+ ## Feature Lead Directory
21
+ FL_DIR=${flDir}
22
+
23
+ ## Feature Signal Tree Root
24
+ FEATURE_DIR=${featureDir}
25
+
26
+ ## Implementation Signal Base
27
+ IMPL_SIGNAL_BASE=${IMPL_BASE}
28
+
29
+ ## iriai-team Directory
30
+ IRIAI_TEAM_DIR=${IRIAI_TEAM_DIR}
31
+
32
+ ## Conversation History
33
+ ${history || "(no prior conversation)"}
34
+
35
+ ## Current Message
36
+ ${userMessage}
37
+
38
+ ---
39
+
40
+ Read your CLAUDE.md at ${operatorDir}/CLAUDE.md for your full role definition and capabilities.
41
+
42
+ Handle the user's current message above. You have the conversation history for context — refer to it to maintain continuity. Write your response to ${operatorDir}/.agent-response and exit.
43
+
44
+ To include file attachments (screenshots, GIFs, logs) in your Slack response, embed markers in your .agent-response text:
45
+ [gif:/absolute/path/to/file.gif]
46
+ The bridge will upload each file as a Slack attachment in the same thread.`;
47
+ }
48
+
49
+ // ─── Role Agent ──────────────────────────────────────────────────────────────
50
+
51
+ export function buildRolePrompt({ role, signalDir, task, recoveryContext }) {
52
+ let recovery = "";
53
+ if (recoveryContext?.type === "handover") {
54
+ recovery = `
55
+ ---
56
+ CONTEXT HANDOVER: Your previous session ran low on context and wrote a structured handover.
57
+ Read the handover below carefully — it contains your completed work, current state, and remaining tasks.
58
+ Pick up EXACTLY where the previous session left off. Do NOT redo completed work.
59
+ ---
60
+
61
+ HANDOVER FROM PREVIOUS SESSION:
62
+ ${recoveryContext.content}
63
+
64
+ ---
65
+ END OF HANDOVER
66
+ `;
67
+ } else if (recoveryContext?.type === "crash") {
68
+ recovery = `
69
+ ---
70
+ RECOVERY (retry ${recoveryContext.retryCount}): Your previous session crashed, possibly from context exhaustion.
71
+ Before starting work, check the current state of any files you would modify — some changes
72
+ may already be done. Use git status and git diff to see what has changed. Do NOT redo completed
73
+ work. Pick up from where the previous session left off.
74
+ ---
75
+
76
+ `;
77
+ }
78
+
79
+ return `You are the ${role}. Read your instructions at ${signalDir}/CLAUDE.md FIRST before starting any work.
80
+ ${recovery}
81
+ Your task is below. If it has YAML frontmatter (between --- delimiters), read ALL fields before starting work. Pay special attention to:
82
+ - scope.modify: ONLY modify these files
83
+ - acceptance.user_criteria: this defines 'done'
84
+ - counterexamples: do NOT do these things
85
+ - context_files: read these FIRST
86
+
87
+ ${task}
88
+
89
+ ---
90
+ IMPORTANT — OUTPUT AND COMPLETION:
91
+ 1. When your work is complete, write a summary to your output file. Use structured YAML frontmatter if your CLAUDE.md specifies it:
92
+ \`\`\`bash
93
+ cat > ${signalDir}/.output << 'OUTPUT_EOF'
94
+ <your structured output here — see CLAUDE.md for format>
95
+ OUTPUT_EOF
96
+ \`\`\`
97
+ 2. Do NOT write to HANDOVER.md — the orchestrator will consolidate all role outputs.
98
+ 3. Then signal completion as your very last action:
99
+ \`\`\`bash
100
+ echo DONE > ${signalDir}/.done
101
+ \`\`\`
102
+ Do NOT forget the .done signal. The orchestrator is waiting for it.`;
103
+ }
104
+
105
+ // ─── Team Orchestrator ───────────────────────────────────────────────────────
106
+
107
+ export function buildOrchestratorPrompt({ teamDir, orchDir, task, recoveryContext }) {
108
+ let recovery = "";
109
+ if (recoveryContext) {
110
+ recovery = `
111
+ ---
112
+ RECOVERY (retry ${recoveryContext.retryCount}): Your previous session crashed, possibly from context exhaustion.
113
+ Before re-dispatching roles, check the current state:
114
+ - Read ${teamDir}/HANDOVER.md to understand what roles have already completed
115
+ - Read ${teamDir}/STEP-SUMMARY.md if it exists for step progress
116
+ - Check each role's signal dir for .done files — roles that already finished do NOT need re-dispatch
117
+ - Use git status and git diff in your worktree to see what code changes exist
118
+ Do NOT redo completed work. Only dispatch roles for remaining uncompleted steps.
119
+ ---
120
+ `;
121
+ }
122
+
123
+ return `You are a Team Orchestrator. Read your instructions at ${orchDir}/CLAUDE.md FIRST.
124
+
125
+ CRITICAL: You are a DISPATCHER. You must NEVER write code, edit source files, run tests, or fix bugs yourself. ALL implementation work is done by your role agents via .task files. If something needs fixing, re-dispatch the appropriate role — do NOT do it yourself.
126
+
127
+ Read your team config at ${teamDir}/.team-config to see which roles are available.
128
+ Read ${teamDir}/GATE-CONTEXT.md for your team's assignment and cross-team context.
129
+ ${recovery}
130
+ CRITICAL — SIGNAL FILE PATHS: Your signal directory is ${teamDir} (NOT your working directory).
131
+ Use these ABSOLUTE paths for ALL signal files:
132
+ - Dispatch to role: ${teamDir}/roles/<role>/.task
133
+ - Monitor role completion: ${teamDir}/roles/<role>/.done
134
+ - Read role output: ${teamDir}/roles/<role>/.output
135
+ - Gate ready signal: ${orchDir}/.gate-ready
136
+ - Question escalation: ${orchDir}/.question
137
+ - Receive answer: ${orchDir}/.answer
138
+ - HANDOVER.md: ${teamDir}/HANDOVER.md
139
+ - STEP-SUMMARY.md: ${teamDir}/STEP-SUMMARY.md
140
+ Do NOT use relative paths for signal files — your working directory is a worktree, not the signal directory.
141
+
142
+ YOUR ASSIGNMENT:
143
+ ${task}
144
+
145
+ ---
146
+ IMPORTANT — GATE COMPLETION SIGNAL: When ALL steps are complete for this gate and your team's code reviewer has approved, you MUST run this exact command:
147
+ \`\`\`bash
148
+ echo READY > ${orchDir}/.gate-ready
149
+ \`\`\`
150
+ Do NOT proceed beyond this gate's assigned work. The Feature Lead will dispatch your next gate.`;
151
+ }
152
+
153
+ // ─── Planning Role ───────────────────────────────────────────────────────────
154
+
155
+ export function buildPlanningRolePrompt({ task, signalDir, featureSlug }) {
156
+ return `${task}
157
+
158
+ ---
159
+
160
+ SLACK MODE ACTIVE: All user interaction happens via signal files in your working directory.
161
+ You are NOT in an interactive terminal. The user is on Slack.
162
+
163
+ COMMUNICATION PROTOCOL:
164
+ 1. To send a message to the user: write your message to .agent-response
165
+ echo "your message here" > .agent-response
166
+ The Slack bridge will post it to the user's thread and delete the file.
167
+
168
+ 2. To receive a message from the user: poll for .user-message
169
+ while [ ! -f .user-message ]; do sleep 5; done
170
+ Read the content, then delete it:
171
+ MSG=$(cat .user-message) && rm -f .user-message
172
+
173
+ 3. For questions needing user input: write to .agent-response with your question.
174
+ Include numbered options and bold the question. Keep messages under 300 words.
175
+ Then poll for .user-message for the user's reply.
176
+
177
+ 4. When you encounter a clarifying question from another agent or need to raise
178
+ a question yourself, write the FULL question verbatim to .agent-response.
179
+ Include: which role is asking, what phase/task it concerns, the options considered,
180
+ and any recommendation. The bridge will post it to Slack with your role attribution.
181
+
182
+ 5. Format for mobile: the user reads on their phone. Under 300 words per message.
183
+ Use numbered options for choices. Bold key questions.
184
+
185
+ IMPORTANT: After each .agent-response write, wait 2 seconds before polling for
186
+ .user-message to give the bridge time to pick up and delete your response file.
187
+
188
+ Your signal directory: ${signalDir}
189
+ Feature: ${featureSlug || "unknown"}
190
+
191
+ When done, signal completion as usual:
192
+ echo "DONE" > .done
193
+ echo "<summary>" > .output`;
194
+ }
195
+
196
+ // ─── Feature Lead: Shared Prompt Fragments ───────────────────────────────────
197
+
198
+ function buildSlackCommInstructions(featureLeadDir) {
199
+ return `
200
+ ## SLACK MODE ACTIVE
201
+
202
+ All user interaction happens via signal files. You are NOT in an interactive terminal. The user is on Slack (mobile).
203
+
204
+ COMMUNICATION PROTOCOL:
205
+ 1. To send a message to the user: write to ${featureLeadDir}/.agent-response
206
+ \`\`\`bash
207
+ cat > ${featureLeadDir}/.agent-response << 'MSG_EOF'
208
+ Your message here
209
+ MSG_EOF
210
+ \`\`\`
211
+ The Slack bridge posts it to #impl-<slug> and deletes the file.
212
+
213
+ 2. To receive a message from the user: poll for .user-message
214
+ \`\`\`bash
215
+ while [ ! -f ${featureLeadDir}/.user-message ]; do sleep 5; done
216
+ MSG=$(cat ${featureLeadDir}/.user-message) && rm -f ${featureLeadDir}/.user-message
217
+ \`\`\`
218
+
219
+ 3. For questions needing user input: write to .agent-response with your question.
220
+ Include numbered options and bold the question. Then poll for .user-message.
221
+
222
+ 4. Gate approval: write gate evidence to .agent-response. The bridge posts it with
223
+ approval reactions. The user's response arrives as .user-message.
224
+
225
+ 5. Format for mobile: under 300 words per message. Numbered options. Bold key questions.
226
+
227
+ 6. After writing .agent-response, wait 2 seconds before polling for .user-message.
228
+
229
+ 7. On startup, introduce yourself by writing to .agent-response:
230
+ 'Feature Lead online for <feature>. Reading plan and preparing dispatch...'
231
+ `;
232
+ }
233
+
234
+ function buildMonitorInstructions(numTeams, teamSignalBase, featureLeadDir, featureReviewDir) {
235
+ return `
236
+ ## Monitor Teams Until All Are Gate-Ready
237
+
238
+ After dispatching, you MUST stay active and monitor teams continuously. Poll every 75 seconds:
239
+ \`\`\`bash
240
+ # Poll loop — run this repeatedly
241
+ for i in $(seq 1 ${numTeams}); do
242
+ orch="${teamSignalBase}/team-$i/orchestrator"
243
+ [ -f "$orch/.gate-ready" ] && echo "READY: Team $i"
244
+ [ -f "$orch/.question" ] && echo "QUESTION: Team $i"
245
+ [ -f "$orch/.crashed" ] && echo "CRASHED: Team $i"
246
+ done
247
+ # Also check for user messages from Slack
248
+ if [ -f "${featureLeadDir}/.user-message" ]; then
249
+ echo "USER MESSAGE: $(cat ${featureLeadDir}/.user-message)"
250
+ rm -f "${featureLeadDir}/.user-message"
251
+ fi
252
+ \`\`\`
253
+
254
+ While monitoring:
255
+ - When a team signals .gate-ready: narrate it to the user using the GATE-READY format from your CLAUDE.md. Read the team's HANDOVER.md for a summary.
256
+ - When a team has a .question: handle it per the Question Handling section (answer or escalate to user)
257
+ - When a team .crashed: handle per Failure Recovery (read HANDOVER.md, re-dispatch with recovery .task)
258
+ - When a USER MESSAGE appears: read it, respond via .agent-response (status update, answer question, etc.), then continue monitoring
259
+ - Keep polling until ALL ${numTeams} teams have signaled .gate-ready
260
+ - Do NOT exit or signal .phase-done until all teams are ready
261
+
262
+ ### Health Monitor
263
+ If a team has been running for > 20 minutes with no new .done signals from roles, or all roles
264
+ show .done but no .gate-ready appears within 10 minutes, dispatch the health-monitor:
265
+ \`\`\`bash
266
+ cat > ${featureReviewDir}/health-monitor/.task << 'TASK_EOF'
267
+ Run a full health check across all teams.
268
+ Specific concern: [describe what you observe]
269
+ Teams to check: [all / specific team numbers]
270
+ TASK_EOF
271
+ \`\`\`
272
+ Then poll for feature-review/health-monitor/.done, read its .output, and act on recommendations.`;
273
+ }
274
+
275
+ function buildGateReviewInstructions(featureLeadDir, featureReviewDir) {
276
+ return `
277
+ ## Gate Review (once all teams are gate-ready)
278
+
279
+ 1. Read each team's HANDOVER.md and STEP-SUMMARY.md for results
280
+ 2. Push team branches and create PRs (team branch → integration branch) per repo using gh CLI
281
+ 3. Dispatch feature-level review agents by writing .task files (these agents are ALREADY RUNNING
282
+ in their own Zellij panes — do NOT spawn subagents, do NOT use the Task tool, just write the file):
283
+ \`\`\`bash
284
+ # If preview-env.json exists, include it in integration tester task
285
+ PREVIEW_ENV=""
286
+ if [ -f "${featureLeadDir}/preview-env.json" ]; then
287
+ PREVIEW_ENV="Preview environment: ${featureLeadDir}/preview-env.json"
288
+ fi
289
+ cat > ${featureReviewDir}/integration-tester/.task << TASK_EOF
290
+ <your review task here>
291
+ $PREVIEW_ENV
292
+ TASK_EOF
293
+ cat > ${featureReviewDir}/code-reviewer/.task << 'TASK_EOF'
294
+ <your review task here>
295
+ TASK_EOF
296
+ cat > ${featureReviewDir}/security-auditor/.task << 'TASK_EOF'
297
+ <your review task here>
298
+ TASK_EOF
299
+ \`\`\`
300
+ 4. Wait for all feature-review agents to complete (.done files) — poll every 75s:
301
+ \`\`\`bash
302
+ while [ ! -f ${featureReviewDir}/integration-tester/.done ] || \\
303
+ [ ! -f ${featureReviewDir}/code-reviewer/.done ] || \\
304
+ [ ! -f ${featureReviewDir}/security-auditor/.done ]; do
305
+ sleep 75
306
+ done
307
+ \`\`\`
308
+ 5. Read their .output files and synthesize results
309
+ 6. Present a GATE SUMMARY to the user with PR links and review results
310
+ 7. WAIT for the user to approve or reject the gate
311
+ 8. If approved: merge PRs, tag gate checkpoint, update worktrees, clear .gate-ready files
312
+ 9. Update FEATURE-STATUS.md and DASHBOARD.md with gate results
313
+ 10. If this is the FINAL gate: create PRs to main, generate RETROSPECTIVE.md, cleanup, then signal:
314
+ \`\`\`bash
315
+ echo COMPLETE > ${featureLeadDir}/.feature-complete
316
+ \`\`\`
317
+
318
+ IMPORTANT: Do NOT dispatch the next gate yourself. After approval, just merge, clear signals,
319
+ update status files, and signal phase-done. A new session will handle the next gate dispatch.
320
+
321
+ When the gate is approved and merged (or final gate complete):
322
+ \`\`\`bash
323
+ echo GATE_HANDLED > ${featureLeadDir}/.phase-done
324
+ \`\`\``;
325
+ }
326
+
327
+ function buildContextManagementInstructions(featureLeadDir, dashboardLog) {
328
+ return `
329
+ ## Context Management (MANDATORY)
330
+
331
+ You run inside a finite context window with NO automatic compaction. If you exhaust it, you crash —
332
+ and ANY state held only in your conversation memory is PERMANENTLY LOST. You must proactively manage
333
+ your context to ensure you NEVER crash before checkpointing.
334
+
335
+ ### Self-Monitoring
336
+
337
+ Track your context usage by counting major operations. Each of these costs significant context:
338
+ - Reading a file (especially large files like implementation plans or HANDOVER.md)
339
+ - Writing a task file, GATE-CONTEXT.md, or status update
340
+ - Running a bash command and processing its output
341
+ - Each polling iteration that produces output
342
+
343
+ **Thresholds:**
344
+ - After ~40 major tool uses in a single session → strongly consider a context refresh
345
+ - After ~60 major tool uses → you MUST refresh at the next natural boundary
346
+ - If you feel the conversation is getting long or you are losing track of details → refresh immediately
347
+
348
+ ### When to Refresh
349
+
350
+ Trigger a context refresh at any natural boundary:
351
+ - After dispatching a gate (all .task files written, status updated)
352
+ - After completing gate review and getting user approval (after merge + cleanup)
353
+ - After handling 3+ questions or crashes in one session
354
+ - After a long monitoring stretch with many poll cycles
355
+ - Whenever you sense your context is getting heavy — trust your judgment
356
+
357
+ ### Pre-Refresh Checklist (MANDATORY — NEVER SKIP)
358
+
359
+ Before writing the context refresh signal, you MUST update ALL of the following.
360
+ Skipping any of these means permanent data loss:
361
+
362
+ 1. **FEATURE-STATUS.md** — Update with:
363
+ - Current phase and gate number
364
+ - All team statuses (which are ready, working, crashed)
365
+ - Decisions you made this session (question answers, contract changes)
366
+ - What you were doing when you decided to refresh
367
+ - What needs to happen next (explicit next steps for the fresh session)
368
+
369
+ 2. **DASHBOARD.md** — Rebuild with latest team status, gate progress, open questions
370
+
371
+ 3. **.dashboard-log** — Append a refresh event:
372
+ \`\`\`bash
373
+ echo "$(date +%H:%M:%S) | feature-lead | context-refresh" >> ${dashboardLog}
374
+ \`\`\`
375
+
376
+ 4. **GATE-CONTEXT.md (all teams)** — Complete or note which teams still need context
377
+
378
+ 5. **Cross-team contracts** — Record any established/modified contracts in FEATURE-STATUS.md
379
+
380
+ 6. **Open questions** — Verify .answer files written, log decision rationale
381
+
382
+ ### How to Refresh
383
+
384
+ After completing the full checklist above:
385
+ \`\`\`bash
386
+ echo REFRESH > ${featureLeadDir}/.context-refresh
387
+ \`\`\`
388
+
389
+ ### Emergency Refresh
390
+
391
+ If context is critically low:
392
+ 1. Write MINIMAL but complete FEATURE-STATUS.md update
393
+ 2. Signal immediately:
394
+ \`\`\`bash
395
+ echo REFRESH > ${featureLeadDir}/.context-refresh
396
+ \`\`\``;
397
+ }
398
+
399
+ // ─── Feature Lead: Init Prompt ───────────────────────────────────────────────
400
+
401
+ export function buildFeatureLeadInitPrompt({
402
+ featureName, numTeams, teamType, teamSignalBase,
403
+ planReadInstruction, featureLeadDir, featureReviewDir, dashboardLog,
404
+ }) {
405
+ const monitor = buildMonitorInstructions(numTeams, teamSignalBase, featureLeadDir, featureReviewDir);
406
+ const gateReview = buildGateReviewInstructions(featureLeadDir, featureReviewDir);
407
+ const contextMgmt = buildContextManagementInstructions(featureLeadDir, dashboardLog);
408
+ const slackComm = buildSlackCommInstructions(featureLeadDir);
409
+
410
+ return `You are the Feature Lead for '${featureName}' with ${numTeams} teams (type: ${teamType}).
411
+
412
+ Read your instructions at ~/src/iriai/iriai-team/roles-v2/feature-lead/CLAUDE.md.
413
+ Read the feature status at ~/src/iriai/iriai-team/FEATURE-STATUS.md.
414
+ ${planReadInstruction}
415
+
416
+ ## Dispatch Gate 1
417
+
418
+ 1. Read and understand the full implementation plan
419
+ 2. Identify the gate boundaries in the plan
420
+ 3. Partition Gate 1 work across ${numTeams} teams
421
+ 4. Write GATE-CONTEXT.md for each team (at ${teamSignalBase}/team-N/GATE-CONTEXT.md)
422
+ 5. Write team manifests if not present (at ${teamSignalBase}/team-N/manifest.yaml)
423
+ 6. Dispatch to each team orchestrator by writing .task files (at ${teamSignalBase}/team-N/orchestrator/.task)
424
+ 7. Update FEATURE-STATUS.md with gate 1 status
425
+ 8. Update DASHBOARD.md
426
+ ${monitor}
427
+ ${gateReview}
428
+ ${contextMgmt}
429
+ ${slackComm}`;
430
+ }
431
+
432
+ // ─── Feature Lead: Refresh/Continue Prompt ───────────────────────────────────
433
+
434
+ export function buildFeatureLeadRefreshPrompt({
435
+ featureName, numTeams, teamSignalBase,
436
+ planReadInstruction, featureLeadDir, featureReviewDir, dashboardLog,
437
+ gateEvidenceTs,
438
+ }) {
439
+ const monitor = buildMonitorInstructions(numTeams, teamSignalBase, featureLeadDir, featureReviewDir);
440
+ const gateReview = buildGateReviewInstructions(featureLeadDir, featureReviewDir);
441
+ const contextMgmt = buildContextManagementInstructions(featureLeadDir, dashboardLog);
442
+ const slackComm = buildSlackCommInstructions(featureLeadDir);
443
+
444
+ const gateDedup = gateEvidenceTs
445
+ ? `\nIMPORTANT: Gate evidence was ALREADY posted to Slack at timestamp ${gateEvidenceTs}.\nDo NOT re-post gate evidence. You are waiting for the user's GATE APPROVED / GATE REJECTED response\nin the impl channel. Poll for .user-message, do not repost.\n`
446
+ : "";
447
+
448
+ return `You are the Feature Lead for '${featureName}' with ${numTeams} teams.
449
+
450
+ Read your instructions at ~/src/iriai/iriai-team/roles-v2/feature-lead/CLAUDE.md.
451
+
452
+ CONTEXT REFRESH: Your previous session requested a context refresh. All state has been
453
+ persisted to disk. Read these files to restore your state:
454
+
455
+ 1. ~/src/iriai/iriai-team/FEATURE-STATUS.md — your persistent memory (source of truth)
456
+ 2. ~/src/iriai/iriai-team/DASHBOARD.md — current team status
457
+ 3. Each team's GATE-CONTEXT.md at ${teamSignalBase}/team-N/GATE-CONTEXT.md
458
+
459
+ Check FEATURE-STATUS.md for 'what was in progress' and 'next steps' to understand
460
+ exactly where to resume. Do not re-do completed work.
461
+ ${gateDedup}
462
+ ${planReadInstruction}
463
+ ${monitor}
464
+ ${gateReview}
465
+ ${contextMgmt}
466
+ ${slackComm}`;
467
+ }
468
+
469
+ // ─── Feature Lead: Trigger-Based Phase Prompt ────────────────────────────────
470
+
471
+ export function buildFeatureLeadTriggerPrompt({
472
+ featureName, numTeams, trigger, teamSignalBase,
473
+ featureLeadDir, featureReviewDir, dashboardLog,
474
+ questionTeams, crashedTeams, recoveryContext,
475
+ }) {
476
+ const monitor = buildMonitorInstructions(numTeams, teamSignalBase, featureLeadDir, featureReviewDir);
477
+ const gateReview = buildGateReviewInstructions(featureLeadDir, featureReviewDir);
478
+ const contextMgmt = buildContextManagementInstructions(featureLeadDir, dashboardLog);
479
+ const slackComm = buildSlackCommInstructions(featureLeadDir);
480
+
481
+ let base = `You are the Feature Lead for '${featureName}' with ${numTeams} teams.
482
+
483
+ Read your instructions at ~/src/iriai/iriai-team/roles-v2/feature-lead/CLAUDE.md.
484
+ Read the feature status at ~/src/iriai/iriai-team/FEATURE-STATUS.md.
485
+ Read ~/src/iriai/iriai-team/DASHBOARD.md for current state.
486
+ `;
487
+
488
+ if (recoveryContext) {
489
+ base = `RECOVERY: Your prior session crashed during this phase. Resume from where you left off.
490
+ Read ~/src/iriai/iriai-team/FEATURE-STATUS.md for current state.
491
+ Read ~/src/iriai/iriai-team/DASHBOARD.md for team status.
492
+
493
+ ${base}`;
494
+ }
495
+
496
+ switch (trigger) {
497
+ case "gate-ready":
498
+ base += `
499
+ TRIGGER: All ${numTeams} teams have signaled .gate-ready.
500
+ ${gateReview}`;
501
+ break;
502
+
503
+ case "question":
504
+ base += `
505
+ TRIGGER: Teams ${questionTeams.join(", ")} have questions that need resolution.
506
+
507
+ You must:
508
+ 1. Read each questioning team's .question file at ${teamSignalBase}/team-N/orchestrator/.question
509
+ 2. Read FEATURE-STATUS.md for cross-team context
510
+ 3. If you can resolve the question with your cross-team knowledge:
511
+ - Write the answer to ${teamSignalBase}/team-N/orchestrator/.answer
512
+ - Remove the .question file
513
+ 4. If you cannot resolve it: surface it to the user and wait for their response
514
+ - Then write the user's answer to ${teamSignalBase}/team-N/orchestrator/.answer
515
+ - Remove the .question file
516
+ 5. Update FEATURE-STATUS.md and DASHBOARD.md
517
+
518
+ After handling questions, continue monitoring teams:
519
+ ${monitor}
520
+ ${gateReview}`;
521
+ break;
522
+
523
+ case "crash":
524
+ base += `
525
+ TRIGGER: Teams ${crashedTeams.join(", ")} have crashed orchestrators.
526
+
527
+ You must:
528
+ 1. Read the crashed team's HANDOVER.md to understand progress
529
+ 2. Determine what work was completed and what remains
530
+ 3. Write a recovery .task to ${teamSignalBase}/team-N/orchestrator/.task that:
531
+ - References HANDOVER.md for completed work
532
+ - Assigns only the remaining work
533
+ 4. Remove the .crashed file (run-team.sh will detect the new .task)
534
+ 5. If recovery isn't possible, surface the issue to the user
535
+ 6. Update FEATURE-STATUS.md and DASHBOARD.md
536
+
537
+ After handling crashes, continue monitoring teams:
538
+ ${monitor}
539
+ ${gateReview}`;
540
+ break;
541
+
542
+ case "idle-redispatch":
543
+ base += `
544
+ TRIGGER: All ${numTeams} teams are idle — they have no active .task files.
545
+ This typically happens after a session restart (launch.sh continue).
546
+
547
+ ## Re-dispatch Teams
548
+
549
+ 1. Read FEATURE-STATUS.md to understand the current gate and what was dispatched
550
+ 2. Read each team's GATE-CONTEXT.md and HANDOVER.md to understand their assignment and progress
551
+ 3. For each team, write a new .task file to ${teamSignalBase}/team-N/orchestrator/.task
552
+ - If the team has made progress (check HANDOVER.md), assign only remaining work
553
+ - If no progress, re-dispatch the full gate assignment from GATE-CONTEXT.md
554
+ 4. Update FEATURE-STATUS.md and DASHBOARD.md
555
+ ${monitor}
556
+ ${gateReview}`;
557
+ break;
558
+ }
559
+
560
+ base += `
561
+ ${contextMgmt}
562
+ ${slackComm}`;
563
+
564
+ return base;
565
+ }