@monoes/monomindcli 1.9.16 → 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 +100 -46
  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 +37 -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 +318 -186
  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
@@ -69,53 +69,60 @@ For simple prompts (single agent, single output):
69
69
  Set up the space and ideation board. The ideation board has a dedicated pipeline with six columns (not master's board).
70
70
 
71
71
  ```bash
72
+ # Compatible with macOS bash 3.2
72
73
  project_name="${project_name:-$(basename "$PWD")}"
73
74
  date=$(date -u +%Y-%m-%dT%H:%M:%SZ)
75
+ idea_canonical="${project_name}-idea"
74
76
 
75
- # Find or create space
76
- space_id=$(monotask space list 2>/dev/null | awk -F' \| ' -v n="$project_name" '$2==n{print $1}' | head -1)
77
- [ -z "$space_id" ] && space_id=$(monotask space create "$project_name" 2>&1 | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
77
+ # Find or create space (by exact name)
78
+ space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$project_name" | head -1)
79
+ [ -z "$space_id" ] && space_id=$(monotask space create "$project_name" 2>/dev/null | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
78
80
  [ -z "$space_id" ] && { echo "ERROR: Could not find or create space '$project_name'"; exit 1; }
79
- ```
80
-
81
- **Memory-first board lookup:** Check memory for `"mastermind-idea board_id"` in namespace `monomind`. If a board ID is returned, use it as `BOARD_ID` and look up the existing column IDs. Otherwise, create the board:
82
-
83
- ```bash
84
- BOARD_ID=$(monotask board create "Ideas & Innovation" --json | jq -r '.id // empty')
85
- [ -z "$BOARD_ID" ] && { echo "ERROR: Failed to create Ideas & Innovation board"; exit 1; }
86
- monotask space boards add "$space_id" "$BOARD_ID" >/dev/null 2>&1 || true
87
- npx monomind@latest memory store --key "mastermind-idea board_id" --value "$BOARD_ID" --namespace monomind
88
-
89
- # Create columns in pipeline order
90
- COL_NEW=$(monotask column create "$BOARD_ID" "New" --json | jq -r '.id')
91
- COL_EVALUATED=$(monotask column create "$BOARD_ID" "Evaluated" --json | jq -r '.id')
92
- COL_ELABORATED=$(monotask column create "$BOARD_ID" "Elaborated" --json | jq -r '.id')
93
- COL_TASKED=$(monotask column create "$BOARD_ID" "Tasked" --json | jq -r '.id')
94
- COL_ICED=$(monotask column create "$BOARD_ID" "Iced" --json | jq -r '.id')
95
- COL_REJECTED=$(monotask column create "$BOARD_ID" "Rejected" --json | jq -r '.id')
96
- ```
97
81
 
98
- If the board already existed, look up column IDs:
99
-
100
- ```bash
101
- columns=$(monotask column list "$BOARD_ID" --json)
102
- COL_NEW=$(echo "$columns" | jq -r '.[] | select(.title == "New") | .id' | head -1)
103
- COL_EVALUATED=$(echo "$columns" | jq -r '.[] | select(.title == "Evaluated") | .id' | head -1)
104
- COL_ELABORATED=$(echo "$columns"| jq -r '.[] | select(.title == "Elaborated") | .id' | head -1)
105
- COL_TASKED=$(echo "$columns" | jq -r '.[] | select(.title == "Tasked") | .id' | head -1)
106
- COL_ICED=$(echo "$columns" | jq -r '.[] | select(.title == "Iced") | .id' | head -1)
107
- COL_REJECTED=$(echo "$columns" | jq -r '.[] | select(.title == "Rejected") | .id' | head -1)
108
- [ -z "$COL_NEW" ] && { echo "ERROR: Could not find 'New' column on BOARD_ID=$BOARD_ID"; exit 1; }
109
- [ -z "$COL_EVALUATED" ] && { echo "ERROR: Could not find 'Evaluated' column on BOARD_ID=$BOARD_ID"; exit 1; }
110
- [ -z "$COL_ELABORATED" ] && { echo "ERROR: Could not find 'Elaborated' column on BOARD_ID=$BOARD_ID"; exit 1; }
111
- [ -z "$COL_TASKED" ] && { echo "ERROR: Could not find 'Tasked' column on BOARD_ID=$BOARD_ID"; exit 1; }
112
- [ -z "$COL_ICED" ] && { echo "ERROR: Could not find 'Iced' column on BOARD_ID=$BOARD_ID"; exit 1; }
113
- [ -z "$COL_REJECTED" ] && { echo "ERROR: Could not find 'Rejected' column on BOARD_ID=$BOARD_ID"; exit 1; }
82
+ # Find existing idea board by canonical name reuse across runs (same pattern as master Step 6)
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)
85
+
86
+ if [ -n "$BOARD_ID" ]; then
87
+ echo "Reusing idea board: $BOARD_ID ($idea_canonical)"
88
+ columns=$(monotask column list "$BOARD_ID" --json)
89
+ COL_NEW=$(echo "$columns" | jq -r '.[] | select(.title == "New") | .id' | head -1)
90
+ COL_EVALUATED=$(echo "$columns" | jq -r '.[] | select(.title == "Evaluated") | .id' | head -1)
91
+ COL_ELABORATED=$(echo "$columns"| jq -r '.[] | select(.title == "Elaborated") | .id' | head -1)
92
+ COL_TASKED=$(echo "$columns" | jq -r '.[] | select(.title == "Tasked") | .id' | head -1)
93
+ COL_ICED=$(echo "$columns" | jq -r '.[] | select(.title == "Iced") | .id' | head -1)
94
+ COL_REJECTED=$(echo "$columns" | jq -r '.[] | select(.title == "Rejected") | .id' | head -1)
95
+ [ -z "$COL_NEW" ] && { echo "ERROR: 'New' column missing on board $BOARD_ID — was board created with wrong schema?"; exit 1; }
96
+ [ -z "$COL_EVALUATED" ] && { echo "ERROR: 'Evaluated' column missing on board $BOARD_ID"; exit 1; }
97
+ [ -z "$COL_ELABORATED" ] && { echo "ERROR: 'Elaborated' column missing on board $BOARD_ID"; exit 1; }
98
+ [ -z "$COL_TASKED" ] && { echo "ERROR: 'Tasked' column missing on board $BOARD_ID"; exit 1; }
99
+ [ -z "$COL_ICED" ] && { echo "ERROR: 'Iced' column missing on board $BOARD_ID"; exit 1; }
100
+ [ -z "$COL_REJECTED" ] && { echo "ERROR: 'Rejected' column missing on board $BOARD_ID"; exit 1; }
101
+ else
102
+ echo "Creating idea board: $idea_canonical"
103
+ BOARD_ID=$(monotask board create --space "$space_id" "$idea_canonical" --json 2>/dev/null | jq -r '.id // empty')
104
+ [ -z "$BOARD_ID" ] && { echo "ERROR: Failed to create idea board '$idea_canonical'"; exit 1; }
105
+ monotask space boards add "$space_id" "$BOARD_ID" >/dev/null 2>&1 || true
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')
112
+ fi
114
113
  ```
115
114
 
116
115
  **After either branch above, validate and echo all values.** This is the canonical source for Step 4 Task construction.
117
116
 
118
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
+
119
126
  # Validate BOARD_ID looks like a UUID before proceeding
120
127
  [[ ! "$BOARD_ID" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]] && \
121
128
  { echo "ERROR: BOARD_ID '$BOARD_ID' is not a valid UUID — aborting to prevent board name corruption"; exit 1; }
@@ -146,20 +153,26 @@ TOP_N=6
146
153
 
147
154
  # Select user/market/ops angle specialists
148
155
  CATEGORIES="marketing strategy product academic specialized"
149
- user_market_agents=$(jq -r \
156
+ user_market_agents=$(jq \
150
157
  --arg cats "$CATEGORIES" \
151
158
  --arg kw "$(echo "$PROMPT" | tr '[:upper:]' '[:lower:]' | grep -oE '[a-z]{5,}' | sort -u | tr '\n' ' ')" \
152
159
  --argjson n "$TOP_N" \
153
160
  '[ .agents[] | select(.deprecated != true)
154
161
  | select(.category as $c | ($cats | split(" ") | any(. == $c)))
155
162
  | {name: .name, slug: .slug, category: .category,
156
- 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
+ )}
157
170
  ] | sort_by(-.score) | unique_by(.slug) | .[0:$n] | [.[].name]' \
158
171
  "$REGISTRY" 2>/dev/null)
