@monoes/monomindcli 1.9.15 → 1.9.17

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.
@@ -166,95 +166,111 @@ If mode = auto: proceed immediately.
166
166
 
167
167
  Follow the Monotask Space+Board Setup Procedure from `_protocol.md`. Resolve the space **once**, then create one board per active domain. Use `project_name` as the space name so all boards across repos and domains share the same space.
168
168
 
169
- ```bash
170
- # Require bash 4.3+ for associative arrays and namerefs (local -n introduced in 4.3)
171
- # macOS ships bash 3.2; install via: brew install bash
172
- (( BASH_VERSINFO[0] * 100 + BASH_VERSINFO[1] < 403 )) && \
173
- { echo "ERROR: bash 4.3+ required for namerefs (current: $BASH_VERSION). Install: brew install bash"; exit 1; }
169
+ **Board naming convention:** Every board is named `<project_name>-<domain>` (e.g. `factory-idea`, `factory-build`). This canonical name is stable across runs — mastermind finds the existing board instead of creating a new one every time.
174
170
 
171
+ ```bash
172
+ # Compatible with macOS bash 3.2 — no associative arrays, uses jq accumulation instead
175
173
  REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
176
174
  SESSION_STATE="$REPO_ROOT/.monomind/sessions/current.json"
177
175
 
178
- # Reload persisted context (this is a fresh shell; Step 3 wrote these)
179
176
  SESSION_ID=$(jq -r '.sessionId // empty' "$SESSION_STATE" 2>/dev/null)
180
177
  [ -z "$SESSION_ID" ] && { echo "ERROR: SESSION_ID missing in current.json — run Step 3 first"; exit 1; }
181
178
  project_name=$(jq -r '.project_name // ""' "$SESSION_STATE")
182
179
  [ -z "$project_name" ] && { echo "ERROR: project_name is empty in current.json — run Step 3 first"; exit 1; }
183
180
  resolved_prompt=$(jq -r '.prompt // ""' "$SESSION_STATE")
184
181
 
185
- # domains_needed: NOT yet in current.json at this point — must be LLM-substituted inline.
186
182
  # LLM: replace DOMAINS_LIST_HERE with space-separated domain names, e.g.: build marketing sales
187
- # Domain names must be single words (no spaces). Example: "build marketing sales"
183
+ domains_needed="DOMAINS_LIST_HERE"
184
+ [ "$domains_needed" = "DOMAINS_LIST_HERE" ] && { echo "ERROR: LLM did not substitute DOMAINS_LIST_HERE"; exit 1; }
185
+ [ -z "$domains_needed" ] && { echo "ERROR: domains_needed is empty — nothing to do"; exit 1; }
188
186
 
189
- # Resolve space once for all domains
190
- # Use awk with literal pipe to avoid BSD awk \| regex fragility
191
- space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$2); if($2==n) gsub(/^ +| +$/,"",$1); if($2==n) print $1}' n="$project_name" | head -1)
187
+ # Resolve space once find existing by exact name or create
188
+ space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$project_name" | head -1)
192
189
  [ -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}')
193
190
  [ -z "$space_id" ] && { echo "ERROR: Could not find or create space '$project_name'"; exit 1; }
191
+ echo "Space: $space_id ($project_name)"
194
192
 
195
- # Associative arrays no eval, no injection risk
196
- declare -A board_ids todo_cols doing_cols done_cols domain_goals
197
-
198
- # Hydrate domain_goals from Step 4's current.json write — prevents Step 4 extraction being clobbered
199
- # Use NUL-delimited pairs (not @tsv) to safely handle backslashes, tabs, and other special chars in goals
200
- while IFS= read -r -d '' k && IFS= read -r -d '' v; do
201
- [[ -n "$k" ]] && domain_goals[$k]="$v"
202
- done < <(jq -j '.domain_goals // {} | to_entries[] | (.key + "\u0000" + (.value // "") + "\u0000")' "$SESSION_STATE" 2>/dev/null)
193
+ # jq accumulation state (replaces bash 4.3+ associative arrays)
194
+ state_patch='{}'
203
195
 
204
- # Loop over every active domain — LLM: replace DOMAINS_LIST_HERE with the resolved domain list
205
- domains_needed="DOMAINS_LIST_HERE"
206
- [ "$domains_needed" = "DOMAINS_LIST_HERE" ] && { echo "ERROR: LLM did not substitute DOMAINS_LIST_HERE with domain names"; exit 1; }
207
- [ -z "$domains_needed" ] && { echo "ERROR: domains_needed is empty — nothing to do"; exit 1; }
208
196
  for domain in $domains_needed; do
209
- board_id=$(monotask board create "$domain" --json | jq -r '.id // empty')
210
- [ -z "$board_id" ] && { echo "ERROR: Failed to create $domain board"; exit 1; }
211
- monotask space boards add "$space_id" "$board_id" >/dev/null 2>&1 \
212
- || echo "WARN: could not attach $domain board to space $space_id (non-fatal)"
213
- todo_col=$(monotask column create "$board_id" "Todo" --json | jq -r '.id // empty')
214
- [ -z "$todo_col" ] && { echo "ERROR: Failed to create Todo column for $domain"; exit 1; }
215
- doing_col=$(monotask column create "$board_id" "Doing" --json | jq -r '.id // empty')
216
- [ -z "$doing_col" ] && { echo "ERROR: Failed to create Doing column for $domain"; exit 1; }
217
- done_col=$(monotask column create "$board_id" "Done" --json | jq -r '.id // empty')
218
- [ -z "$done_col" ] && { echo "ERROR: Failed to create Done column for $domain"; exit 1; }
219
- board_ids[$domain]=$board_id
220
- todo_cols[$domain]=$todo_col
221
- doing_cols[$domain]=$doing_col
222
- done_cols[$domain]=$done_col
223
- # Fall back to full prompt only for domains not extracted by Step 4
224
- [ -z "${domain_goals[$domain]}" ] && domain_goals[$domain]="$resolved_prompt"
225
- done
197
+ canonical="${project_name}-${domain}"
226
198
 
