@monoes/monomindcli 1.9.17 → 1.10.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 (118) hide show
  1. package/.claude/commands/mastermind/_repeat.md +182 -39
  2. package/.claude/commands/mastermind/architect.md +17 -11
  3. package/.claude/commands/mastermind/brain.md +4 -0
  4. package/.claude/commands/mastermind/build.md +4 -0
  5. package/.claude/commands/mastermind/content.md +4 -0
  6. package/.claude/commands/mastermind/createorg.md +5 -3
  7. package/.claude/commands/mastermind/finance.md +4 -0
  8. package/.claude/commands/mastermind/idea.md +4 -0
  9. package/.claude/commands/mastermind/marketing.md +4 -0
  10. package/.claude/commands/mastermind/master.md +63 -37
  11. package/.claude/commands/mastermind/ops.md +4 -0
  12. package/.claude/commands/mastermind/release.md +4 -0
  13. package/.claude/commands/mastermind/research.md +4 -0
  14. package/.claude/commands/mastermind/review.md +4 -0
  15. package/.claude/commands/mastermind/runorg.md +5 -3
  16. package/.claude/commands/mastermind/sales.md +4 -0
  17. package/.claude/commands/mastermind/techport.md +9 -0
  18. package/.claude/commands/monomind/do.md +5 -1
  19. package/.claude/commands/monomind/idea.md +5 -1
  20. package/.claude/commands/monomind/improve.md +5 -1
  21. package/.claude/commands/monomind/repeat.md +85 -29
  22. package/.claude/commands/monomind/review.md +6 -2
  23. package/.claude/commands/monomind/understand.md +10 -8
  24. package/.claude/helpers/extras-registry.json +235 -235
  25. package/.claude/helpers/graphify-freshen.cjs +13 -1
  26. package/.claude/helpers/hook-handler.cjs +1 -1
  27. package/.claude/helpers/router.cjs +4 -1
  28. package/.claude/skills/mastermind/_protocol.md +28 -21
  29. package/.claude/skills/mastermind/access.md +236 -0
  30. package/.claude/skills/mastermind/activity.md +191 -0
  31. package/.claude/skills/mastermind/adapter-manager.md +259 -0
  32. package/.claude/skills/mastermind/adapters.md +204 -0
  33. package/.claude/skills/mastermind/agent-detail.md +242 -0
  34. package/.claude/skills/mastermind/agents.md +178 -0
  35. package/.claude/skills/mastermind/approval-detail.md +259 -0
  36. package/.claude/skills/mastermind/approve.md +181 -0
  37. package/.claude/skills/mastermind/architect.md +24 -8
  38. package/.claude/skills/mastermind/backup.md +197 -0
  39. package/.claude/skills/mastermind/bootstrap.md +190 -0
  40. package/.claude/skills/mastermind/budgets.md +237 -0
  41. package/.claude/skills/mastermind/companies.md +256 -0
  42. package/.claude/skills/mastermind/costs.md +151 -0
  43. package/.claude/skills/mastermind/createorg.md +23 -5
  44. package/.claude/skills/mastermind/diagnose.md +249 -0
  45. package/.claude/skills/mastermind/env.md +198 -0
  46. package/.claude/skills/mastermind/environments.md +250 -0
  47. package/.claude/skills/mastermind/export.md +324 -0
  48. package/.claude/skills/mastermind/goal-detail.md +255 -0
  49. package/.claude/skills/mastermind/goals.md +149 -0
  50. package/.claude/skills/mastermind/heartbeat.md +164 -0
  51. package/.claude/skills/mastermind/idea.md +250 -122
  52. package/.claude/skills/mastermind/import.md +281 -0
  53. package/.claude/skills/mastermind/inbox.md +214 -0
  54. package/.claude/skills/mastermind/instance-settings.md +315 -0
  55. package/.claude/skills/mastermind/instance.md +231 -0
  56. package/.claude/skills/mastermind/invite-landing.md +227 -0
  57. package/.claude/skills/mastermind/invites.md +254 -0
  58. package/.claude/skills/mastermind/issue-detail.md +291 -0
  59. package/.claude/skills/mastermind/issues.md +235 -0
  60. package/.claude/skills/mastermind/join-queue.md +170 -0
  61. package/.claude/skills/mastermind/liveness.md +392 -0
  62. package/.claude/skills/mastermind/memory.md +321 -0
  63. package/.claude/skills/mastermind/my-issues.md +146 -0
  64. package/.claude/skills/mastermind/new-agent.md +241 -0
  65. package/.claude/skills/mastermind/org-chart.md +207 -0
  66. package/.claude/skills/mastermind/org-settings.md +217 -0
  67. package/.claude/skills/mastermind/plan-to-tasks.md +136 -0
  68. package/.claude/skills/mastermind/plugin-manager.md +241 -0
  69. package/.claude/skills/mastermind/plugin-settings.md +273 -0
  70. package/.claude/skills/mastermind/plugins.md +190 -0
  71. package/.claude/skills/mastermind/profile.md +187 -0
  72. package/.claude/skills/mastermind/project-detail.md +249 -0
  73. package/.claude/skills/mastermind/project-workspace.md +244 -0
  74. package/.claude/skills/mastermind/projects.md +164 -0
  75. package/.claude/skills/mastermind/routine-detail.md +253 -0
  76. package/.claude/skills/mastermind/routines.md +202 -0
  77. package/.claude/skills/mastermind/runorg.md +74 -9
  78. package/.claude/skills/mastermind/search.md +186 -0
  79. package/.claude/skills/mastermind/secrets.md +199 -0
  80. package/.claude/skills/mastermind/skills.md +156 -0
  81. package/.claude/skills/mastermind/tasks.md +149 -0
  82. package/.claude/skills/mastermind/techport.md +5 -5
  83. package/.claude/skills/mastermind/threads.md +259 -0
  84. package/.claude/skills/mastermind/tree-control.md +250 -0
  85. package/.claude/skills/mastermind/wiki.md +314 -0
  86. package/.claude/skills/mastermind/workspace-detail.md +317 -0
  87. package/.claude/skills/mastermind/workspaces.md +261 -0
  88. package/.claude/skills/mastermind/worktree.md +187 -0
  89. package/dist/src/init/executor.js +8 -8
  90. package/dist/src/init/executor.js.map +1 -1
  91. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  92. package/dist/src/init/statusline-generator.js +12 -0
  93. package/dist/src/init/statusline-generator.js.map +1 -1
  94. package/dist/src/ui/.monomind/data/ranked-context.json +1 -1
  95. package/dist/src/ui/.monomind/loops/mastermind-review-1778664132789.json +16 -0
  96. package/dist/src/ui/.monomind/sessions/current.json +5 -5
  97. package/dist/src/ui/.monomind/sessions/session-1776778451399.json +15 -0
  98. package/dist/src/ui/dashboard.html +3030 -181
  99. package/dist/src/ui/data/mastermind-events.jsonl +8 -0
  100. package/dist/src/ui/data/mastermind-sessions.json +1 -0
  101. package/dist/src/ui/server.mjs +738 -0
  102. package/dist/tsconfig.tsbuildinfo +1 -1
  103. package/package.json +1 -1
  104. package/.claude/skills/.monomind/data/ranked-context.json +0 -5
  105. package/.claude/skills/.monomind/sessions/current.json +0 -13
  106. package/.claude/skills/.monomind/sessions/session-1777829336455.json +0 -15
  107. package/.claude/skills/.monomind/sessions/session-1777831614725.json +0 -15
  108. package/.claude/skills/.monomind/sessions/session-1777832095857.json +0 -15
  109. package/.claude/skills/.monomind/sessions/session-1777839814183.json +0 -15
  110. package/.claude/skills/.monomind/sessions/session-1777841847131.json +0 -15
  111. package/.claude/skills/.monomind/sessions/session-1777843309463.json +0 -15
  112. package/.claude/skills/.monomind/sessions/session-1777880867159.json +0 -15
  113. package/.claude/skills/.monomind/sessions/session-1777881884593.json +0 -15
  114. package/.claude/skills/.monomind/sessions/session-1777884090471.json +0 -15
  115. package/.claude/skills/.monomind/sessions/session-1777884808221.json +0 -15
  116. package/.claude/skills/.monomind/sessions/session-1777885672155.json +0 -15
  117. package/.claude/skills/.monomind/sessions/session-1777886852818.json +0 -15
  118. package/.claude/skills/.monomind/sessions/session-1777896532690.json +0 -15
