@monoes/monomindcli 1.9.17 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/.claude/commands/mastermind/_repeat.md +182 -39
  2. package/.claude/commands/mastermind/architect.md +17 -11
  3. package/.claude/commands/mastermind/brain.md +4 -0
  4. package/.claude/commands/mastermind/build.md +4 -0
  5. package/.claude/commands/mastermind/content.md +4 -0
  6. package/.claude/commands/mastermind/createorg.md +5 -3
  7. package/.claude/commands/mastermind/finance.md +4 -0
  8. package/.claude/commands/mastermind/idea.md +4 -0
  9. package/.claude/commands/mastermind/marketing.md +4 -0
  10. package/.claude/commands/mastermind/master.md +63 -37
  11. package/.claude/commands/mastermind/ops.md +4 -0
  12. package/.claude/commands/mastermind/release.md +4 -0
  13. package/.claude/commands/mastermind/research.md +4 -0
  14. package/.claude/commands/mastermind/review.md +4 -0
  15. package/.claude/commands/mastermind/runorg.md +5 -3
  16. package/.claude/commands/mastermind/sales.md +4 -0
  17. package/.claude/commands/mastermind/techport.md +9 -0
  18. package/.claude/commands/monomind/do.md +5 -1
  19. package/.claude/commands/monomind/idea.md +5 -1
  20. package/.claude/commands/monomind/improve.md +5 -1
  21. package/.claude/commands/monomind/repeat.md +85 -29
  22. package/.claude/commands/monomind/review.md +6 -2
  23. package/.claude/commands/monomind/understand.md +10 -8
  24. package/.claude/helpers/extras-registry.json +235 -235
  25. package/.claude/helpers/graphify-freshen.cjs +13 -1
  26. package/.claude/helpers/hook-handler.cjs +1 -1
  27. package/.claude/helpers/router.cjs +4 -1
  28. package/.claude/skills/mastermind/_protocol.md +28 -21
  29. package/.claude/skills/mastermind/access.md +236 -0
  30. package/.claude/skills/mastermind/activity.md +191 -0
  31. package/.claude/skills/mastermind/adapter-manager.md +259 -0
  32. package/.claude/skills/mastermind/adapters.md +204 -0
  33. package/.claude/skills/mastermind/agent-detail.md +242 -0
  34. package/.claude/skills/mastermind/agents.md +178 -0
  35. package/.claude/skills/mastermind/approval-detail.md +259 -0
  36. package/.claude/skills/mastermind/approve.md +181 -0
  37. package/.claude/skills/mastermind/architect.md +24 -8
  38. package/.claude/skills/mastermind/backup.md +197 -0
  39. package/.claude/skills/mastermind/bootstrap.md +190 -0
  40. package/.claude/skills/mastermind/budgets.md +237 -0
  41. package/.claude/skills/mastermind/companies.md +256 -0
  42. package/.claude/skills/mastermind/costs.md +151 -0
  43. package/.claude/skills/mastermind/createorg.md +23 -5
  44. package/.claude/skills/mastermind/diagnose.md +249 -0
  45. package/.claude/skills/mastermind/env.md +198 -0
  46. package/.claude/skills/mastermind/environments.md +250 -0
  47. package/.claude/skills/mastermind/export.md +324 -0
  48. package/.claude/skills/mastermind/goal-detail.md +255 -0
  49. package/.claude/skills/mastermind/goals.md +149 -0
  50. package/.claude/skills/mastermind/heartbeat.md +164 -0
  51. package/.claude/skills/mastermind/idea.md +250 -122
  52. package/.claude/skills/mastermind/import.md +281 -0
  53. package/.claude/skills/mastermind/inbox.md +214 -0
  54. package/.claude/skills/mastermind/instance-settings.md +315 -0
  55. package/.claude/skills/mastermind/instance.md +231 -0
  56. package/.claude/skills/mastermind/invite-landing.md +227 -0
  57. package/.claude/skills/mastermind/invites.md +254 -0
  58. package/.claude/skills/mastermind/issue-detail.md +291 -0
  59. package/.claude/skills/mastermind/issues.md +235 -0
  60. package/.claude/skills/mastermind/join-queue.md +170 -0
  61. package/.claude/skills/mastermind/liveness.md +392 -0
  62. package/.claude/skills/mastermind/memory.md +321 -0
  63. package/.claude/skills/mastermind/my-issues.md +146 -0
  64. package/.claude/skills/mastermind/new-agent.md +241 -0
  65. package/.claude/skills/mastermind/org-chart.md +207 -0
  66. package/.claude/skills/mastermind/org-settings.md +217 -0
  67. package/.claude/skills/mastermind/plan-to-tasks.md +136 -0
  68. package/.claude/skills/mastermind/plugin-manager.md +241 -0
  69. package/.claude/skills/mastermind/plugin-settings.md +273 -0
  70. package/.claude/skills/mastermind/plugins.md +190 -0
  71. package/.claude/skills/mastermind/profile.md +187 -0
  72. package/.claude/skills/mastermind/project-detail.md +249 -0
  73. package/.claude/skills/mastermind/project-workspace.md +244 -0
  74. package/.claude/skills/mastermind/projects.md +164 -0
  75. package/.claude/skills/mastermind/routine-detail.md +253 -0
  76. package/.claude/skills/mastermind/routines.md +202 -0
  77. package/.claude/skills/mastermind/runorg.md +74 -9
  78. package/.claude/skills/mastermind/search.md +186 -0
  79. package/.claude/skills/mastermind/secrets.md +199 -0
  80. package/.claude/skills/mastermind/skills.md +156 -0
  81. package/.claude/skills/mastermind/tasks.md +149 -0
  82. package/.claude/skills/mastermind/techport.md +5 -5
  83. package/.claude/skills/mastermind/threads.md +259 -0
  84. package/.claude/skills/mastermind/tree-control.md +250 -0
  85. package/.claude/skills/mastermind/wiki.md +314 -0
  86. package/.claude/skills/mastermind/workspace-detail.md +317 -0
  87. package/.claude/skills/mastermind/workspaces.md +261 -0
  88. package/.claude/skills/mastermind/worktree.md +187 -0
  89. package/dist/src/init/executor.js +8 -8
  90. package/dist/src/init/executor.js.map +1 -1
  91. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  92. package/dist/src/init/statusline-generator.js +12 -0
  93. package/dist/src/init/statusline-generator.js.map +1 -1
  94. package/dist/src/ui/.monomind/data/ranked-context.json +1 -1
  95. package/dist/src/ui/.monomind/loops/mastermind-review-1778664132789.json +16 -0
  96. package/dist/src/ui/.monomind/sessions/current.json +5 -5
  97. package/dist/src/ui/.monomind/sessions/session-1776778451399.json +15 -0
  98. package/dist/src/ui/dashboard.html +3030 -181
  99. package/dist/src/ui/data/mastermind-events.jsonl +8 -0
  100. package/dist/src/ui/data/mastermind-sessions.json +1 -0
  101. package/dist/src/ui/server.mjs +738 -0
  102. package/dist/tsconfig.tsbuildinfo +1 -1
  103. package/package.json +2 -2
  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