227
- # Persist all session state needed by later shellsboard/col IDs, goals, domain list
228
- # (each Bash tool call is a fresh shell associative arrays don't survive)
229
- _to_json_map() {
230
- local -n _arr=$1
231
- for k in "${!_arr[@]}"; do
232
- jq -n --arg k "$k" --arg v "${_arr[$k]}" '{key:$k,value:$v}'
233
- done | jq -s 'from_entries // {}'
234
- }
235
- domains_goals_json=$(_to_json_map domain_goals)
236
- board_ids_json=$(_to_json_map board_ids)
237
- todo_cols_json=$(_to_json_map todo_cols)
238
- doing_cols_json=$(_to_json_map doing_cols)
239
- done_cols_json=$(_to_json_map done_cols)
199
+ # Find existing board by canonical namereuse across runs
200
+ board_id=$(monotask board list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$canonical" | head -1)
240
201
 
202
+ # Domain-specific column schema:
203
+ # idea → New | Evaluated | Elaborated | Tasked | Iced | Rejected (intake = "New")
204
+ # all others → Todo | In Progress | Human in Loop | Review | Done | Cancelled (intake = "Todo")
205
+ if [ "$domain" = "idea" ]; then
206
+ intake_col_name="New"
207
+ else
208
+ intake_col_name="Todo"
209
+ fi
210
+
211
+ if [ -n "$board_id" ]; then
212
+ echo "Reusing board: $board_id ($canonical)"
213
+ cols_json=$(monotask column list "$board_id" --json 2>/dev/null || echo '[]')
214
+ todo_col=$(echo "$cols_json" | jq -r --arg n "$intake_col_name" '[.[] | select(.title==$n)] | .[0].id // empty')
215
+ doing_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="In Progress" or .title=="Doing")] | .[0].id // empty')
216
+ done_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="Done")] | .[0].id // empty')
217
+ else
218
+ echo "Creating board: $canonical"
219
+ board_id=$(monotask board create --space "$space_id" "$canonical" --json 2>/dev/null | jq -r '.id // empty')
220
+ [ -z "$board_id" ] && { echo "ERROR: Failed to create board '$canonical'"; exit 1; }
221
+ monotask space boards add "$space_id" "$board_id" >/dev/null 2>&1 || true
222
+ if [ "$domain" = "idea" ]; then
223
+ todo_col=$(monotask column create "$board_id" "New" --json | jq -r '.id // empty')
224
+ doing_col=$(monotask column create "$board_id" "Evaluated" --json | jq -r '.id // empty')
225
+ monotask column create "$board_id" "Elaborated" --json >/dev/null
226
+ monotask column create "$board_id" "Tasked" --json >/dev/null
227
+ monotask column create "$board_id" "Iced" --json >/dev/null
228
+ done_col=$(monotask column create "$board_id" "Rejected" --json | jq -r '.id // empty')
229
+ else
230
+ todo_col=$(monotask column create "$board_id" "Todo" --json | jq -r '.id // empty')
231
+ doing_col=$(monotask column create "$board_id" "In Progress" --json | jq -r '.id // empty')
232
+ monotask column create "$board_id" "Human in Loop" --json >/dev/null
233
+ monotask column create "$board_id" "Review" --json >/dev/null
234
+ done_col=$(monotask column create "$board_id" "Done" --json | jq -r '.id // empty')
235
+ monotask column create "$board_id" "Cancelled" --json >/dev/null
236
+ fi
237
+ [ -z "$todo_col" ] && { echo "ERROR: Failed to create intake column for $domain"; exit 1; }
238
+ fi
239
+
240
+ domain_goal=$(jq -r --arg d "$domain" '.domain_goals[$d] // empty' "$SESSION_STATE")
241
+ [ -z "$domain_goal" ] && domain_goal="$resolved_prompt"
242
+
243
+ state_patch=$(echo "$state_patch" | jq \
244
+ --arg d "$domain" --arg b "$board_id" \
245
+ --arg t "$todo_col" --arg g "$doing_col" --arg e "$done_col" \
246
+ --arg goal "$domain_goal" \
247
+ '.board_ids[$d]=$b | .todo_cols[$d]=$t | .doing_cols[$d]=$g | .done_cols[$d]=$e | .domain_goals[$d]=$goal')
248
+
249
+ echo "DOMAIN=$domain BOARD=$board_id TODO=$todo_col DOING=$doing_col DONE=$done_col"
250
+ done
251
+
252
+ # Persist to current.json — one atomic merge
241
253
  jq --arg domains "$domains_needed" \