@@ -80,7 +80,8 @@ space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);g
80
80
  [ -z "$space_id" ] && { echo "ERROR: Could not find or create space '$project_name'"; exit 1; }
81
81
 
82
82
  # Find existing idea board by canonical name — reuse across runs (same pattern as master Step 6)
83
- BOARD_ID=$(monotask board list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$idea_canonical" | head -1)
83
+ # board list format is "uuid: name" (colon-space separator, NOT pipe)
84
+ BOARD_ID=$(monotask board list 2>/dev/null | awk -F': ' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$idea_canonical" | head -1)
84
85
 
85
86
  if [ -n "$BOARD_ID" ]; then
86
87
  echo "Reusing idea board: $BOARD_ID ($idea_canonical)"
@@ -102,18 +103,26 @@ else
102
103
  BOARD_ID=$(monotask board create --space "$space_id" "$idea_canonical" --json 2>/dev/null | jq -r '.id // empty')
103
104
  [ -z "$BOARD_ID" ] && { echo "ERROR: Failed to create idea board '$idea_canonical'"; exit 1; }
104
105
  monotask space boards add "$space_id" "$BOARD_ID" >/dev/null 2>&1 || true
105
- COL_NEW=$(monotask column create "$BOARD_ID" "New" --json | jq -r '.id')
106
- COL_EVALUATED=$(monotask column create "$BOARD_ID" "Evaluated" --json | jq -r '.id')
107
- COL_ELABORATED=$(monotask column create "$BOARD_ID" "Elaborated" --json | jq -r '.id')
108
- COL_TASKED=$(monotask column create "$BOARD_ID" "Tasked" --json | jq -r '.id')
109
- COL_ICED=$(monotask column create "$BOARD_ID" "Iced" --json | jq -r '.id')
110
- COL_REJECTED=$(monotask column create "$BOARD_ID" "Rejected" --json | jq -r '.id')
106
+ COL_NEW=$(monotask column create "$BOARD_ID" "New" --json | jq -r '.id // empty')
107
+ COL_EVALUATED=$(monotask column create "$BOARD_ID" "Evaluated" --json | jq -r '.id // empty')
108
+ COL_ELABORATED=$(monotask column create "$BOARD_ID" "Elaborated" --json | jq -r '.id // empty')
109
+ COL_TASKED=$(monotask column create "$BOARD_ID" "Tasked" --json | jq -r '.id // empty')
110
+ COL_ICED=$(monotask column create "$BOARD_ID" "Iced" --json | jq -r '.id // empty')
111
+ COL_REJECTED=$(monotask column create "$BOARD_ID" "Rejected" --json | jq -r '.id // empty')
111
112
  fi
112
113
  ```
113
114
 
114
115
  **After either branch above, validate and echo all values.** This is the canonical source for Step 4 Task construction.
115
116
 
116
117
  ```bash
118
+ # Guard all column IDs — catches silent jq failures in the create branch
119
+ [ -z "$COL_NEW" ] && { echo "ERROR: COL_NEW empty after board setup"; exit 1; }
120
+ [ -z "$COL_EVALUATED" ] && { echo "ERROR: COL_EVALUATED empty after board setup"; exit 1; }
121
+ [ -z "$COL_ELABORATED" ] && { echo "ERROR: COL_ELABORATED empty after board setup"; exit 1; }
122
+ [ -z "$COL_TASKED" ] && { echo "ERROR: COL_TASKED empty after board setup"; exit 1; }
123
+ [ -z "$COL_ICED" ] && { echo "ERROR: COL_ICED empty after board setup"; exit 1; }
124
+ [ -z "$COL_REJECTED" ] && { echo "ERROR: COL_REJECTED empty after board setup"; exit 1; }
125
+
117
126
  # Validate BOARD_ID looks like a UUID before proceeding
118
127
  [[ ! "$BOARD_ID" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]] && \
119
128
  { echo "ERROR: BOARD_ID '$BOARD_ID' is not a valid UUID — aborting to prevent board name corruption"; exit 1; }
@@ -144,20 +153,26 @@ TOP_N=6
144
153
 
145
154
  # Select user/market/ops angle specialists
146
155
  CATEGORIES="marketing strategy product academic specialized"
147
- user_market_agents=$(jq -r \
156
+ user_market_agents=$(jq \
148
157
  --arg cats "$CATEGORIES" \
149
158
  --arg kw "$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]' | grep -oE '[a-z]{5,}' | sort -u | tr '\n' ' ')" \
150
159
  --argjson n "$TOP_N" \
151
160
  '[ .agents[] | select(.deprecated != true)
152
161
  | select(.category as $c | ($cats | split(" ") | any(. == $c)))
153
162
  | {name: .name, slug: .slug, category: .category,
154
- score: (.name | ascii_downcase | if contains($kw | split(" ") | .[0]) then 2 else 0 end)}
163
+ score: (
164
+ (.name | ascii_downcase) as $n |
165
+ # Score on ANY keyword match (mirrors master.md pick_domain_manager scoring)
166
+ (if ($kw | length) > 0
167
+ then ([$kw | split(" ")[] | select(length > 0) | if ($n | contains(.)) then 1 else 0 end] | add // 0)
168
+ else 0 end)
169
+ )}
155
170
  ] | sort_by(-.score) | unique_by(.slug) | .[0:$n] | [.[].name]' \
156
171
  "$REGISTRY" 2>/dev/null)
157
172
 
158
173
  # Select technical angle specialists
159
174
  CATEGORIES="engineering development architecture"
160
- tech_agents=$(jq -r \
175
+ tech_agents=$(jq \
161
176
  --arg cats "$CATEGORIES" \
162
177
  --argjson n 3 \
163
178
  '[ .agents[] | select(.deprecated != true)
@@ -167,11 +182,14 @@ tech_agents=$(jq -r \
167
182
  "$REGISTRY" 2>/dev/null)
168
183
 
169
184
  # Merge: take top 6 from market/ops + top 2 from tech (cap at 8 total)
170
- specialist_list=$(echo "$user_market_agents $tech_agents" | jq -Rs \
171
- 'split("\n") | map(select(length>0)) | unique | .[0:8]' 2>/dev/null)
185
+ # Both variables hold JSON arrays (no -r flag) use jq -s add to merge properly
186
+ specialist_list=$(jq -s 'add // [] | unique | .[0:8]' \
187
+ <(printf '%s' "$user_market_agents") \
188
+ <(printf '%s' "$tech_agents") 2>/dev/null)
172
189
 
173
- # Fallback if registry missing
174
- [ -z "$specialist_list" ] && specialist_list='["researcher","Trend Researcher","Growth Hacker","UX Researcher","Content Creator","Account Strategist"]'
190
+ # Fallback if registry missing or returned an empty array — need at least 2 specialists
191
+ specialist_count=$(echo "$specialist_list" | jq 'length // 0' 2>/dev/null || echo 0)
192
+ [ "$specialist_count" -lt 2 ] && specialist_list='["researcher","Trend Researcher","Growth Hacker","UX Researcher","Content Creator","Account Strategist"]'
175
193
 
176
194
  echo "Selected specialists: $specialist_list"
177
195
  ```
@@ -246,6 +264,7 @@ For each unique idea, create one card in the New column (COL_NEW = ${COL_NEW}):
246
264
 
247
265
  result=$(monotask card create "${BOARD_ID}" "${COL_NEW}" "<idea title ≤80 chars>" --json)
248
266
  CARD_ID=$(echo "$result" | jq -r '.id // empty')
267
+ [ -z "$CARD_ID" ] && { echo "WARN: card creation failed for '<idea title>', skipping"; continue; }
249
268
  monotask card set-description "${BOARD_ID}" "$CARD_ID" "<2-3 sentence description>"
250
269
  monotask card comment add "${BOARD_ID}" "$CARD_ID" "CATEGORY: <feature | technical-baseline | business-operation>
251
270
  SOURCE: <which specialist angle produced this>"
@@ -272,7 +291,8 @@ Parse the `IDEAS_OUTPUT` JSON block from the agent's response and assign it:
272
291
  ```bash
273
292
  ideas_output_json='<paste the JSON array from IDEAS_OUTPUT here>'
274
293
  ```
275
- If zero ideas were returned, report "Idea Manager produced no ideas." and STOP.
294
+ If the `IDEAS_OUTPUT` block is absent from the agent's response (agent error, timeout, or unrecoverable failure), set `ideas_output_json='[]'` and treat as zero ideas.
295
+ If zero ideas were returned, report "Idea Manager produced no ideas." — skip Steps 5–6 and proceed to Step 7 (Brain Write).
276
296
 
277
297
  ---
278
298
 
@@ -289,11 +309,11 @@ ideas_list=$(echo "$ideas_output_json" | jq -r \
289
309
  **CRITICAL — Variable substitution required for Step 5 Task call:**
290
310
  Before constructing the Task prompt below, read the literal UUID values from the `=== IDEA BOARD LITERAL VALUES ===` echo block (Step 3) and embed them as hard-coded strings. Also embed the full `brain_context`, `prompt`, and `ideas_list` (built above) as literal text. Replace every `${BOARD_ID}`, `${COL_EVALUATED}`, `${COL_ICED}`, `${COL_REJECTED}`, `${brain_context}`, `${prompt}`, `${project_name}`, `${date}`, and `${ideas_list}` with its actual value before calling Task — the agent receives unsubstituted `${...}` strings verbatim and silently skips every board update.
291
311
 
292
- Spawn a single `Product Manager` agent via the Task tool. The PM agent has Bash tool access and is responsible for both producing verdicts and executing all board updates directly.
312
+ Spawn a single `general-purpose` agent via the Task tool. Do NOT use `Product Manager` — that agent type lacks Bash tool access and cannot execute `monotask` CLI commands. The evaluator agent produces verdicts and executes all board updates directly via Bash.
293
313
 
294
314
  ```javascript
295
315
  Task({
296
- subagent_type: "Product Manager",
316
+ subagent_type: "general-purpose",
297
317
  description: "PM validation for project " + project_name,
298
318
  run_in_background: false,
299
319
  prompt: `SAFETY CHECK: Verify that the BOARD_ID you received matches UUID format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12 hex chars). If it does not, STOP and report "ERROR: BOARD_ID not substituted — received: <value>". Do NOT call monotask board create, space create, or column create. Your only job is evaluating cards and running impact/effort updates on existing cards.
@@ -321,23 +341,31 @@ For EVERY idea above, determine:
321
341
  - skipElaboration: true (simple, no deep research needed) | false (edge cases should be explored) — only for evaluated
322
342
  - rationale: 1-2 sentence value statement (evaluated), blocking question (iced), or rejection reason (rejected)
323
343
 
324
- MANDATORY BOARD UPDATES — run these bash commands for EVERY idea, no exceptions:
325
-
326
- For evaluated ideas:
327
- monotask card move "${BOARD_ID}" "<CARD_ID>" "${COL_EVALUATED}" --json
328
- monotask card set-impact "${BOARD_ID}" "<CARD_ID>" <impact>
329
- monotask card set-effort "${BOARD_ID}" "<CARD_ID>" <effort>
330
- monotask card comment add "${BOARD_ID}" "<CARD_ID>" "Value: <rationale>"
331
-
332
- For iced ideas:
333
- monotask card move "${BOARD_ID}" "<CARD_ID>" "${COL_ICED}" --json
334
- monotask card set-impact "${BOARD_ID}" "<CARD_ID>" <impact>
335
- monotask card set-effort "${BOARD_ID}" "<CARD_ID>" <effort>
336
- monotask card comment add "${BOARD_ID}" "<CARD_ID>" "Blocked: <blocking question>"
337
-
338
- For rejected ideas:
339
- monotask card move "${BOARD_ID}" "<CARD_ID>" "${COL_REJECTED}" --json
340
- monotask card comment add "${BOARD_ID}" "<CARD_ID>" "Rejected: <reason>"
344
+ MANDATORY BOARD UPDATES — after determining all verdicts, build your verdicts as a JSON array and iterate over it:
345
+
346
+ # Paste your full VERDICTS_OUTPUT array here as verdicts_json (before outputting the block)
347
+ verdicts_json='[ ... your verdict objects ... ]'
348
+ while IFS= read -r row; do
349
+ CARD_ID=$(echo "$row" | jq -r '.card_id')
350
+ verdict=$(echo "$row" | jq -r '.verdict')
351
+ impact=$(echo "$row" | jq -r '.impact')
352
+ effort=$(echo "$row" | jq -r '.effort')
353
+ rationale=$(echo "$row" | jq -r '.rationale')
354
+ if [ "$verdict" = "evaluated" ]; then
355
+ monotask card move "${BOARD_ID}" "$CARD_ID" "${COL_EVALUATED}" --json
356
+ monotask card set-impact "${BOARD_ID}" "$CARD_ID" "$impact"
357
+ monotask card set-effort "${BOARD_ID}" "$CARD_ID" "$effort"
358
+ monotask card comment add "${BOARD_ID}" "$CARD_ID" "Value: $rationale"
359
+ elif [ "$verdict" = "iced" ]; then
360
+ monotask card move "${BOARD_ID}" "$CARD_ID" "${COL_ICED}" --json
361
+ monotask card set-impact "${BOARD_ID}" "$CARD_ID" "$impact"
362
+ monotask card set-effort "${BOARD_ID}" "$CARD_ID" "$effort"
363
+ monotask card comment add "${BOARD_ID}" "$CARD_ID" "Blocked: $rationale"
364
+ elif [ "$verdict" = "rejected" ]; then
365
+ monotask card move "${BOARD_ID}" "$CARD_ID" "${COL_REJECTED}" --json
366
+ monotask card comment add "${BOARD_ID}" "$CARD_ID" "Rejected: $rationale"
367
+ fi
368
+ done < <(echo "$verdicts_json" | jq -c '.[]')
341
369
 
342
370
  IMPORTANT: set-impact and set-effort MUST be called for every evaluated and iced idea. Do not skip them.
343
371
 
@@ -364,7 +392,8 @@ After the PM agent completes, parse the `VERDICTS_OUTPUT` block from the agent's
364
392
  ```bash
365
393
  verdicts_output_json='<paste the JSON array from VERDICTS_OUTPUT here>'
366
394
  ```
367
- This variable is used throughout Steps 6a and 6c to build idea lists, registry keywords, and inherit impact/effort scores it must be set before proceeding. If **all** ideas are iced or rejected, output a summary table and STOP skip Steps 6–7.
395
+ If the `VERDICTS_OUTPUT` block is absent (agent error or malformed output), set `verdicts_output_json='[]'` — all ideas will be treated as iced and Step 6 will be skipped.
396
+ This variable is used throughout Steps 6a and 6c to build idea lists, registry keywords, and inherit impact/effort scores — it must be set before proceeding. If **all** ideas are iced or rejected, output a summary table — skip Step 6 and proceed to Step 7 (Brain Write).
368
397
 
369
398
  ---
370
399
 
@@ -374,9 +403,20 @@ This variable is used throughout Steps 6a and 6c to build idea lists, registry k
374
403
 
375
404
  For any evaluated idea with `skipElaboration: true`, move it directly to `Elaborated`, set a description, and write a rationale comment so future readers understand why no deep elaboration was needed:
376
405
  ```bash
377
- monotask card set-description "$BOARD_ID" "$CARD_ID" "Elaboration skipped — PM assessed this as straightforward.\n\nRationale: <rationale from VERDICTS_OUTPUT for this card_id>\n\nImpact: <impact>/10 | Effort: <effort>/10"
378
- monotask card move "$BOARD_ID" "$CARD_ID" "$COL_ELABORATED" --json
379
- monotask card comment add "$BOARD_ID" "$CARD_ID" "Elaboration skipped: PM assessed this idea as straightforward with no significant unknowns. Rationale: <rationale from VERDICTS_OUTPUT for this card_id>"
406
+ while IFS= read -r skip_idea; do
407
+ CARD_ID=$(echo "$skip_idea" | jq -r '.card_id')
408
+ skip_title=$(echo "$skip_idea" | jq -r '.title')
409
+ skip_rationale=$(echo "$skip_idea" | jq -r '.rationale // "No rationale provided"')
410
+ skip_impact=$(echo "$skip_idea" | jq -r '.impact // 5')
411
+ skip_effort=$(echo "$skip_idea" | jq -r '.effort // 5')
412
+ monotask card set-description "$BOARD_ID" "$CARD_ID" "Elaboration skipped — PM assessed this as straightforward.
413
+
414
+ Rationale: $skip_rationale
415
+
416
+ Impact: $skip_impact/10 | Effort: $skip_effort/10"
417
+ monotask card move "$BOARD_ID" "$CARD_ID" "$COL_ELABORATED" --json
418
+ monotask card comment add "$BOARD_ID" "$CARD_ID" "Elaboration skipped: PM assessed this idea as straightforward with no significant unknowns. Rationale: $skip_rationale"
419
+ done < <(echo "$verdicts_output_json" | jq -c '[.[] | select(.verdict == "evaluated") | select(.skipElaboration == true)] | .[]')
380
420
  ```
381
421
 
382
422
  For ideas with `skipElaboration: false`, **split by category** before spawning agents:
@@ -384,19 +424,23 @@ For ideas with `skipElaboration: false`, **split by category** before spawning a
384
424
  **Build `dev_ideas_list` and `ops_ideas_list` before constructing the Step 6a Task prompts:**
385
425
  ```bash
386
426
  # Filter VERDICTS_OUTPUT (parsed in Step 5) by category and format as literal text.
427
+ # IMPORTANT: exclude skipElaboration:true ideas — they were already moved to Elaborated above
428
+ # and must not be sent to elaboration agents again.
387
429
  dev_ideas_list=$(echo "$verdicts_output_json" | jq -r \
388
- '.[] | select(.verdict == "evaluated") | select(.category == "feature" or .category == "technical-baseline") |
430
+ '.[] | select(.verdict == "evaluated") | select(.skipElaboration != true)
431
+ | select(.category == "feature" or .category == "technical-baseline") |
389
432
  "- card_id: \(.card_id)\n title: \(.title)\n category: \(.category)\n rationale: \(.rationale)\n"')
390
433
 
391
434
  ops_ideas_list=$(echo "$verdicts_output_json" | jq -r \
392
- '.[] | select(.verdict == "evaluated") | select(.category == "business-operation") |
435
+ '.[] | select(.verdict == "evaluated") | select(.skipElaboration != true)
436
+ | select(.category == "business-operation") |
393
437
  "- card_id: \(.card_id)\n title: \(.title)\n category: \(.category)\n rationale: \(.rationale)\n"')
394
438
  ```
395
439
 
396
440
  **CRITICAL — Variable substitution required for Step 6a Task calls:**
397
441
  Elaboration agents run in isolated Task contexts. Before constructing each Task prompt, replace every `${brain_context}`, `${dev_ideas_list}`, and `${ops_ideas_list}` with the actual literal text — `brain_context` from the brain load, `dev_ideas_list` and `ops_ideas_list` built above. Do NOT leave any `${...}` placeholders in the prompt — the agent receives them as literal dollar-sign strings and produces empty ELABORATION_OUTPUT blocks.
398
442
 
399
- **Dev ideas** (`feature` or `technical-baseline`):
443
+ **Dev ideas** (`feature` or `technical-baseline`) — **skip if `dev_ideas_list` is empty** (no evaluated feature/technical-baseline ideas without skipElaboration; set `dev_researcher_json='[]'` and `dev_codebase_json='[]'` instead and do not spawn these agents):
400
444
  Spawn two agents in parallel via Task tool:
401
445
 
402
446
  ```javascript
@@ -455,7 +499,7 @@ END_ELABORATION_OUTPUT`
455
499
  })
456
500
  ```
457
501
 
458
- **Business-operation ideas** (`business-operation`):
502
+ **Business-operation ideas** (`business-operation`) — **skip if `ops_ideas_list` is empty** (no evaluated business-operation ideas without skipElaboration; set `ops_researcher_json='[]'` and `ops_pm_json='[]'` instead and do not spawn these agents):
459
503
  Spawn two agents in parallel via Task tool:
460
504
 
461
505
  ```javascript
@@ -514,7 +558,7 @@ END_ELABORATION_OUTPUT`
514
558
  })
515
559
  ```
516
560
 
517
- Wait for all background agents to complete (do not proceed until all or two, if only one category return ELABORATION_OUTPUT blocks). Then build `merged_elaboration_json` by merging agent outputs per `card_id` and injecting `category` from `verdicts_output_json`:
561
+ Wait for all spawned background elaboration agents to complete before proceeding (0, 2, or 4 agents depending on which lists were non-emptysee guards above). Then build `merged_elaboration_json` by merging agent outputs per `card_id` and injecting `category` from `verdicts_output_json`:
518
562
 
519
563
  ```bash
520
564
  # Assign each agent's ELABORATION_OUTPUT JSON array from its output block:
@@ -523,29 +567,45 @@ dev_codebase_json='<ELABORATION_OUTPUT array from the dev code-explorer agent>'
523
567
  ops_researcher_json='<ELABORATION_OUTPUT array from the ops researcher agent>'
524
568
  ops_pm_json='<ELABORATION_OUTPUT array from the ops PM agent>'
525
569
  # Use '[]' for any track that had no ideas (e.g. if all ideas were dev, set ops_* to '[]')
570
+ # If an ELABORATION_OUTPUT block is absent from an agent's response (error/timeout), set that variable to '[]'
526
571
 
527
- # Merge dev track: join researcher + codebase findings by card_id, inject category from verdicts
572
+ # Merge dev track: full outer join researcher + codebase by card_id, inject category from verdicts.
573
+ # Use union of card_ids from both agents — if one agent skips a card the other covers, it's preserved.
574
+ # blocking_issue: take from whichever agent found one (researcher OR codebase).
528
575
  dev_merged=$(jq -n \
529
576
  --argjson r "$dev_researcher_json" \
530
577
  --argjson c "$dev_codebase_json" \
531
578
  --argjson v "$verdicts_output_json" \
532
- '[$r[] | {card_id: .card_id, blocking_issue: .blocking_issue,
533
- researcher_findings: .findings,
534
- codebase_findings: ([$c[] | select(.card_id == .card_id)] | first | .findings // ""),
535
- category: ([$v[] | select(.card_id == .card_id)] | first | .category // "feature")}]')
536
-
537
- # Merge ops track: join researcher + PM findings by card_id, inject category
579
+ '([$r[], $c[]] | map(.card_id) | unique) as $ids |
580
+ [$ids[] | . as $id |
581
+ { card_id: $id,
582
+ blocking_issue: (
583
+ ([$r[] | select(.card_id == $id)] | first | .blocking_issue // null) //
584
+ ([$c[] | select(.card_id == $id)] | first | .blocking_issue // null)
585
+ ),
586
+ researcher_findings: ([$r[] | select(.card_id == $id)] | first | .findings // ""),
587
+ codebase_findings: ([$c[] | select(.card_id == $id)] | first | .findings // ""),
588
+ category: ([$v[] | select(.card_id == $id)] | first | .category // "feature") }]')
589
+
590
+ # Merge ops track: full outer join researcher + PM findings by card_id, inject category.
591
+ # blocking_issue: take from whichever agent found one (researcher OR PM).
538
592
  ops_merged=$(jq -n \
539
593
  --argjson r "$ops_researcher_json" \
540
594
  --argjson p "$ops_pm_json" \
541
595
  --argjson v "$verdicts_output_json" \
542
- '[$r[] | {card_id: .card_id, blocking_issue: .blocking_issue,
543
- researcher_findings: .findings,
544
- pm_findings: ([$p[] | select(.card_id == .card_id)] | first | .findings // ""),
545
- category: ([$v[] | select(.card_id == .card_id)] | first | .category // "business-operation")}]')
596
+ '([$r[], $p[]] | map(.card_id) | unique) as $ids |
597
+ [$ids[] | . as $id |
598
+ { card_id: $id,
599
+ blocking_issue: (
600
+ ([$r[] | select(.card_id == $id)] | first | .blocking_issue // null) //
601
+ ([$p[] | select(.card_id == $id)] | first | .blocking_issue // null)
602
+ ),
603
+ researcher_findings: ([$r[] | select(.card_id == $id)] | first | .findings // ""),
604
+ pm_findings: ([$p[] | select(.card_id == $id)] | first | .findings // ""),
605
+ category: ([$v[] | select(.card_id == $id)] | first | .category // "business-operation") }]')
546
606
 
547
607
  # Combine both tracks
548
- merged_elaboration_json=$(jq -s 'add' <(echo "$dev_merged") <(echo "$ops_merged"))
608
+ merged_elaboration_json=$(jq -s 'add // []' <(echo "$dev_merged") <(echo "$ops_merged"))
549
609
  ```
550
610
 
551
611
  Use process substitution (not a pipeline) so the while loop runs in the main shell and variables remain in scope after `done`:
@@ -554,7 +614,8 @@ Use process substitution (not a pipeline) so the while loop runs in the main she
554
614
  while IFS= read -r idea; do
555
615
  CARD_ID=$(echo "$idea" | jq -r '.card_id')
556
616
  category=$(echo "$idea" | jq -r '.category')
557
- blocking_issue=$(echo "$idea" | jq -r '.blocking_issue // empty')
617
+ blocking_issue=$(echo "$idea" | jq -r '.blocking_issue // ""')
618
+ [ "$blocking_issue" = "null" ] && blocking_issue="" # guard against agents outputting the string "null"
558
619
 
559
620
  if [ "$category" = "business-operation" ]; then
560
621
  researcher_findings=$(echo "$idea" | jq -r '.researcher_findings')
@@ -597,7 +658,7 @@ done < <(echo "$merged_elaboration_json" | jq -c '.[]')
597
658
 
598
659
  **Confirm mode only:** If `mode` is `confirm` (default), present a review table of all elaborated ideas to the user.
599
660
 
600
- Build the table from `verdicts_output_json` (filtered to `verdict == "evaluated"`). For each row:
661
+ Build the table from `verdicts_output_json` (filtered to `verdict == "evaluated"` AND `card_id` not in the set of ideas with a non-null `blocking_issue` in `merged_elaboration_json`). Exclude ideas iced during elaboration — they are already in the `Iced` column and must not appear in this review. For each row:
601
662
  - **Impact** and **Effort** come from `.impact` and `.effort` fields in `verdicts_output_json`
602
663
  - **Track**: `feature` or `technical-baseline` → `dev`; `business-operation` → `ops`
603
664
 
@@ -638,7 +699,7 @@ Wait for the user's response before continuing. Do not spawn any agents until a
638
699
  ```bash
639
700
  monotask card comment add "$BOARD_ID" "$CARD_ID" "User notes: <notes>"
640
701
  ```
641
- - **"stop"**: skip Step 6c and Step 7. Print a summary of ideas in Elaborated/Iced/Rejected and return `status: partial`.
702
+ - **"stop"**: skip Step 6c. Proceed directly to Step 7 (Brain Write). Print a summary of ideas in Elaborated/Iced/Rejected and return `status: partial`.
642
703
  - Combined instructions ("remove 2,4 | add detail to 1: ...") are processed together.
643
704
 
644
705
  After applying all user instructions, proceed to Step 6c with the remaining ideas.
@@ -653,11 +714,7 @@ After applying all user instructions, proceed to Step 6c with the remaining idea
653
714
  REGISTRY=".monomind/registry.json"
654
715
 
655
716
  # Dev decomposition agent — pick the most relevant engineering/architecture specialist
656
- # Build keyword signal from elaborated dev idea titles (from VERDICTS_OUTPUT filtered above)
657
- DEV_IDEA_CONTEXT=$(echo "$verdicts_output_json" | jq -r \
658
- '[.[] | select(.verdict=="evaluated") | select(.category=="feature" or .category=="technical-baseline") | .title] | join(" ")')
659
717
  dev_decomp_agent=$(jq -r \
660
- --arg kw "$(echo "$DEV_IDEA_CONTEXT" | tr '[:upper:]' '[:lower:]' | grep -oE '[a-z]{5,}' | sort -u | tr '\n' ' ')" \
661
718
  '[ .agents[] | select(.deprecated != true)
662
719
  | select(.category == "engineering" or .category == "architecture")
663
720
  | {name: .name,
@@ -675,10 +732,7 @@ dev_decomp_agent=$(jq -r \
675
732
  dev_decomp_agent="${dev_decomp_agent:-Software Architect}"
676
733
 
677
734
  # Ops decomposition agent — pick the most relevant strategy/sales/product specialist
678
- OPS_IDEA_CONTEXT=$(echo "$verdicts_output_json" | jq -r \
679
- '[.[] | select(.verdict=="evaluated") | select(.category=="business-operation") | .title] | join(" ")')
680
735
  ops_decomp_agent=$(jq -r \
681
- --arg kw "$(echo "$OPS_IDEA_CONTEXT" | tr '[:upper:]' '[:lower:]' | grep -oE '[a-z]{5,}' | sort -u | tr '\n' ' ')" \
682
736
  '[ .agents[] | select(.deprecated != true)
683
737
  | select(.category == "strategy" or .category == "sales" or .category == "product" or .category == "marketing")
684
738
  | {name: .name,
@@ -702,13 +756,29 @@ echo "Dev decomp: $dev_decomp_agent | Ops decomp: $ops_decomp_agent"
702
756
  Before constructing each Task prompt, replace `${brain_context}`, `${prompt}`, `${project_name}`, `${dev_ideas_elaborated}`, and `${ops_ideas_elaborated}` with actual literal text. Also substitute the `subagent_type` values: replace `dev_decomp_agent` and `ops_decomp_agent` with the string values echoed by the registry selection above (e.g. `"Software Architect"`). Build those lists from the VERDICTS_OUTPUT and ELABORATION_OUTPUT results:
703
757
 
704
758
  ```bash
705
- # Build elaborated idea lists including card comments (full context for decomposition agents)
759
+ # Collect IDs of cards iced during elaboration (blocking_issue was set) — exclude from decomposition.
760
+ # merged_elaboration_json covers agent-elaborated ideas only (not skipElaboration:true ones).
761
+ elaboration_blocked=$(echo "$merged_elaboration_json" | jq \
762
+ '[.[] | select(.blocking_issue != null and .blocking_issue != "" and .blocking_issue != "null") | .card_id]')
763
+ # Safeguard: if jq failed (e.g. null input), default to empty array so decomp proceeds safely
764
+ [ -z "$elaboration_blocked" ] && elaboration_blocked='[]'
765
+
766
+ # Build elaborated idea lists for decomposition agents.
767
+ # Include: evaluated ideas (PM verdict) that were NOT iced during elaboration.
768
+ # This covers both skipElaboration:true ideas and agent-elaborated ideas in the Elaborated column.
769
+ # Use `any(. == $id)` not `contains([$id])` — contains does substring matching on strings (wrong for UUIDs).
706
770
  dev_ideas_elaborated=$(echo "$verdicts_output_json" | jq -r \
707
- '[.[] | select(.verdict=="evaluated") | select(.category=="feature" or .category=="technical-baseline") |
771
+ --argjson blocked "$elaboration_blocked" \
772
+ '[.[] | select(.verdict=="evaluated")
773
+ | select(.card_id as $id | ($blocked | any(. == $id)) | not)
774
+ | select(.category=="feature" or .category=="technical-baseline") |
708
775
  "card_id: \(.card_id)\ntitle: \(.title)\ncategory: \(.category)\nrationale: \(.rationale)\nimpact: \(.impact) effort: \(.effort)"] | join("\n\n")')
709
776
 
710
777
  ops_ideas_elaborated=$(echo "$verdicts_output_json" | jq -r \
711
- '[.[] | select(.verdict=="evaluated") | select(.category=="business-operation") |
778
+ --argjson blocked "$elaboration_blocked" \
779
+ '[.[] | select(.verdict=="evaluated")
780
+ | select(.card_id as $id | ($blocked | any(. == $id)) | not)
781
+ | select(.category=="business-operation") |
712
782
  "card_id: \(.card_id)\ntitle: \(.title)\ncategory: \(.category)\nrationale: \(.rationale)\nimpact: \(.impact) effort: \(.effort)"] | join("\n\n")')
713
783
  ```
714
784
 
@@ -803,8 +873,15 @@ END_TASKS_OUTPUT`
803
873
  Canonical board name: `${project_name}-tasks-dev`. Find-or-create:
804
874
 
805
875
  ```bash
876
+ # space_id from Step 3 is gone (each Bash tool call is a new shell).
877
+ # Re-derive from project_name so board creation works correctly on first run.
878
+ if [ -z "$space_id" ]; then
879
+ space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$project_name" | head -1)
880
+ [ -z "$space_id" ] && { echo "ERROR: space '$project_name' not found — run Step 3 first"; exit 1; }
881
+ fi
806
882
  dev_task_canonical="${project_name}-tasks-dev"
807
- TASK_BOARD_ID=$(monotask board list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$dev_task_canonical" | head -1)
883
+ # board list format is "uuid: name" (colon-space separator, NOT pipe)
884
+ TASK_BOARD_ID=$(monotask board list 2>/dev/null | awk -F': ' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$dev_task_canonical" | head -1)
808
885
  if [ -n "$TASK_BOARD_ID" ]; then
809
886
  echo "Reusing dev task board: $TASK_BOARD_ID ($dev_task_canonical)"
810
887
  task_columns=$(monotask column list "$TASK_BOARD_ID" --json)
@@ -815,8 +892,8 @@ else
815
892
  TASK_BOARD_ID=$(monotask board create --space "$space_id" "$dev_task_canonical" --json 2>/dev/null | jq -r '.id // empty')
816
893
  [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: Failed to create dev task board"; exit 1; }
817
894
  monotask space boards add "$space_id" "$TASK_BOARD_ID" >/dev/null 2>&1 || true
818
- TASK_COL_BACKLOG=$(monotask column create "$TASK_BOARD_ID" "Backlog" --json | jq -r '.id')
819
- TASK_COL_TODO=$(monotask column create "$TASK_BOARD_ID" "Todo" --json | jq -r '.id')
895
+ TASK_COL_BACKLOG=$(monotask column create "$TASK_BOARD_ID" "Backlog" --json | jq -r '.id // empty')
896
+ TASK_COL_TODO=$(monotask column create "$TASK_BOARD_ID" "Todo" --json | jq -r '.id // empty')
820
897
  monotask column create "$TASK_BOARD_ID" "In Progress" --json >/dev/null
821
898
  monotask column create "$TASK_BOARD_ID" "Human in Loop" --json >/dev/null
822
899
  monotask column create "$TASK_BOARD_ID" "Review" --json >/dev/null
@@ -825,6 +902,7 @@ else
825
902
  fi
826
903
  [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: TASK_BOARD_ID empty — aborting"; exit 1; }
827
904
  [ -z "$TASK_COL_TODO" ] && { echo "ERROR: Could not find Todo column on dev task board"; exit 1; }
905
+ [ -z "$TASK_COL_BACKLOG" ] && { echo "ERROR: Could not find Backlog column on dev task board"; exit 1; }
828
906
  ```
829
907
 
830
908
  ---
@@ -834,8 +912,14 @@ fi
834
912
  Canonical board name: `${project_name}-tasks-ops`. Find-or-create:
835
913
 
836
914
  ```bash
915
+ # Restore space_id if not available (same pattern as dev task board block above).
916
+ if [ -z "$space_id" ]; then
917
+ space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$project_name" | head -1)
918
+ [ -z "$space_id" ] && { echo "ERROR: space '$project_name' not found"; exit 1; }
919
+ fi
837
920
  ops_task_canonical="${project_name}-tasks-ops"
838
- OPS_BOARD_ID=$(monotask board list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$ops_task_canonical" | head -1)
921
+ # board list format is "uuid: name" (colon-space separator, NOT pipe)
922
+ OPS_BOARD_ID=$(monotask board list 2>/dev/null | awk -F': ' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$ops_task_canonical" | head -1)
839
923
  if [ -n "$OPS_BOARD_ID" ]; then
840
924
  echo "Reusing ops task board: $OPS_BOARD_ID ($ops_task_canonical)"
841
925
  ops_columns=$(monotask column list "$OPS_BOARD_ID" --json)
@@ -846,8 +930,8 @@ else
846
930
  OPS_BOARD_ID=$(monotask board create --space "$space_id" "$ops_task_canonical" --json 2>/dev/null | jq -r '.id // empty')
847
931
  [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: Failed to create ops task board"; exit 1; }
848
932
  monotask space boards add "$space_id" "$OPS_BOARD_ID" >/dev/null 2>&1 || true
849
- OPS_COL_BACKLOG=$(monotask column create "$OPS_BOARD_ID" "Backlog" --json | jq -r '.id')
850
- OPS_COL_TODO=$(monotask column create "$OPS_BOARD_ID" "Todo" --json | jq -r '.id')
933
+ OPS_COL_BACKLOG=$(monotask column create "$OPS_BOARD_ID" "Backlog" --json | jq -r '.id // empty')
934
+ OPS_COL_TODO=$(monotask column create "$OPS_BOARD_ID" "Todo" --json | jq -r '.id // empty')
851
935
  monotask column create "$OPS_BOARD_ID" "In Progress" --json >/dev/null
852
936
  monotask column create "$OPS_BOARD_ID" "Human in Loop" --json >/dev/null
853
937
  monotask column create "$OPS_BOARD_ID" "Review" --json >/dev/null
@@ -856,6 +940,7 @@ else
856
940
  fi
857
941
  [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: OPS_BOARD_ID empty — aborting"; exit 1; }
858
942
  [ -z "$OPS_COL_TODO" ] && { echo "ERROR: Could not find Todo column on ops task board"; exit 1; }
943
+ [ -z "$OPS_COL_BACKLOG" ] && { echo "ERROR: Could not find Backlog column on ops task board"; exit 1; }
859
944
  ```
860
945
 
861
946
  ---
@@ -867,13 +952,13 @@ fi
867
952
  dev_tasks_json='<TASKS_OUTPUT JSON array from dev decomp agent, or [] if no dev ideas>'
868
953
  # Parse the TASKS_OUTPUT block from the ops decomp agent's response and assign:
869
954
  ops_tasks_json='<TASKS_OUTPUT JSON array from ops decomp agent, or [] if no ops ideas>'
955
+ # If TASKS_OUTPUT block is absent from an agent's response (error/timeout), set that variable to '[]'
870
956
 
871
- merged_tasks_json=$(jq -s 'add' <(echo "$dev_tasks_json") <(echo "$ops_tasks_json"))
957
+ merged_tasks_json=$(jq -s 'add // []' <(echo "$dev_tasks_json") <(echo "$ops_tasks_json"))
872
958
 
873
- # Use process substitution (not a pipeline) so variables set inside the loop
874
- # remain in scope after done needed for the parent-annotation step below.
875
- # Also initialise the subtask-accumulator map before the loop.
876
- declare -A parent_subtask_summaries # parent_card_id -> newline-separated task summary lines
959
+ # Use a temp directory to accumulate per-parent subtask summaries (bash 3.2 compatible —
960
+ # avoids declare -A associative arrays which require bash 4.3+)
961
+ SUBTASK_TMPDIR=$(mktemp -d)
877
962
 
878
963
  while IFS= read -r task; do
879
964
  parent_card_id=$(echo "$task" | jq -r '.parent_card_id')
@@ -885,59 +970,78 @@ while IFS= read -r task; do
885
970
  has_prerequisites=$(echo "$task" | jq -r '.has_prerequisites')
886
971
 
887
972
  if [ "$category" = "business-operation" ]; then
888
- TARGET_BOARD="$OPS_BOARD_ID"
889
- COL_TARGET=$([ "$has_prerequisites" = "true" ] && echo "$OPS_COL_BACKLOG" || echo "$OPS_COL_TODO")
890
- BOARD_LABEL="Operations Tasks"
891
- else
892
- TARGET_BOARD="$TASK_BOARD_ID"
893
- COL_TARGET=$([ "$has_prerequisites" = "true" ] && echo "$TASK_COL_BACKLOG" || echo "$TASK_COL_TODO")
894
- BOARD_LABEL="Implementation Tasks"
895
- fi
973
+ TARGET_BOARD="$OPS_BOARD_ID"
974
+ COL_TARGET=$([ "$has_prerequisites" = "true" ] && echo "$OPS_COL_BACKLOG" || echo "$OPS_COL_TODO")
975
+ BOARD_LABEL="Operations Tasks"
976
+ else
977
+ TARGET_BOARD="$TASK_BOARD_ID"
978
+ COL_TARGET=$([ "$has_prerequisites" = "true" ] && echo "$TASK_COL_BACKLOG" || echo "$TASK_COL_TODO")
979
+ BOARD_LABEL="Implementation Tasks"
980
+ fi
896
981
 
897
- # Inherit impact and effort from parent idea — look up from verdicts_output_json by parent_card_id
898
- parent_impact=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .impact // 5')
899
- parent_effort=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .effort // 5')
900
- # Default to 5 if lookup returned empty (e.g. parent_card_id was "UNKNOWN")
901
- [ -z "$parent_impact" ] && parent_impact=5
902
- [ -z "$parent_effort" ] && parent_effort=5
903
-
904
- # Create task card as a proper subtask of the parent idea card (cross-board link)
905
- # Signature: subtask add <PARENT_BOARD_ID> <PARENT_CARD_ID> <CHILD_BOARD_ID> <COL_ID> <TITLE>
906
- TASK_CARD_ID=$(monotask card subtask add "$BOARD_ID" "$parent_card_id" "$TARGET_BOARD" "$COL_TARGET" "<task title>" --json | jq -r '.id')
907
- # Set the task description as the primary content field
908
- monotask card set-description "$TARGET_BOARD" "$TASK_CARD_ID" "<what to build/do from TASKS_OUTPUT description>"
909
- monotask card set-impact "$TARGET_BOARD" "$TASK_CARD_ID" "$parent_impact"
910
- monotask card set-effort "$TARGET_BOARD" "$TASK_CARD_ID" "$parent_effort"
911
- monotask card comment add "$TARGET_BOARD" "$TASK_CARD_ID" \
912
- "SOURCE: mastermind:idea | <first 100 chars of prompt>
913
- AGENT: <agent>
914
- TASK EFFORT: <task_effort>/10
915
- PARENT IDEA IMPACT: <parent_impact>/10 PARENT IDEA EFFORT: <parent_effort>/10
916
- CATEGORY: <category>
917
- PARENT IDEA: <idea title> (card: <parent_card_id> on ideation board)"
918
- monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "mastermind:idea"
919
- monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "category:$category"
920
-
921
- # Accumulate subtask summary for this parent (used in the post-loop annotation step)
922
- parent_subtask_summaries[$parent_card_id]+=" - $title (agent: $agent, effort: $task_effort/10, board: $BOARD_LABEL)\n"
982
+ # Inherit impact and effort from parent idea — look up from verdicts_output_json by parent_card_id
983
+ parent_impact=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .impact // 5')
984
+ parent_effort=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .effort // 5')
985
+ # Default to 5 if lookup returned empty (e.g. parent_card_id was "UNKNOWN")
986
+ [ -z "$parent_impact" ] && parent_impact=5
987
+ [ -z "$parent_effort" ] && parent_effort=5
988
+
989
+ # Create task card as a proper subtask of the parent idea card (cross-board link)
990
+ # Signature: subtask add <PARENT_BOARD_ID> <PARENT_CARD_ID> <CHILD_BOARD_ID> <COL_ID> <TITLE>
991
+ TASK_CARD_ID=$(monotask card subtask add "$BOARD_ID" "$parent_card_id" "$TARGET_BOARD" "$COL_TARGET" "$title" --json | jq -r '.id // empty')
992
+ [ -z "$TASK_CARD_ID" ] && { echo "WARN: subtask creation failed for '$title' (parent: $parent_card_id), skipping"; continue; }
993
+ # Set the task description as the primary content field
994
+ monotask card set-description "$TARGET_BOARD" "$TASK_CARD_ID" "$description"
995
+ monotask card set-impact "$TARGET_BOARD" "$TASK_CARD_ID" "$parent_impact"
996
+ monotask card set-effort "$TARGET_BOARD" "$TASK_CARD_ID" "$parent_effort"
997
+ # Derive parent idea title for the comment
998
+ parent_idea_title=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .title // "unknown"')
999
+ prompt_prefix=$(echo "$prompt" | cut -c1-100)
1000
+ monotask card comment add "$TARGET_BOARD" "$TASK_CARD_ID" \
1001
+ "SOURCE: mastermind:idea | $prompt_prefix
1002
+ AGENT: $agent
1003
+ TASK EFFORT: $task_effort/10
1004
+ PARENT IDEA IMPACT: $parent_impact/10 PARENT IDEA EFFORT: $parent_effort/10
1005
+ CATEGORY: $category
1006
+ PARENT IDEA: $parent_idea_title (card: $parent_card_id on ideation board)"
1007
+ monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "mastermind:idea"
1008
+ monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "category:$category"
1009
+
1010
+ # Append subtask summary line to per-parent file (replaces declare -A accumulation)
1011
+ printf ' - %s (agent: %s, effort: %s/10, board: %s)\n' \
1012
+ "$title" "$agent" "$task_effort" "$BOARD_LABEL" >> "$SUBTASK_TMPDIR/$parent_card_id"
923
1013
 
924
1014
  done < <(echo "$merged_tasks_json" | jq -c '.[]')
925
1015
  ```
926
1016
 
927
1017
  After the loop, annotate each parent idea card and move it to `Tasked`:
928
1018
  ```bash
929
- for parent_card_id in "${!parent_subtask_summaries[@]}"; do
930
- subtask_list="${parent_subtask_summaries[$parent_card_id]}"
1019
+ for summary_file in "$SUBTASK_TMPDIR"/*; do
1020
+ [ -f "$summary_file" ] || continue
1021
+ parent_card_id=$(basename "$summary_file")
1022
+ subtask_list=$(cat "$summary_file")
931
1023
  monotask card comment add "$BOARD_ID" "$parent_card_id" \
932
- "Subtasks created:\n${subtask_list}"
1024
+ "Subtasks created:
1025
+ ${subtask_list}"
933
1026
  monotask card move "$BOARD_ID" "$parent_card_id" "$COL_TASKED" --json
934
1027
  done
1028
+ rm -rf "$SUBTASK_TMPDIR"
935
1029
  ```
936
1030
 
937
- For each entry in FLAGGED, move the idea to `Iced`:
1031
+ For each entry in FLAGGED, parse the flagged JSON from both decomp agents' FLAGGED blocks and iterate:
938
1032
  ```bash
939
- monotask card comment add "$BOARD_ID" "$flagged_card_id" "Needs clarification: <question>"
940
- monotask card move "$BOARD_ID" "$flagged_card_id" "$COL_ICED" --json
1033
+ # Collect flagged entries from both decomp agents
1034
+ dev_flagged_json='<FLAGGED array from dev decomp agent, or [] if none>'
1035
+ ops_flagged_json='<FLAGGED array from ops decomp agent, or [] if none>'
1036
+ # If FLAGGED block is absent from an agent's response, set that variable to '[]'
1037
+ merged_flagged_json=$(jq -s 'add // []' <(echo "$dev_flagged_json") <(echo "$ops_flagged_json"))
1038
+
1039
+ while IFS= read -r flagged; do
1040
+ flagged_card_id=$(echo "$flagged" | jq -r '.card_id')
1041
+ flagged_question=$(echo "$flagged" | jq -r '.question // "Needs clarification before decomposition"')
1042
+ monotask card comment add "$BOARD_ID" "$flagged_card_id" "Needs clarification: $flagged_question"
1043
+ monotask card move "$BOARD_ID" "$flagged_card_id" "$COL_ICED" --json
1044
+ done < <(echo "$merged_flagged_json" | jq -c '.[]')
941
1045
  ```
942
1046
 
943
1047
  ---
@@ -946,6 +1050,30 @@ monotask card move "$BOARD_ID" "$flagged_card_id" "$COL_ICED" --json
946
1050
 
947
1051
  Follow _protocol.md Brain Write Procedure (namespace: `idea`).
948
1052
 
1053
+ **Write domain output to session file** so master Step 9 aggregation can include this domain. Skip silently if running standalone (no SESSION_ID in current.json):
1054
+
1055
+ ```bash
1056
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
1057
+ SESSION_ID=$(jq -r '.sessionId // empty' "$REPO_ROOT/.monomind/sessions/current.json" 2>/dev/null)
1058
+ if [ -n "$SESSION_ID" ]; then
1059
+ mkdir -p "$REPO_ROOT/.monomind/sessions/${SESSION_ID}"
1060
+ CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
1061
+ # LLM: substitute <status>: complete (all steps ran), partial (some skipped), blocked (critical error)
1062
+ # LLM: substitute next_actions with actual suggestions derived from this run's top ideas
1063
+ jq -n \
1064
+ --arg domain "idea" \
1065
+ --arg status "<status>" \
1066
+ --argjson artifacts '[]' \
1067
+ --argjson next_actions '["<next_action_1>","<next_action_2>"]' \
1068
+ '{domain:$domain,status:$status,artifacts:$artifacts,next_actions:$next_actions}' \
1069
+ > "$REPO_ROOT/.monomind/sessions/${SESSION_ID}/idea.json"
1070
+ curl -s -o /dev/null -X POST "${CTRL_URL}/api/mastermind/event" \
1071
+ -H "Content-Type: application/json" \
1072
+ -d "$(jq -cn --arg sid "$SESSION_ID" --arg status "<status>" \
1073
+ '{type:"domain:complete",session:$sid,domain:"idea",status:$status,ts:(now*1000|floor)}')" || true
1074
+ fi
1075
+ ```
1076
+
949
1077
  Return unified output schema to caller:
950
1078
 
951
1079
  ```yaml
@@ -963,9 +1091,9 @@ lessons:
963
1091
  next_actions:
964
1092
  - <e.g. "run mastermind:build to prototype chosen direction">
965
1093
  - <e.g. "run mastermind:research to validate top idea">
966
- board_url: "monotask://<project_name>/Ideas & Innovation"
967
- task_board_url: "monotask://<project_name>/Implementation Tasks"
968
- ops_task_board_url: "monotask://<project_name>/Operations Tasks"
1094
+ board_url: "monotask://<project_name>/${project_name}-idea"
1095
+ task_board_url: "monotask://<project_name>/${project_name}-tasks-dev"
1096
+ ops_task_board_url: "monotask://<project_name>/${project_name}-tasks-ops"
969
1097
  run_id: <ISO8601-timestamp>
970
1098
  summary:
971
1099
  ideas_generated: N