@monoes/monomindcli 1.11.7 → 1.11.9

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 (222) hide show
  1. package/.claude/agents/github/issue-tracker.md +5 -5
  2. package/.claude/agents/github/pr-manager.md +5 -5
  3. package/.claude/agents/github/release-manager.md +3 -3
  4. package/.claude/agents/github/repo-architect.md +3 -3
  5. package/.claude/agents/github/swarm-issue.md +1 -1
  6. package/.claude/agents/github/sync-coordinator.md +1 -1
  7. package/.claude/agents/github/workflow-automation.md +1 -1
  8. package/.claude/commands/github/repo-architect.md +1 -1
  9. package/.claude/commands/github/sync-coordinator.md +1 -1
  10. package/.claude/commands/mastermind/createorg.md +4 -1
  11. package/.claude/commands/mastermind/help.md +2 -2
  12. package/.claude/commands/mastermind/orgs.md +21 -0
  13. package/.claude/commands/mastermind/orgstatus.md +59 -0
  14. package/.claude/commands/mastermind/runorg.md +4 -2
  15. package/.claude/commands/mastermind/stoporg.md +78 -0
  16. package/.claude/commands/mastermind/swarm.md +1 -1
  17. package/.claude/helpers/handlers/gates-handler.cjs +135 -0
  18. package/.claude/helpers/handlers/task-handler.cjs +7 -3
  19. package/.claude/helpers/hook-handler.cjs +11 -2
  20. package/.claude/helpers/intelligence.cjs +87 -0
  21. package/.claude/helpers/learning-service.mjs +60 -0
  22. package/.claude/helpers/memory.cjs +69 -0
  23. package/.claude/helpers/router.cjs +68 -0
  24. package/.claude/helpers/session.cjs +63 -0
  25. package/.claude/helpers/utils/monograph.cjs +4 -2
  26. package/.claude/helpers/utils/telemetry.cjs +3 -2
  27. package/.claude/skills/agentic-jujutsu/SKILL.md +1 -1
  28. package/.claude/skills/hive-mind-advanced/SKILL.md +4 -4
  29. package/.claude/skills/mastermind/_agent-select.md +2 -2
  30. package/.claude/skills/mastermind/access.md +11 -11
  31. package/.claude/skills/mastermind/adapter-manager.md +13 -13
  32. package/.claude/skills/mastermind/adapters.md +7 -7
  33. package/.claude/skills/mastermind/agent-detail.md +1 -1
  34. package/.claude/skills/mastermind/agents.md +5 -5
  35. package/.claude/skills/mastermind/approval-detail.md +6 -6
  36. package/.claude/skills/mastermind/approve.md +9 -10
  37. package/.claude/skills/mastermind/backup.md +2 -2
  38. package/.claude/skills/mastermind/bootstrap.md +2 -2
  39. package/.claude/skills/mastermind/companies.md +7 -7
  40. package/.claude/skills/mastermind/createorg.md +213 -8
  41. package/.claude/skills/mastermind/diagnose.md +4 -4
  42. package/.claude/skills/mastermind/env.md +1 -1
  43. package/.claude/skills/mastermind/environments.md +8 -8
  44. package/.claude/skills/mastermind/export.md +12 -3
  45. package/.claude/skills/mastermind/goal-detail.md +9 -9
  46. package/.claude/skills/mastermind/goals.md +4 -4
  47. package/.claude/skills/mastermind/heartbeat.md +1 -1
  48. package/.claude/skills/mastermind/idea.md +4 -4
  49. package/.claude/skills/mastermind/import.md +8 -8
  50. package/.claude/skills/mastermind/inbox.md +4 -4
  51. package/.claude/skills/mastermind/instance-settings.md +9 -9
  52. package/.claude/skills/mastermind/instance.md +9 -7
  53. package/.claude/skills/mastermind/invite-landing.md +5 -5
  54. package/.claude/skills/mastermind/invites.md +12 -12
  55. package/.claude/skills/mastermind/issue-detail.md +8 -8
  56. package/.claude/skills/mastermind/monitor.md +11 -11
  57. package/.claude/skills/mastermind/my-issues.md +6 -6
  58. package/.claude/skills/mastermind/new-agent.md +4 -4
  59. package/.claude/skills/mastermind/org-chart.md +8 -6
  60. package/.claude/skills/mastermind/org-settings.md +58 -21
  61. package/.claude/skills/mastermind/orgs.md +98 -0
  62. package/.claude/skills/mastermind/orgstatus.md +194 -0
  63. package/.claude/skills/mastermind/plan-to-tasks.md +1 -1
  64. package/.claude/skills/mastermind/plugin-manager.md +12 -12
  65. package/.claude/skills/mastermind/plugin-settings.md +5 -5
  66. package/.claude/skills/mastermind/plugins.md +5 -5
  67. package/.claude/skills/mastermind/profile.md +2 -2
  68. package/.claude/skills/mastermind/project-detail.md +12 -12
  69. package/.claude/skills/mastermind/project-workspace.md +4 -4
  70. package/.claude/skills/mastermind/projects.md +4 -4
  71. package/.claude/skills/mastermind/review.md +50 -0
  72. package/.claude/skills/mastermind/routine-detail.md +3 -3
  73. package/.claude/skills/mastermind/routines.md +7 -6
  74. package/.claude/skills/mastermind/runorg.md +178 -8
  75. package/.claude/skills/mastermind/search.md +6 -6
  76. package/.claude/skills/mastermind/secrets.md +6 -6
  77. package/.claude/skills/mastermind/skills.md +4 -4
  78. package/.claude/skills/mastermind/stoporg.md +138 -0
  79. package/.claude/skills/mastermind/workspace-detail.md +5 -5
  80. package/.claude/skills/mastermind/workspaces.md +9 -9
  81. package/.claude/skills/performance-analysis/SKILL.md +3 -3
  82. package/.claude/skills/sparc-methodology/SKILL.md +2 -2
  83. package/.claude/skills/swarm-advanced/SKILL.md +4 -4
  84. package/README.md +129 -376
  85. package/dist/src/agents/registry-builder.d.ts +27 -1
  86. package/dist/src/agents/registry-builder.d.ts.map +1 -1
  87. package/dist/src/agents/registry-builder.js +2 -2
  88. package/dist/src/agents/registry-builder.js.map +1 -1
  89. package/dist/src/commands/agent.d.ts.map +1 -1
  90. package/dist/src/commands/agent.js +4 -9
  91. package/dist/src/commands/agent.js.map +1 -1
  92. package/dist/src/commands/analyze.d.ts +1 -1
  93. package/dist/src/commands/analyze.js +1 -1
  94. package/dist/src/commands/claims.d.ts +1 -1
  95. package/dist/src/commands/claims.js +2 -2
  96. package/dist/src/commands/claims.js.map +1 -1
  97. package/dist/src/commands/cleanup.d.ts +1 -1
  98. package/dist/src/commands/cleanup.js +1 -1
  99. package/dist/src/commands/completions.d.ts +1 -1
  100. package/dist/src/commands/completions.js +1 -1
  101. package/dist/src/commands/deployment.d.ts +1 -1
  102. package/dist/src/commands/deployment.js +2 -2
  103. package/dist/src/commands/deployment.js.map +1 -1
  104. package/dist/src/commands/doctor.d.ts +1 -1
  105. package/dist/src/commands/doctor.d.ts.map +1 -1
  106. package/dist/src/commands/doctor.js +69 -4
  107. package/dist/src/commands/doctor.js.map +1 -1
  108. package/dist/src/commands/guidance.d.ts.map +1 -1
  109. package/dist/src/commands/guidance.js +129 -0
  110. package/dist/src/commands/guidance.js.map +1 -1
  111. package/dist/src/commands/index.d.ts.map +1 -1
  112. package/dist/src/commands/index.js +4 -0
  113. package/dist/src/commands/index.js.map +1 -1
  114. package/dist/src/commands/init.d.ts.map +1 -1
  115. package/dist/src/commands/init.js +18 -0
  116. package/dist/src/commands/init.js.map +1 -1
  117. package/dist/src/commands/monovector/import.d.ts +1 -1
  118. package/dist/src/commands/monovector/import.js +1 -1
  119. package/dist/src/commands/monovector/index.d.ts +1 -1
  120. package/dist/src/commands/monovector/index.js +1 -1
  121. package/dist/src/commands/monovector/setup.d.ts +1 -1
  122. package/dist/src/commands/monovector/setup.js +2 -2
  123. package/dist/src/commands/neural.d.ts +1 -1
  124. package/dist/src/commands/neural.js +2 -2
  125. package/dist/src/commands/neural.js.map +1 -1
  126. package/dist/src/commands/performance.d.ts +1 -1
  127. package/dist/src/commands/performance.js +2 -2
  128. package/dist/src/commands/performance.js.map +1 -1
  129. package/dist/src/commands/platforms.d.ts +1 -1
  130. package/dist/src/commands/platforms.js +1 -1
  131. package/dist/src/commands/plugins.d.ts +1 -1
  132. package/dist/src/commands/plugins.d.ts.map +1 -1
  133. package/dist/src/commands/plugins.js +2 -4
  134. package/dist/src/commands/plugins.js.map +1 -1
  135. package/dist/src/commands/providers.d.ts +1 -1
  136. package/dist/src/commands/providers.js +2 -2
  137. package/dist/src/commands/providers.js.map +1 -1
  138. package/dist/src/commands/route.d.ts +1 -1
  139. package/dist/src/commands/route.d.ts.map +1 -1
  140. package/dist/src/commands/route.js +5 -11
  141. package/dist/src/commands/route.js.map +1 -1
  142. package/dist/src/commands/security.d.ts +1 -1
  143. package/dist/src/commands/security.d.ts.map +1 -1
  144. package/dist/src/commands/security.js +140 -91
  145. package/dist/src/commands/security.js.map +1 -1
  146. package/dist/src/dlq/dlq-replayer.d.ts +7 -1
  147. package/dist/src/dlq/dlq-replayer.d.ts.map +1 -1
  148. package/dist/src/dlq/dlq-replayer.js.map +1 -1
  149. package/dist/src/index.d.ts +1 -1
  150. package/dist/src/index.d.ts.map +1 -1
  151. package/dist/src/index.js +10 -26
  152. package/dist/src/index.js.map +1 -1
  153. package/dist/src/init/claudemd-generator.js +2 -2
  154. package/dist/src/init/claudemd-generator.js.map +1 -1
  155. package/dist/src/init/executor.js +3 -3
  156. package/dist/src/init/settings-generator.js +2 -2
  157. package/dist/src/init/settings-generator.js.map +1 -1
  158. package/dist/src/mcp-client.d.ts +5 -0
  159. package/dist/src/mcp-client.d.ts.map +1 -1
  160. package/dist/src/mcp-client.js +7 -0
  161. package/dist/src/mcp-client.js.map +1 -1
  162. package/dist/src/mcp-server.d.ts.map +1 -1
  163. package/dist/src/mcp-server.js +17 -1
  164. package/dist/src/mcp-server.js.map +1 -1
  165. package/dist/src/mcp-tools/a2a-tools.js +6 -6
  166. package/dist/src/mcp-tools/a2a-tools.js.map +1 -1
  167. package/dist/src/mcp-tools/auto-install.d.ts +2 -2
  168. package/dist/src/mcp-tools/auto-install.js +1 -1
  169. package/dist/src/mcp-tools/auto-install.js.map +1 -1
  170. package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
  171. package/dist/src/mcp-tools/hive-mind-tools.js +1 -52
  172. package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
  173. package/dist/src/mcp-tools/index.d.ts +4 -0
  174. package/dist/src/mcp-tools/index.d.ts.map +1 -1
  175. package/dist/src/mcp-tools/index.js +4 -0
  176. package/dist/src/mcp-tools/index.js.map +1 -1
  177. package/dist/src/mcp-tools/monograph-compat.d.ts.map +1 -1
  178. package/dist/src/mcp-tools/monograph-compat.js +1 -2
  179. package/dist/src/mcp-tools/monograph-compat.js.map +1 -1
  180. package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
  181. package/dist/src/mcp-tools/monograph-tools.js +107 -5
  182. package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
  183. package/dist/src/mcp-tools/security-tools.d.ts +6 -6
  184. package/dist/src/mcp-tools/security-tools.d.ts.map +1 -1
  185. package/dist/src/mcp-tools/security-tools.js +48 -61
  186. package/dist/src/mcp-tools/security-tools.js.map +1 -1
  187. package/dist/src/memory/memory-bridge.d.ts +0 -1
  188. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  189. package/dist/src/memory/memory-bridge.js +232 -57
  190. package/dist/src/memory/memory-bridge.js.map +1 -1
  191. package/dist/src/memory/memory-initializer.d.ts.map +1 -1
  192. package/dist/src/memory/memory-initializer.js +3 -32
  193. package/dist/src/memory/memory-initializer.js.map +1 -1
  194. package/dist/src/plugins/store/discovery.d.ts.map +1 -1
  195. package/dist/src/plugins/store/discovery.js +0 -69
  196. package/dist/src/plugins/store/discovery.js.map +1 -1
  197. package/dist/src/routing/embed-worker.d.ts +2 -0
  198. package/dist/src/routing/embed-worker.d.ts.map +1 -0
  199. package/dist/src/routing/embed-worker.js +55 -0
  200. package/dist/src/routing/embed-worker.js.map +1 -0
  201. package/dist/src/routing/embedder.d.ts +31 -0
  202. package/dist/src/routing/embedder.d.ts.map +1 -0
  203. package/dist/src/routing/embedder.js +0 -0
  204. package/dist/src/routing/embedder.js.map +1 -0
  205. package/dist/src/routing/llm-caller.d.ts +1 -1
  206. package/dist/src/routing/llm-caller.d.ts.map +1 -1
  207. package/dist/src/routing/llm-caller.js +18 -3
  208. package/dist/src/routing/llm-caller.js.map +1 -1
  209. package/dist/src/routing/route-layer-factory.d.ts +9 -0
  210. package/dist/src/routing/route-layer-factory.d.ts.map +1 -0
  211. package/dist/src/routing/route-layer-factory.js +151 -0
  212. package/dist/src/routing/route-layer-factory.js.map +1 -0
  213. package/dist/src/services/worker-daemon.d.ts.map +1 -1
  214. package/dist/src/services/worker-daemon.js +0 -1
  215. package/dist/src/services/worker-daemon.js.map +1 -1
  216. package/dist/src/suggest.d.ts +1 -1
  217. package/dist/src/suggest.js +1 -1
  218. package/dist/src/ui/server.mjs +5 -2
  219. package/dist/tsconfig.tsbuildinfo +1 -1
  220. package/package.json +9 -10
  221. package/scripts/publish-registry.ts +0 -2
  222. package/scripts/understand-analyze.mjs +1 -1