242
- --argjson goals "$domains_goals_json" \
243
- --argjson boards "$board_ids_json" \
244
- --argjson todos "$todo_cols_json" \
245
- --argjson doings "$doing_cols_json" \
246
- --argjson dones "$done_cols_json" \
247
- '. + {domains_needed:($domains | split(" ") | map(select(length>0))),
248
- domain_goals:$goals, board_ids:$boards,
249
- todo_cols:$todos, doing_cols:$doings, done_cols:$dones}' \
250
- "$REPO_ROOT/.monomind/sessions/current.json" > "$REPO_ROOT/.monomind/sessions/current.json.tmp" \
251
- && mv "$REPO_ROOT/.monomind/sessions/current.json.tmp" "$REPO_ROOT/.monomind/sessions/current.json"
254
+ --argjson patch "$state_patch" \
255
+ '. + $patch + {domains_needed:($domains | split(" ") | map(select(length>0)))}' \
256
+ "$SESSION_STATE" > "$SESSION_STATE.tmp" && mv "$SESSION_STATE.tmp" "$SESSION_STATE"
257
+ echo "Session state saved to current.json"
252
258
  ```
253
259
 
254
260
  ### Step 7 — Spawn Domain Managers
255
261
 
256
262
  **BEFORE THIS STEP:** If `idea` is in `domains_needed`, invoke `Skill("mastermind:idea")` directly now (master context has Skill tool access). Pass the resolved prompt, project path, and mode. Write the result to `.monomind/sessions/<SESSION_ID>/idea.json` and mark the `idea` domain as handled. Do NOT include `idea` in the Task spawning below.
257
263
 
264
+ **IDEA PIPELINE REQUIREMENT:** `mastermind:idea` runs a multi-step pipeline (Steps 3–6 inside idea.md). You MUST follow all of those steps — do NOT shortcut to manually creating cards. The full pipeline is:
265
+ - Step 3: Board setup — find-or-create `<project_name>-idea` board (master's Step 6 already created it with correct columns: New → Evaluated → Elaborated → Tasked → Iced → Rejected). Load column IDs from existing board.
266
+ - Step 4: Spawn Idea Manager agent (coordinator) with specialist sub-agents per angle — generates ideas as cards in the `New` column.
267
+ - Step 5: Spawn PM agent for validation — moves each card to `Evaluated`, `Iced`, or `Rejected`, sets impact/effort.
268
+ - Step 6a: Elaboration agents enrich each `Evaluated` card and move it to `Elaborated`.
269
+ - Step 6b: User gate (skip in auto mode).
270
+ - Step 6c: Task decomposition — creates subtask cards on `<project_name>-tasks-dev` and `<project_name>-tasks-ops` boards, linked as subtasks of their parent idea card. Moves parent idea cards to `Tasked`.
271
+
272
+ Skipping any of these steps produces an incomplete pipeline run — card content is generated but no evaluation, elaboration, or task breakdown occurs.
273
+
258
274
  **Before spawning**, select the best domain manager agent type from the registry for each active domain. Do not hardcode `coordinator` — pick the agent whose expertise best fits the domain goal.
259
275
 
260
276
  **BASH TOOL REQUIREMENT:** Domain managers must run `monotask` CLI commands. Only use subagent_types that include Bash in their tool list. If the registry returns an agent without Bash (e.g. `Product Manager`, `Backend Architect`), override it with `general-purpose` (which has all tools). Agents without Bash cannot create cards, emit curl events, or write session files — they will silently produce degraded output.
@@ -247,53 +247,87 @@ curl -s -o /dev/null -X POST "http://localhost:4242/api/mastermind/event" \
247
247
 
248
248
  **Always follow this exact order — never create a board without first ensuring a space exists.**
249
249
 
250
+ **Board naming convention:** Boards are named `<project_name>-<domain>` (e.g. `factory-idea`, `factory-build`). This canonical name is stable across runs — find the existing board first, create only if it does not exist.
251
+
252
+ **Column schemas by domain — use these exact column names, in this order:**
253
+
254
+ | Domain | Columns (left → right) | Intake column |
255
+ |---|---|---|
256
+ | `idea` | New → Evaluated → Elaborated → Tasked → Iced → Rejected | New |
257
+ | `build`, `release`, `architect`, `review` | Todo → In Progress → Human in Loop → Review → Done → Cancelled | Todo |
258
+ | `marketing`, `content`, `sales`, `ops`, `finance`, `research` | Todo → In Progress → Human in Loop → Review → Done → Cancelled | Todo |
259
+ | Task boards (`<proj>-tasks-dev`, `<proj>-tasks-ops`) | Backlog → Todo → In Progress → Human in Loop → Review → Done → Cancelled | Todo |
260
+
250
261
  Every mastermind run that needs a task board MUST:
251
262
  1. Resolve the space (find existing or create new) — space name = `project_name`
252
- 2. Create the board within that space
253
- 3. Link the board to the space immediately after creation
254
- 4. Create columns (Todo Doing → Done)
255
- 5. Create cards within those columns
263
+ 2. Find existing board by canonical name `<project_name>-<domain>` or create it with `--space`
264
+ 3. Fetch column IDs from existing board OR create columns for new board
265
+ 4. Create cards within those columns
256
266
 
257
267
  If the user is running across multiple repos for the same project, they MUST use the same `project_name` so all boards land in one space.
258
268
 
259
269
  ### Canonical bash block (substitute `<domain>` with: build, marketing, ops, content, etc.)
260
270
 
261
271
  ```bash
262
- # Step 1 Resolve space (required; abort if it cannot be created)
272
+ # Compatible with macOS bash 3.2
263
273
  project_name="${project_name:-$(basename "$PWD")}"
