@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.
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 +1 -1
  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,237 @@
1
+ ---
2
+ name: mastermind-budgets
3
+ description: Mastermind budgets — view, set, and track token/cost budgets for agents and the entire org. Shows current spend vs. limits, alerts on overages, and lets board members adjust per-agent or org-wide budgets. Reads from -budgets.json org state files.
4
+ type: domain-skill
5
+ default_mode: auto
6
+ ---
7
+
8
+ # Mastermind Budgets
9
+
10
+ This skill is invoked by `mastermind:budgets` or directly via `/mastermind:budgets`.
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 manage budgets for (required)
18
+ - `action`: show | set | reset | alert
19
+ - `agent_id`: scope to a specific agent (optional — omit for org-wide)
20
+ - `limit_tokens`: token limit to set (for set)
21
+ - `limit_usd`: USD cost limit to set (for set)
22
+ - `caller`: command | master
23
+
24
+ ---
25
+
26
+ ## Step 0 — Brain Load (standalone only)
27
+
28
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
29
+
30
+ ---
31
+
32
+ ## Step 1 — Load Org and Budget File
33
+
34
+ ```bash
35
+ orgFile=".monomind/orgs/${org_name}.json"
36
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
37
+
38
+ budgetsFile=".monomind/orgs/${org_name}-budgets.json"
39
+ stateFile=".monomind/orgs/${org_name}-state.json"
40
+
41
+ if [ ! -f "$budgetsFile" ]; then
42
+ echo '{"org_budget":{},"agent_budgets":{},"period":"monthly","currency":"USD"}' > "$budgetsFile"
43
+ fi
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Step 2 — Execute Action
49
+
50
+ ### show (default)
51
+
52
+ ```bash
53
+ echo "BUDGETS — $org_name"
54
+ echo "════════════════════════════════════════════════════════"
55
+
56
+ python3 - "$orgFile" "$budgetsFile" "$stateFile" "${agent_id:-}" <<'PYEOF'
57
+ import json, sys, os
58
+
59
+ orgData = json.load(open(sys.argv[1]))
60
+ budgetData = json.load(open(sys.argv[2]))
61
+ statePath = sys.argv[3]
62
+ agentFilter= sys.argv[4]
63
+
64
+ # Load heartbeat state for per-agent token usage
65
+ agentTokens = {}
66
+ if os.path.exists(statePath):
67
+ try:
68
+ state = json.load(open(statePath))
69
+ for r in state.get("roles", []):
70
+ rid = r.get("id","")
71
+ agentTokens[rid] = {
72
+ "tokensIn": r.get("tokens_in", 0),
73
+ "tokensOut": r.get("tokens_out", 0),
74
+ "totalCostUsd": r.get("total_cost_usd", 0.0),
75
+ }
76
+ except: pass
77
+
78
+ orgBudget = budgetData.get("org_budget", {})
79
+ agentBudgets= budgetData.get("agent_budgets", {})
80
+ period = budgetData.get("period", "monthly")
81
+
82
+ print(f" Period: {period}")
83
+ print()
84
+
85
+ # Org-wide budget
86
+ orgLimitTokens = orgBudget.get("limit_tokens")
87
+ orgLimitUsd = orgBudget.get("limit_usd")
88
+ orgSpentTokens = sum(v.get("tokensIn",0) + v.get("tokensOut",0) for v in agentTokens.values())
89
+ orgSpentUsd = sum(v.get("totalCostUsd",0) for v in agentTokens.values())
90
+
91
+ print("ORG BUDGET")
92
+ print("────────────────────────────────────────────────────────")
93
+ print(f" Tokens spent: {orgSpentTokens:>12,}")
94
+ if orgLimitTokens:
95
+ pct = orgSpentTokens / orgLimitTokens * 100
96
+ bar = "█" * int(pct / 5) + "░" * (20 - int(pct / 5))
97
+ print(f" Token limit: {orgLimitTokens:>12,} [{bar}] {pct:.1f}%")
98
+ print(f" Cost (USD): ${orgSpentUsd:>11.4f}")
99
+ if orgLimitUsd:
100
+ pct = orgSpentUsd / orgLimitUsd * 100
101
+ bar = "█" * int(pct / 5) + "░" * (20 - int(pct / 5))
102
+ print(f" Cost limit: ${orgLimitUsd:>11.2f} [{bar}] {pct:.1f}%")
103
+ print()
104
+
105
+ # Per-agent budgets
106
+ roles = orgData.get("roles", [])
107
+ if agentFilter:
108
+ roles = [r for r in roles if r.get("id") == agentFilter]
109
+
110
+ print("AGENT BUDGETS")
111
+ print("────────────────────────────────────────────────────────")
112
+ print(f" {'AGENT':<28} {'TOKENS IN':<12} {'TOKENS OUT':<12} {'COST USD':<12} {'LIMIT USD'}")
113
+ print(" " + "─" * 82)
114
+
115
+ for role in roles:
116
+ rid = role.get("id","?")
117
+ title = role.get("title", rid)[:26]
118
+ tok = agentTokens.get(rid, {})
119
+ tIn = tok.get("tokensIn", 0)
120
+ tOut = tok.get("tokensOut", 0)
121
+ cost = tok.get("totalCostUsd", 0.0)
122
+ lim = agentBudgets.get(rid, {}).get("limit_usd")
123
+ limStr= f"${lim:.2f}" if lim else "—"
124
+
125
+ overBudget = lim and cost > lim
126
+ flag = " ⚠ OVER" if overBudget else ""
127
+ print(f" {title:<28} {tIn:<12,} {tOut:<12,} ${cost:<11.4f} {limStr}{flag}")
128
+
129
+ if not roles:
130
+ print(" (no agents)")
131
+ PYEOF
132
+
133
+ echo ""
134
+ echo " Set limit: /mastermind:budgets --org $org_name --action set --agent-id <id> --limit-usd 5.00"
135
+ echo " Reset: /mastermind:budgets --org $org_name --action reset"
136
+ ```
137
+
138
+ ### set
139
+
140
+ ```bash
141
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
142
+
143
+ python3 - "$budgetsFile" "${agent_id:-}" "${limit_tokens:-}" "${limit_usd:-}" "$ts" <<'PYEOF'
144
+ import json, sys
145
+
146
+ path, agentId, limitTok, limitUsd, ts = sys.argv[1:]
147
+
148
+ data = json.load(open(path))
149
+
150
+ if agentId:
151
+ entry = data.setdefault("agent_budgets", {}).setdefault(agentId, {})
152
+ if limitTok: entry["limit_tokens"] = int(limitTok)
153
+ if limitUsd: entry["limit_usd"] = float(limitUsd)
154
+ entry["updatedAt"] = ts
155
+ print(f" Budget set for agent '{agentId}':")
156
+ if limitTok: print(f" Token limit: {int(limitTok):,}")
157
+ if limitUsd: print(f" USD limit: ${float(limitUsd):.2f}")
158
+ else:
159
+ org = data.setdefault("org_budget", {})
160
+ if limitTok: org["limit_tokens"] = int(limitTok)
161
+ if limitUsd: org["limit_usd"] = float(limitUsd)
162
+ org["updatedAt"] = ts
163
+ print(f" Org-wide budget updated:")
164
+ if limitTok: print(f" Token limit: {int(limitTok):,}")
165
+ if limitUsd: print(f" USD limit: ${float(limitUsd):.2f}")
166
+
167
+ with open(path, "w") as f:
168
+ json.dump(data, f, indent=2)
169
+ PYEOF
170
+ ```
171
+
172
+ ### reset
173
+
174
+ ```bash
175
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
176
+ echo '{"org_budget":{},"agent_budgets":{},"period":"monthly","currency":"USD","resetAt":"'"$ts"'"}' > "$budgetsFile"
177
+ echo " Budget counters reset for '$org_name' ($ts)"
178
+ echo " Note: resets limit configs too. Re-run --action set to restore limits."
179
+ ```
180
+
181
+ ### alert
182
+
183
+ Check for agents over their budget limits:
184
+
185
+ ```bash
186
+ echo "BUDGET ALERTS — $org_name"
187
+ echo "────────────────────────────────────────────────────────"
188
+
189
+ python3 - "$orgFile" "$budgetsFile" "$stateFile" <<'PYEOF'
190
+ import json, sys, os
191
+
192
+ orgData = json.load(open(sys.argv[1]))
193
+ budgetData = json.load(open(sys.argv[2]))
194
+ statePath = sys.argv[3]
195
+
196
+ agentTokens = {}
197
+ if os.path.exists(statePath):
198
+ try:
199
+ state = json.load(open(statePath))
200
+ for r in state.get("roles", []):
201
+ rid = r.get("id","")
202
+ agentTokens[rid] = r.get("total_cost_usd", 0.0)
203
+ except: pass
204
+
205
+ agentBudgets = budgetData.get("agent_budgets", {})
206
+ alerts = []
207
+ for rid, ab in agentBudgets.items():
208
+ lim = ab.get("limit_usd")
209
+ spent = agentTokens.get(rid, 0.0)
210
+ if lim and spent > lim:
211
+ alerts.append((rid, spent, lim))
212
+
213
+ if not alerts:
214
+ print(" ✓ All agents within budget.")
215
+ else:
216
+ print(f" ⚠ {len(alerts)} agent(s) over budget:")
217
+ for rid, spent, lim in alerts:
218
+ print(f" {rid}: spent ${spent:.4f} / limit ${lim:.2f}")
219
+ PYEOF
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Step 3 — Return Output
225
+
226
+ ```yaml
227
+ domain: ops
228
+ status: complete
229
+ action: <action>
230
+ org_name: <org_name>
231
+ ```
232
+
233
+ ---
234
+
235
+ ## Step 4 — Brain Write (standalone only)
236
+
237
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
@@ -0,0 +1,256 @@
1
+ ---
2
+ name: mastermind-companies
3
+ description: Mastermind companies — multi-org management. List all orgs with agent/issue stats, switch the active org, rename an org, delete an org (with confirmation), and view per-org summary. Mirrors Companies.tsx.
4
+ type: domain-skill
5
+ default_mode: confirm
6
+ ---
7
+
8
+ # Mastermind Companies
9
+
10
+ This skill is invoked by `mastermind:companies` or directly via `/mastermind:companies`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
17
+ - `action`: list | select | rename | delete | stats | create
18
+ - `org_name`: org name to target (required for select/rename/delete/stats)
19
+ - `new_name`: new org name (required for rename)
20
+ - `confirm`: yes (required second step for delete)
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 — Locate All Orgs
32
+
33
+ ```bash
34
+ orgsDir=".monomind/orgs"
35
+ [ ! -d "$orgsDir" ] && { echo "No orgs directory found. Run /mastermind:createorg to create your first org."; exit 0; }
36
+
37
+ # Collect all org names from .json files (not -members, -issues, etc.)
38
+ orgNames=$(ls "$orgsDir"/*.json 2>/dev/null | grep -v '\-' | xargs -I{} basename {} .json | sort)
39
+
40
+ # Track active org
41
+ activeFile=".monomind/active-org"
42
+ activeOrg=$([ -f "$activeFile" ] && cat "$activeFile" || echo "")
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Step 2 — Execute Action
48
+
49
+ ### list (default)
50
+
51
+ ```bash
52
+ echo "ORGS"
53
+ echo "────────────────────────────────────────────────────────"
54
+ printf "%-22s %-8s %-8s %-8s %s\n" "NAME" "AGENTS" "ISSUES" "MEMBERS" "STATUS"
55
+ echo "────────────────────────────────────────────────────────"
56
+
57
+ [ -z "$orgNames" ] && { echo " No orgs found. Create one: /mastermind:createorg"; exit 0; }
58
+
59
+ echo "$orgNames" | while read -r name; do
60
+ orgFile="$orgsDir/${name}.json"
61
+ [ ! -f "$orgFile" ] && continue
62
+
63
+ agents=$(jq -r '(.roles // []) | length' "$orgFile" 2>/dev/null || echo 0)
64
+ issues=$([ -f "$orgsDir/${name}-issues.json" ] && jq '[.issues[] | select(.status == "open" or .status == "in_progress")] | length' "$orgsDir/${name}-issues.json" 2>/dev/null || echo 0)
65
+ members=$([ -f "$orgsDir/${name}-members.json" ] && jq '.members | length' "$orgsDir/${name}-members.json" 2>/dev/null || echo 0)
66
+ status=$([ "$name" = "$activeOrg" ] && echo "● ACTIVE" || echo "")
67
+
68
+ printf "%-22s %-8s %-8s %-8s %s\n" "$name" "$agents" "$issues" "$members" "$status"
69
+ done
70
+
71
+ echo ""
72
+ total=$(echo "$orgNames" | wc -w | tr -d ' ')
73
+ echo " Total orgs: $total"
74
+ [ -n "$activeOrg" ] && echo " Active org: $activeOrg"
75
+ echo ""
76
+ echo " Select: --action select --org-name <name>"
77
+ echo " Rename: --action rename --org-name <name> --new-name <new>"
78
+ echo " Delete: --action delete --org-name <name>"
79
+ ```
80
+
81
+ ### select
82
+
83
+ ```bash
84
+ [ -z "$org_name" ] && { echo "ERROR: --org-name required."; exit 1; }
85
+
86
+ orgFile="$orgsDir/${org_name}.json"
87
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '$org_name' not found."; exit 1; }
88
+
89
+ echo "$org_name" > "$activeFile"
90
+ echo "Active org set to: $org_name"
91
+ echo " All mastermind commands will default to this org."
92
+ echo " To use a different org, pass --org-name explicitly."
93
+ ```
94
+
95
+ ### rename
96
+
97
+ ```bash
98
+ [ -z "$org_name" ] && { echo "ERROR: --org-name required."; exit 1; }
99
+ [ -z "$new_name" ] && { echo "ERROR: --new-name required."; exit 1; }
100
+
101
+ # Validate new name
102
+ echo "$new_name" | grep -qE '^[a-z0-9][a-z0-9_-]*$' || {
103
+ echo "ERROR: --new-name must be lowercase alphanumeric with hyphens/underscores (e.g. my-org)."
104
+ exit 1
105
+ }
106
+
107
+ orgFile="$orgsDir/${org_name}.json"
108
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '$org_name' not found."; exit 1; }
109
+
110
+ [ -f "$orgsDir/${new_name}.json" ] && { echo "ERROR: Org '$new_name' already exists."; exit 1; }
111
+
112
+ # Rename main config file
113
+ mv "$orgFile" "$orgsDir/${new_name}.json"
114
+
115
+ # Rename all associated files
116
+ for suffix in members issues goals projects routines approvals adapters plugins environments workspaces activity threads budgets; do
117
+ f="$orgsDir/${org_name}-${suffix}.json"
118
+ [ -f "$f" ] && mv "$f" "$orgsDir/${new_name}-${suffix}.json"
119
+ f2="$orgsDir/${org_name}-${suffix}.jsonl"
120
+ [ -f "$f2" ] && mv "$f2" "$orgsDir/${new_name}-${suffix}.jsonl"
121
+ done
122
+
123
+ # Update name field inside config
124
+ tmp="$orgsDir/${new_name}.json.tmp"
125
+ jq --arg n "$new_name" '.name = $n' "$orgsDir/${new_name}.json" > "$tmp" && mv "$tmp" "$orgsDir/${new_name}.json"
126
+
127
+ # Update active org pointer if needed
128
+ [ "$(cat "$activeFile" 2>/dev/null)" = "$org_name" ] && echo "$new_name" > "$activeFile"
129
+
130
+ echo "Org renamed: $org_name → $new_name"
131
+ ```
132
+
133
+ ### delete
134
+
135
+ ```bash
136
+ [ -z "$org_name" ] && { echo "ERROR: --org-name required."; exit 1; }
137
+
138
+ orgFile="$orgsDir/${org_name}.json"
139
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '$org_name' not found."; exit 1; }
140
+
141
+ if [ "${confirm:-}" != "yes" ]; then
142
+ agentCount=$(jq '(.roles // []) | length' "$orgFile" 2>/dev/null || echo "?")
143
+ echo "DELETE CONFIRMATION REQUIRED"
144
+ echo "────────────────────────────────────────────────────────"
145
+ echo " Org: $org_name"
146
+ echo " Agents: $agentCount"
147
+ echo ""
148
+ echo " This will permanently delete the org and ALL associated data."
149
+ echo " To confirm: --action delete --org-name $org_name --confirm yes"
150
+ exit 0
151
+ fi
152
+
153
+ # Delete all org files
154
+ rm -f "$orgsDir/${org_name}.json"
155
+ for suffix in members issues goals projects routines approvals adapters plugins environments workspaces activity threads budgets project-workspaces approval-comments; do
156
+ rm -f "$orgsDir/${org_name}-${suffix}.json"
157
+ rm -f "$orgsDir/${org_name}-${suffix}.jsonl"
158
+ done
159
+
160
+ # Clear active org if it was this org
161
+ [ "$(cat "$activeFile" 2>/dev/null)" = "$org_name" ] && rm -f "$activeFile"
162
+
163
+ echo "Org '$org_name' deleted permanently."
164
+ echo " All associated data removed."
165
+ ```
166
+
167
+ ### stats
168
+
169
+ ```bash
170
+ [ -z "$org_name" ] && { echo "ERROR: --org-name required."; exit 1; }
171
+
172
+ orgFile="$orgsDir/${org_name}.json"
173
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '$org_name' not found."; exit 1; }
174
+
175
+ echo "ORG STATS — $org_name"
176
+ echo "────────────────────────────────────────────────────────"
177
+
178
+ # Agent stats
179
+ agents=$(jq '(.roles // []) | length' "$orgFile")
180
+ gov=$(jq -r '.governance // "(not set)"' "$orgFile")
181
+ echo " Agents: $agents"
182
+ echo " Governance: $gov"
183
+
184
+ # Issues
185
+ if [ -f "$orgsDir/${org_name}-issues.json" ]; then
186
+ total=$(jq '.issues | length' "$orgsDir/${org_name}-issues.json")
187
+ open=$(jq '[.issues[] | select(.status == "open" or .status == "in_progress")] | length' "$orgsDir/${org_name}-issues.json")
188
+ done=$(jq '[.issues[] | select(.status == "done")] | length' "$orgsDir/${org_name}-issues.json")
189
+ echo " Issues: $total total ($open open, $done done)"
190
+ fi
191
+
192
+ # Goals
193
+ [ -f "$orgsDir/${org_name}-goals.json" ] && echo " Goals: $(jq '.goals | length' "$orgsDir/${org_name}-goals.json")"
194
+
195
+ # Projects
196
+ [ -f "$orgsDir/${org_name}-projects.json" ] && echo " Projects: $(jq '.projects | length' "$orgsDir/${org_name}-projects.json")"
197
+
198
+ # Members
199
+ [ -f "$orgsDir/${org_name}-members.json" ] && echo " Members: $(jq '.members | length' "$orgsDir/${org_name}-members.json")"
200
+
201
+ # Routines
202
+ [ -f "$orgsDir/${org_name}-routines.json" ] && echo " Routines: $(jq '.routines | length' "$orgsDir/${org_name}-routines.json")"
203
+
204
+ # Pending approvals
205
+ if [ -f "$orgsDir/${org_name}-approvals.json" ]; then
206
+ pending=$(jq '[.approvals[] | select(.status == "pending")] | length' "$orgsDir/${org_name}-approvals.json")
207
+ echo " Pending approvals: $pending"
208
+ fi
209
+ ```
210
+
211
+ ### create
212
+
213
+ ```bash
214
+ [ -z "$org_name" ] && { echo "ERROR: --org-name required."; exit 1; }
215
+
216
+ echo "$org_name" | grep -qE '^[a-z0-9][a-z0-9_-]*$' || {
217
+ echo "ERROR: --org-name must be lowercase alphanumeric with hyphens/underscores."
218
+ exit 1
219
+ }
220
+
221
+ orgFile="$orgsDir/${org_name}.json"
222
+ [ -f "$orgFile" ] && { echo "ERROR: Org '$org_name' already exists."; exit 1; }
223
+
224
+ mkdir -p "$orgsDir"
225
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
226
+ cat > "$orgFile" <<EOF
227
+ {
228
+ "name": "$org_name",
229
+ "governance": "auto",
230
+ "roles": [],
231
+ "created_at": "$ts"
232
+ }
233
+ EOF
234
+
235
+ echo "Org '$org_name' created."
236
+ echo " Add agents: /mastermind:new-agent --org $org_name --title 'My Agent'"
237
+ echo " Run: /mastermind:runorg --org $org_name"
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Step 3 — Return Output
243
+
244
+ ```yaml
245
+ domain: ops
246
+ status: complete
247
+ action: <action>
248
+ org_name: <org_name>
249
+ active_org: <active_org>
250
+ ```
251
+
252
+ ---
253
+
254
+ ## Step 4 — Brain Write (standalone only)
255
+
256
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
@@ -0,0 +1,151 @@
1
+ ---
2
+ name: mastermind-costs
3
+ description: Mastermind costs — track token spend and budget burn rate per agent in a running org. Shows current window spend, budget policy, and alerts when approaching limits.
4
+ type: domain-skill
5
+ default_mode: auto
6
+ ---
7
+
8
+ # Mastermind Costs
9
+
10
+ This skill is invoked by `mastermind:costs` or directly via `/mastermind:costs`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `brain_context`: BRAIN CONTEXT block
17
+ - `org_name`: org to inspect costs for
18
+ - `action`: report | set-budget | alert
19
+ - `budget_tokens`: max token budget for the org run (for set-budget)
20
+ - `alert_threshold`: fraction of budget that triggers alert (default 0.8)
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 — Load Cost Data
32
+
33
+ Cost data is pulled from monomind's token summary and the org state file:
34
+
35
+ ```bash
36
+ orgFile=".monomind/orgs/${org_name}.json"
37
+ stateFile=".monomind/orgs/${org_name}-state.json"
38
+ tokenSummary=".monomind/metrics/token-summary.json"
39
+
40
+ memNs="org:${org_name}"
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Step 2 — Execute Action
46
+
47
+ ### report (default)
48
+
49
+ Aggregate token usage per agent from state file and token summary:
50
+
51
+ ```bash
52
+ # Get total token usage from the global summary for context
53
+ if [ -f "$tokenSummary" ]; then
54
+ echo "=== GLOBAL TOKEN SUMMARY ==="
55
+ jq -r '"Today: $\(.today.cost | tostring) calls: \(.today.calls)"' "$tokenSummary" 2>/dev/null || true
56
+ fi
57
+
58
+ echo ""
59
+ echo "=== ORG SPEND — ${org_name} ==="
60
+
61
+ # Per-agent spend from state file
62
+ if [ -f "$stateFile" ]; then
63
+ jq -r '.agents // {} | to_entries[] | " \(.key): tokens_in=\(.value.tokens_in // 0) tokens_out=\(.value.tokens_out // 0) status=\(.value.status // "unknown")"' "$stateFile" 2>/dev/null
64
+ else
65
+ echo " (no state file — org has not run yet)"
66
+ fi
67
+
68
+ # Budget check
69
+ budget=$(jq -r '.run_config.budget_tokens // "unlimited"' "$orgFile" 2>/dev/null)
70
+ echo ""
71
+ echo "Budget: $budget tokens"
72
+ ```
73
+
74
+ Render as:
75
+ ```
76
+ COSTS — org: <org_name>
77
+ ──────────────────────────────────────────────
78
+ AGENT STATUS TOKENS IN TOKENS OUT EST. COST
79
+ boss running 48,230 12,100 ~$0.42
80
+ content-writer idle 21,400 8,900 ~$0.18
81
+ reviewer waiting 5,100 2,300 ~$0.05
82
+ ──────────────────────────────────────────────
83
+ TOTAL 74,730 23,300 ~$0.65
84
+ BUDGET: 500,000 tokens | USED: 14.8% | REMAINING: 85.2%
85
+
86
+ BURN RATE: ~4,900 tokens/hour | EST. RUNWAY: ~87 hours
87
+ ```
88
+
89
+ Calculate costs using approximate rates: input ~$3/1M tokens, output ~$15/1M tokens (Sonnet-class).
90
+
91
+ ### set-budget
92
+
93
+ Write budget to org config:
94
+
95
+ ```bash
96
+ tmp="${orgFile}.tmp"
97
+ jq --argjson budget "$budget_tokens" \
98
+ --argjson threshold "${alert_threshold:-0.8}" \
99
+ '.run_config.budget_tokens = $budget | .run_config.alert_threshold = $threshold' \
100
+ "$orgFile" > "$tmp" && mv "$tmp" "$orgFile"
101
+ echo "Budget set: $budget_tokens tokens (alert at $(echo "$alert_threshold * 100" | bc)%)"
102
+ ```
103
+
104
+ ### alert
105
+
106
+ Check current usage against budget and emit alert if over threshold:
107
+
108
+ ```bash
109
+ budget=$(jq -r '.run_config.budget_tokens // 0' "$orgFile")
110
+ threshold=$(jq -r '.run_config.alert_threshold // 0.8' "$orgFile")
111
+
112
+ if [ "$budget" -gt 0 ] && [ -f "$stateFile" ]; then
113
+ total_in=$(jq '[.agents // {} | to_entries[] | .value.tokens_in // 0] | add // 0' "$stateFile")
114
+ total_out=$(jq '[.agents // {} | to_entries[] | .value.tokens_out // 0] | add // 0' "$stateFile")
115
+ total=$((total_in + total_out))
116
+
117
+ # Use awk for float comparison
118
+ over=$(awk -v total="$total" -v budget="$budget" -v threshold="$threshold" \
119
+ 'BEGIN { print (total/budget >= threshold) ? "yes" : "no" }')
120
+
121
+ if [ "$over" = "yes" ]; then
122
+ echo "ALERT: Org $org_name has used $(awk -v t=$total -v b=$budget 'BEGIN{printf "%.1f", t/b*100}')% of budget"
123
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
124
+ CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
125
+ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
126
+ -H "Content-Type: application/json" \
127
+ -d "$(jq -cn --arg org "$org_name" --argjson total $total --argjson budget $budget \
128
+ '{type:"org:budget:alert",org:$org,tokens_used:$total,budget:$budget,ts:(now*1000|floor)}')" || true
129
+ fi
130
+ fi
131
+ ```
132
+
133
+ ---
134
+
135
+ ## Step 3 — Return Output
136
+
137
+ ```yaml
138
+ domain: ops
139
+ status: complete
140
+ action: <action>
141
+ org: <org_name>
142
+ total_tokens: <N>
143
+ budget_tokens: <N>
144
+ usage_pct: <N>%
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Step 4 — Brain Write (standalone only)
150
+
151
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.