@@ -53,7 +53,7 @@ Show all routines with their schedule and status:
53
53
 
54
54
  ```bash
55
55
  jq -r '
56
- .routines[] |
56
+ (.routines // [])[] |
57
57
  "[\(.id)] \(.name) agent=\(.agent_id) schedule=\"\(.schedule)\" status=\(.status // "active")\n" +
58
58
  " task: \(.task_title)\n concurrency: \(.concurrency) catchup: \(.catchup)\n last_run: \(.last_run // "never") next_run: \(.next_run // "unknown")"
59
59
  ' "$routinesFile" 2>/dev/null || echo "No routines defined."
@@ -114,7 +114,7 @@ After creating, use `ScheduleWakeup` to schedule the first trigger at the approp
114
114
  Manually trigger a routine immediately (same as a scheduled run):
115
115
 
116
116
  ```bash
117
- routine=$(jq --arg id "$routine_id" '.routines[] | select(.id == $id)' "$routinesFile")
117
+ routine=$(jq --arg id "$routine_id" '(.routines // [])[] | select(.id == $id)' "$routinesFile")
118
118
  rt_agent=$(echo "$routine" | jq -r '.agent_id')
119
119
  rt_task=$(echo "$routine" | jq -r '.task_title')
120
120
  rt_context=$(echo "$routine" | jq -r '.context // ""')