264
- space_id=$(monotask space list 2>/dev/null | awk -F' \| ' -v n="$project_name" '$2==n{print $1}' | head -1)
265
- [ -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}')
266
- [ -z "$space_id" ] && { echo "ERROR: Could not find or create space '$project_name' — verify monotask is installed (monotask --version)"; exit 1; }
267
-
268
- # Step 2 — Create board
269
- board_id=$(monotask board create "<domain>" --json | jq -r '.id // empty')
270
- [ -z "$board_id" ] && { echo "ERROR: Failed to create board '<domain>'"; exit 1; }
274
+ canonical="${project_name}-<domain>"
271
275
 
272
- # Step 3Link board to space immediately
273
- monotask space boards add "$space_id" "$board_id" >/dev/null 2>&1 || true
276
+ # Step 1Resolve space
277
+ space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$project_name" | head -1)
278
+ [ -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}')
279
+ [ -z "$space_id" ] && { echo "ERROR: Could not find or create space '$project_name' — verify monotask is installed (monotask --version)"; exit 1; }
274
280
 
275
- # Step 4Create columns
276
- todo_col=$(monotask column create "$board_id" "Todo" --json | jq -r '.id')
277
- doing_col=$(monotask column create "$board_id" "Doing" --json | jq -r '.id')
278
- done_col=$(monotask column create "$board_id" "Done" --json | jq -r '.id')
281
+ # Step 2Find existing board by canonical name or create
282
+ board_id=$(monotask board list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$canonical" | head -1)
283
+ if [ -n "$board_id" ]; then
284
+ # Step 3a Fetch column IDs from existing board
285
+ cols_json=$(monotask column list "$board_id" --json 2>/dev/null || echo '[]')
286
+ todo_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="Todo" or .title=="Backlog")] | .[0].id // empty')
287
+ doing_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="Doing" or .title=="In Progress")] | .[0].id // empty')
288
+ done_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="Done")] | .[0].id // empty')
289
+ else
290
+ # Step 3b — Create board and columns
291
+ board_id=$(monotask board create --space "$space_id" "$canonical" --json | jq -r '.id // empty')
292
+ [ -z "$board_id" ] && { echo "ERROR: Failed to create board '$canonical'"; exit 1; }
293
+ monotask space boards add "$space_id" "$board_id" >/dev/null 2>&1 || true
294
+ todo_col=$(monotask column create "$board_id" "Todo" --json | jq -r '.id')
295
+ doing_col=$(monotask column create "$board_id" "Doing" --json | jq -r '.id')
296
+ done_col=$(monotask column create "$board_id" "Done" --json | jq -r '.id')
297
+ fi
279
298
  ```
280
299
 
281
- When master.md runs multiple domains, resolve the space **once** before the loop, then repeat steps 2–4 per domain:
300
+ When master.md runs multiple domains, resolve the space **once** before the loop, then repeat steps 2–3 per domain using jq accumulation (no bash 4.3+ needed):
282
301
 
283
302
  ```bash
284
- # Resolve space once
303
+ # Compatible with macOS bash 3.2 — jq accumulation instead of declare -A
285
304
  project_name="<resolved project_name>"
286
- space_id=$(monotask space list 2>/dev/null | awk -F' \| ' -v n="$project_name" '$2==n{print $1}' | head -1)
287
- [ -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}')
305
+ space_id=$(monotask space list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$project_name" | head -1)
306
+ [ -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}')
288
307
  [ -z "$space_id" ] && { echo "ERROR: Could not find or create space '$project_name'"; exit 1; }
289
308
 
290
- # Repeat per active domain (e.g. build, marketing, ops):
291
- board_<domain>=$(monotask board create "<domain>" --json | jq -r '.id // empty')
292
- [ -z "$board_<domain>" ] && { echo "ERROR: Failed to create <domain> board"; exit 1; }
293
- monotask space boards add "$space_id" "$board_<domain>" >/dev/null 2>&1 || true
294
- todo_<domain>=$(monotask column create "$board_<domain>" "Todo" --json | jq -r '.id')
295
- doing_<domain>=$(monotask column create "$board_<domain>" "Doing" --json | jq -r '.id')
296
- done_<domain>=$(monotask column create "$board_<domain>" "Done" --json | jq -r '.id')
309
+ state_patch='{}'
310
+ for domain in build marketing ops; do # substitute actual domain list
311
+ canonical="${project_name}-${domain}"
312
+ board_id=$(monotask board list 2>/dev/null | awk -F'|' '{gsub(/^ +| +$/,"",$1);gsub(/^ +| +$/,"",$2);if($2==n)print $1}' n="$canonical" | head -1)
313
+ if [ -n "$board_id" ]; then
314
+ cols_json=$(monotask column list "$board_id" --json 2>/dev/null || echo '[]')
315
+ todo_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="Todo" or .title=="Backlog")] | .[0].id // empty')
316
+ doing_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="Doing" or .title=="In Progress")] | .[0].id // empty')
317
+ done_col=$(echo "$cols_json" | jq -r '[.[] | select(.title=="Done")] | .[0].id // empty')
318
+ else
319
+ board_id=$(monotask board create --space "$space_id" "$canonical" --json | jq -r '.id // empty')
320
+ [ -z "$board_id" ] && { echo "ERROR: Failed to create $canonical board"; exit 1; }
321
+ monotask space boards add "$space_id" "$board_id" >/dev/null 2>&1 || true
322
+ todo_col=$(monotask column create "$board_id" "Todo" --json | jq -r '.id')
323
+ doing_col=$(monotask column create "$board_id" "Doing" --json | jq -r '.id')
324
+ done_col=$(monotask column create "$board_id" "Done" --json | jq -r '.id')
325
+ fi
326
+ state_patch=$(echo "$state_patch" | jq \
327
+ --arg d "$domain" --arg b "$board_id" \
328
+ --arg t "$todo_col" --arg g "$doing_col" --arg e "$done_col" \
329
+ '.board_ids[$d]=$b | .todo_cols[$d]=$t | .doing_cols[$d]=$g | .done_cols[$d]=$e')
330
+ done
297
331
  ```
298
332
 
299
333
  ---
@@ -69,42 +69,46 @@ 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)
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)
84
+
85
+ if [ -n "$BOARD_ID" ]; then
86
+ echo "Reusing idea board: $BOARD_ID ($idea_canonical)"
87
+ columns=$(monotask column list "$BOARD_ID" --json)
88
+ COL_NEW=$(echo "$columns" | jq -r '.[] | select(.title == "New") | .id' | head -1)
89
+ COL_EVALUATED=$(echo "$columns" | jq -r '.[] | select(.title == "Evaluated") | .id' | head -1)
90
+ COL_ELABORATED=$(echo "$columns"| jq -r '.[] | select(.title == "Elaborated") | .id' | head -1)
91
+ COL_TASKED=$(echo "$columns" | jq -r '.[] | select(.title == "Tasked") | .id' | head -1)
92
+ COL_ICED=$(echo "$columns" | jq -r '.[] | select(.title == "Iced") | .id' | head -1)
93
+ COL_REJECTED=$(echo "$columns" | jq -r '.[] | select(.title == "Rejected") | .id' | head -1)
94
+ [ -z "$COL_NEW" ] && { echo "ERROR: 'New' column missing on board $BOARD_ID — was board created with wrong schema?"; exit 1; }
95
+ [ -z "$COL_EVALUATED" ] && { echo "ERROR: 'Evaluated' column missing on board $BOARD_ID"; exit 1; }
96
+ [ -z "$COL_ELABORATED" ] && { echo "ERROR: 'Elaborated' column missing on board $BOARD_ID"; exit 1; }
97
+ [ -z "$COL_TASKED" ] && { echo "ERROR: 'Tasked' column missing on board $BOARD_ID"; exit 1; }
98
+ [ -z "$COL_ICED" ] && { echo "ERROR: 'Iced' column missing on board $BOARD_ID"; exit 1; }
99
+ [ -z "$COL_REJECTED" ] && { echo "ERROR: 'Rejected' column missing on board $BOARD_ID"; exit 1; }
100
+ else
101
+ echo "Creating idea board: $idea_canonical"
102
+ BOARD_ID=$(monotask board create --space "$space_id" "$idea_canonical" --json 2>/dev/null | jq -r '.id // empty')
103
+ [ -z "$BOARD_ID" ] && { echo "ERROR: Failed to create idea board '$idea_canonical'"; exit 1; }
104
+ 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')
111
+ fi
108
112
  ```