159
172
 
160
173
  # Select technical angle specialists
161
174
  CATEGORIES="engineering development architecture"
162
- tech_agents=$(jq -r \
175
+ tech_agents=$(jq \
163
176
  --arg cats "$CATEGORIES" \
164
177
  --argjson n 3 \
165
178
  '[ .agents[] | select(.deprecated != true)
@@ -169,11 +182,14 @@ tech_agents=$(jq -r \
169
182
  "$REGISTRY" 2>/dev/null)
170
183
 
171
184
  # Merge: take top 6 from market/ops + top 2 from tech (cap at 8 total)
172
- specialist_list=$(echo "$user_market_agents $tech_agents" | jq -Rs \
173
- '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)
174
189
 
175
- # Fallback if registry missing
176
- [ -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"]'
177
193
 
178
194
  echo "Selected specialists: $specialist_list"
179
195
  ```
@@ -248,6 +264,7 @@ For each unique idea, create one card in the New column (COL_NEW = ${COL_NEW}):
248
264
 
249
265
  result=$(monotask card create "${BOARD_ID}" "${COL_NEW}" "<idea title ≤80 chars>" --json)
250
266
  CARD_ID=$(echo "$result" | jq -r '.id // empty')
267
+ [ -z "$CARD_ID" ] && { echo "WARN: card creation failed for '<idea title>', skipping"; continue; }
251
268
  monotask card set-description "${BOARD_ID}" "$CARD_ID" "<2-3 sentence description>"
252
269
  monotask card comment add "${BOARD_ID}" "$CARD_ID" "CATEGORY: <feature | technical-baseline | business-operation>
253
270
  SOURCE: <which specialist angle produced this>"
@@ -274,7 +291,8 @@ Parse the `IDEAS_OUTPUT` JSON block from the agent's response and assign it:
274
291
  ```bash
275
292
  ideas_output_json='<paste the JSON array from IDEAS_OUTPUT here>'
276
293
  ```
277
- 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).
278
296
 
279
297
  ---
280
298
 
@@ -291,11 +309,11 @@ ideas_list=$(echo "$ideas_output_json" | jq -r \
291
309
  **CRITICAL — Variable substitution required for Step 5 Task call:**
292
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.
293
311
 
294
- 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.
295
313
 
296
314
  ```javascript
297
315
  Task({
298
- subagent_type: "Product Manager",
316
+ subagent_type: "general-purpose",
299
317
  description: "PM validation for project " + project_name,
300
318
  run_in_background: false,
301
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.
@@ -323,23 +341,31 @@ For EVERY idea above, determine:
323
341
  - skipElaboration: true (simple, no deep research needed) | false (edge cases should be explored) — only for evaluated
324
342
  - rationale: 1-2 sentence value statement (evaluated), blocking question (iced), or rejection reason (rejected)
325
343
 
326
- MANDATORY BOARD UPDATES — run these bash commands for EVERY idea, no exceptions:
327
-
328
- For evaluated ideas:
329
- monotask card move "${BOARD_ID}" "<CARD_ID>" "${COL_EVALUATED}" --json
330
- monotask card set-impact "${BOARD_ID}" "<CARD_ID>" <impact>
331
- monotask card set-effort "${BOARD_ID}" "<CARD_ID>" <effort>
332
- monotask card comment add "${BOARD_ID}" "<CARD_ID>" "Value: <rationale>"
333
-
334
- For iced ideas:
335
- monotask card move "${BOARD_ID}" "<CARD_ID>" "${COL_ICED}" --json
336
- monotask card set-impact "${BOARD_ID}" "<CARD_ID>" <impact>
337
- monotask card set-effort "${BOARD_ID}" "<CARD_ID>" <effort>
338
- monotask card comment add "${BOARD_ID}" "<CARD_ID>" "Blocked: <blocking question>"
339
-
340
- For rejected ideas:
341
- monotask card move "${BOARD_ID}" "<CARD_ID>" "${COL_REJECTED}" --json
342
- 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 '.[]')
343
369
 
344
370
  IMPORTANT: set-impact and set-effort MUST be called for every evaluated and iced idea. Do not skip them.
345
371
 
@@ -366,7 +392,8 @@ After the PM agent completes, parse the `VERDICTS_OUTPUT` block from the agent's
366
392
  ```bash
367
393
  verdicts_output_json='<paste the JSON array from VERDICTS_OUTPUT here>'
368
394
  ```
369
- 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).
370
397
 
371
398
  ---
372
399
 
@@ -376,9 +403,20 @@ This variable is used throughout Steps 6a and 6c to build idea lists, registry k
376
403
 
377
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:
378
405
  ```bash
379
- 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"
380
- monotask card move "$BOARD_ID" "$CARD_ID" "$COL_ELABORATED" --json
381
- 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)] | .[]')
382
420
  ```
383
421
 
384
422
  For ideas with `skipElaboration: false`, **split by category** before spawning agents:
@@ -386,19 +424,23 @@ For ideas with `skipElaboration: false`, **split by category** before spawning a
386
424
  **Build `dev_ideas_list` and `ops_ideas_list` before constructing the Step 6a Task prompts:**
387
425
  ```bash
388
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.
389
429
  dev_ideas_list=$(echo "$verdicts_output_json" | jq -r \
390
- '.[] | 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") |
391
432
  "- card_id: \(.card_id)\n title: \(.title)\n category: \(.category)\n rationale: \(.rationale)\n"')
392
433
 
393
434
  ops_ideas_list=$(echo "$verdicts_output_json" | jq -r \
394
- '.[] | select(.verdict == "evaluated") | select(.category == "business-operation") |
435
+ '.[] | select(.verdict == "evaluated") | select(.skipElaboration != true)
436
+ | select(.category == "business-operation") |
395
437
  "- card_id: \(.card_id)\n title: \(.title)\n category: \(.category)\n rationale: \(.rationale)\n"')
396
438
  ```
397
439
 
398
440
  **CRITICAL — Variable substitution required for Step 6a Task calls:**
399
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.
400
442
 
401
- **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):
402
444
  Spawn two agents in parallel via Task tool:
403
445
 
404
446
  ```javascript
@@ -457,7 +499,7 @@ END_ELABORATION_OUTPUT`
457
499
  })
458
500
  ```
459
501
 
460
- **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):
461
503
  Spawn two agents in parallel via Task tool:
462
504
 
463
505
  ```javascript
@@ -516,7 +558,7 @@ END_ELABORATION_OUTPUT`
516
558
  })
517
559
  ```
518
560
 
519
- 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`:
520
562
 
521
563
  ```bash
522
564
  # Assign each agent's ELABORATION_OUTPUT JSON array from its output block:
@@ -525,29 +567,45 @@ dev_codebase_json='<ELABORATION_OUTPUT array from the dev code-explorer agent>'
525
567
  ops_researcher_json='<ELABORATION_OUTPUT array from the ops researcher agent>'
526
568
  ops_pm_json='<ELABORATION_OUTPUT array from the ops PM agent>'
527
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 '[]'
528
571
 
529
- # 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).
530
575
  dev_merged=$(jq -n \
531
576
  --argjson r "$dev_researcher_json" \
532
577
  --argjson c "$dev_codebase_json" \
533
578
  --argjson v "$verdicts_output_json" \
534
- '[$r[] | {card_id: .card_id, blocking_issue: .blocking_issue,
535
- researcher_findings: .findings,
536
- codebase_findings: ([$c[] | select(.card_id == .card_id)] | first | .findings // ""),
537
- category: ([$v[] | select(.card_id == .card_id)] | first | .category // "feature")}]')
538
-
539
- # 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).
540
592
  ops_merged=$(jq -n \
541
593
  --argjson r "$ops_researcher_json" \
542
594
  --argjson p "$ops_pm_json" \
543
595
  --argjson v "$verdicts_output_json" \
544
- '[$r[] | {card_id: .card_id, blocking_issue: .blocking_issue,
545
- researcher_findings: .findings,
546
- pm_findings: ([$p[] | select(.card_id == .card_id)] | first | .findings // ""),
547
- 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") }]')
548
606
 
549
607
  # Combine both tracks
550
- 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"))
551
609
  ```
552
610
 
553
611
  Use process substitution (not a pipeline) so the while loop runs in the main shell and variables remain in scope after `done`:
@@ -556,7 +614,8 @@ Use process substitution (not a pipeline) so the while loop runs in the main she
556
614
  while IFS= read -r idea; do
557
615
  CARD_ID=$(echo "$idea" | jq -r '.card_id')
558
616
  category=$(echo "$idea" | jq -r '.category')
559
- 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"
560
619
 
561
620
  if [ "$category" = "business-operation" ]; then
562
621
  researcher_findings=$(echo "$idea" | jq -r '.researcher_findings')
@@ -599,7 +658,7 @@ done < <(echo "$merged_elaboration_json" | jq -c '.[]')
599
658
 
600
659
  **Confirm mode only:** If `mode` is `confirm` (default), present a review table of all elaborated ideas to the user.
601
660
 
602
- 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:
603
662
  - **Impact** and **Effort** come from `.impact` and `.effort` fields in `verdicts_output_json`
604
663
  - **Track**: `feature` or `technical-baseline` → `dev`; `business-operation` → `ops`
605
664
 
@@ -640,7 +699,7 @@ Wait for the user's response before continuing. Do not spawn any agents until a
640
699
  ```bash
641
700
  monotask card comment add "$BOARD_ID" "$CARD_ID" "User notes: <notes>"
642
701
  ```
643
- - **"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`.
644
703
  - Combined instructions ("remove 2,4 | add detail to 1: ...") are processed together.
645
704
 
646
705
  After applying all user instructions, proceed to Step 6c with the remaining ideas.
@@ -655,11 +714,7 @@ After applying all user instructions, proceed to Step 6c with the remaining idea
655
714
  REGISTRY=".monomind/registry.json"
656
715
 
657
716
  # Dev decomposition agent — pick the most relevant engineering/architecture specialist
658
- # Build keyword signal from elaborated dev idea titles (from VERDICTS_OUTPUT filtered above)
659
- DEV_IDEA_CONTEXT=$(echo "$verdicts_output_json" | jq -r \
660
- '[.[] | select(.verdict=="evaluated") | select(.category=="feature" or .category=="technical-baseline") | .title] | join(" ")')
661
717
  dev_decomp_agent=$(jq -r \
662
- --arg kw "$(echo "$DEV_IDEA_CONTEXT" | tr '[:upper:]' '[:lower:]' | grep -oE '[a-z]{5,}' | sort -u | tr '\n' ' ')" \
663
718
  '[ .agents[] | select(.deprecated != true)
664
719
  | select(.category == "engineering" or .category == "architecture")
665
720
  | {name: .name,
@@ -677,10 +732,7 @@ dev_decomp_agent=$(jq -r \
677
732
  dev_decomp_agent="${dev_decomp_agent:-Software Architect}"
678
733
 
679
734
  # Ops decomposition agent — pick the most relevant strategy/sales/product specialist
680
- OPS_IDEA_CONTEXT=$(echo "$verdicts_output_json" | jq -r \
681
- '[.[] | select(.verdict=="evaluated") | select(.category=="business-operation") | .title] | join(" ")')
682
735
  ops_decomp_agent=$(jq -r \
683
- --arg kw "$(echo "$OPS_IDEA_CONTEXT" | tr '[:upper:]' '[:lower:]' | grep -oE '[a-z]{5,}' | sort -u | tr '\n' ' ')" \
684
736
  '[ .agents[] | select(.deprecated != true)
685
737
  | select(.category == "strategy" or .category == "sales" or .category == "product" or .category == "marketing")
686
738
  | {name: .name,
@@ -704,13 +756,29 @@ echo "Dev decomp: $dev_decomp_agent | Ops decomp: $ops_decomp_agent"
704
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:
705
757
 
706
758
  ```bash
707
- # 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).
708
770
  dev_ideas_elaborated=$(echo "$verdicts_output_json" | jq -r \
709
- '[.[] | 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") |
710
775
  "card_id: \(.card_id)\ntitle: \(.title)\ncategory: \(.category)\nrationale: \(.rationale)\nimpact: \(.impact) effort: \(.effort)"] | join("\n\n")')
711
776
 
712
777
  ops_ideas_elaborated=$(echo "$verdicts_output_json" | jq -r \
713
- '[.[] | 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") |
714
782
  "card_id: \(.card_id)\ntitle: \(.title)\ncategory: \(.category)\nrationale: \(.rationale)\nimpact: \(.impact) effort: \(.effort)"] | join("\n\n")')
715
783
  ```
716
784
 
@@ -802,56 +870,77 @@ END_TASKS_OUTPUT`
802
870
 
803
871
  **Dev task board** (`feature` / `technical-baseline` → `Implementation Tasks`):
804
872
 
805
- Check memory for `"implementation-tasks board_id"` in namespace `monomind`. If found, use it as `TASK_BOARD_ID`. Otherwise create it:
806
-
807
- ```bash
808
- TASK_BOARD_ID=$(monotask board create "Implementation Tasks" --json | jq -r '.id // empty')
809
- monotask space boards add "$space_id" "$TASK_BOARD_ID" >/dev/null 2>&1 || true
810
- npx monomind@latest memory store --key "implementation-tasks board_id" --value "$TASK_BOARD_ID" --namespace monomind
811
- monotask column create "$TASK_BOARD_ID" "Backlog" --json >/dev/null
812
- monotask column create "$TASK_BOARD_ID" "Todo" --json >/dev/null
813
- monotask column create "$TASK_BOARD_ID" "In Progress" --json >/dev/null
814
- monotask column create "$TASK_BOARD_ID" "Review" --json >/dev/null
815
- monotask column create "$TASK_BOARD_ID" "Human in Loop" --json >/dev/null
816
- monotask column create "$TASK_BOARD_ID" "Done" --json >/dev/null
817
- ```
873
+ Canonical board name: `${project_name}-tasks-dev`. Find-or-create:
818
874
 
819
- Look up and validate column IDs:
820
875
  ```bash
821
- [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: TASK_BOARD_ID is empty aborting to prevent card creation on null board"; exit 1; }
822
- task_columns=$(monotask column list "$TASK_BOARD_ID" --json)
823
- TASK_COL_TODO=$(echo "$task_columns" | jq -r '.[] | select(.title == "Todo") | .id' | head -1)
824
- TASK_COL_BACKLOG=$(echo "$task_columns" | jq -r '.[] | select(.title == "Backlog") | .id' | head -1)
825
- [ -z "$TASK_COL_TODO" ] && { echo "ERROR: Could not find 'Todo' column on TASK_BOARD_ID=$TASK_BOARD_ID"; exit 1; }
826
- [ -z "$TASK_COL_BACKLOG" ] && { echo "ERROR: Could not find 'Backlog' column on TASK_BOARD_ID=$TASK_BOARD_ID"; exit 1; }
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
882
+ dev_task_canonical="${project_name}-tasks-dev"
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)
885
+ if [ -n "$TASK_BOARD_ID" ]; then
886
+ echo "Reusing dev task board: $TASK_BOARD_ID ($dev_task_canonical)"
887
+ task_columns=$(monotask column list "$TASK_BOARD_ID" --json)
888
+ TASK_COL_TODO=$(echo "$task_columns" | jq -r '.[] | select(.title=="Todo") | .id' | head -1)
889
+ TASK_COL_BACKLOG=$(echo "$task_columns" | jq -r '.[] | select(.title=="Backlog") | .id' | head -1)
890
+ else
891
+ echo "Creating dev task board: $dev_task_canonical"
892
+ TASK_BOARD_ID=$(monotask board create --space "$space_id" "$dev_task_canonical" --json 2>/dev/null | jq -r '.id // empty')
893
+ [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: Failed to create dev task board"; exit 1; }
894
+ monotask space boards add "$space_id" "$TASK_BOARD_ID" >/dev/null 2>&1 || true
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')
897
+ monotask column create "$TASK_BOARD_ID" "In Progress" --json >/dev/null
898
+ monotask column create "$TASK_BOARD_ID" "Human in Loop" --json >/dev/null
899
+ monotask column create "$TASK_BOARD_ID" "Review" --json >/dev/null
900
+ monotask column create "$TASK_BOARD_ID" "Done" --json >/dev/null
901
+ monotask column create "$TASK_BOARD_ID" "Cancelled" --json >/dev/null
902
+ fi
903
+ [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: TASK_BOARD_ID empty — aborting"; exit 1; }
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; }
827
906
  ```
828
907
 
829
908
  ---
830
909
 
831
910
  **Ops task board** (`business-operation` → `Operations Tasks`):
832
911
 
833
- Check memory for `"operations-tasks board_id"` in namespace `monomind`. If found, use it as `OPS_BOARD_ID`. Otherwise create it:
912
+ Canonical board name: `${project_name}-tasks-ops`. Find-or-create:
834
913
 
835
914
  ```bash
836
- OPS_BOARD_ID=$(monotask board create "Operations Tasks" --json | jq -r '.id // empty')
837
- monotask space boards add "$space_id" "$OPS_BOARD_ID" >/dev/null 2>&1 || true
838
- npx monomind@latest memory store --key "operations-tasks board_id" --value "$OPS_BOARD_ID" --namespace monomind
839
- monotask column create "$OPS_BOARD_ID" "Backlog" --json >/dev/null
840
- monotask column create "$OPS_BOARD_ID" "Todo" --json >/dev/null
841
- monotask column create "$OPS_BOARD_ID" "In Progress" --json >/dev/null
842
- monotask column create "$OPS_BOARD_ID" "Review" --json >/dev/null
843
- monotask column create "$OPS_BOARD_ID" "Human in Loop" --json >/dev/null
844
- monotask column create "$OPS_BOARD_ID" "Done" --json >/dev/null
845
- ```
846
-
847
- Look up and validate column IDs:
848
- ```bash
849
- [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: OPS_BOARD_ID is empty — aborting to prevent card creation on null board"; exit 1; }
850
- ops_columns=$(monotask column list "$OPS_BOARD_ID" --json)
851
- OPS_COL_TODO=$(echo "$ops_columns" | jq -r '.[] | select(.title == "Todo") | .id' | head -1)
852
- OPS_COL_BACKLOG=$(echo "$ops_columns" | jq -r '.[] | select(.title == "Backlog") | .id' | head -1)
853
- [ -z "$OPS_COL_TODO" ] && { echo "ERROR: Could not find 'Todo' column on OPS_BOARD_ID=$OPS_BOARD_ID"; exit 1; }
854
- [ -z "$OPS_COL_BACKLOG" ] && { echo "ERROR: Could not find 'Backlog' column on OPS_BOARD_ID=$OPS_BOARD_ID"; exit 1; }
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
920
+ ops_task_canonical="${project_name}-tasks-ops"
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)
923
+ if [ -n "$OPS_BOARD_ID" ]; then
924
+ echo "Reusing ops task board: $OPS_BOARD_ID ($ops_task_canonical)"
925
+ ops_columns=$(monotask column list "$OPS_BOARD_ID" --json)
926
+ OPS_COL_TODO=$(echo "$ops_columns" | jq -r '.[] | select(.title=="Todo") | .id' | head -1)
927
+ OPS_COL_BACKLOG=$(echo "$ops_columns" | jq -r '.[] | select(.title=="Backlog") | .id' | head -1)
928
+ else
929
+ echo "Creating ops task board: $ops_task_canonical"
930
+ OPS_BOARD_ID=$(monotask board create --space "$space_id" "$ops_task_canonical" --json 2>/dev/null | jq -r '.id // empty')
931
+ [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: Failed to create ops task board"; exit 1; }
932
+ monotask space boards add "$space_id" "$OPS_BOARD_ID" >/dev/null 2>&1 || true
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')
935
+ monotask column create "$OPS_BOARD_ID" "In Progress" --json >/dev/null
936
+ monotask column create "$OPS_BOARD_ID" "Human in Loop" --json >/dev/null
937
+ monotask column create "$OPS_BOARD_ID" "Review" --json >/dev/null
938
+ monotask column create "$OPS_BOARD_ID" "Done" --json >/dev/null
939
+ monotask column create "$OPS_BOARD_ID" "Cancelled" --json >/dev/null
940
+ fi
941
+ [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: OPS_BOARD_ID empty — aborting"; exit 1; }
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; }
855
944
  ```
856
945
 
857
946
  ---
@@ -863,13 +952,13 @@ OPS_COL_BACKLOG=$(echo "$ops_columns" | jq -r '.[] | select(.title == "Backlog")
863
952
  dev_tasks_json='<TASKS_OUTPUT JSON array from dev decomp agent, or [] if no dev ideas>'
864
953
  # Parse the TASKS_OUTPUT block from the ops decomp agent's response and assign:
865
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 '[]'
866
956
 
867
- 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"))
868
958
 
869
- # Use process substitution (not a pipeline) so variables set inside the loop
870
- # remain in scope after done needed for the parent-annotation step below.
871
- # Also initialise the subtask-accumulator map before the loop.
872
- 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)
873
962
 
874
963
  while IFS= read -r task; do
875
964
  parent_card_id=$(echo "$task" | jq -r '.parent_card_id')
@@ -881,59 +970,78 @@ while IFS= read -r task; do
881
970
  has_prerequisites=$(echo "$task" | jq -r '.has_prerequisites')
882
971
 
883
972
  if [ "$category" = "business-operation" ]; then
884
- TARGET_BOARD="$OPS_BOARD_ID"
885
- COL_TARGET=$([ "$has_prerequisites" = "true" ] && echo "$OPS_COL_BACKLOG" || echo "$OPS_COL_TODO")
886
- BOARD_LABEL="Operations Tasks"
887
- else
888
- TARGET_BOARD="$TASK_BOARD_ID"
889
- COL_TARGET=$([ "$has_prerequisites" = "true" ] && echo "$TASK_COL_BACKLOG" || echo "$TASK_COL_TODO")
890
- BOARD_LABEL="Implementation Tasks"
891
- 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
892
981
 
893
- # Inherit impact and effort from parent idea — look up from verdicts_output_json by parent_card_id
894
- parent_impact=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .impact // 5')
895
- parent_effort=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .effort // 5')
896
- # Default to 5 if lookup returned empty (e.g. parent_card_id was "UNKNOWN")
897
- [ -z "$parent_impact" ] && parent_impact=5
898
- [ -z "$parent_effort" ] && parent_effort=5
899
-
900
- # Create task card as a proper subtask of the parent idea card (cross-board link)
901
- # Signature: subtask add <PARENT_BOARD_ID> <PARENT_CARD_ID> <CHILD_BOARD_ID> <COL_ID> <TITLE>
902
- TASK_CARD_ID=$(monotask card subtask add "$BOARD_ID" "$parent_card_id" "$TARGET_BOARD" "$COL_TARGET" "<task title>" --json | jq -r '.id')
903
- # Set the task description as the primary content field
904
- monotask card set-description "$TARGET_BOARD" "$TASK_CARD_ID" "<what to build/do from TASKS_OUTPUT description>"
905
- monotask card set-impact "$TARGET_BOARD" "$TASK_CARD_ID" "$parent_impact"
906
- monotask card set-effort "$TARGET_BOARD" "$TASK_CARD_ID" "$parent_effort"
907
- monotask card comment add "$TARGET_BOARD" "$TASK_CARD_ID" \
908
- "SOURCE: mastermind:idea | <first 100 chars of prompt>
909
- AGENT: <agent>
910
- TASK EFFORT: <task_effort>/10
911
- PARENT IDEA IMPACT: <parent_impact>/10 PARENT IDEA EFFORT: <parent_effort>/10
912
- CATEGORY: <category>
913
- PARENT IDEA: <idea title> (card: <parent_card_id> on ideation board)"
914
- monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "mastermind:idea"
915
- monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "category:$category"
916
-
917
- # Accumulate subtask summary for this parent (used in the post-loop annotation step)
918
- 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"
919
1013
 
920
1014
  done < <(echo "$merged_tasks_json" | jq -c '.[]')
921
1015
  ```
922
1016
 
923
1017
  After the loop, annotate each parent idea card and move it to `Tasked`:
924
1018
  ```bash
925
- for parent_card_id in "${!parent_subtask_summaries[@]}"; do
926
- 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")
927
1023
  monotask card comment add "$BOARD_ID" "$parent_card_id" \
928
- "Subtasks created:\n${subtask_list}"
1024
+ "Subtasks created:
1025
+ ${subtask_list}"
929
1026
  monotask card move "$BOARD_ID" "$parent_card_id" "$COL_TASKED" --json
930
1027
  done
1028
+ rm -rf "$SUBTASK_TMPDIR"
931
1029
  ```
932
1030
 
933
- 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:
934
1032
  ```bash
935
- monotask card comment add "$BOARD_ID" "$flagged_card_id" "Needs clarification: <question>"
936
- 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 '.[]')
937
1045
  ```
938
1046
 
939
1047
  ---
@@ -942,6 +1050,30 @@ monotask card move "$BOARD_ID" "$flagged_card_id" "$COL_ICED" --json
942
1050
 
943
1051
  Follow _protocol.md Brain Write Procedure (namespace: `idea`).
944
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
+
945
1077
  Return unified output schema to caller:
946
1078
 
947
1079
  ```yaml
@@ -959,9 +1091,9 @@ lessons:
959
1091
  next_actions:
960
1092
  - <e.g. "run mastermind:build to prototype chosen direction">
961
1093
  - <e.g. "run mastermind:research to validate top idea">
962
- board_url: "monotask://<project_name>/Ideas & Innovation"
963
- task_board_url: "monotask://<project_name>/Implementation Tasks"
964
- 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"
965
1097
  run_id: <ISO8601-timestamp>
966
1098
  summary:
967
1099
  ideas_generated: N