@@ -122,7 +122,8 @@ rt_concurrency=$(echo "$routine" | jq -r '.concurrency')
122
122
 
123
123
  # Check concurrency policy
124
124
  stateFile=".monomind/orgs/${org_name}-state.json"
125
- agent_status=$(jq -r --arg a "$rt_agent" '.agents[$a].status // "idle"' "$stateFile" 2>/dev/null)
125
+ [ ! -f "$stateFile" ] && echo '{"agents":{}}' > "$stateFile"
126
+ agent_status=$(jq -r --arg a "$rt_agent" '.agents[$a].status // "idle"' "$stateFile")
126
127
 
127
128
  case "$rt_concurrency" in
128
129
  skip_if_active)
@@ -141,7 +142,7 @@ Update routine's `last_run` and schedule next wakeup:
141
142
  ```bash
142
143
  tmp="${routinesFile}.tmp"
143
144
  jq --arg id "$routine_id" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
144
- '.routines = [.routines[] | if .id == $id then .last_run = $ts else . end]' \
145
+ '.routines = [(.routines // [])[] | if .id == $id then .last_run = $ts else . end]' \
145
146
  "$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
146
147
  ```
147
148
 
@@ -150,7 +151,7 @@ jq --arg id "$routine_id" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
150
151
  ```bash
151
152
  tmp="${routinesFile}.tmp"
152
153
  jq --arg id "$routine_id" --arg status "$action" \
153
- '.routines = [.routines[] | if .id == $id then .status = $status else . end]' \
154
+ '.routines = [(.routines // [])[] | if .id == $id then .status = $status else . end]' \
154
155
  "$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
155
156
  echo "Routine $routine_id set to: $action"
156
157
  ```
@@ -159,7 +160,7 @@ echo "Routine $routine_id set to: $action"
159
160
 
160
161
  ```bash
161
162
  tmp="${routinesFile}.tmp"
162
- jq --arg id "$routine_id" '.routines = [.routines[] | select(.id != $id)]' \
163
+ jq --arg id "$routine_id" '.routines = [(.routines // [])[] | select(.id != $id)]' \
163
164
  "$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
164
165
  echo "Routine $routine_id removed."
165
166
  ```
@@ -31,7 +31,7 @@ If `caller` is not "command", load brain context following _protocol.md Brain Lo
31
31
 
32
32
  Read `.monomind/orgs/<org_name>.json`. If the file does not exist:
33
33
  ```bash
34
- orgs=$(ls .monomind/orgs/*.json 2>/dev/null | xargs -I{} basename {} .json)
34
+ orgs=$(ls .monomind/orgs/*.json 2>/dev/null | grep -vE -- '-approvals|-state|-activity|-goals|-routines|-projects|-members|-issues|-workspaces|-worktrees|-environments|-plugins|-adapters|-bootstrap|-threads|-budgets|-project-workspaces|-approval-comments' | xargs -I{} basename {} .json)
35
35
  if [ -z "$orgs" ]; then
36
36
  echo "No saved orgs found. Run /mastermind:createorg to define one."
37
37
  else
@@ -44,6 +44,170 @@ Validate the config has at minimum: `name`, `goal`, `roles` (non-empty array), `
44
44
 