109
113
 
110
114
  **After either branch above, validate and echo all values.** This is the canonical source for Step 4 Task construction.
@@ -510,44 +514,81 @@ END_ELABORATION_OUTPUT`
510
514
  })
511
515
  ```
512
516
 
513
- After all agents complete, merge their outputs per idea (same card_id concatenate findings). For each idea, write findings to the card description and as comments, then move the card:
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`:
514
518
 
515
519
  ```bash
516
- # Set the card description to the merged elaboration findings (this is the primary content field)
517
- if [ "$category" = "business-operation" ]; then
518
- monotask card set-description "$BOARD_ID" "$CARD_ID" "## Elaboration Findings
520
+ # Assign each agent's ELABORATION_OUTPUT JSON array from its output block:
521
+ dev_researcher_json='<ELABORATION_OUTPUT array from the dev researcher agent>'
522
+ dev_codebase_json='<ELABORATION_OUTPUT array from the dev code-explorer agent>'
523
+ ops_researcher_json='<ELABORATION_OUTPUT array from the ops researcher agent>'
524
+ ops_pm_json='<ELABORATION_OUTPUT array from the ops PM agent>'
525
+ # Use '[]' for any track that had no ideas (e.g. if all ideas were dev, set ops_* to '[]')
526
+
527
+ # Merge dev track: join researcher + codebase findings by card_id, inject category from verdicts
528
+ dev_merged=$(jq -n \
529
+ --argjson r "$dev_researcher_json" \
530
+ --argjson c "$dev_codebase_json" \
531
+ --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
538
+ ops_merged=$(jq -n \
539
+ --argjson r "$ops_researcher_json" \
540
+ --argjson p "$ops_pm_json" \
541
+ --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")}]')
546
+
547
+ # Combine both tracks
548
+ merged_elaboration_json=$(jq -s 'add' <(echo "$dev_merged") <(echo "$ops_merged"))
549
+ ```
550
+
551
+ Use process substitution (not a pipeline) so the while loop runs in the main shell and variables remain in scope after `done`:
552
+
553
+ ```bash
554
+ while IFS= read -r idea; do
555
+ CARD_ID=$(echo "$idea" | jq -r '.card_id')
556
+ category=$(echo "$idea" | jq -r '.category')
557
+ blocking_issue=$(echo "$idea" | jq -r '.blocking_issue // empty')
558
+
559
+ if [ "$category" = "business-operation" ]; then
560
+ researcher_findings=$(echo "$idea" | jq -r '.researcher_findings')
561
+ pm_findings=$(echo "$idea" | jq -r '.pm_findings')
562
+ monotask card set-description "$BOARD_ID" "$CARD_ID" "## Elaboration Findings
519
563
 
520
564
  ### Industry context & benchmarks:
521
- <researcher findings>
565
+ $researcher_findings
522
566
 
523
567
  ### Feasibility & stakeholder impact:
524
- <PM findings>"
525
- else
526
- # feature or technical-baseline
527
- monotask card set-description "$BOARD_ID" "$CARD_ID" "## Elaboration Findings
568
+ $pm_findings"
569
+ monotask card comment add "$BOARD_ID" "$CARD_ID" "Industry context & benchmarks: $researcher_findings"
570
+ monotask card comment add "$BOARD_ID" "$CARD_ID" "Feasibility & stakeholder impact: $pm_findings"
571
+ else
572
+ researcher_findings=$(echo "$idea" | jq -r '.researcher_findings')
573
+ codebase_findings=$(echo "$idea" | jq -r '.codebase_findings')
574
+ monotask card set-description "$BOARD_ID" "$CARD_ID" "## Elaboration Findings
528
575
 
529
576
  ### Edge cases & prior art:
530
- <researcher findings>
577
+ $researcher_findings
531
578
 
532
579
  ### Codebase constraints:
533
- <code-explorer findings>"
534
- fi
535
-
536
- # Also add each finding as a comment for traceability
537
- # Dev ideas:
538
- monotask card comment add "$BOARD_ID" "$CARD_ID" "Edge cases & prior art: <researcher findings>"
539
- monotask card comment add "$BOARD_ID" "$CARD_ID" "Codebase constraints: <code-explorer findings>"
540
-
541
- # Business-operation ideas:
542
- monotask card comment add "$BOARD_ID" "$CARD_ID" "Industry context & benchmarks: <researcher findings>"
543
- monotask card comment add "$BOARD_ID" "$CARD_ID" "Feasibility & stakeholder impact: <PM findings>"
544
-
545
- # If neither agent found a blocking issue:
546
- monotask card move "$BOARD_ID" "$CARD_ID" "$COL_ELABORATED" --json
547
-
548
- # If either agent found a blocking issue (mutually exclusive with the above):
549
- monotask card move "$BOARD_ID" "$CARD_ID" "$COL_ICED" --json
550
- monotask card comment add "$BOARD_ID" "$CARD_ID" "Blocked during elaboration: <issue>"
580
+ $codebase_findings"
581
+ monotask card comment add "$BOARD_ID" "$CARD_ID" "Edge cases & prior art: $researcher_findings"
582
+ monotask card comment add "$BOARD_ID" "$CARD_ID" "Codebase constraints: $codebase_findings"
583
+ fi
584
+
585
+ if [ -n "$blocking_issue" ]; then
586
+ monotask card move "$BOARD_ID" "$CARD_ID" "$COL_ICED" --json
587
+ monotask card comment add "$BOARD_ID" "$CARD_ID" "Blocked during elaboration: $blocking_issue"
588
+ else
589
+ monotask card move "$BOARD_ID" "$CARD_ID" "$COL_ELABORATED" --json
590
+ fi
591
+ done < <(echo "$merged_elaboration_json" | jq -c '.[]')
551
592
  ```
552
593
 
553
594
  #### 6b. User Confirmation Gate
@@ -556,6 +597,10 @@ monotask card comment add "$BOARD_ID" "$CARD_ID" "Blocked during elaboration: <i
556
597
 
557
598
  **Confirm mode only:** If `mode` is `confirm` (default), present a review table of all elaborated ideas to the user.
558
599
 
600
+ Build the table from `verdicts_output_json` (filtered to `verdict == "evaluated"`). For each row:
601
+ - **Impact** and **Effort** come from `.impact` and `.effort` fields in `verdicts_output_json`
602
+ - **Track**: `feature` or `technical-baseline` → `dev`; `business-operation` → `ops`
603
+
559
604
  Print this exact format:
560
605
 
561
606
  ```
@@ -654,7 +699,7 @@ echo "Dev decomp: $dev_decomp_agent | Ops decomp: $ops_decomp_agent"
654
699
  ```
655
700
 
656
701
  **CRITICAL — Variable substitution required for Step 6c Task calls:**
657
- Before constructing each Task prompt, replace `${brain_context}`, `${prompt}`, `${project_name}`, and `${dev_ideas_elaborated}` / `${ops_ideas_elaborated}` with actual literal text. Build those lists from the VERDICTS_OUTPUT and ELABORATION_OUTPUT results:
702
+ 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:
658
703
 
659
704
  ```bash
660
705
  # Build elaborated idea lists including card comments (full context for decomposition agents)
@@ -755,64 +800,91 @@ END_TASKS_OUTPUT`
755
800
 
756
801
  **Dev task board** (`feature` / `technical-baseline` → `Implementation Tasks`):
757
802
 
758
- Check memory for `"implementation-tasks board_id"` in namespace `monomind`. If found, use it as `TASK_BOARD_ID`. Otherwise create it:
803
+ Canonical board name: `${project_name}-tasks-dev`. Find-or-create:
759
804
 
760
805
  ```bash
761
- TASK_BOARD_ID=$(monotask board create "Implementation Tasks" --json | jq -r '.id // empty')
762
- monotask space boards add "$space_id" "$TASK_BOARD_ID" >/dev/null 2>&1 || true
763
- npx monomind@latest memory store --key "implementation-tasks board_id" --value "$TASK_BOARD_ID" --namespace monomind
764
- monotask column create "$TASK_BOARD_ID" "Backlog" --json >/dev/null
765
- monotask column create "$TASK_BOARD_ID" "Todo" --json >/dev/null
766
- monotask column create "$TASK_BOARD_ID" "In Progress" --json >/dev/null
767
- monotask column create "$TASK_BOARD_ID" "Review" --json >/dev/null
768
- monotask column create "$TASK_BOARD_ID" "Human in Loop" --json >/dev/null
769
- monotask column create "$TASK_BOARD_ID" "Done" --json >/dev/null
770
- ```
771
-
772
- Look up and validate column IDs:
773
- ```bash
774
- [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: TASK_BOARD_ID is empty — aborting to prevent card creation on null board"; exit 1; }
775
- task_columns=$(monotask column list "$TASK_BOARD_ID" --json)
776
- TASK_COL_TODO=$(echo "$task_columns" | jq -r '.[] | select(.title == "Todo") | .id' | head -1)
777
- TASK_COL_BACKLOG=$(echo "$task_columns" | jq -r '.[] | select(.title == "Backlog") | .id' | head -1)
778
- [ -z "$TASK_COL_TODO" ] && { echo "ERROR: Could not find 'Todo' column on TASK_BOARD_ID=$TASK_BOARD_ID"; exit 1; }
779
- [ -z "$TASK_COL_BACKLOG" ] && { echo "ERROR: Could not find 'Backlog' column on TASK_BOARD_ID=$TASK_BOARD_ID"; exit 1; }
806
+ 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)
808
+ if [ -n "$TASK_BOARD_ID" ]; then
809
+ echo "Reusing dev task board: $TASK_BOARD_ID ($dev_task_canonical)"
810
+ task_columns=$(monotask column list "$TASK_BOARD_ID" --json)
811
+ TASK_COL_TODO=$(echo "$task_columns" | jq -r '.[] | select(.title=="Todo") | .id' | head -1)
812
+ TASK_COL_BACKLOG=$(echo "$task_columns" | jq -r '.[] | select(.title=="Backlog") | .id' | head -1)
813
+ else
814
+ echo "Creating dev task board: $dev_task_canonical"
815
+ TASK_BOARD_ID=$(monotask board create --space "$space_id" "$dev_task_canonical" --json 2>/dev/null | jq -r '.id // empty')
816
+ [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: Failed to create dev task board"; exit 1; }
817
+ 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')
820
+ monotask column create "$TASK_BOARD_ID" "In Progress" --json >/dev/null
821
+ monotask column create "$TASK_BOARD_ID" "Human in Loop" --json >/dev/null
822
+ monotask column create "$TASK_BOARD_ID" "Review" --json >/dev/null
823
+ monotask column create "$TASK_BOARD_ID" "Done" --json >/dev/null
824
+ monotask column create "$TASK_BOARD_ID" "Cancelled" --json >/dev/null
825
+ fi
826
+ [ -z "$TASK_BOARD_ID" ] && { echo "ERROR: TASK_BOARD_ID empty — aborting"; exit 1; }
827
+ [ -z "$TASK_COL_TODO" ] && { echo "ERROR: Could not find Todo column on dev task board"; exit 1; }
780
828
  ```
781
829
 
782
830
  ---
783
831
 
784
832
  **Ops task board** (`business-operation` → `Operations Tasks`):
785
833
 
786
- Check memory for `"operations-tasks board_id"` in namespace `monomind`. If found, use it as `OPS_BOARD_ID`. Otherwise create it:
787
-
788
- ```bash
789
- OPS_BOARD_ID=$(monotask board create "Operations Tasks" --json | jq -r '.id // empty')
790
- monotask space boards add "$space_id" "$OPS_BOARD_ID" >/dev/null 2>&1 || true
791
- npx monomind@latest memory store --key "operations-tasks board_id" --value "$OPS_BOARD_ID" --namespace monomind
792
- monotask column create "$OPS_BOARD_ID" "Backlog" --json >/dev/null
793
- monotask column create "$OPS_BOARD_ID" "Todo" --json >/dev/null
794
- monotask column create "$OPS_BOARD_ID" "In Progress" --json >/dev/null
795
- monotask column create "$OPS_BOARD_ID" "Review" --json >/dev/null
796
- monotask column create "$OPS_BOARD_ID" "Human in Loop" --json >/dev/null
797
- monotask column create "$OPS_BOARD_ID" "Done" --json >/dev/null
798
- ```
834
+ Canonical board name: `${project_name}-tasks-ops`. Find-or-create:
799
835
 
800
- Look up and validate column IDs:
801
836
  ```bash
802
- [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: OPS_BOARD_ID is empty — aborting to prevent card creation on null board"; exit 1; }
803
- ops_columns=$(monotask column list "$OPS_BOARD_ID" --json)
804
- OPS_COL_TODO=$(echo "$ops_columns" | jq -r '.[] | select(.title == "Todo") | .id' | head -1)
805
- OPS_COL_BACKLOG=$(echo "$ops_columns" | jq -r '.[] | select(.title == "Backlog") | .id' | head -1)
806
- [ -z "$OPS_COL_TODO" ] && { echo "ERROR: Could not find 'Todo' column on OPS_BOARD_ID=$OPS_BOARD_ID"; exit 1; }
807
- [ -z "$OPS_COL_BACKLOG" ] && { echo "ERROR: Could not find 'Backlog' column on OPS_BOARD_ID=$OPS_BOARD_ID"; exit 1; }
837
+ 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)
839
+ if [ -n "$OPS_BOARD_ID" ]; then
840
+ echo "Reusing ops task board: $OPS_BOARD_ID ($ops_task_canonical)"
841
+ ops_columns=$(monotask column list "$OPS_BOARD_ID" --json)
842
+ OPS_COL_TODO=$(echo "$ops_columns" | jq -r '.[] | select(.title=="Todo") | .id' | head -1)
843
+ OPS_COL_BACKLOG=$(echo "$ops_columns" | jq -r '.[] | select(.title=="Backlog") | .id' | head -1)
844
+ else
845
+ echo "Creating ops task board: $ops_task_canonical"
846
+ OPS_BOARD_ID=$(monotask board create --space "$space_id" "$ops_task_canonical" --json 2>/dev/null | jq -r '.id // empty')
847
+ [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: Failed to create ops task board"; exit 1; }
848
+ 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')
851
+ monotask column create "$OPS_BOARD_ID" "In Progress" --json >/dev/null
852
+ monotask column create "$OPS_BOARD_ID" "Human in Loop" --json >/dev/null
853
+ monotask column create "$OPS_BOARD_ID" "Review" --json >/dev/null
854
+ monotask column create "$OPS_BOARD_ID" "Done" --json >/dev/null
855
+ monotask column create "$OPS_BOARD_ID" "Cancelled" --json >/dev/null
856
+ fi
857
+ [ -z "$OPS_BOARD_ID" ] && { echo "ERROR: OPS_BOARD_ID empty — aborting"; exit 1; }
858
+ [ -z "$OPS_COL_TODO" ] && { echo "ERROR: Could not find Todo column on ops task board"; exit 1; }
808
859
  ```
809
860
 
810
861
  ---
811
862
 
812
- **Create task cards** for each task in the merged TASKS_OUTPUT:
863
+ **Assign TASKS_OUTPUT from each decomposition agent, then merge and iterate:**
813
864
 
814
865
  ```bash
815
- if [ "$category" = "business-operation" ]; then
866
+ # Parse the TASKS_OUTPUT block from the dev decomp agent's response and assign:
867
+ dev_tasks_json='<TASKS_OUTPUT JSON array from dev decomp agent, or [] if no dev ideas>'
868
+ # Parse the TASKS_OUTPUT block from the ops decomp agent's response and assign:
869
+ ops_tasks_json='<TASKS_OUTPUT JSON array from ops decomp agent, or [] if no ops ideas>'
870
+
871
+ merged_tasks_json=$(jq -s 'add' <(echo "$dev_tasks_json") <(echo "$ops_tasks_json"))
872
+
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
877
+
878
+ while IFS= read -r task; do
879
+ parent_card_id=$(echo "$task" | jq -r '.parent_card_id')
880
+ title=$(echo "$task" | jq -r '.title')
881
+ description=$(echo "$task" | jq -r '.description')
882
+ category=$(echo "$task" | jq -r '.category')
883
+ agent=$(echo "$task" | jq -r '.agent')
884
+ task_effort=$(echo "$task" | jq -r '.effort')
885
+ has_prerequisites=$(echo "$task" | jq -r '.has_prerequisites')
886
+
887
+ if [ "$category" = "business-operation" ]; then
816
888
  TARGET_BOARD="$OPS_BOARD_ID"
817
889
  COL_TARGET=$([ "$has_prerequisites" = "true" ] && echo "$OPS_COL_BACKLOG" || echo "$OPS_COL_TODO")
818
890
  BOARD_LABEL="Operations Tasks"
@@ -823,8 +895,11 @@ else
823
895
  fi
824
896
 
825
897
  # Inherit impact and effort from parent idea — look up from verdicts_output_json by parent_card_id
826
- parent_impact=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .impact')
827
- parent_effort=$(echo "$verdicts_output_json" | jq -r --arg id "$parent_card_id" '.[] | select(.card_id == $id) | .effort')
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
828
903
 
829
904
  # Create task card as a proper subtask of the parent idea card (cross-board link)
830
905
  # Signature: subtask add <PARENT_BOARD_ID> <PARENT_CARD_ID> <CHILD_BOARD_ID> <COL_ID> <TITLE>
@@ -841,14 +916,22 @@ PARENT IDEA IMPACT: <parent_impact>/10 PARENT IDEA EFFORT: <parent_effort>/10
841
916
  CATEGORY: <category>
842
917
  PARENT IDEA: <idea title> (card: <parent_card_id> on ideation board)"
843
918
  monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "mastermind:idea"
844
- monotask card label add "$TARGET_BOARD" "$TASK_CARD_ID" "category:<category>"
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"
923
+
924
+ done < <(echo "$merged_tasks_json" | jq -c '.[]')
845
925
  ```
846
926
 
847
- Group tasks by `parent_card_id`. For each parent idea, annotate and move to `Tasked`:
927
+ After the loop, annotate each parent idea card and move it to `Tasked`:
848
928
  ```bash
849
- monotask card comment add "$BOARD_ID" "$parent_card_id" \
850
- "Subtasks created on <board_label>: <list of titles with agent and effort>"
851
- monotask card move "$BOARD_ID" "$parent_card_id" "$COL_TASKED" --json
929
+ for parent_card_id in "${!parent_subtask_summaries[@]}"; do
930
+ subtask_list="${parent_subtask_summaries[$parent_card_id]}"
931
+ monotask card comment add "$BOARD_ID" "$parent_card_id" \
932
+ "Subtasks created:\n${subtask_list}"
933
+ monotask card move "$BOARD_ID" "$parent_card_id" "$COL_TASKED" --json
934
+ done
852
935
  ```
853
936
 
854
937
  For each entry in FLAGGED, move the idea to `Iced`:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monomindcli",
3
- "version": "1.9.15",
3
+ "version": "1.9.17",
4
4
  "type": "module",
5
5
  "description": "Monomind CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",