@monoes/monomindcli 1.9.17 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/mastermind/_repeat.md +182 -39
- package/.claude/commands/mastermind/architect.md +17 -11
- package/.claude/commands/mastermind/brain.md +4 -0
- package/.claude/commands/mastermind/build.md +4 -0
- package/.claude/commands/mastermind/content.md +4 -0
- package/.claude/commands/mastermind/createorg.md +5 -3
- package/.claude/commands/mastermind/finance.md +4 -0
- package/.claude/commands/mastermind/idea.md +4 -0
- package/.claude/commands/mastermind/marketing.md +4 -0
- package/.claude/commands/mastermind/master.md +63 -37
- package/.claude/commands/mastermind/ops.md +4 -0
- package/.claude/commands/mastermind/release.md +4 -0
- package/.claude/commands/mastermind/research.md +4 -0
- package/.claude/commands/mastermind/review.md +4 -0
- package/.claude/commands/mastermind/runorg.md +5 -3
- package/.claude/commands/mastermind/sales.md +4 -0
- package/.claude/commands/mastermind/techport.md +9 -0
- package/.claude/commands/monomind/do.md +5 -1
- package/.claude/commands/monomind/idea.md +5 -1
- package/.claude/commands/monomind/improve.md +5 -1
- package/.claude/commands/monomind/repeat.md +85 -29
- package/.claude/commands/monomind/review.md +6 -2
- package/.claude/commands/monomind/understand.md +10 -8
- package/.claude/helpers/extras-registry.json +235 -235
- package/.claude/helpers/graphify-freshen.cjs +13 -1
- package/.claude/helpers/hook-handler.cjs +1 -1
- package/.claude/helpers/router.cjs +4 -1
- package/.claude/skills/mastermind/_protocol.md +28 -21
- package/.claude/skills/mastermind/access.md +236 -0
- package/.claude/skills/mastermind/activity.md +191 -0
- package/.claude/skills/mastermind/adapter-manager.md +259 -0
- package/.claude/skills/mastermind/adapters.md +204 -0
- package/.claude/skills/mastermind/agent-detail.md +242 -0
- package/.claude/skills/mastermind/agents.md +178 -0
- package/.claude/skills/mastermind/approval-detail.md +259 -0
- package/.claude/skills/mastermind/approve.md +181 -0
- package/.claude/skills/mastermind/architect.md +24 -8
- package/.claude/skills/mastermind/backup.md +197 -0
- package/.claude/skills/mastermind/bootstrap.md +190 -0
- package/.claude/skills/mastermind/budgets.md +237 -0
- package/.claude/skills/mastermind/companies.md +256 -0
- package/.claude/skills/mastermind/costs.md +151 -0
- package/.claude/skills/mastermind/createorg.md +23 -5
- package/.claude/skills/mastermind/diagnose.md +249 -0
- package/.claude/skills/mastermind/env.md +198 -0
- package/.claude/skills/mastermind/environments.md +250 -0
- package/.claude/skills/mastermind/export.md +324 -0
- package/.claude/skills/mastermind/goal-detail.md +255 -0
- package/.claude/skills/mastermind/goals.md +149 -0
- package/.claude/skills/mastermind/heartbeat.md +164 -0
- package/.claude/skills/mastermind/idea.md +250 -122
- package/.claude/skills/mastermind/import.md +281 -0
- package/.claude/skills/mastermind/inbox.md +214 -0
- package/.claude/skills/mastermind/instance-settings.md +315 -0
- package/.claude/skills/mastermind/instance.md +231 -0
- package/.claude/skills/mastermind/invite-landing.md +227 -0
- package/.claude/skills/mastermind/invites.md +254 -0
- package/.claude/skills/mastermind/issue-detail.md +291 -0
- package/.claude/skills/mastermind/issues.md +235 -0
- package/.claude/skills/mastermind/join-queue.md +170 -0
- package/.claude/skills/mastermind/liveness.md +392 -0
- package/.claude/skills/mastermind/memory.md +321 -0
- package/.claude/skills/mastermind/my-issues.md +146 -0
- package/.claude/skills/mastermind/new-agent.md +241 -0
- package/.claude/skills/mastermind/org-chart.md +207 -0
- package/.claude/skills/mastermind/org-settings.md +217 -0
- package/.claude/skills/mastermind/plan-to-tasks.md +136 -0
- package/.claude/skills/mastermind/plugin-manager.md +241 -0
- package/.claude/skills/mastermind/plugin-settings.md +273 -0
- package/.claude/skills/mastermind/plugins.md +190 -0
- package/.claude/skills/mastermind/profile.md +187 -0
- package/.claude/skills/mastermind/project-detail.md +249 -0
- package/.claude/skills/mastermind/project-workspace.md +244 -0
- package/.claude/skills/mastermind/projects.md +164 -0
- package/.claude/skills/mastermind/routine-detail.md +253 -0
- package/.claude/skills/mastermind/routines.md +202 -0
- package/.claude/skills/mastermind/runorg.md +74 -9
- package/.claude/skills/mastermind/search.md +186 -0
- package/.claude/skills/mastermind/secrets.md +199 -0
- package/.claude/skills/mastermind/skills.md +156 -0
- package/.claude/skills/mastermind/tasks.md +149 -0
- package/.claude/skills/mastermind/techport.md +5 -5
- package/.claude/skills/mastermind/threads.md +259 -0
- package/.claude/skills/mastermind/tree-control.md +250 -0
- package/.claude/skills/mastermind/wiki.md +314 -0
- package/.claude/skills/mastermind/workspace-detail.md +317 -0
- package/.claude/skills/mastermind/workspaces.md +261 -0
- package/.claude/skills/mastermind/worktree.md +187 -0
- package/dist/src/init/executor.js +8 -8
- package/dist/src/init/executor.js.map +1 -1
- package/dist/src/init/statusline-generator.d.ts.map +1 -1
- package/dist/src/init/statusline-generator.js +12 -0
- package/dist/src/init/statusline-generator.js.map +1 -1
- package/dist/src/ui/.monomind/data/ranked-context.json +1 -1
- package/dist/src/ui/.monomind/loops/mastermind-review-1778664132789.json +16 -0
- package/dist/src/ui/.monomind/sessions/current.json +5 -5
- package/dist/src/ui/.monomind/sessions/session-1776778451399.json +15 -0
- package/dist/src/ui/dashboard.html +3030 -181
- package/dist/src/ui/data/mastermind-events.jsonl +8 -0
- package/dist/src/ui/data/mastermind-sessions.json +1 -0
- package/dist/src/ui/server.mjs +738 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/.claude/skills/.monomind/data/ranked-context.json +0 -5
- package/.claude/skills/.monomind/sessions/current.json +0 -13
- package/.claude/skills/.monomind/sessions/session-1777829336455.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777831614725.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777832095857.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777839814183.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777841847131.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777843309463.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777880867159.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777881884593.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777884090471.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777884808221.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777885672155.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777886852818.json +0 -15
- package/.claude/skills/.monomind/sessions/session-1777896532690.json +0 -15
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-routines
|
|
3
|
+
description: Mastermind routines — schedule recurring tasks that trigger agent heartbeats on a cron-like schedule within a running org. Configure concurrency policy and catch-up behavior.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: confirm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Routines
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:routines` or directly via `/mastermind:routines`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block
|
|
17
|
+
- `org_name`: org to manage routines for
|
|
18
|
+
- `action`: list | add | pause | resume | remove | trigger
|
|
19
|
+
- `routine_id`: slug of the routine (for pause/resume/remove/trigger)
|
|
20
|
+
- `routine_name`: display name (for add)
|
|
21
|
+
- `agent_id`: role id of the agent to trigger
|
|
22
|
+
- `schedule`: cron expression (e.g. "0 9 * * 1-5" = weekdays at 9am)
|
|
23
|
+
- `task_title`: task to create on each trigger
|
|
24
|
+
- `context`: optional context passed to agent on each heartbeat
|
|
25
|
+
- `concurrency`: coalesce_if_active | always_enqueue | skip_if_active (default: coalesce_if_active)
|
|
26
|
+
- `catchup`: skip_missed | enqueue_missed_with_cap (default: skip_missed)
|
|
27
|
+
- `caller`: command | master
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Step 0 — Brain Load (standalone only)
|
|
32
|
+
|
|
33
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Step 1 — Load Routines
|
|
38
|
+
|
|
39
|
+
Routines are stored in `.monomind/orgs/<org_name>-routines.json`:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
routinesFile=".monomind/orgs/${org_name}-routines.json"
|
|
43
|
+
[ ! -f "$routinesFile" ] && echo '{"routines":[]}' > "$routinesFile"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Step 2 — Execute Action
|
|
49
|
+
|
|
50
|
+
### list (default)
|
|
51
|
+
|
|
52
|
+
Show all routines with their schedule and status:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
jq -r '
|
|
56
|
+
.routines[] |
|
|
57
|
+
"[\(.id)] \(.name) agent=\(.agent_id) schedule=\"\(.schedule)\" status=\(.status // "active")\n" +
|
|
58
|
+
" task: \(.task_title)\n concurrency: \(.concurrency) catchup: \(.catchup)\n last_run: \(.last_run // "never") next_run: \(.next_run // "unknown")"
|
|
59
|
+
' "$routinesFile" 2>/dev/null || echo "No routines defined."
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Render as:
|
|
63
|
+
```
|
|
64
|
+
ROUTINES — org: <org_name>
|
|
65
|
+
──────────────────────────────────────────────────────
|
|
66
|
+
[weekly-report] Weekly Status Report
|
|
67
|
+
Agent: boss | Schedule: 0 9 * * 1 (Mondays 9am)
|
|
68
|
+
Status: active
|
|
69
|
+
Task: "Compile weekly progress report from all agents"
|
|
70
|
+
Concurrency: coalesce_if_active | Catchup: skip_missed
|
|
71
|
+
Last run: 3 days ago | Next run: in 4 days
|
|
72
|
+
|
|
73
|
+
[daily-content] Daily Content Draft
|
|
74
|
+
Agent: content-writer | Schedule: 0 10 * * 1-5 (weekdays 10am)
|
|
75
|
+
Status: active
|
|
76
|
+
Task: "Draft one content piece for the content calendar"
|
|
77
|
+
Concurrency: skip_if_active | Catchup: skip_missed
|
|
78
|
+
Last run: yesterday | Next run: tomorrow 10am
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### add
|
|
82
|
+
|
|
83
|
+
Add a new routine and register a ScheduleWakeup via Claude's native scheduler:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
routine_id=$(echo "$routine_name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | tr -s '-')
|
|
87
|
+
tmp="${routinesFile}.tmp"
|
|
88
|
+
jq --arg id "$routine_id" \
|
|
89
|
+
--arg name "$routine_name" \
|
|
90
|
+
--arg agent "$agent_id" \
|
|
91
|
+
--arg schedule "$schedule" \
|
|
92
|
+
--arg task "$task_title" \
|
|
93
|
+
--arg context "${context:-}" \
|
|
94
|
+
--arg concurrency "${concurrency:-coalesce_if_active}" \
|
|
95
|
+
--arg catchup "${catchup:-skip_missed}" \
|
|
96
|
+
'.routines += [{
|
|
97
|
+
"id":$id,"name":$name,"agent_id":$agent,"schedule":$schedule,
|
|
98
|
+
"task_title":$task,"context":$context,"concurrency":$concurrency,
|
|
99
|
+
"catchup":$catchup,"status":"active","created_at":(now|todate)
|
|
100
|
+
}]' \
|
|
101
|
+
"$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
|
|
102
|
+
echo "Routine added: $routine_id"
|
|
103
|
+
echo "Schedule: $schedule"
|
|
104
|
+
echo ""
|
|
105
|
+
echo "NOTE: To activate this routine, use ScheduleWakeup with:"
|
|
106
|
+
echo " prompt: '/mastermind:routines --action trigger --org $org_name --routine-id $routine_id'"
|
|
107
|
+
echo " delaySeconds: <seconds until next scheduled run>"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
After creating, use `ScheduleWakeup` to schedule the first trigger at the appropriate delay based on the cron expression.
|
|
111
|
+
|
|
112
|
+
### trigger
|
|
113
|
+
|
|
114
|
+
Manually trigger a routine immediately (same as a scheduled run):
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
routine=$(jq --arg id "$routine_id" '.routines[] | select(.id == $id)' "$routinesFile")
|
|
118
|
+
rt_agent=$(echo "$routine" | jq -r '.agent_id')
|
|
119
|
+
rt_task=$(echo "$routine" | jq -r '.task_title')
|
|
120
|
+
rt_context=$(echo "$routine" | jq -r '.context // ""')
|
|
121
|
+
rt_concurrency=$(echo "$routine" | jq -r '.concurrency')
|
|
122
|
+
|
|
123
|
+
# Check concurrency policy
|
|
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)
|
|
126
|
+
|
|
127
|
+
case "$rt_concurrency" in
|
|
128
|
+
skip_if_active)
|
|
129
|
+
[ "$agent_status" = "running" ] && { echo "Skipped: agent $rt_agent is already running (skip_if_active policy)"; exit 0; }
|
|
130
|
+
;;
|
|
131
|
+
coalesce_if_active)
|
|
132
|
+
# Queue at most one pending run
|
|
133
|
+
;;
|
|
134
|
+
esac
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Then invoke the heartbeat skill logic: create a task card for `rt_task`, trigger the agent heartbeat.
|
|
138
|
+
|
|
139
|
+
Update routine's `last_run` and schedule next wakeup:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
tmp="${routinesFile}.tmp"
|
|
143
|
+
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
|
+
"$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### pause / resume
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
tmp="${routinesFile}.tmp"
|
|
152
|
+
jq --arg id "$routine_id" --arg status "$action" \
|
|
153
|
+
'.routines = [.routines[] | if .id == $id then .status = $status else . end]' \
|
|
154
|
+
"$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
|
|
155
|
+
echo "Routine $routine_id set to: $action"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### remove
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
tmp="${routinesFile}.tmp"
|
|
162
|
+
jq --arg id "$routine_id" '.routines = [.routines[] | select(.id != $id)]' \
|
|
163
|
+
"$routinesFile" > "$tmp" && mv "$tmp" "$routinesFile"
|
|
164
|
+
echo "Routine $routine_id removed."
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Concurrency Policies
|
|
170
|
+
|
|
171
|
+
| Policy | Behavior |
|
|
172
|
+
|--------|----------|
|
|
173
|
+
| `coalesce_if_active` | If a run is already active, keep just one follow-up queued |
|
|
174
|
+
| `always_enqueue` | Queue every trigger, even if routine is already running |
|
|
175
|
+
| `skip_if_active` | Drop new triggers while a run is active |
|
|
176
|
+
|
|
177
|
+
## Catch-up Policies
|
|
178
|
+
|
|
179
|
+
| Policy | Behavior |
|
|
180
|
+
|--------|----------|
|
|
181
|
+
| `skip_missed` | Ignore windows missed while paused/down |
|
|
182
|
+
| `enqueue_missed_with_cap` | Catch up missed windows in capped batches |
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Step 3 — Return Output
|
|
187
|
+
|
|
188
|
+
```yaml
|
|
189
|
+
domain: ops
|
|
190
|
+
status: complete
|
|
191
|
+
action: <action>
|
|
192
|
+
org: <org_name>
|
|
193
|
+
routine_id: <routine_id if applicable>
|
|
194
|
+
routines_count: <N>
|
|
195
|
+
routines_file: .monomind/orgs/<org_name>-routines.json
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Step 4 — Brain Write (standalone only)
|
|
201
|
+
|
|
202
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -114,14 +114,39 @@ The board and column IDs were written into the org config by `createorg`. If mis
|
|
|
114
114
|
[ -z "$todo_col" ] && { echo "ERROR: org config missing todo_col_id — re-run /mastermind:createorg --name ${orgName}."; exit 1; }
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
**Create stop-file
|
|
117
|
+
**Create stop-file and state directories:**
|
|
118
118
|
```bash
|
|
119
119
|
mkdir -p .monomind/orgs/.stops
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
**Initialize org state file** (tracks per-agent status, heartbeat timestamps, token usage):
|
|
123
|
+
```bash
|
|
124
|
+
stateFile=".monomind/orgs/${orgName}-state.json"
|
|
125
|
+
if [ ! -f "$stateFile" ]; then
|
|
126
|
+
jq -n \
|
|
127
|
+
--arg org "$orgName" \
|
|
128
|
+
--arg runId "$runId" \
|
|
129
|
+
'{org:$org,run_id:$runId,started_at:(now|todate),agents:{}}' \
|
|
130
|
+
> "$stateFile"
|
|
131
|
+
else
|
|
132
|
+
# Update run_id and started_at for this run
|
|
133
|
+
tmp="${stateFile}.tmp"
|
|
134
|
+
jq --arg runId "$runId" \
|
|
135
|
+
'.run_id = $runId | .started_at = (now|todate)' \
|
|
136
|
+
"$stateFile" > "$tmp" && mv "$tmp" "$stateFile"
|
|
137
|
+
fi
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Remove any stale stop file:**
|
|
141
|
+
```bash
|
|
142
|
+
rm -f "$stopFile"
|
|
143
|
+
```
|
|
144
|
+
|
|
122
145
|
**Emit `org:start` to dashboard:**
|
|
123
146
|
```bash
|
|
124
|
-
|
|
147
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
148
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
149
|
+
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
125
150
|
-H "Content-Type: application/json" \
|
|
126
151
|
-d "$(jq -cn \
|
|
127
152
|
--arg session "$sessionId" \
|
|
@@ -158,7 +183,7 @@ SHARED INFRASTRUCTURE:
|
|
|
158
183
|
- Task board (monotask): board_id=${board_id}
|
|
159
184
|
Columns: Todo=${todo_col} Doing=${doing_col} Done=${done_col}
|
|
160
185
|
- Memory namespace: ${memNs} (use: npx monomind@latest memory store/search --namespace ${memNs})
|
|
161
|
-
- Dashboard events: POST
|
|
186
|
+
- Dashboard events: POST to mastermind control server via curl — see CTRL_URL resolution in DASHBOARD EVENTS section below
|
|
162
187
|
- Session ID for all events: ${sessionId}
|
|
163
188
|
|
|
164
189
|
TASK BOARD COMMANDS (use these for all task management):
|
|
@@ -191,6 +216,42 @@ TASK BOARD COMMANDS (use these for all task management):
|
|
|
191
216
|
# Complete a task:
|
|
192
217
|
monotask card move ${board_id} $CARD_ID ${done_col}
|
|
193
218
|
|
|
219
|
+
ORG STATE FILE (update per agent per cycle for dashboard visibility):
|
|
220
|
+
stateFile=".monomind/orgs/${orgName}-state.json"
|
|
221
|
+
# Mark agent as running:
|
|
222
|
+
jq --arg id "<role_id>" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
223
|
+
'.agents[$id].status = "running" | .agents[$id].last_heartbeat = $ts' \
|
|
224
|
+
"$stateFile" > "${stateFile}.tmp" && mv "${stateFile}.tmp" "$stateFile"
|
|
225
|
+
# Mark agent as idle after completing:
|
|
226
|
+
jq --arg id "<role_id>" \
|
|
227
|
+
'.agents[$id].status = "idle" | .agents[$id].last_heartbeat_complete = (now|todate)' \
|
|
228
|
+
"$stateFile" > "${stateFile}.tmp" && mv "${stateFile}.tmp" "$stateFile"
|
|
229
|
+
# Add token counts when known:
|
|
230
|
+
jq --arg id "<role_id>" --argjson in <tokens_in> --argjson out <tokens_out> \
|
|
231
|
+
'.agents[$id].tokens_in = ((.agents[$id].tokens_in // 0) + $in) | .agents[$id].tokens_out = ((.agents[$id].tokens_out // 0) + $out)' \
|
|
232
|
+
"$stateFile" > "${stateFile}.tmp" && mv "${stateFile}.tmp" "$stateFile"
|
|
233
|
+
|
|
234
|
+
APPROVAL GATE (when governance.policy is "board" or "strict"):
|
|
235
|
+
Before any external action (sending emails, posting content, making purchases, modifying infrastructure):
|
|
236
|
+
approvalsFile=".monomind/orgs/${orgName}-approvals.json"
|
|
237
|
+
[ ! -f "$approvalsFile" ] && echo '{"approvals":[]}' > "$approvalsFile"
|
|
238
|
+
approval_id="req-$(date +%s)"
|
|
239
|
+
jq --arg id "$approval_id" --arg agent "<role_id>" --arg title "<action summary>" \
|
|
240
|
+
--arg action "<full action description>" --arg risk "medium" \
|
|
241
|
+
'.approvals += [{"id":$id,"agent_id":$agent,"title":$title,"action":$action,"risk_level":$risk,"status":"pending","requested_at":(now|todate)}]' \
|
|
242
|
+
"$approvalsFile" > "${approvalsFile}.tmp" && mv "${approvalsFile}.tmp" "$approvalsFile"
|
|
243
|
+
# Emit approval request event so human sees it in dashboard
|
|
244
|
+
curl -s -X POST "${CTRL_URL}/api/mastermind/event" -H "Content-Type: application/json" \
|
|
245
|
+
-d "$(jq -cn --arg org "${orgName}" --arg id "$approval_id" --arg title "<title>" \
|
|
246
|
+
'{type:"org:approval:requested",org:$org,approval_id:$id,title:$title,ts:(now*1000|floor)}')" || true
|
|
247
|
+
# Poll until approved or rejected (max 30 min):
|
|
248
|
+
for i in $(seq 1 60); do
|
|
249
|
+
status=$(npx monomind@latest memory search --query "approval:${approval_id}" --namespace "${memNs}" 2>/dev/null | jq -r '.[0].value.status // ""' 2>/dev/null)
|
|
250
|
+
[ "$status" = "approved" ] && break
|
|
251
|
+
[ "$status" = "rejected" ] && { echo "Action rejected by governance policy — skip this action"; break; }
|
|
252
|
+
sleep 30
|
|
253
|
+
done
|
|
254
|
+
|
|
194
255
|
STOP DETECTION (check this FIRST in every loop iteration):
|
|
195
256
|
ls ${stopFile} 2>/dev/null && echo STOP_REQUESTED
|
|
196
257
|
If the file exists: emit org:complete event, clean up with "rm -f ${stopFile}", then exit.
|
|
@@ -218,7 +279,9 @@ ${orgConfig.roles.filter(r => r.id !== bossRole.id).map(r =>
|
|
|
218
279
|
).join('\n')}
|
|
219
280
|
|
|
220
281
|
DASHBOARD EVENTS — emit via curl (NOT WebFetch — WebFetch does not support POST):
|
|
221
|
-
|
|
282
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
283
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
284
|
+
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
222
285
|
-H "Content-Type: application/json" \
|
|
223
286
|
-d "$(jq -cn --arg type TYPE --arg session SESSION --arg org ORG '{type:$type,session:$session,org:$org,ts:(now*1000|floor)}')"
|
|
224
287
|
Payloads:
|
|
@@ -238,7 +301,9 @@ START NOW: check for stop signal, assess the board, create initial tasks if none
|
|
|
238
301
|
Emit `org:agent:online` for the boss role (team member events are emitted by the boss itself):
|
|
239
302
|
|
|
240
303
|
```bash
|
|
241
|
-
|
|
304
|
+
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
305
|
+
CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
|
|
306
|
+
curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
|
|
242
307
|
-H "Content-Type: application/json" \
|
|
243
308
|
-d "$(jq -cn \
|
|
244
309
|
--arg session "$sessionId" \
|
|
@@ -272,10 +337,10 @@ ACTIVE ROLES
|
|
|
272
337
|
|
|
273
338
|
BOARD: <orgName>/org-tasks
|
|
274
339
|
MEMORY: org:<orgName>
|
|
275
|
-
DASHBOARD: http://localhost:4242
|
|
340
|
+
DASHBOARD: see .monomind/control.json for URL (default http://localhost:4242)
|
|
276
341
|
|
|
277
342
|
To stop: click STOP in the dashboard Orgs panel
|
|
278
|
-
or run:
|
|
343
|
+
or run: CTRL_URL=$(jq -r '.url // "http://localhost:4242"' .monomind/control.json 2>/dev/null || echo "http://localhost:4242"); curl -X POST "${CTRL_URL}/api/orgs/<orgName>/stop"
|
|
279
344
|
```
|
|
280
345
|
|
|
281
346
|
---
|
|
@@ -295,8 +360,8 @@ lessons:
|
|
|
295
360
|
- what_worked: "Boss agent spawned and org loop started"
|
|
296
361
|
- what_didnt: ""
|
|
297
362
|
next_actions:
|
|
298
|
-
- "Monitor
|
|
299
|
-
- "To stop: click STOP in dashboard or
|
|
363
|
+
- "Monitor in Mastermind Orgs panel (CTRL_URL from .monomind/control.json, default http://localhost:4242)"
|
|
364
|
+
- "To stop: click STOP in dashboard or: CTRL_URL=$(jq -r '.url // \"http://localhost:4242\"' .monomind/control.json); curl -X POST \"${CTRL_URL}/api/orgs/<orgName>/stop\""
|
|
300
365
|
board_url: "monotask://<orgName>/org-tasks"
|
|
301
366
|
run_id: "<runId>"
|
|
302
367
|
```
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-search
|
|
3
|
+
description: Mastermind search — fuzzy cross-org search across tasks, goals, agents, approvals, routines, projects, and activity log. Returns ranked results with org context.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: auto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Search
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:search` or directly via `/mastermind:search`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
|
|
17
|
+
- `query`: search term (required)
|
|
18
|
+
- `org_name`: filter to a specific org (optional — searches all orgs if omitted)
|
|
19
|
+
- `scope`: all | tasks | goals | agents | approvals | routines | projects | activity (default: all)
|
|
20
|
+
- `limit`: max results per category (default: 10)
|
|
21
|
+
- `caller`: command | master
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Step 0 — Brain Load (standalone only)
|
|
26
|
+
|
|
27
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Step 1 — Resolve Orgs
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
if [ -n "$org_name" ]; then
|
|
35
|
+
orgs="$org_name"
|
|
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)
|
|
38
|
+
fi
|
|
39
|
+
[ -z "$orgs" ] && { echo "No orgs found. Run /mastermind:createorg first."; exit 0; }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Step 2 — Search All Scopes
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
query_lower=$(echo "$query" | tr '[:upper:]' '[:lower:]')
|
|
48
|
+
limit="${limit:-10}"
|
|
49
|
+
total_hits=0
|
|
50
|
+
|
|
51
|
+
echo "SEARCH: \"${query}\""
|
|
52
|
+
echo "════════════════════════════════════════════════"
|
|
53
|
+
echo ""
|
|
54
|
+
|
|
55
|
+
for org in $orgs; do
|
|
56
|
+
orgFile=".monomind/orgs/${org}.json"
|
|
57
|
+
[ ! -f "$orgFile" ] && continue
|
|
58
|
+
|
|
59
|
+
org_hits=0
|
|
60
|
+
|
|
61
|
+
# ── Agents ────────────────────────────────────────
|
|
62
|
+
if [ "$scope" = "all" ] || [ "$scope" = "agents" ]; then
|
|
63
|
+
hits=$(jq -r --arg q "$query_lower" \
|
|
64
|
+
'.roles[] | select((.id + " " + .title + " " + (.responsibilities // [] | join(" "))) | ascii_downcase | test($q)) |
|
|
65
|
+
"[AGENT] \(.id): \(.title) type=\(.agent_type)"' \
|
|
66
|
+
"$orgFile" 2>/dev/null | head -"$limit")
|
|
67
|
+
if [ -n "$hits" ]; then
|
|
68
|
+
echo "── $org / agents ──"
|
|
69
|
+
echo "$hits"
|
|
70
|
+
echo ""
|
|
71
|
+
org_hits=$((org_hits + $(echo "$hits" | wc -l)))
|
|
72
|
+
fi
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
# ── Goals ─────────────────────────────────────────
|
|
76
|
+
goalsFile=".monomind/orgs/${org}-goals.json"
|
|
77
|
+
if [ -f "$goalsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "goals" ]; }; then
|
|
78
|
+
hits=$(jq -r --arg q "$query_lower" \
|
|
79
|
+
'.goals[] | select((.title + " " + (.description // "") + " " + (.status // "")) | ascii_downcase | test($q)) |
|
|
80
|
+
"[GOAL] [\(.id)] \(.title) status=\(.status // "open")"' \
|
|
81
|
+
"$goalsFile" 2>/dev/null | head -"$limit")
|
|
82
|
+
if [ -n "$hits" ]; then
|
|
83
|
+
echo "── $org / goals ──"
|
|
84
|
+
echo "$hits"
|
|
85
|
+
echo ""
|
|
86
|
+
org_hits=$((org_hits + $(echo "$hits" | wc -l)))
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# ── Routines ──────────────────────────────────────
|
|
91
|
+
routinesFile=".monomind/orgs/${org}-routines.json"
|
|
92
|
+
if [ -f "$routinesFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "routines" ]; }; then
|
|
93
|
+
hits=$(jq -r --arg q "$query_lower" \
|
|
94
|
+
'.routines[] | select((.name + " " + (.description // "") + " " + (.schedule // "")) | ascii_downcase | test($q)) |
|
|
95
|
+
"[ROUTINE] \(.name) schedule=\(.schedule // "-")"' \
|
|
96
|
+
"$routinesFile" 2>/dev/null | head -"$limit")
|
|
97
|
+
if [ -n "$hits" ]; then
|
|
98
|
+
echo "── $org / routines ──"
|
|
99
|
+
echo "$hits"
|
|
100
|
+
echo ""
|
|
101
|
+
org_hits=$((org_hits + $(echo "$hits" | wc -l)))
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
# ── Approvals ─────────────────────────────────────
|
|
106
|
+
approvalsFile=".monomind/orgs/${org}-approvals.json"
|
|
107
|
+
if [ -f "$approvalsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "approvals" ]; }; then
|
|
108
|
+
hits=$(jq -r --arg q "$query_lower" \
|
|
109
|
+
'.approvals[] | select((.title + " " + (.action // "") + " " + (.agent_id // "")) | ascii_downcase | test($q)) |
|
|
110
|
+
"[APPROVAL] [\(.id)] \(.agent_id): \(.title) status=\(.status)"' \
|
|
111
|
+
"$approvalsFile" 2>/dev/null | head -"$limit")
|
|
112
|
+
if [ -n "$hits" ]; then
|
|
113
|
+
echo "── $org / approvals ──"
|
|
114
|
+
echo "$hits"
|
|
115
|
+
echo ""
|
|
116
|
+
org_hits=$((org_hits + $(echo "$hits" | wc -l)))
|
|
117
|
+
fi
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# ── Projects ──────────────────────────────────────
|
|
121
|
+
projectsFile=".monomind/orgs/${org}-projects.json"
|
|
122
|
+
if [ -f "$projectsFile" ] && { [ "$scope" = "all" ] || [ "$scope" = "projects" ]; }; then
|
|
123
|
+
hits=$(jq -r --arg q "$query_lower" \
|
|
124
|
+
'.projects[] | select((.name + " " + (.description // "") + " " + (.lead // "")) | ascii_downcase | test($q)) |
|
|
125
|
+
"[PROJECT] \(.name) status=\(.status // "active") lead=\(.lead // "-")"' \
|
|
126
|
+
"$projectsFile" 2>/dev/null | head -"$limit")
|
|
127
|
+
if [ -n "$hits" ]; then
|
|
128
|
+
echo "── $org / projects ──"
|
|
129
|
+
echo "$hits"
|
|
130
|
+
echo ""
|
|
131
|
+
org_hits=$((org_hits + $(echo "$hits" | wc -l)))
|
|
132
|
+
fi
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
# ── Activity log ──────────────────────────────────
|
|
136
|
+
if [ "$scope" = "all" ] || [ "$scope" = "activity" ]; then
|
|
137
|
+
eventsFile="data/mastermind-events.jsonl"
|
|
138
|
+
if [ -f "$eventsFile" ]; then
|
|
139
|
+
hits=$(grep "\"org\":\"$org\"" "$eventsFile" 2>/dev/null | \
|
|
140
|
+
jq -r --arg q "$query_lower" \
|
|
141
|
+
'select((tostring | ascii_downcase | test($q))) |
|
|
142
|
+
"[EVENT] \(.type) org=\(.org) \(if .task then "task=\(.task)" elif .role then "role=\(.role)" else "" end)"' \
|
|
143
|
+
2>/dev/null | tail -"$limit")
|
|
144
|
+
if [ -n "$hits" ]; then
|
|
145
|
+
echo "── $org / activity ──"
|
|
146
|
+
echo "$hits"
|
|
147
|
+
echo ""
|
|
148
|
+
org_hits=$((org_hits + $(echo "$hits" | wc -l)))
|
|
149
|
+
fi
|
|
150
|
+
fi
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
total_hits=$((total_hits + org_hits))
|
|
154
|
+
done
|
|
155
|
+
|
|
156
|
+
if [ "$total_hits" -eq 0 ]; then
|
|
157
|
+
echo " No results found for \"${query}\""
|
|
158
|
+
echo ""
|
|
159
|
+
echo " Tips:"
|
|
160
|
+
echo " • Try a shorter or more general query"
|
|
161
|
+
echo " • Use --scope to narrow: tasks, goals, agents, approvals, routines, projects, activity"
|
|
162
|
+
echo " • Use --org to limit to a specific org"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
echo "════════════════════════════════════════════════"
|
|
166
|
+
echo "Found: ${total_hits} result(s)"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Step 3 — Return Output
|
|
172
|
+
|
|
173
|
+
```yaml
|
|
174
|
+
domain: ops
|
|
175
|
+
status: complete
|
|
176
|
+
query: <query>
|
|
177
|
+
scope: <scope>
|
|
178
|
+
orgs_searched: <N>
|
|
179
|
+
total_hits: <N>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## Step 4 — Brain Write (standalone only)
|
|
185
|
+
|
|
186
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|