45
45
  ---
46
46
 
47
+ ## Step 1.5 — Detect Scheduled Org
48
+
49
+ After loading the org config, check whether this is a scheduled (loop) org:
50
+
51
+ ```bash
52
+ orgFile=".monomind/orgs/${org_name}.json"
53
+ has_schedule=$(jq -r 'if .loop.poll_interval_minutes then "yes" else "no" end' "$orgFile")
54
+ ```
55
+
56
+ If `has_schedule == "yes"`, this is a **scheduled org**. Follow the **Scheduled Org Path** below (Steps 1.6 onward) instead of the standard Steps 2–8.
57
+
58
+ If `has_schedule == "no"`, skip to **Step 2** (standard persistent daemon path).
59
+
60
+ ---
61
+
62
+ ## Step 1.6 — Scheduled Org Path
63
+
64
+ This section handles orgs created with `--schedule`. The loop is owned by the org — it starts with `runorg`, runs each iteration via the loop prompt file, and stops with `stoporg`.
65
+
66
+ ### 1.6.1 — Guard against double-activation, then set status to "active"
67
+
68
+ ```bash
69
+ orgFile=".monomind/orgs/${org_name}.json"
70
+ current_loop_status=$(jq -r '.status // "stopped"' "$orgFile")
71
+ ```
72
+
73
+ If `current_loop_status == "active"`:
74
+ - Print:
75
+ ```
76
+ WARNING: Org '<org_name>' is already active. Starting a second instance would create parallel loop chains.
77
+ To restart cleanly: run /mastermind:stoporg --org <org_name> first, then /mastermind:runorg --org <org_name>.
78
+ To force restart anyway, set status to "stopped" in .monomind/orgs/<org_name>.json and re-run.
79
+ ```
80
+ - Return `status: blocked`. **STOP — do not proceed.**
81
+
82
+ If `current_loop_status == "paused"`:
83
+ - Print: "Org '<org_name>' was paused. Reactivating..."
84
+ - Proceed (set to "active" below).
85
+
86
+ For all other statuses (stopped, or absent):
87
+
88
+ ```bash
89
+ tmp="${orgFile}.tmp"
90
+ jq '.status = "active"' "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
91
+ ```
92
+
93
+ ### 1.6.2 — Derive scheduled-org variables
94
+
95
+ ```bash
96
+ orgName=$(jq -r '.name' "$orgFile")
97
+ goal="${task:-$(jq -r '.goal' "$orgFile")}"
98
+ sessionId="$session_id"
99
+ poll_interval_minutes=$(jq -r '.loop.poll_interval_minutes' "$orgFile")
100
+ poll_interval_seconds=$(( poll_interval_minutes * 60 ))
101
+ run_prompt_file=$(jq -r '.loop.run_prompt_file' "$orgFile")
102
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
103
+ CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
104
+ ```
105
+
106
+ ### 1.6.3 — Emit org:start event
107
+
108
+ ```bash
109
+ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
110
+ -H "Content-Type: application/json" \
111
+ -d "$(jq -cn \
112
+ --arg session "$sessionId" \
113
+ --arg org "$orgName" \
114
+ --arg goal "$goal" \
115
+ --arg proj "$REPO_ROOT" \
116
+ '{type:"org:start",session:$session,org:$org,goal:$goal,project:$proj,ts:(now*1000|floor)}')" || true
117
+ ```
118
+
119
+ ### 1.6.4 — Execute first iteration inline
120
+
121
+ Read the loop prompt file and execute its instructions directly (this IS the first iteration):
122
+
123
+ ```bash
124
+ [ ! -f "$run_prompt_file" ] && {
125
+ echo "ERROR: Loop prompt file '${run_prompt_file}' not found."
126
+ echo "Re-run: /mastermind:createorg --name ${orgName} --schedule \"every ${poll_interval_minutes} minutes\" to regenerate it."
127
+ exit 1
128
+ }
129
+ ```
130
+
131
+ Execute the steps described in `$run_prompt_file` — the file contains the full iteration instructions for this org. Follow them exactly, starting from Step 0 (status gate) through the org-specific work steps.
132
+
133
+ Since this is the first run and status was just set to "active", Step 0 will pass. The org-specific iteration steps run normally.
134
+
135
+ ### 1.6.5 — Schedule next iteration via ScheduleWakeup
136
+
137
+ After the iteration completes, re-check status and schedule the next wakeup:
138
+
139
+ ```bash
140
+ LOOP_STATUS=$(jq -r '.status // "stopped"' "$orgFile" 2>/dev/null || echo "stopped")
141
+ ```
142
+
143
+ If `LOOP_STATUS == "active"` or `LOOP_STATUS == "paused"`:
144
+
145
+ 1. Read the loop prompt:
146
+ ```bash
147
+ LOOP_PROMPT=$(cat "$run_prompt_file")
148
+ ```
149
+
150
+ 2. Call `ScheduleWakeup` with:
151
+ - `delaySeconds`: `$poll_interval_seconds`
152
+ - `reason`: `"<orgName>: next scheduled poll (every <poll_interval_minutes> min)"`
153
+ - `prompt`: full contents of `$LOOP_PROMPT`
154
+
155
+ 3. Update `next_run` in org JSON:
156
+ ```bash
157
+ next_ts=$(( $(date +%s) + poll_interval_seconds ))
158
+ next_iso=$(date -u -r "$next_ts" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
159
+ || date -u -d "@$next_ts" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
160
+ || python3 -c "import datetime; print(datetime.datetime.utcfromtimestamp($next_ts).strftime('%Y-%m-%dT%H:%M:%SZ'))")
161
+ tmp="${orgFile}.tmp"
162
+ jq --arg next "$next_iso" '.loop.next_run = $next' "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
163
+ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
164
+ -H "Content-Type: application/json" \
165
+ -d "$(jq -cn --arg org "$orgName" --arg next "$next_iso" --arg proj "$REPO_ROOT" \
166
+ '{type:"org:loop:scheduled",org:$org,next_run:$next,project:$proj,ts:(now*1000|floor)}')" || true
167
+ ```
168
+
169
+ If `LOOP_STATUS` is anything else → print "Org was stopped during this run — loop will not continue." No ScheduleWakeup.
170
+
171
+ ### 1.6.6 — Report to user
172
+
173
+ ```
174
+ ╔══════════════════════════════════════════════════════════╗
175
+ ║ ORG STARTED: <orgName> ║
176
+ ║ GOAL: <goal> ║
177
+ ║ MODE: scheduled loop ║
178
+ ╚══════════════════════════════════════════════════════════╝
179
+
180
+ SCHEDULE
181
+ ────────
182
+ Interval: every <poll_interval_minutes> minutes
183
+ Status: active
184
+ Next run: <next_iso (or "see .monomind/orgs/<orgName>.json")>
185
+
186
+ To stop: /mastermind:stoporg --org <orgName>
187
+ Status: /mastermind:orgstatus --org <orgName>
188
+ All orgs: /mastermind:orgs
189
+ ```
190
+
191
+ ### 1.6.7 — Return (skip Steps 2–8)
192
+
193
+ ```yaml
194
+ domain: ops
195
+ status: complete
196
+ decisions:
197
+ - what: "Scheduled org <orgName> activated, first iteration complete, next wakeup in <poll_interval_minutes> min"
198
+ why: "Loop started by runorg; ScheduleWakeup queued"
199
+ confidence: 0.9
200
+ outcome: pending
201
+ next_actions:
202
+ - "Stop: /mastermind:stoporg --org <orgName>"
203
+ - "Status: /mastermind:orgstatus --org <orgName>"
204
+ run_id: "<runId>"
205
+ ```
206
+
207
+ **STOP HERE** — do not execute Steps 2–8 for scheduled orgs.
208
+
209
+ ---
210
+
47
211
  ## Step 2 — Derive Variables