@@ -0,0 +1,392 @@
1
+ ---
2
+ name: mastermind-liveness
3
+ description: Mastermind liveness — enforce the non-terminal issue liveness contract for agent-owned work. Checks if every in_progress/blocked/in_review issue has a valid action path (active run, queued wake, explicit blocker, or recovery action). Can checkout an issue to an agent run, release checkout, trigger wakeup decisions, and file explicit recovery actions for stalled issues. Based on Paperclip's execution-semantics.md liveness contract.
4
+ type: domain-skill
5
+ default_mode: auto
6
+ ---
7
+
8
+ # Mastermind Liveness
9
+
10
+ This skill is invoked by `mastermind:liveness` or directly via `/mastermind:liveness`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
17
+ - `org_name`: org to check (required)
18
+ - `action`: check | checkout | release | wakeup | recover
19
+ - `issue_id`: specific issue to operate on (required for checkout/release/wakeup/recover)
20
+ - `agent_id`: agent claiming checkout (required for checkout)
21
+ - `run_id`: execution run ID (required for checkout)
22
+ - `reason`: recovery reason (required for recover)
23
+ - `caller`: command | master
24
+
25
+ ---
26
+
27
+ ## Liveness Contract
28
+
29
+ An issue is **healthy** when the product can answer "what moves this forward next?" without requiring a human to reconstruct intent.
30
+
31
+ An issue is **stalled** when it is non-terminal but has no:
32
+ - active run linked to the issue
33
+ - queued wake or continuation deliverable to the responsible agent
34
+ - explicit execution-policy participant
35
+ - pending interaction waiting on a specific responder
36
+ - one-shot monitor (`nextCheckAt`) that will wake the assignee
37
+ - human owner (`assigneeUserId`)
38
+ - first-class blocker chain whose leaf issues are themselves healthy
39
+ - open explicit recovery action naming owner + next action
40
+
41
+ **Valid non-terminal statuses for agent-owned work:** `todo`, `in_progress`, `blocked`, `in_review`
42
+
43
+ **Status → execution expectation:**
44
+ - `todo`: actionable but not yet claimed — may still need wake path to assignee
45
+ - `in_progress`: must have agent assignee + active execution backing (strict)
46
+ - `blocked`: must have named external dependency (blockedByIssueIds) or explicit human decision needed
47
+ - `in_review`: review participant must be named; next move belongs to reviewer
48
+
49
+ ---
50
+
51
+ ## Step 0 — Brain Load (standalone only)
52
+
53
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
54
+
55
+ ---
56
+
57
+ ## Step 1 — Load Org and Issues
58
+
59
+ ```bash
60
+ orgFile=".monomind/orgs/${org_name}.json"
61
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
62
+
63
+ issuesFile=".monomind/orgs/${org_name}-issues.json"
64
+ stateFile=".monomind/orgs/${org_name}-state.json"
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Step 2 — Execute Action
70
+
71
+ ### check (default)
72
+
73
+ Audit every non-terminal agent-owned issue for liveness. Flag stalled issues.
74
+
75
+ ```bash
76
+ echo "LIVENESS CHECK — ${org_name}"
77
+ echo "════════════════════════════════════════════════════════"
78
+
79
+ python3 - "$issuesFile" "$stateFile" <<'PYEOF'
80
+ import json, sys, os
81
+ from datetime import datetime, timedelta
82
+
83
+ issues_path = sys.argv[1]
84
+ state_path = sys.argv[2]
85
+
86
+ # Load issues
87
+ if not os.path.exists(issues_path):
88
+ print(" No issues file found. Org has no tracked issues.")
89
+ sys.exit(0)
90
+
91
+ data = json.load(open(issues_path))
92
+ issues = data.get("issues", [])
93
+
94
+ # Load active agent run IDs from state
95
+ active_runs = set()
96
+ if os.path.exists(state_path):
97
+ try:
98
+ state = json.load(open(state_path))
99
+ for role in state.get("roles", []):
100
+ if role.get("currentRunId"): active_runs.add(role["currentRunId"])
101
+ except: pass
102
+
103
+ non_terminal_statuses = {"todo","in_progress","blocked","in_review"}
104
+ terminal_statuses = {"done","cancelled"}
105
+
106
+ healthy, stalled, warnings = [], [], []
107
+ now = datetime.utcnow()
108
+
109
+ for iss in issues:
110
+ status = iss.get("status","")
111
+ if status in terminal_statuses or status not in non_terminal_statuses:
112
+ continue
113
+
114
+ aId = iss.get("assigneeAgentId") or iss.get("assigneeId")
115
+ uId = iss.get("assigneeUserId")
116
+ iid = iss.get("id","?")
117
+ title = iss.get("title","?")[:50]
118
+
119
+ # User-owned: skip strict execution checks
120
+ if uId and not aId:
121
+ healthy.append((iid, title, status, "user-owned"))
122
+ continue
123
+
124
+ # Evaluate liveness
125
+ paths = []
126
+
127
+ run_id = iss.get("executionRunId") or iss.get("checkoutRunId")
128
+ if run_id and run_id in active_runs:
129
+ paths.append("active-run")
130
+
131
+ blockers = iss.get("blockedByIssueIds") or []
132
+ if status == "blocked" and blockers:
133
+ unresolved = [b for b in blockers if b not in
134
+ {i["id"] for i in issues if i.get("status") in terminal_statuses}]
135
+ if unresolved:
136
+ paths.append(f"blocked-by:{','.join(unresolved[:2])}")
137
+ else:
138
+ # All blockers resolved — should transition
139
+ warnings.append((iid, title, status, "all blockers resolved but issue still blocked"))
140
+
141
+ if iss.get("executionPolicy", {}).get("monitor", {}).get("nextCheckAt"):
142
+ paths.append("monitor")
143
+
144
+ if iss.get("recoveryActions") and any(
145
+ r.get("status") not in ("resolved","cancelled")
146
+ for r in iss.get("recoveryActions",[])
147
+ ):
148
+ paths.append("recovery-action")
149
+
150
+ if iss.get("currentParticipant"):
151
+ paths.append("participant")
152
+
153
+ # Stale heartbeat check (in_progress with no run and no recent update)
154
+ if status == "in_progress" and aId and not paths:
155
+ updated = iss.get("updatedAt","")
156
+ if updated:
157
+ try:
158
+ age = now - datetime.fromisoformat(updated[:19])
159
+ if age > timedelta(hours=2):
160
+ stalled.append((iid, title, status, f"in_progress {int(age.total_seconds()//3600)}h with no active path"))
161
+ continue
162
+ except: pass
163
+ stalled.append((iid, title, status, "in_progress with no active execution path"))
164
+ continue
165
+
166
+ if not paths and status == "todo" and aId:
167
+ warnings.append((iid, title, status, "todo assigned to agent — may need wakeup"))
168
+ elif paths:
169
+ healthy.append((iid, title, status, " + ".join(paths)))
170
+ else:
171
+ healthy.append((iid, title, status, "no agent assignee"))
172
+
173
+ print(f" ✓ Healthy: {len(healthy)}")
174
+ if healthy:
175
+ for iid, t, s, p in healthy[:5]:
176
+ print(f" {iid}: [{s}] {t} — {p}")
177
+ if len(healthy) > 5: print(f" … {len(healthy)-5} more")
178
+
179
+ print()
180
+ if stalled:
181
+ print(f" ✗ STALLED: {len(stalled)}")
182
+ for iid, t, s, p in stalled:
183
+ print(f" {iid}: [{s}] {t}")
184
+ print(f" → {p}")
185
+ print()
186
+ print(" Fix: /mastermind:liveness --org <org> --action recover --issue-id <id> --reason 'execution path lost'")
187
+ else:
188
+ print(" ✓ No stalled issues.")
189
+
190
+ if warnings:
191
+ print()
192
+ print(f" ⚠ Warnings: {len(warnings)}")
193
+ for iid, t, s, p in warnings:
194
+ print(f" {iid}: [{s}] {t} — {p}")
195
+ PYEOF
196
+ ```
197
+
198
+ ### checkout
199
+
200
+ Claim an issue for execution by an agent run. Sets `checkoutRunId` and `executionRunId`.
201
+
202
+ ```bash
203
+ [ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
204
+ [ -z "$agent_id" ] && { echo "ERROR: --agent-id required."; exit 1; }
205
+ [ -z "$run_id" ] && { echo "ERROR: --run-id required."; exit 1; }
206
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
207
+
208
+ python3 - "$issuesFile" "$issue_id" "$agent_id" "$run_id" "$ts" <<'PYEOF'
209
+ import json, sys
210
+
211
+ path, iid, agentId, runId, ts = sys.argv[1:]
212
+ data = json.load(open(path))
213
+ issues = data.get("issues", [])
214
+
215
+ found = False
216
+ for iss in issues:
217
+ if iss.get("id") == iid:
218
+ existing = iss.get("checkoutRunId")
219
+ if existing and existing != runId:
220
+ print(f" CONFLICT: Issue already checked out by run {existing}")
221
+ print(f" Release first: /mastermind:liveness --org <org> --action release --issue-id {iid}")
222
+ sys.exit(1)
223
+ iss["checkoutRunId"] = runId
224
+ iss["executionRunId"] = runId
225
+ iss["assigneeId"] = agentId
226
+ iss["assigneeAgentId"]= agentId
227
+ iss["status"] = "in_progress"
228
+ iss["checkedOutAt"] = ts
229
+ iss["updatedAt"] = ts
230
+ found = True
231
+ print(f" CHECKOUT: Issue {iid} → agent {agentId}, run {runId}")
232
+ print(f" Status set to: in_progress")
233
+ break
234
+
235
+ if not found:
236
+ print(f" ERROR: Issue '{iid}' not found.")
237
+ sys.exit(1)
238
+
239
+ data["issues"] = issues
240
+ with open(path, "w") as f:
241
+ json.dump(data, f, indent=2)
242
+ PYEOF
243
+ ```
244
+
245
+ ### release
246
+
247
+ Release the checkout lock on an issue.
248
+
249
+ ```bash
250
+ [ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
251
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
252
+
253
+ python3 - "$issuesFile" "$issue_id" "$ts" "${run_id:-}" <<'PYEOF'
254
+ import json, sys, os
255
+
256
+ path, iid, ts, run_id = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]
257
+ data = json.load(open(path))
258
+ issues = data.get("issues", [])
259
+
260
+ for iss in issues:
261
+ if iss.get("id") == iid:
262
+ current = iss.get("checkoutRunId","")
263
+ if run_id and current != run_id:
264
+ print(f" WARNING: Releasing run {run_id} but issue has run {current}. Proceeding.")
265
+ iss.pop("checkoutRunId", None)
266
+ iss.pop("executionRunId", None)
267
+ iss.pop("checkedOutAt", None)
268
+ iss["updatedAt"] = ts
269
+ print(f" RELEASED: Checkout cleared for issue {iid}")
270
+ print(f" Status remains: {iss.get('status','?')} — update separately if needed.")
271
+ data["issues"] = issues
272
+ with open(path, "w") as f:
273
+ json.dump(data, f, indent=2)
274
+ sys.exit(0)
275
+
276
+ print(f" ERROR: Issue '{iid}' not found.")
277
+ sys.exit(1)
278
+ PYEOF
279
+ ```
280
+
281
+ ### wakeup
282
+
283
+ Decide whether the assignee of a `todo` or `blocked` issue should be woken.
284
+
285
+ ```bash
286
+ [ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
287
+
288
+ python3 - "$issuesFile" "$stateFile" "$issue_id" "${agent_id:-}" <<'PYEOF'
289
+ import json, sys, os
290
+
291
+ issues_path, state_path, iid, actor_agent_id = sys.argv[1:]
292
+
293
+ data = json.load(open(issues_path))
294
+ iss = next((i for i in data.get("issues",[]) if i.get("id") == iid), None)
295
+ if not iss:
296
+ print(f" ERROR: Issue '{iid}' not found.")
297
+ sys.exit(1)
298
+
299
+ checkout_agent = iss.get("assigneeAgentId") or iss.get("assigneeId","")
300
+ checkout_run = iss.get("checkoutRunId","")
301
+
302
+ # Port of Paperclip's shouldWakeAssigneeOnCheckout logic
303
+ actor_is_agent = bool(actor_agent_id)
304
+ actor_differs = actor_agent_id != checkout_agent
305
+ checkout_has_no_run= not checkout_run
306
+
307
+ should_wake = (
308
+ not actor_is_agent # non-agent actor (board/human) → always wake
309
+ or actor_differs # different agent claiming → wake original
310
+ or checkout_has_no_run # no active run → wake to get work started
311
+ )
312
+
313
+ print(f" Issue: {iid} — {iss.get('title','?')[:60]}")
314
+ print(f" Status: {iss.get('status','?')}")
315
+ print(f" Assignee:{checkout_agent or '(none)'}")
316
+ print(f" Run: {checkout_run or '(none)'}")
317
+ print(f" Actor: {actor_agent_id or '(board)'}")
318
+ print()
319
+ if should_wake:
320
+ print(" WAKE: YES — assignee should be notified to pick up this issue.")
321
+ print(" Reasons:")
322
+ if not actor_is_agent: print(" · Non-agent actor (board/human)")
323
+ if actor_is_agent and actor_differs: print(f" · Actor ({actor_agent_id}) != assignee ({checkout_agent})")
324
+ if checkout_has_no_run: print(" · No active execution run")
325
+ else:
326
+ print(" WAKE: NO — assignee already has an active run for this issue.")
327
+ PYEOF
328
+ ```
329
+
330
+ ### recover
331
+
332
+ File an explicit recovery action on a stalled issue with a named owner and next step.
333
+
334
+ ```bash
335
+ [ -z "$issue_id" ] && { echo "ERROR: --issue-id required."; exit 1; }
336
+ [ -z "$reason" ] && { echo "ERROR: --reason required."; exit 1; }
337
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
338
+ recoveryId="recovery-$(python3 -c 'import time; print(int(time.time()*1000))')"
339
+
340
+ python3 - "$issuesFile" "$issue_id" "$recoveryId" "${agent_id:-operator}" "$reason" "$ts" <<'PYEOF'
341
+ import json, sys
342
+
343
+ path, iid, rid, owner, cause, ts = sys.argv[1:]
344
+ data = json.load(open(path))
345
+ issues = data.get("issues", [])
346
+
347
+ for iss in issues:
348
+ if iss.get("id") == iid:
349
+ recovery = {
350
+ "id": rid,
351
+ "kind": "restore-liveness",
352
+ "owner": owner,
353
+ "cause": cause,
354
+ "createdAt": ts,
355
+ "status": "open",
356
+ "nextAction": f"Investigate why issue '{iid}' has no active execution path and restore it.",
357
+ }
358
+ iss.setdefault("recoveryActions", []).append(recovery)
359
+ iss["status"] = "blocked"
360
+ iss["updatedAt"] = ts
361
+ data["issues"] = issues
362
+ with open(path, "w") as f:
363
+ json.dump(data, f, indent=2)
364
+ print(f" RECOVERY ACTION FILED: {rid}")
365
+ print(f" Issue {iid} → status: blocked (pending recovery)")
366
+ print(f" Owner: {owner}")
367
+ print(f" Cause: {cause}")
368
+ print(f" Resolve with: /mastermind:liveness --org <org> --action checkout --issue-id {iid} --agent-id <id> --run-id <id>")
369
+ sys.exit(0)
370
+
371
+ print(f" ERROR: Issue '{iid}' not found.")
372
+ sys.exit(1)
373
+ PYEOF
374
+ ```
375
+
376
+ ---
377
+
378
+ ## Step 3 — Return Output
379
+
380
+ ```yaml
381
+ domain: ops
382
+ status: complete
383
+ action: <action>
384
+ org_name: <org_name>
385
+ issue_id: <issue_id or all>
386
+ ```
387
+
388
+ ---
389
+
390
+ ## Step 4 — Brain Write (standalone only)
391
+
392
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.