@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,281 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-import
|
|
3
|
+
description: Mastermind import — import an org from a portable ZIP archive exported by mastermind:export. Previews the archive contents, shows agent plans (create/update/skip), lets you choose a collision strategy, and applies the import to the local .monomind/orgs/ directory. Mirrors CompanyImport.tsx.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: confirm
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Import
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:import` or directly via `/mastermind:import`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
|
|
17
|
+
- `action`: preview | apply | list-archive
|
|
18
|
+
- `archive_path`: absolute or relative path to the ZIP archive file (required)
|
|
19
|
+
- `org_name`: override org name from archive (default: use name in archive)
|
|
20
|
+
- `collision`: skip | merge | overwrite (what to do if org already exists; default: skip)
|
|
21
|
+
- `adapter_override`: optional; adapter type to replace all agents' adapters (e.g. `claude-local`)
|
|
22
|
+
- `caller`: command | master
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Collision Strategy Reference
|
|
27
|
+
|
|
28
|
+
| Strategy | Behavior |
|
|
29
|
+
|----------|----------|
|
|
30
|
+
| `skip` | If org already exists, abort. Safe default. |
|
|
31
|
+
| `merge` | Merge: add agents/goals/etc from archive, skip duplicates by id. |
|
|
32
|
+
| `overwrite` | Delete existing org files and replace with archive contents. |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Step 0 — Brain Load (standalone only)
|
|
37
|
+
|
|
38
|
+
If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Step 1 — Validate Archive
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
[ -z "$archive_path" ] && { echo "ERROR: --archive-path required (path to the exported .zip file)."; exit 1; }
|
|
46
|
+
[ ! -f "$archive_path" ] && { echo "ERROR: Archive not found: $archive_path"; exit 1; }
|
|
47
|
+
|
|
48
|
+
# Detect format
|
|
49
|
+
case "$archive_path" in
|
|
50
|
+
*.zip) fmt="zip" ;;
|
|
51
|
+
*.tar.gz|*.tgz) fmt="tgz" ;;
|
|
52
|
+
*.json) fmt="json" ;;
|
|
53
|
+
*) echo "ERROR: Unsupported archive format. Expected .zip, .tar.gz, or .json"; exit 1 ;;
|
|
54
|
+
esac
|
|
55
|
+
|
|
56
|
+
echo "Archive: $archive_path (format: $fmt)"
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Step 2 — Execute Action
|
|
62
|
+
|
|
63
|
+
### list-archive
|
|
64
|
+
|
|
65
|
+
List files in the archive without extracting:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
if [ "$fmt" = "zip" ]; then
|
|
69
|
+
unzip -l "$archive_path" 2>/dev/null | grep -v "^Archive\|^--\|files$" | awk '{print $NF}' | grep -v "^$"
|
|
70
|
+
elif [ "$fmt" = "tgz" ]; then
|
|
71
|
+
tar -tzf "$archive_path"
|
|
72
|
+
elif [ "$fmt" = "json" ]; then
|
|
73
|
+
echo "(JSON format — single file, no archive listing needed)"
|
|
74
|
+
fi
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### preview
|
|
78
|
+
|
|
79
|
+
Extract and preview the org configuration without writing:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
tmpDir=$(mktemp -d /tmp/mastermind-import-XXXXXX)
|
|
83
|
+
trap 'rm -rf "$tmpDir"' EXIT
|
|
84
|
+
|
|
85
|
+
if [ "$fmt" = "zip" ]; then
|
|
86
|
+
unzip -q "$archive_path" -d "$tmpDir" 2>/dev/null
|
|
87
|
+
elif [ "$fmt" = "tgz" ]; then
|
|
88
|
+
tar -xzf "$archive_path" -C "$tmpDir" 2>/dev/null
|
|
89
|
+
elif [ "$fmt" = "json" ]; then
|
|
90
|
+
cp "$archive_path" "$tmpDir/org.json"
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# Find the main org config file
|
|
94
|
+
orgConfigFile=$(find "$tmpDir" -name "*.json" | grep -v '\-' | head -1)
|
|
95
|
+
[ -z "$orgConfigFile" ] && orgConfigFile=$(find "$tmpDir" -name "org.json" -o -name "export.json" | head -1)
|
|
96
|
+
|
|
97
|
+
if [ -z "$orgConfigFile" ]; then
|
|
98
|
+
echo "ERROR: Could not find org config file in archive."
|
|
99
|
+
exit 1
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
importedOrgName="${org_name:-$(jq -r '.name // "unknown"' "$orgConfigFile")}"
|
|
103
|
+
agentCount=$(jq '(.roles // []) | length' "$orgConfigFile")
|
|
104
|
+
createdAt=$(jq -r '.created_at // "-"' "$orgConfigFile")
|
|
105
|
+
gov=$(jq -r '.governance // "-"' "$orgConfigFile")
|
|
106
|
+
|
|
107
|
+
echo "IMPORT PREVIEW"
|
|
108
|
+
echo "────────────────────────────────────────────────────────"
|
|
109
|
+
echo " Archive: $archive_path"
|
|
110
|
+
echo " Org name: $importedOrgName"
|
|
111
|
+
echo " Agents: $agentCount"
|
|
112
|
+
echo " Governance: $gov"
|
|
113
|
+
echo " Created: $createdAt"
|
|
114
|
+
echo ""
|
|
115
|
+
|
|
116
|
+
# Check if org already exists
|
|
117
|
+
targetOrgFile=".monomind/orgs/${importedOrgName}.json"
|
|
118
|
+
if [ -f "$targetOrgFile" ]; then
|
|
119
|
+
existingAgents=$(jq '(.roles // []) | length' "$targetOrgFile")
|
|
120
|
+
echo " WARNING: Org '${importedOrgName}' already exists ($existingAgents agents)."
|
|
121
|
+
echo " Collision strategy: ${collision:-skip}"
|
|
122
|
+
echo ""
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# Preview agent plans
|
|
126
|
+
echo "AGENT PLANS"
|
|
127
|
+
echo "────────────────────────────────────────────────────────"
|
|
128
|
+
jq -r --arg target "$targetOrgFile" '.roles[] |
|
|
129
|
+
[.id, (.title // "-"), (.adapter.type // "?"), (.adapter.model // "-")] | @tsv' \
|
|
130
|
+
"$orgConfigFile" | while IFS=$'\t' read -r id title adapter model; do
|
|
131
|
+
if [ -f "$targetOrgFile" ]; then
|
|
132
|
+
exists=$(jq -r --arg id "$id" '[.roles[] | select(.id == $id)] | length' "$targetOrgFile")
|
|
133
|
+
action=$([ "$exists" -gt 0 ] && echo "UPDATE" || echo "CREATE")
|
|
134
|
+
else
|
|
135
|
+
action="CREATE"
|
|
136
|
+
fi
|
|
137
|
+
printf " %-8s %-24s %-20s %-16s %s\n" "$action" "$id" "$title" "$adapter" "$model"
|
|
138
|
+
done
|
|
139
|
+
|
|
140
|
+
echo ""
|
|
141
|
+
echo " To apply: --action apply --archive-path $archive_path --collision ${collision:-skip}"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### apply
|
|
145
|
+
|
|
146
|
+
Apply the import (write org files):
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
tmpDir=$(mktemp -d /tmp/mastermind-import-XXXXXX)
|
|
150
|
+
trap 'rm -rf "$tmpDir"' EXIT
|
|
151
|
+
|
|
152
|
+
if [ "$fmt" = "zip" ]; then
|
|
153
|
+
unzip -q "$archive_path" -d "$tmpDir" 2>/dev/null
|
|
154
|
+
elif [ "$fmt" = "tgz" ]; then
|
|
155
|
+
tar -xzf "$archive_path" -C "$tmpDir" 2>/dev/null
|
|
156
|
+
elif [ "$fmt" = "json" ]; then
|
|
157
|
+
cp "$archive_path" "$tmpDir/org.json"
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
orgConfigFile=$(find "$tmpDir" -name "*.json" | grep -v '\-' | head -1)
|
|
161
|
+
[ -z "$orgConfigFile" ] && orgConfigFile=$(find "$tmpDir" -name "org.json" -o -name "export.json" | head -1)
|
|
162
|
+
[ -z "$orgConfigFile" ] && { echo "ERROR: Could not find org config file in archive."; exit 1; }
|
|
163
|
+
|
|
164
|
+
importedOrgName="${org_name:-$(jq -r '.name // "unnamed"' "$orgConfigFile")}"
|
|
165
|
+
targetOrgFile=".monomind/orgs/${importedOrgName}.json"
|
|
166
|
+
|
|
167
|
+
mkdir -p ".monomind/orgs"
|
|
168
|
+
|
|
169
|
+
# Handle collision
|
|
170
|
+
if [ -f "$targetOrgFile" ]; then
|
|
171
|
+
collisionStrategy="${collision:-skip}"
|
|
172
|
+
case "$collisionStrategy" in
|
|
173
|
+
skip)
|
|
174
|
+
echo "ERROR: Org '${importedOrgName}' already exists. Use --collision merge or --collision overwrite to proceed."
|
|
175
|
+
exit 1
|
|
176
|
+
;;
|
|
177
|
+
overwrite)
|
|
178
|
+
echo " Overwriting existing org '${importedOrgName}'..."
|
|
179
|
+
rm -f ".monomind/orgs/${importedOrgName}"*.json ".monomind/orgs/${importedOrgName}"*.jsonl
|
|
180
|
+
;;
|
|
181
|
+
merge)
|
|
182
|
+
echo " Merging into existing org '${importedOrgName}'..."
|
|
183
|
+
# Merge will be handled per-file below
|
|
184
|
+
;;
|
|
185
|
+
esac
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
189
|
+
|
|
190
|
+
# Apply adapter override if specified
|
|
191
|
+
if [ -n "$adapter_override" ]; then
|
|
192
|
+
tmp="${orgConfigFile}.ovr"
|
|
193
|
+
jq --arg a "$adapter_override" \
|
|
194
|
+
'.roles = [.roles[] | .adapter.type = $a]' \
|
|
195
|
+
"$orgConfigFile" > "$tmp" && mv "$tmp" "$orgConfigFile"
|
|
196
|
+
echo " Applied adapter override: $adapter_override to all agents"
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# Copy main config (or merge if merge strategy)
|
|
200
|
+
if [ -f "$targetOrgFile" ] && [ "${collision:-skip}" = "merge" ]; then
|
|
201
|
+
tmp="$targetOrgFile.tmp"
|
|
202
|
+
python3 - "$targetOrgFile" "$orgConfigFile" > "$tmp" << 'PYEOF'
|
|
203
|
+
import json, sys
|
|
204
|
+
existing = json.load(open(sys.argv[1]))
|
|
205
|
+
incoming = json.load(open(sys.argv[2]))
|
|
206
|
+
existing_ids = {r['id'] for r in existing.get('roles', [])}
|
|
207
|
+
new_roles = [r for r in incoming.get('roles', []) if r['id'] not in existing_ids]
|
|
208
|
+
existing['roles'] = existing.get('roles', []) + new_roles
|
|
209
|
+
print(json.dumps(existing, indent=2))
|
|
210
|
+
PYEOF
|
|
211
|
+
mv "$tmp" "$targetOrgFile"
|
|
212
|
+
mergedCount=$(python3 -c "import json; d=json.load(open('$targetOrgFile')); print(len(d.get('roles',[])))")
|
|
213
|
+
echo " Merged: $mergedCount total agents"
|
|
214
|
+
else
|
|
215
|
+
cp "$orgConfigFile" "$targetOrgFile"
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# Copy associated files (goals, routines, issues, etc.) from archive
|
|
219
|
+
for suffix in members issues goals projects routines approvals adapters plugins environments workspaces activity threads budgets; do
|
|
220
|
+
src=$(find "$tmpDir" -name "*-${suffix}.json" | head -1)
|
|
221
|
+
[ -z "$src" ] && src=$(find "$tmpDir" -name "*-${suffix}.jsonl" | head -1)
|
|
222
|
+
if [ -n "$src" ]; then
|
|
223
|
+
ext="${src##*.}"
|
|
224
|
+
dest=".monomind/orgs/${importedOrgName}-${suffix}.${ext}"
|
|
225
|
+
if [ -f "$dest" ] && [ "${collision:-skip}" = "merge" ]; then
|
|
226
|
+
# Merge arrays
|
|
227
|
+
python3 - "$dest" "$src" "$suffix" > "${dest}.tmp" << 'PYEOF'
|
|
228
|
+
import json, sys, os
|
|
229
|
+
dest_path, src_path, suffix = sys.argv[1], sys.argv[2], sys.argv[3]
|
|
230
|
+
try:
|
|
231
|
+
dest_data = json.load(open(dest_path))
|
|
232
|
+
src_data = json.load(open(src_path))
|
|
233
|
+
arr_key = suffix if suffix in dest_data else list(dest_data.keys())[0] if dest_data else suffix
|
|
234
|
+
existing_ids = {item.get('id') for item in dest_data.get(arr_key, []) if 'id' in item}
|
|
235
|
+
new_items = [item for item in src_data.get(arr_key, []) if item.get('id') not in existing_ids]
|
|
236
|
+
dest_data[arr_key] = dest_data.get(arr_key, []) + new_items
|
|
237
|
+
print(json.dumps(dest_data, indent=2))
|
|
238
|
+
except Exception as e:
|
|
239
|
+
print(json.dumps(json.load(open(dest_path))), file=__import__('sys').stdout)
|
|
240
|
+
PYEOF
|
|
241
|
+
mv "${dest}.tmp" "$dest"
|
|
242
|
+
else
|
|
243
|
+
cp "$src" "$dest"
|
|
244
|
+
fi
|
|
245
|
+
echo " Imported: ${importedOrgName}-${suffix}.${ext}"
|
|
246
|
+
fi
|
|
247
|
+
done
|
|
248
|
+
|
|
249
|
+
agentCount=$(jq '(.roles // []) | length' "$targetOrgFile")
|
|
250
|
+
|
|
251
|
+
echo ""
|
|
252
|
+
echo "IMPORT COMPLETE"
|
|
253
|
+
echo "────────────────────────────────────────────────────────"
|
|
254
|
+
echo " Org: $importedOrgName"
|
|
255
|
+
echo " Agents: $agentCount"
|
|
256
|
+
echo " Location: $targetOrgFile"
|
|
257
|
+
echo " Collision: ${collision:-skip}"
|
|
258
|
+
echo " Applied at: $ts"
|
|
259
|
+
echo ""
|
|
260
|
+
echo " Run org: /mastermind:runorg --org $importedOrgName"
|
|
261
|
+
echo " View chart: /mastermind:org-chart --org $importedOrgName"
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Step 3 — Return Output
|
|
267
|
+
|
|
268
|
+
```yaml
|
|
269
|
+
domain: ops
|
|
270
|
+
status: complete
|
|
271
|
+
action: <action>
|
|
272
|
+
org_name: <importedOrgName>
|
|
273
|
+
agent_count: <N>
|
|
274
|
+
collision: <strategy>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Step 4 — Brain Write (standalone only)
|
|
280
|
+
|
|
281
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mastermind-inbox
|
|
3
|
+
description: Mastermind inbox — unified view of everything that needs human attention across all orgs: pending approvals, running heartbeats, active task assignments, and budget alerts. The single place to check before starting work.
|
|
4
|
+
type: domain-skill
|
|
5
|
+
default_mode: auto
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mastermind Inbox
|
|
9
|
+
|
|
10
|
+
This skill is invoked by `mastermind:inbox` or directly via `/mastermind:inbox`.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Inputs
|
|
15
|
+
|
|
16
|
+
- `brain_context`: BRAIN CONTEXT block
|
|
17
|
+
- `org_name`: optional — filter to a single org (default: all orgs)
|
|
18
|
+
- `filter`: all | approvals | heartbeats | tasks | alerts (default: all)
|
|
19
|
+
- `action`: read | mark-done | archive
|
|
20
|
+
- `item_id`: id of item to action
|
|
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 — Collect All 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
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Step 2 — Gather Inbox Items
|
|
44
|
+
|
|
45
|
+
For each org, collect:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
total_approvals=0
|
|
49
|
+
total_heartbeats=0
|
|
50
|
+
total_alerts=0
|
|
51
|
+
|
|
52
|
+
for org in $orgs; do
|
|
53
|
+
orgFile=".monomind/orgs/${org}.json"
|
|
54
|
+
stateFile=".monomind/orgs/${org}-state.json"
|
|
55
|
+
approvalsFile=".monomind/orgs/${org}-approvals.json"
|
|
56
|
+
|
|
57
|
+
# 1. Pending approvals
|
|
58
|
+
if [ -f "$approvalsFile" ]; then
|
|
59
|
+
pending=$(jq '[.approvals[] | select(.status == "pending")] | length' "$approvalsFile" 2>/dev/null || echo 0)
|
|
60
|
+
total_approvals=$((total_approvals + pending))
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# 2. Running agents (active heartbeats)
|
|
64
|
+
if [ -f "$stateFile" ]; then
|
|
65
|
+
running=$(jq '[.agents // {} | to_entries[] | select(.value.status == "running")] | length' "$stateFile" 2>/dev/null || echo 0)
|
|
66
|
+
total_heartbeats=$((total_heartbeats + running))
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# 3. Budget alerts
|
|
70
|
+
budget=$(jq -r '.run_config.budget_tokens // 0' "$orgFile" 2>/dev/null || echo 0)
|
|
71
|
+
threshold=$(jq -r '.run_config.alert_threshold // 0.8' "$orgFile" 2>/dev/null || echo 0.8)
|
|
72
|
+
if [ "$budget" -gt 0 ] && [ -f "$stateFile" ]; then
|
|
73
|
+
total_in=$(jq '[.agents // {} | to_entries[] | .value.tokens_in // 0] | add // 0' "$stateFile" 2>/dev/null || echo 0)
|
|
74
|
+
total_out=$(jq '[.agents // {} | to_entries[] | .value.tokens_out // 0] | add // 0' "$stateFile" 2>/dev/null || echo 0)
|
|
75
|
+
total_tok=$((total_in + total_out))
|
|
76
|
+
over=$(awk -v t="$total_tok" -v b="$budget" -v thr="$threshold" \
|
|
77
|
+
'BEGIN { print (b>0 && t/b >= thr) ? "yes" : "no" }')
|
|
78
|
+
[ "$over" = "yes" ] && total_alerts=$((total_alerts + 1))
|
|
79
|
+
fi
|
|
80
|
+
done
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Step 3 — Render Inbox
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
echo "╔══════════════════════════════════════════════════════╗"
|
|
89
|
+
echo "║ MASTERMIND INBOX ║"
|
|
90
|
+
echo "╚══════════════════════════════════════════════════════╝"
|
|
91
|
+
echo ""
|
|
92
|
+
echo " 🔴 APPROVALS NEEDED: $total_approvals"
|
|
93
|
+
echo " 🟡 AGENTS RUNNING: $total_heartbeats"
|
|
94
|
+
echo " 🟠 BUDGET ALERTS: $total_alerts"
|
|
95
|
+
echo ""
|
|
96
|
+
|
|
97
|
+
for org in $orgs; do
|
|
98
|
+
orgFile=".monomind/orgs/${org}.json"
|
|
99
|
+
stateFile=".monomind/orgs/${org}-state.json"
|
|
100
|
+
approvalsFile=".monomind/orgs/${org}-approvals.json"
|
|
101
|
+
|
|
102
|
+
has_items=0
|
|
103
|
+
|
|
104
|
+
# Pending approvals
|
|
105
|
+
if [ -f "$approvalsFile" ]; then
|
|
106
|
+
pending_approvals=$(jq -r '.approvals[] | select(.status == "pending") | " [APPROVAL] [\(.id)] \(.agent_id): \(.title) risk=\(.risk_level // "low")"' \
|
|
107
|
+
"$approvalsFile" 2>/dev/null)
|
|
108
|
+
[ -n "$pending_approvals" ] && { has_items=1; echo "ORG: $org"; echo "$pending_approvals"; }
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# Running agents
|
|
112
|
+
if [ -f "$stateFile" ]; then
|
|
113
|
+
running_agents=$(jq -r '
|
|
114
|
+
.agents // {} | to_entries[] | select(.value.status == "running") |
|
|
115
|
+
" [RUNNING] [\(.key)] since=\(.value.last_heartbeat // "unknown")"
|
|
116
|
+
' "$stateFile" 2>/dev/null)
|
|
117
|
+
[ -n "$running_agents" ] && { has_items=1; [ $has_items -eq 1 ] || echo "ORG: $org"; echo "$running_agents"; }
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
[ $has_items -eq 1 ] && echo ""
|
|
121
|
+
done
|
|
122
|
+
|
|
123
|
+
if [ "$total_approvals" -eq 0 ] && [ "$total_heartbeats" -eq 0 ] && [ "$total_alerts" -eq 0 ]; then
|
|
124
|
+
echo " ✓ Inbox is clear. No items need attention."
|
|
125
|
+
fi
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### filter: approvals only
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
for org in $orgs; do
|
|
132
|
+
approvalsFile=".monomind/orgs/${org}-approvals.json"
|
|
133
|
+
[ -f "$approvalsFile" ] || continue
|
|
134
|
+
echo "=== $org ==="
|
|
135
|
+
jq -r '.approvals[] | select(.status == "pending") |
|
|
136
|
+
"[\(.id)] \(.agent_id): \(.title)\n Action: \(.action)\n Risk: \(.risk_level // "low")\n → /mastermind:approve --org '"$org"' --action approve --approval-id \(.id)"
|
|
137
|
+
' "$approvalsFile" 2>/dev/null || echo " No pending approvals."
|
|
138
|
+
echo ""
|
|
139
|
+
done
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### filter: heartbeats only
|
|
143
|
+
|
|
144
|
+
Show currently running agent heartbeats across all orgs:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
for org in $orgs; do
|
|
148
|
+
stateFile=".monomind/orgs/${org}-state.json"
|
|
149
|
+
[ -f "$stateFile" ] || continue
|
|
150
|
+
running=$(jq -r '
|
|
151
|
+
.agents // {} | to_entries[] | select(.value.status == "running") |
|
|
152
|
+
" [\(.key)] since=\(.value.last_heartbeat // "?")"
|
|
153
|
+
' "$stateFile" 2>/dev/null)
|
|
154
|
+
[ -n "$running" ] && { echo "=== $org ==="; echo "$running"; echo ""; }
|
|
155
|
+
done
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### filter: alerts only
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
echo "BUDGET ALERTS:"
|
|
162
|
+
for org in $orgs; do
|
|
163
|
+
orgFile=".monomind/orgs/${org}.json"
|
|
164
|
+
stateFile=".monomind/orgs/${org}-state.json"
|
|
165
|
+
budget=$(jq -r '.run_config.budget_tokens // 0' "$orgFile" 2>/dev/null || echo 0)
|
|
166
|
+
[ "$budget" -le 0 ] && continue
|
|
167
|
+
[ -f "$stateFile" ] || continue
|
|
168
|
+
total_in=$(jq '[.agents // {} | to_entries[] | .value.tokens_in // 0] | add // 0' "$stateFile" 2>/dev/null || echo 0)
|
|
169
|
+
total_out=$(jq '[.agents // {} | to_entries[] | .value.tokens_out // 0] | add // 0' "$stateFile" 2>/dev/null || echo 0)
|
|
170
|
+
total_tok=$((total_in + total_out))
|
|
171
|
+
pct=$(awk -v t="$total_tok" -v b="$budget" 'BEGIN{printf "%.1f", t/b*100}')
|
|
172
|
+
echo " $org: ${pct}% of $budget token budget used"
|
|
173
|
+
done
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Quick Action Shortcuts
|
|
179
|
+
|
|
180
|
+
From the inbox, the user can directly:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Approve a pending request:
|
|
184
|
+
/mastermind:approve --org <org> --action approve --approval-id <id>
|
|
185
|
+
|
|
186
|
+
# Stop a running agent:
|
|
187
|
+
/mastermind:agents --org <org> --action pause --agent-id <id>
|
|
188
|
+
|
|
189
|
+
# Check costs:
|
|
190
|
+
/mastermind:costs --org <org> --action report
|
|
191
|
+
|
|
192
|
+
# Set budget:
|
|
193
|
+
/mastermind:costs --org <org> --action set-budget --budget-tokens 500000
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Step 4 — Return Output
|
|
199
|
+
|
|
200
|
+
```yaml
|
|
201
|
+
domain: ops
|
|
202
|
+
status: complete
|
|
203
|
+
filter: <filter>
|
|
204
|
+
orgs_checked: <N>
|
|
205
|
+
pending_approvals: <N>
|
|
206
|
+
running_heartbeats: <N>
|
|
207
|
+
budget_alerts: <N>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Step 5 — Brain Write (standalone only)
|
|
213
|
+
|
|
214
|
+
If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
|