48
212
 
49
213
  Before spawning any agents, derive all variables from the loaded config. These are used in Steps 3 and 4.
@@ -91,9 +255,13 @@ stopFile=".monomind/orgs/.stops/${orgName}.stop"
91
255
  memNs="org:${orgName}"
92
256
  topology=$(jq -r '.topology' "$orgFile")
93
257
  checkpointMin=$(jq -r '.run_config.checkpoint_interval_min // 30' "$orgFile")
94
- bossRole_id=$(jq -r '[.roles[] | select(.reports_to == null)][0].id' "$orgFile")
95
- bossRole_title=$(jq -r '[.roles[] | select(.reports_to == null)][0].title' "$orgFile")
96
- bossRole_agent_type=$(jq -r '[.roles[] | select(.reports_to == null)][0].agent_type' "$orgFile")
258
+ bossRole_id=$(jq -r '[(.roles // [])[] | select(.reports_to == null or .reports_to == "")][0].id' "$orgFile")
259
+ bossRole_title=$(jq -r '[(.roles // [])[] | select(.reports_to == null or .reports_to == "")][0].title' "$orgFile")
260
+ bossRole_agent_type=$(jq -r '[(.roles // [])[] | select(.reports_to == null or .reports_to == "")][0].agent_type' "$orgFile")
261
+ if [ -z "$bossRole_id" ] || [ "$bossRole_id" = "null" ]; then
262
+ echo "ERROR: Org '${org_name}' has no root role (reports_to: null). Check the org config."
263
+ exit 1
264
+ fi
97
265
  board_id=$(jq -r '.board_id // empty' "$orgFile")
98
266
  todo_col=$(jq -r '.todo_col_id // empty' "$orgFile")
99
267
  doing_col=$(jq -r '.doing_col_id // empty' "$orgFile")
@@ -110,8 +278,10 @@ runId=$(date -u +%Y-%m-%dT%H:%M:%SZ)
110
278
  The board and column IDs were written into the org config by `createorg`. If missing, the org was not created correctly.
111
279
 
112
280
  ```bash
113
- [ -z "$board_id" ] && { echo "ERROR: org config missing board_id — re-run /mastermind:createorg --name ${orgName} to rebuild the org."; exit 1; }
281
+ [ -z "$board_id" ] && { echo "ERROR: org config missing board_id — re-run /mastermind:createorg --name ${orgName} to rebuild the org."; exit 1; }
114
282
  [ -z "$todo_col" ] && { echo "ERROR: org config missing todo_col_id — re-run /mastermind:createorg --name ${orgName}."; exit 1; }
283
+ [ -z "$doing_col" ] && { echo "ERROR: org config missing doing_col_id — re-run /mastermind:createorg --name ${orgName}."; exit 1; }
284
+ [ -z "$done_col" ] && { echo "ERROR: org config missing done_col_id — re-run /mastermind:createorg --name ${orgName}."; exit 1; }
115
285
  ```
116
286
 
117
287
  **Create stop-file and state directories:**
@@ -236,7 +406,7 @@ APPROVAL GATE (when governance.policy is "board" or "strict"):
236
406
  Before any external action (sending emails, posting content, making purchases, modifying infrastructure):
237
407
  approvalsFile=".monomind/orgs/${orgName}-approvals.json"
238
408
  [ ! -f "$approvalsFile" ] && echo '{"approvals":[]}' > "$approvalsFile"
239
- approval_id="req-$(date +%s)"
409
+ approval_id="req-$(date +%s)-$$-$RANDOM"
240
410
  jq --arg id "$approval_id" --arg agent "<role_id>" --arg title "<action summary>" \
241
411
  --arg action "<full action description>" --arg risk "medium" \
242
412
  '.approvals += [{"id":$id,"agent_id":$agent,"title":$title,"action":$action,"risk_level":$risk,"status":"pending","requested_at":(now|todate)}]' \
@@ -249,9 +419,9 @@ APPROVAL GATE (when governance.policy is "board" or "strict"):
249
419
  # Check the approvals file first (updated by both dashboard UI and /mastermind:approve command),
250
420
  # then fall back to memory in case an external notifier wrote there.
251
421
  for i in $(seq 1 60); do
252
- status=$(jq --arg id "$approval_id" '.approvals[] | select(.id == $id) | .status // ""' "$approvalsFile" 2>/dev/null || echo "")
422
+ status=$(jq -r --arg id "$approval_id" '(.approvals // [])[] | select(.id == $id) | .status // ""' "$approvalsFile" 2>/dev/null || echo "")
253
423
  if [ -z "$status" ] || [ "$status" = "pending" ]; then
254
- mem_status=$(npx monomind@latest memory search --query "approval:${approval_id}" --namespace "${memNs}" 2>/dev/null | jq -r '.[0].value.status // ""' 2>/dev/null)
424
+ mem_status=$(npx monomind@latest memory get --key "approval:${approval_id}" --namespace "${memNs}" 2>/dev/null | jq -r '.status // ""' 2>/dev/null)
255
425
  [ -n "$mem_status" ] && status="$mem_status"
256
426
  fi
257
427
  [ "$status" = "approved" ] && break
@@ -34,7 +34,7 @@ If `caller` is not "command", load brain context following _protocol.md Brain Lo
34
34
  if [ -n "$org_name" ]; then
35
35
  orgs="$org_name"
36
36
  else
37
- orgs=$(ls .monomind/orgs/*.json 2>/dev/null | grep -v '\-state\|-goals\|-routines\|-approvals\|-projects\|-worktrees\|-secrets' | xargs -I{} basename {} .json | sort)
37
+ orgs=$(ls .monomind/orgs/*.json 2>/dev/null | grep -vE -- '-approvals|-state|-activity|-goals|-routines|-projects|-members|-issues|-workspaces|-worktrees|-environments|-plugins|-adapters|-bootstrap|-threads|-budgets|-project-workspaces|-approval-comments' | xargs -I{} basename {} .json | sort)
38
38
  fi
39
39
  [ -z "$orgs" ] && { echo "No orgs found. Run /mastermind:createorg first."; exit 0; }
40
40
  ```
@@ -61,7 +61,7 @@ for org in $orgs; do
61
61
  # ── Agents ────────────────────────────────────────
62
62
  if [ "$scope" = "all" ] || [ "$scope" = "agents" ]; then
63
63
  hits=$(jq -r --arg q "$query_lower" \
64
- '.roles[] | select((.id + " " + .title + " " + (.responsibilities // [] | join(" "))) | ascii_downcase | test($q)) |
64
+ '(.roles // [])[] | select((.id + " " + .title + " " + (.responsibilities // [] | join(" "))) | ascii_downcase | test($q)) |
65
65
  "[AGENT] \(.id): \(.title) type=\(.agent_type)"' \
66
66
  "$orgFile" 2>/dev/null | head -"$limit")
67
67
  if [ -n "$hits" ]; then
@@ -76,7 +76,7 @@ for org in $orgs; do
76
76
  goalsFile=".monomind/orgs/${org}-goals.json"
77
77
  if [ -f "$goalsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "goals" ]; }; then
78
78
  hits=$(jq -r --arg q "$query_lower" \
79
- '.goals[] | select((.title + " " + (.description // "") + " " + (.status // "")) | ascii_downcase | test($q)) |
79
+ '(.goals // [])[] | select((.title + " " + (.description // "") + " " + (.status // "")) | ascii_downcase | test($q)) |
80
80
  "[GOAL] [\(.id)] \(.title) status=\(.status // "open")"' \
81
81
  "$goalsFile" 2>/dev/null | head -"$limit")
82
82
  if [ -n "$hits" ]; then
@@ -91,7 +91,7 @@ for org in $orgs; do
91
91
  routinesFile=".monomind/orgs/${org}-routines.json"
92
92
  if [ -f "$routinesFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "routines" ]; }; then
93
93
  hits=$(jq -r --arg q "$query_lower" \
94
- '.routines[] | select((.name + " " + (.description // "") + " " + (.schedule // "")) | ascii_downcase | test($q)) |
94
+ '(.routines // [])[] | select((.name + " " + (.description // "") + " " + (.schedule // "")) | ascii_downcase | test($q)) |
95
95
  "[ROUTINE] \(.name) schedule=\(.schedule // "-")"' \
96
96
  "$routinesFile" 2>/dev/null | head -"$limit")
97
97
  if [ -n "$hits" ]; then
@@ -106,7 +106,7 @@ for org in $orgs; do
106
106
  approvalsFile=".monomind/orgs/${org}-approvals.json"
107
107
  if [ -f "$approvalsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "approvals" ]; }; then
108
108
  hits=$(jq -r --arg q "$query_lower" \
109
- '.approvals[] | select((.title + " " + (.action // "") + " " + (.agent_id // "")) | ascii_downcase | test($q)) |
109
+ '(.approvals // [])[] | select((.title + " " + (.action // "") + " " + (.agent_id // "")) | ascii_downcase | test($q)) |
110
110
  "[APPROVAL] [\(.id)] \(.agent_id): \(.title) status=\(.status)"' \
111
111
  "$approvalsFile" 2>/dev/null | head -"$limit")
112
112
  if [ -n "$hits" ]; then
@@ -121,7 +121,7 @@ for org in $orgs; do
121
121
  projectsFile=".monomind/orgs/${org}-projects.json"
122
122
  if [ -f "$projectsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "projects" ]; }; then
123
123
  hits=$(jq -r --arg q "$query_lower" \
124
- '.projects[] | select((.name + " " + (.description // "") + " " + (.lead // "")) | ascii_downcase | test($q)) |
124
+ '(.projects // [])[] | select((.name + " " + (.description // "") + " " + (.lead // "")) | ascii_downcase | test($q)) |
125
125
  "[PROJECT] \(.name) status=\(.status // "active") lead=\(.lead // "-")"' \
126
126
  "$projectsFile" 2>/dev/null | head -"$limit")
127
127
  if [ -n "$hits" ]; then
@@ -61,7 +61,7 @@ Show all registered secrets for this org (metadata only, masked values):
61
61
 
62
62
  ```bash
63
63
  jq -r '
64
- .secrets[] |
64
+ (.secrets // [])[] |
65
65
  "[\(.name)] provider=\(.provider) hint=\(.masked_hint // "***") set=\(.set_at // "unknown") rotated=\(.rotated_at // "never")"
66
66
  ' "$secretsFile" 2>/dev/null || echo "No secrets registered."
67
67
  ```
@@ -108,7 +108,7 @@ jq --arg name "$secret_name" \
108
108
  --arg provider "${provider:-local}" \
109
109
  --arg hint "$hint" \
110
110
  --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
111
- '.secrets = [.secrets[] | select(.name != $name)] +
111
+ '.secrets = [(.secrets // [])[] | select(.name != $name)] +
112
112
  [{"name":$name,"provider":$provider,"masked_hint":$hint,"set_at":$ts}]' \
113
113
  "$secretsFile" > "$tmp" && mv "$tmp" "$secretsFile"
114
114
 
@@ -128,7 +128,7 @@ Generate a new value from env var and update:
128
128
  # Same as set but also records rotated_at
129
129
  tmp="${secretsFile}.tmp"
130
130
  jq --arg name "$secret_name" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
131
- '.secrets = [.secrets[] | if .name == $name then .rotated_at = $ts | .set_at = $ts else . end]' \
131
+ '.secrets = [(.secrets // [])[] | if .name == $name then .rotated_at = $ts | .set_at = $ts else . end]' \
132
132
  "$secretsFile" > "$tmp" && mv "$tmp" "$secretsFile"
133
133
  # Then re-run the set logic above with new value
134
134
  ```
@@ -140,7 +140,7 @@ Remove secret value and registry entry:
140
140
  ```bash
141
141
  rm -f ".monomind/orgs/.secrets/${org_name}/${secret_name}"
142
142
  tmp="${secretsFile}.tmp"
143
- jq --arg name "$secret_name" '.secrets = [.secrets[] | select(.name != $name)]' \
143
+ jq --arg name "$secret_name" '.secrets = [(.secrets // [])[] | select(.name != $name)]' \
144
144
  "$secretsFile" > "$tmp" && mv "$tmp" "$secretsFile"
145
145
  echo "Secret $secret_name revoked."
146
146
  ```
@@ -152,9 +152,9 @@ Show which agents reference each secret in their adapter_config or responsibilit
152
152
  ```bash
153
153
  orgFile=".monomind/orgs/${org_name}.json"
154
154
  echo "=== SECRET USAGE AUDIT — org: $org_name ==="
155
- jq -r '.roles[] | "\(.id): \(.responsibilities | join(", "))"' "$orgFile" | \
155
+ jq -r '(.roles // [])[] | "\(.id): \((.responsibilities // []) | join(", "))"' "$orgFile" | \
156
156
  while IFS=: read -r role resp; do
157
- refs=$(jq -r '.secrets[].name' "$secretsFile" | while read -r sname; do
157
+ refs=$(jq -r '(.secrets // [])[].name' "$secretsFile" | while read -r sname; do
158
158
  echo "$resp" | grep -q "$sname" && echo " → $sname"
159
159
  done)
160
160
  [ -n "$refs" ] && echo "$role$refs"
@@ -76,12 +76,12 @@ orgFile=".monomind/orgs/${org_name}.json"
76
76
  echo "SKILL MAP — org: $org_name"
77
77
  echo "────────────────────────────────────────────────────────"
78
78
 
79
- jq -r '.roles[] | "[\(.id)] \(.title) agent_type=\(.agent_type)"' "$orgFile" | while IFS= read -r line; do
79
+ jq -r '(.roles // [])[] | "[\(.id)] \(.title) agent_type=\(.agent_type)"' "$orgFile" | while IFS= read -r line; do
80
80
  echo "$line"
81
81
  roleId=$(echo "$line" | grep -o '^\[[^]]*\]' | tr -d '[]')
82
82
  # Show skills configured for this role
83
83
  mappedSkills=$(jq -r --arg id "$roleId" \
84
- '.roles[] | select(.id == $id) | .skills // [] | join(", ")' \
84
+ '(.roles // [])[] | select(.id == $id) | .skills // [] | join(", ")' \
85
85
  "$orgFile" 2>/dev/null)
86
86
  if [ -n "$mappedSkills" ] && [ "$mappedSkills" != "null" ]; then
87
87
  echo " Skills: $mappedSkills"
@@ -126,12 +126,12 @@ orgFile=".monomind/orgs/${org_name}.json"
126
126
  tmp="${orgFile}.tmp"
127
127
  if [ "$action" = "enable" ]; then
128
128
  jq --arg id "$role_id" --arg skill "$skill_name" \
129
- '.roles = [.roles[] | if .id == $id then .skills = ((.skills // []) + [$skill] | unique) else . end]' \
129
+ '.roles = [(.roles // [])[] | if .id == $id then .skills = ((.skills // []) + [$skill] | unique) else . end]' \
130
130
  "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
131
131
  echo "Enabled skill '$skill_name' for role '$role_id'"
132
132
  else
133
133
  jq --arg id "$role_id" --arg skill "$skill_name" \
134
- '.roles = [.roles[] | if .id == $id then .skills = ((.skills // []) | map(select(. != $skill))) else . end]' \
134
+ '.roles = [(.roles // [])[] | if .id == $id then .skills = ((.skills // []) | map(select(. != $skill))) else . end]' \
135
135
  "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
136
136
  echo "Disabled skill '$skill_name' for role '$role_id'"
137
137
  fi
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: mastermind-stoporg
3
+ description: Mastermind stoporg — stop a running scheduled org loop by setting its status to "stopped". The next scheduled wakeup will read the status, skip all work, and not reschedule. Loop dies within one interval — no orphaned wakeups.
4
+ type: domain-skill
5
+ default_mode: auto
6
+ ---
7
+
8
+ # Mastermind Stop Org
9
+
10
+ This skill is invoked by `mastermind:stoporg` or directly via `/mastermind:stoporg`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `org_name`: name of the org to stop (matches `.monomind/orgs/<org_name>.json`)
17
+ - `session_id`: session ID generated by the command wrapper
18
+ - `caller`: command | master
19
+
20
+ ---
21
+
22
+ ## Step 0 — Brain Load (standalone only)
23
+
24
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
25
+
26
+ ---
27
+
28
+ ## Step 1 — Validate Org
29
+
30
+ ```bash
31
+ orgFile=".monomind/orgs/${org_name}.json"
32
+ [ ! -f "$orgFile" ] && {
33
+ echo "ERROR: Org '${org_name}' not found."
34
+ echo "Available orgs: $(ls .monomind/orgs/*.json 2>/dev/null | grep -vE -- '-approvals|-state|-activity|-goals|-routines|-projects|-members|-issues|-workspaces|-worktrees|-environments|-plugins|-adapters|-bootstrap|-threads|-budgets|-project-workspaces|-approval-comments' | xargs -I{} basename {} .json | tr '\n' ' ')"
35
+ exit 1
36
+ }
37
+ ```
38
+
39
+ Read current status:
40
+ ```bash
41
+ current_status=$(jq -r '.status // "no-schedule"' "$orgFile")
42
+ has_schedule=$(jq -r 'if .loop.poll_interval_minutes then "yes" else "no" end' "$orgFile")
43
+ ```
44
+
45
+ If `has_schedule == "no"`:
46
+ ```bash
47
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
48
+ CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
49
+ # Write stop file so any running boss agent detects it at next loop iteration
50
+ mkdir -p ".monomind/orgs/.stops"
51
+ touch ".monomind/orgs/.stops/${org_name}.stop"
52
+ # Also POST to the control server in case a dashboard-started instance is running
53
+ curl -s -X POST "${CTRL_URL}/api/orgs/${org_name}/stop" >/dev/null 2>&1 || true
54
+ echo "Stop signal sent to org '${org_name}' (non-scheduled). The boss agent will exit at the next loop checkpoint."
55
+ ```
56
+ - Exit.
57
+
58
+ If `current_status == "stopped"`:
59
+ - Print: "Org '<org_name>' is already stopped."
60
+ - Exit.
61
+
62
+ ---
63
+
64
+ ## Step 2 — Set Status to Stopped and Clear next_run
65
+
66
+ ```bash
67
+ orgFile=".monomind/orgs/${org_name}.json"
68
+ tmp="${orgFile}.tmp"
69
+ # Clear next_run to avoid showing a stale future timestamp in orgstatus
70
+ jq '.status = "stopped" | if .loop then .loop.next_run = null else . end' "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Step 3 — Write Stop File (for any running boss agents)
76
+
77
+ Any persistent boss agent checks for this file at the start of each loop iteration:
78
+
79
+ ```bash
80
+ mkdir -p .monomind/orgs/.stops
81
+ touch ".monomind/orgs/.stops/${org_name}.stop"
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Step 4 — Emit Dashboard Events
87
+
88
+ ```bash
89
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
90
+ CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
91
+
92
+ # org:stop — signals dashboard to update status to stopped
93
+ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
94
+ -H "Content-Type: application/json" \
95
+ -d "$(jq -cn \
96
+ --arg session "${session_id:-manual}" \
97
+ --arg org "$org_name" \
98
+ --arg proj "$REPO_ROOT" \
99
+ '{type:"org:stop",session:$session,org:$org,project:$proj,ts:(now*1000|floor)}')" || true
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Step 5 — Report to User
105
+
106
+ ```
107
+ ✓ Org "<org_name>" stopped.
108
+
109
+ Current status: stopped
110
+ The loop will exit at its next scheduled wakeup without rescheduling.
111
+ Loop fully dead within: ≤<poll_interval_minutes> minutes
112
+
113
+ To restart: /mastermind:runorg --org <org_name>
114
+ Status: /mastermind:orgstatus --org <org_name>
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Step 6 — Return Output
120
+
121
+ ```yaml
122
+ domain: ops
123
+ status: complete
124
+ decisions:
125
+ - what: "Org <org_name> stopped"
126
+ why: "status set to 'stopped'; next wakeup exits without rescheduling"
127
+ confidence: 1.0
128
+ outcome: shipped
129
+ next_actions:
130
+ - "To restart: /mastermind:runorg --org <org_name>"
131
+ - "To check current state: /mastermind:orgstatus --org <org_name>"
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Step 7 — Brain Write (standalone only)
137
+
138
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
@@ -56,7 +56,7 @@ orgFile=".monomind/orgs/${org_name}.json"
56
56
  wsFile=".monomind/orgs/${org_name}-workspaces.json"
57
57
  [ ! -f "$wsFile" ] && { echo "ERROR: No workspaces file for org '$org_name'. Create workspaces via /mastermind:workspaces."; exit 1; }
58
58
 
59
- wsDef=$(jq -r --arg id "$workspace_id" '.workspaces[] | select(.id == $id)' "$wsFile")
59
+ wsDef=$(jq -r --arg id "$workspace_id" '(.workspaces // [])[] | select(.id == $id)' "$wsFile")
60
60
  [ -z "$wsDef" ] && { echo "ERROR: Workspace '$workspace_id' not found in org '$org_name'."; exit 1; }
61
61
 
62
62
  issuesFile=".monomind/orgs/${org_name}-issues.json"
@@ -145,7 +145,7 @@ else
145
145
  ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
146
146
  tmp="${wsFile}.tmp"
147
147
  jq --arg id "$workspace_id" --arg ts "$ts" \
148
- '.workspaces = [.workspaces[] | if .id == $id then .last_provisioned = $ts else . end]' \
148
+ '.workspaces = [(.workspaces // [])[] | if .id == $id then .last_provisioned = $ts else . end]' \
149
149
  "$wsFile" > "$tmp" && mv "$tmp" "$wsFile"
150
150
  echo " Provision complete."
151
151
  } || echo " Provision command exited with error."
@@ -230,7 +230,7 @@ echo "────────────────────────
230
230
  if [ ! -f "$issuesFile" ]; then
231
231
  echo " No issues file found."
232
232
  else
233
- jq -r --arg wid "$workspace_id" '.issues[] |
233
+ jq -r --arg wid "$workspace_id" '(.issues // [])[] |
234
234
  select(.workspace_id == $wid or (.assigned_workspace == $wid)) |
235
235
  [.id, (.status // "open"), (.priority // "medium"), (.title // "(no title)")] | @tsv' \
236
236
  "$issuesFile" | while IFS=$'\t' read -r id st pri title; do
@@ -250,7 +250,7 @@ if [ ! -f "$routinesFile" ]; then
250
250
  else
251
251
  # Show routines that have workspace-specific variable bindings
252
252
  jq -r --arg wid "$workspace_id" \
253
- '.routines[] | select((.variables // {}) | to_entries[] | .key | startswith("WS_") or contains("workspace")) |
253
+ '(.routines // [])[] | select((.variables // {}) | to_entries[] | .key | startswith("WS_") or contains("workspace")) |
254
254
  "\(.id) \(.name // "(no name)") vars: \((.variables // {}) | keys | join(", "))"' \
255
255
  "$routinesFile" 2>/dev/null || echo " No routines with workspace-specific variables."
256
256
  fi
@@ -279,7 +279,7 @@ if [ -n "$provision_command" ] || [ -n "$teardown_command" ] || [ -n "$cleanup_c
279
279
  --arg base "${base_ref:-}" \
280
280
  --arg branch "${branch_name:-}" \
281
281
  --arg ts "$ts" \
282
- '.workspaces = [.workspaces[] | if .id == $id then
282
+ '.workspaces = [(.workspaces // [])[] | if .id == $id then
283
283
  if .config == null then .config = {} else . end |
284
284
  (if $prov != "" then .config.provisionCommand = $prov else . end) |
285
285
  (if $td != "" then .config.teardownCommand = $td else . end) |