@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,190 @@
1
+ ---
2
+ name: mastermind-plugins
3
+ description: Mastermind plugins — install, enable, disable, uninstall, and inspect plugins for an org. Plugins extend agent capabilities with workers, events, and custom tools. Supports npm packages and local paths.
4
+ type: domain-skill
5
+ default_mode: confirm
6
+ ---
7
+
8
+ # Mastermind Plugins
9
+
10
+ This skill is invoked by `mastermind:plugins` or directly via `/mastermind:plugins`.
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 plugins for (optional — uses global plugin registry if omitted)
18
+ - `action`: list | install | uninstall | enable | disable | status | examples
19
+ - `plugin_id`: plugin id or package name (required for uninstall/enable/disable/status)
20
+ - `package_name`: npm package or local path (required for install)
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 Plugin Registry
32
+
33
+ ```bash
34
+ pluginsDir=".monomind/plugins"
35
+ mkdir -p "$pluginsDir"
36
+ registryFile="${pluginsDir}/registry.json"
37
+ [ ! -f "$registryFile" ] && echo '{"plugins":[]}' > "$registryFile"
38
+
39
+ # If org scoped, also check org-level plugin overrides
40
+ if [ -n "$org_name" ]; then
41
+ orgPluginsFile=".monomind/orgs/${org_name}-plugins.json"
42
+ [ ! -f "$orgPluginsFile" ] && echo '{"plugins":[]}' > "$orgPluginsFile"
43
+ fi
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Step 2 — Execute Action
49
+
50
+ ### list (default)
51
+
52
+ ```bash
53
+ echo "PLUGINS"
54
+ echo "──────────────────────────────────────────────────────────"
55
+ printf "%-28s %-12s %-10s %-10s %s\n" "ID / PACKAGE" "VERSION" "STATUS" "CATEGORY" "ERROR"
56
+ echo "──────────────────────────────────────────────────────────"
57
+
58
+ count=$(jq '.plugins | length' "$registryFile")
59
+ if [ "$count" -eq 0 ]; then
60
+ echo " No plugins installed. Use --action install --package-name <pkg> to add one."
61
+ else
62
+ jq -r '.plugins[] |
63
+ [
64
+ (.id // .packageName // "unknown"),
65
+ (.version // "-"),
66
+ (.status // "unknown"),
67
+ (.category // "general"),
68
+ (if .lastError then (.lastError | split("\n")[0] | .[0:40]) else "-" end)
69
+ ] | @tsv' "$registryFile" | while IFS=$'\t' read -r id ver status cat err; do
70
+ statusColor=""
71
+ printf "%-28s %-12s %-10s %-10s %s\n" "$id" "$ver" "$status" "$cat" "$err"
72
+ done
73
+ fi
74
+
75
+ echo ""
76
+ echo "Total: $count plugin(s)"
77
+ [ -n "$org_name" ] && echo "Org overrides: $(jq '.plugins | length' "$orgPluginsFile" 2>/dev/null || echo 0)"
78
+ ```
79
+
80
+ ### examples
81
+
82
+ Show example/available plugins from the monomind registry:
83
+
84
+ ```bash
85
+ echo "AVAILABLE PLUGINS (monomind registry)"
86
+ echo "──────────────────────────────────────"
87
+ cat <<'EXAMPLES'
88
+ @monomind/plugin-sentry — Error tracking and alerting
89
+ @monomind/plugin-github — GitHub issue/PR sync
90
+ @monomind/plugin-slack — Slack notifications and commands
91
+ @monomind/plugin-linear — Linear issue sync
92
+ @monomind/plugin-datadog — Metrics and monitoring
93
+ @monomind/plugin-vault — HashiCorp Vault secrets integration
94
+ @monomind/plugin-webhook — Generic inbound/outbound webhooks
95
+ @monomind/plugin-memory-ext — Extended memory backend
96
+
97
+ Install: /mastermind:plugins --action install --package-name @monomind/plugin-<name>
98
+ EXAMPLES
99
+ ```
100
+
101
+ ### install
102
+
103
+ ```bash
104
+ [ -z "$package_name" ] && { echo "ERROR: --package-name required."; exit 1; }
105
+
106
+ isLocal=false
107
+ [[ "$package_name" == /* || "$package_name" == "./"* ]] && isLocal=true
108
+
109
+ # Generate a stable id
110
+ pluginId=$(echo "$package_name" | sed 's|[/@]|_|g' | tr -cd 'a-z0-9_-')
111
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
112
+
113
+ tmp="${registryFile}.tmp"
114
+ jq --arg id "$pluginId" \
115
+ --arg pkg "$package_name" \
116
+ --argjson local "$isLocal" \
117
+ --arg ts "$ts" \
118
+ '.plugins = [.plugins[] | select(.id != $id)] +
119
+ [{"id":$id,"packageName":$pkg,"isLocalPath":$local,
120
+ "status":"installed","version":"latest","category":"general",
121
+ "installedAt":$ts,"lastError":null}]' \
122
+ "$registryFile" > "$tmp" && mv "$tmp" "$registryFile"
123
+
124
+ echo "Installed: $package_name (id: $pluginId)"
125
+ echo "NOTE: Agents must be restarted to load the new plugin."
126
+ ```
127
+
128
+ Emit `org:plugin:installed` event:
129
+
130
+ ```bash
131
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
132
+ CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
133
+ curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
134
+ -H "Content-Type: application/json" \
135
+ -d "$(jq -cn --arg org "${org_name:-global}" --arg id "$pluginId" --arg pkg "$package_name" \
136
+ '{type:"org:plugin:installed",org:$org,plugin:$id,package:$pkg,ts:(now*1000|floor)}')" || true
137
+ ```
138
+
139
+ ### uninstall
140
+
141
+ ```bash
142
+ [ -z "$plugin_id" ] && { echo "ERROR: --plugin-id required."; exit 1; }
143
+ echo "Uninstalling plugin '$plugin_id'…"
144
+
145
+ tmp="${registryFile}.tmp"
146
+ jq --arg id "$plugin_id" '.plugins = [.plugins[] | select(.id != $id)]' \
147
+ "$registryFile" > "$tmp" && mv "$tmp" "$registryFile"
148
+ echo "Uninstalled: $plugin_id"
149
+ ```
150
+
151
+ ### enable / disable
152
+
153
+ ```bash
154
+ [ -z "$plugin_id" ] && { echo "ERROR: --plugin-id required."; exit 1; }
155
+ newStatus=$([ "$action" = "enable" ] && echo "installed" || echo "disabled")
156
+
157
+ tmp="${registryFile}.tmp"
158
+ jq --arg id "$plugin_id" --arg s "$newStatus" \
159
+ '.plugins = [.plugins[] | if .id == $id then .status = $s else . end]' \
160
+ "$registryFile" > "$tmp" && mv "$tmp" "$registryFile"
161
+ echo "Plugin '$plugin_id' → $newStatus"
162
+ ```
163
+
164
+ ### status
165
+
166
+ Show detailed status for a specific plugin:
167
+
168
+ ```bash
169
+ [ -z "$plugin_id" ] && { echo "ERROR: --plugin-id required."; exit 1; }
170
+ jq --arg id "$plugin_id" '.plugins[] | select(.id == $id)' "$registryFile"
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Step 3 — Return Output
176
+
177
+ ```yaml
178
+ domain: ops
179
+ status: complete
180
+ action: <action>
181
+ org: <org_name or global>
182
+ plugin_id: <id if applicable>
183
+ plugins_total: <N>
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Step 4 — Brain Write (standalone only)
189
+
190
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
@@ -0,0 +1,187 @@
1
+ ---
2
+ name: mastermind-profile
3
+ description: Mastermind profile — view and edit the current operator profile (display name, preferences) and inspect any user's activity statistics, completion rate, and token usage. Merges ProfileSettings.tsx and UserProfile.tsx.
4
+ type: domain-skill
5
+ default_mode: confirm
6
+ ---
7
+
8
+ # Mastermind Profile
9
+
10
+ This skill is invoked by `mastermind:profile` or directly via `/mastermind:profile`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
17
+ - `action`: show | edit | view-user | stats
18
+ - `user_id`: user id to view (for view-user/stats; defaults to current operator)
19
+ - `org_name`: org context for per-org stats (optional)
20
+ - `display_name`: new display name (for edit)
21
+ - `email`: new email (for edit)
22
+ - `theme`: light | dark | system (for edit)
23
+ - `caller`: command | master
24
+
25
+ ---
26
+
27
+ ## Step 0 — Brain Load (standalone only)
28
+
29
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
30
+
31
+ ---
32
+
33
+ ## Step 1 — Load Profile File
34
+
35
+ ```bash
36
+ profileFile=".monomind/operator-profile.json"
37
+ [ ! -f "$profileFile" ] && cat > "$profileFile" <<'EOF'
38
+ {
39
+ "id": "local-operator",
40
+ "displayName": "Operator",
41
+ "email": "",
42
+ "theme": "system",
43
+ "avatarInitials": "OP",
44
+ "keyboardShortcutsEnabled": true,
45
+ "createdAt": null
46
+ }
47
+ EOF
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Step 2 — Execute Action
53
+
54
+ ### show (default)
55
+
56
+ ```bash
57
+ echo "OPERATOR PROFILE"
58
+ echo "────────────────────────────────────────────────────────"
59
+ jq -r '
60
+ " ID: \(.id // "local-operator")",
61
+ " Display name: \(.displayName // "(not set)")",
62
+ " Email: \(.email // "(not set)")",
63
+ " Theme: \(.theme // "system")",
64
+ " Initials: \(.avatarInitials // "OP")",
65
+ " Shortcuts: \(.keyboardShortcutsEnabled // true)",
66
+ " Created: \(.createdAt // "(local)")"
67
+ ' "$profileFile"
68
+
69
+ echo ""
70
+ echo " To edit: --action edit --display-name 'New Name'"
71
+ echo " To view stats: --action stats"
72
+ ```
73
+
74
+ ### edit
75
+
76
+ ```bash
77
+ if [ -z "$display_name" ] && [ -z "$email" ] && [ -z "$theme" ]; then
78
+ echo "ERROR: Provide at least one of: --display-name, --email, --theme (light|dark|system)"
79
+ exit 1
80
+ fi
81
+
82
+ case "${theme:-}" in
83
+ light|dark|system|"") : ;;
84
+ *) echo "ERROR: --theme must be light, dark, or system"; exit 1 ;;
85
+ esac
86
+
87
+ tmp="${profileFile}.tmp"
88
+ jq \
89
+ --arg name "${display_name:-}" \
90
+ --arg email "${email:-}" \
91
+ --arg theme "${theme:-}" \
92
+ '(if $name != "" then .displayName = $name else . end) |
93
+ (if $email != "" then .email = $email else . end) |
94
+ (if $theme != "" then .theme = $theme else . end) |
95
+ (if $name != "" then .avatarInitials = ($name | split(" ") |
96
+ map(select(length > 0) | .[0:1] | ascii_upcase) | .[0:2] | join(""))
97
+ else . end)' \
98
+ "$profileFile" > "$tmp" && mv "$tmp" "$profileFile"
99
+
100
+ echo "Profile updated."
101
+ jq -r '" displayName: \(.displayName) email: \(.email) theme: \(.theme)"' "$profileFile"
102
+ ```
103
+
104
+ ### view-user
105
+
106
+ ```bash
107
+ targetId="${user_id:-local-operator}"
108
+ echo "USER PROFILE — $targetId"
109
+ echo "────────────────────────────────────────────────────────"
110
+
111
+ # Try to find in instance access file
112
+ accessFile=".monomind/instance-access.json"
113
+ if [ -f "$accessFile" ]; then
114
+ userEntry=$(jq -r --arg id "$targetId" '.users[] | select(.id == $id)' "$accessFile")
115
+ if [ -n "$userEntry" ]; then
116
+ isAdmin=$(echo "$userEntry" | jq -r '.isInstanceAdmin // false')
117
+ orgs=$(echo "$userEntry" | jq -r '(.companyAccess // []) | join(", ")')
118
+ echo " ID: $targetId"
119
+ echo " Instance admin: $isAdmin"
120
+ echo " Org access: ${orgs:-(none)}"
121
+ else
122
+ echo " ID: $targetId"
123
+ echo " (User not found in instance access registry)"
124
+ fi
125
+ else
126
+ echo " ID: $targetId (no instance access file)"
127
+ fi
128
+
129
+ echo ""
130
+ echo " For activity stats: --action stats --user-id $targetId"
131
+ ```
132
+
133
+ ### stats
134
+
135
+ ```bash
136
+ targetId="${user_id:-local-operator}"
137
+ echo "ACTIVITY STATS — $targetId"
138
+ echo "────────────────────────────────────────────────────────"
139
+
140
+ # Scan activity files for user contributions
141
+ totalRuns=0; successRuns=0; totalInputTokens=0; totalOutputTokens=0
142
+
143
+ for actFile in data/mastermind-sessions.json .monomind/orgs/*-activity.jsonl; do
144
+ [ -f "$actFile" ] || continue
145
+ if echo "$actFile" | grep -q "\.jsonl$"; then
146
+ cnt=$(grep -c "\"actorId\":\"${targetId}\"" "$actFile" 2>/dev/null || echo 0)
147
+ succ=$(grep "\"actorId\":\"${targetId}\"" "$actFile" 2>/dev/null | grep -c '"outcome":"success"' || echo 0)
148
+ totalRuns=$((totalRuns + cnt))
149
+ successRuns=$((successRuns + succ))
150
+ fi
151
+ done
152
+
153
+ # Per-org if org_name set
154
+ if [ -n "$org_name" ]; then
155
+ issuesFile=".monomind/orgs/${org_name}-issues.json"
156
+ if [ -f "$issuesFile" ]; then
157
+ assigned=$(jq --arg uid "$targetId" '[.issues[] | select(.assigneeId == $uid)] | length' "$issuesFile")
158
+ echo " Issues assigned (org $org_name): $assigned"
159
+ fi
160
+ fi
161
+
162
+ completionRate=0
163
+ [ "$totalRuns" -gt 0 ] && completionRate=$((successRuns * 100 / totalRuns))
164
+
165
+ echo " Total runs tracked: $totalRuns"
166
+ echo " Successful runs: $successRuns"
167
+ echo " Completion rate: ${completionRate}%"
168
+ echo ""
169
+ echo " (Token usage stats require agent run logs with token tracking enabled)"
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Step 3 — Return Output
175
+
176
+ ```yaml
177
+ domain: ops
178
+ status: complete
179
+ action: <action>
180
+ user_id: <user_id or local-operator>
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Step 4 — Brain Write (standalone only)
186
+
187
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.
@@ -0,0 +1,249 @@
1
+ ---
2
+ name: mastermind-project-detail
3
+ description: Mastermind project-detail — deep per-project inspection and management. Tabs mirror Paperclip's ProjectDetail page: overview (metrics/issues), configuration (color/visibility/description), budget policy, workspaces, and linked issues list.
4
+ type: domain-skill
5
+ default_mode: auto
6
+ ---
7
+
8
+ # Mastermind Project Detail
9
+
10
+ This skill is invoked by `mastermind:project-detail` or directly via `/mastermind:project-detail`.
11
+
12
+ ---
13
+
14
+ ## Inputs
15
+
16
+ - `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
17
+ - `org_name`: org the project belongs to (required)
18
+ - `project_id`: project id/slug (required)
19
+ - `action`: show | overview | issues | config | budget | workspaces
20
+ - `field`: config field to edit (name|description|color|visibility)
21
+ - `value`: new field value (for config --field)
22
+ - `budget_policy`: none | soft_limit | hard_limit (for budget action)
23
+ - `budget_limit`: token limit (integer, required if policy != none)
24
+ - `budget_period`: daily | weekly | monthly (default: daily)
25
+ - `caller`: command | master
26
+
27
+ ---
28
+
29
+ ## Project Colors
30
+
31
+ `red` | `orange` | `yellow` | `green` | `teal` | `blue` | `purple` | `pink` | `gray`
32
+
33
+ ## Visibility
34
+
35
+ `private` — visible only to org members with access
36
+ `internal` — visible to all org members
37
+ `public` — visible to anyone with the link
38
+
39
+ ---
40
+
41
+ ## Step 0 — Brain Load (standalone only)
42
+
43
+ If `caller` is not "command", load brain context following _protocol.md Brain Load Procedure with namespace: `ops`.
44
+
45
+ ---
46
+
47
+ ## Step 1 — Load Project Data
48
+
49
+ ```bash
50
+ orgFile=".monomind/orgs/${org_name}.json"
51
+ [ ! -f "$orgFile" ] && { echo "ERROR: Org '${org_name}' not found."; exit 1; }
52
+
53
+ projectsFile=".monomind/orgs/${org_name}-projects.json"
54
+ [ ! -f "$projectsFile" ] && { echo "ERROR: No projects file for org '$org_name'. Create via /mastermind:projects."; exit 1; }
55
+
56
+ projectDef=$(jq -r --arg id "$project_id" '.projects[] | select(.id == $id or .slug == $id)' "$projectsFile")
57
+ [ -z "$projectDef" ] && { echo "ERROR: Project '$project_id' not found in org '$org_name'."; exit 1; }
58
+
59
+ resolvedId=$(echo "$projectDef" | jq -r '.id')
60
+ issuesFile=".monomind/orgs/${org_name}-issues.json"
61
+ wsFile=".monomind/orgs/${org_name}-workspaces.json"
62
+ budgetFile=".monomind/orgs/${org_name}-budgets.json"
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Step 2 — Execute Action
68
+
69
+ ### show (default) — same as overview
70
+
71
+ ```bash
72
+ echo "PROJECT — $project_id @ $org_name"
73
+ echo "────────────────────────────────────────────────────────"
74
+
75
+ echo "$projectDef" | jq -r '
76
+ " ID: \(.id)",
77
+ " Name: \(.name // "(unnamed)")",
78
+ " Status: \(.status // "active")",
79
+ " Color: \(.color // "gray")",
80
+ " Visibility: \(.visibility // "internal")",
81
+ " Description: \(.description // "(none)")",
82
+ " Created: \(.created_at // "-")"
83
+ '
84
+
85
+ # Issues summary
86
+ if [ -f "$issuesFile" ]; then
87
+ totalIssues=$(jq --arg pid "$resolvedId" '[.issues[] | select(.project_id == $pid)] | length' "$issuesFile")
88
+ openIssues=$(jq --arg pid "$resolvedId" '[.issues[] | select(.project_id == $pid and .status == "open")] | length' "$issuesFile")
89
+ inProgIssues=$(jq --arg pid "$resolvedId" '[.issues[] | select(.project_id == $pid and .status == "in_progress")] | length' "$issuesFile")
90
+ doneIssues=$(jq --arg pid "$resolvedId" '[.issues[] | select(.project_id == $pid and .status == "done")] | length' "$issuesFile")
91
+ echo ""
92
+ echo "ISSUES"
93
+ echo " Total: $totalIssues"
94
+ echo " Open: $openIssues"
95
+ echo " In progress: $inProgIssues"
96
+ echo " Done: $doneIssues"
97
+ fi
98
+
99
+ # Workspaces summary
100
+ if [ -f "$wsFile" ]; then
101
+ wsCount=$(jq --arg pid "$resolvedId" '[.workspaces[] | select(.project_id == $pid)] | length' "$wsFile")
102
+ activeWs=$(jq --arg pid "$resolvedId" '[.workspaces[] | select(.project_id == $pid and .status == "active")] | length' "$wsFile")
103
+ echo ""
104
+ echo "WORKSPACES"
105
+ echo " Total: $wsCount | Active: $activeWs"
106
+ fi
107
+ ```
108
+
109
+ ### overview
110
+
111
+ Alias for `show` — print the overview section above.
112
+
113
+ ### issues
114
+
115
+ ```bash
116
+ echo "ISSUES — project: $project_id"
117
+ echo "────────────────────────────────────────────────────────"
118
+ printf "%-24s %-12s %-10s %s\n" "ID" "STATUS" "PRIORITY" "TITLE"
119
+ echo "────────────────────────────────────────────────────────"
120
+
121
+ if [ ! -f "$issuesFile" ]; then
122
+ echo " No issues file found."
123
+ else
124
+ count=0
125
+ jq -r --arg pid "$resolvedId" '.issues[] | select(.project_id == $pid) |
126
+ [.id, (.status // "open"), (.priority // "medium"), (.title // "(no title)")] | @tsv' \
127
+ "$issuesFile" | while IFS=$'\t' read -r id st pri title; do
128
+ printf "%-24s %-12s %-10s %s\n" "$id" "$st" "$pri" "$title"
129
+ count=$((count + 1))
130
+ done
131
+ fi
132
+ ```
133
+
134
+ ### config
135
+
136
+ ```bash
137
+ echo "PROJECT CONFIG — $project_id"
138
+ echo "────────────────────────────────────────────────────────"
139
+
140
+ if [ -n "$field" ]; then
141
+ [ -z "$value" ] && { echo "ERROR: --value required when --field is set."; exit 1; }
142
+ validFields="name description color visibility status"
143
+ echo "$validFields" | tr ' ' '\n' | grep -qx "$field" || {
144
+ echo "ERROR: Unknown field '$field'. Valid: $validFields"; exit 1
145
+ }
146
+ if [ "$field" = "color" ]; then
147
+ case "$value" in red|orange|yellow|green|teal|blue|purple|pink|gray) : ;; *)
148
+ echo "ERROR: color must be one of: red orange yellow green teal blue purple pink gray"; exit 1 ;;
149
+ esac
150
+ fi
151
+ if [ "$field" = "visibility" ]; then
152
+ case "$value" in private|internal|public) : ;; *)
153
+ echo "ERROR: visibility must be one of: private, internal, public"; exit 1 ;;
154
+ esac
155
+ fi
156
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
157
+ tmp="${projectsFile}.tmp"
158
+ jq --arg id "$resolvedId" --arg f "$field" --arg v "$value" --arg ts "$ts" \
159
+ '.projects = [.projects[] | if .id == $id then .[$f] = $v | .updated_at = $ts else . end]' \
160
+ "$projectsFile" > "$tmp" && mv "$tmp" "$projectsFile"
161
+ echo "Updated: $field = $value"
162
+ else
163
+ echo "$projectDef" | jq '{name, description, color, visibility, status}'
164
+ fi
165
+ ```
166
+
167
+ ### budget
168
+
169
+ ```bash
170
+ echo "BUDGET POLICY — $project_id"
171
+ echo "────────────────────────────────────────────────────────"
172
+
173
+ [ ! -f "$budgetFile" ] && echo '{"budgets":[]}' > "$budgetFile"
174
+
175
+ existing=$(jq -r --arg pid "$resolvedId" '.budgets[] | select(.project_id == $pid)' "$budgetFile")
176
+ if [ -z "$existing" ]; then
177
+ echo " No budget policy set."
178
+ else
179
+ echo "$existing" | jq -r '
180
+ " Policy: \(.policy // "none")",
181
+ " Limit: \(.limit_tokens // "unlimited") tokens",
182
+ " Period: \(.period // "daily")"
183
+ '
184
+ fi
185
+
186
+ if [ -n "$budget_policy" ]; then
187
+ case "$budget_policy" in none|soft_limit|hard_limit) : ;; *)
188
+ echo "ERROR: --budget-policy must be none, soft_limit, or hard_limit"; exit 1 ;;
189
+ esac
190
+ [ "$budget_policy" != "none" ] && [ -z "$budget_limit" ] && {
191
+ echo "ERROR: --budget-limit required for '$budget_policy' policy."; exit 1
192
+ }
193
+ ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
194
+ tmp="${budgetFile}.tmp"
195
+ jq --arg pid "$resolvedId" \
196
+ --arg policy "$budget_policy" \
197
+ --argjson limit "${budget_limit:-0}" \
198
+ --arg period "${budget_period:-daily}" \
199
+ --arg ts "$ts" \
200
+ '.budgets = [.budgets[] | select(.project_id != $pid)] +
201
+ [{"project_id":$pid,"policy":$policy,
202
+ "limit_tokens":(if $policy != "none" then $limit else null end),
203
+ "period":$period,"updatedAt":$ts}]' \
204
+ "$budgetFile" > "$tmp" && mv "$tmp" "$budgetFile"
205
+ echo ""
206
+ echo "Budget policy updated: $budget_policy"
207
+ [ "$budget_policy" != "none" ] && echo " Limit: $budget_limit tokens / ${budget_period:-daily}"
208
+ fi
209
+ ```
210
+
211
+ ### workspaces
212
+
213
+ ```bash
214
+ echo "WORKSPACES — project: $project_id"
215
+ echo "────────────────────────────────────────────────────────"
216
+
217
+ if [ ! -f "$wsFile" ]; then
218
+ echo " No workspaces file."
219
+ else
220
+ printf "%-20s %-12s %-18s %-8s %s\n" "ID" "STATUS" "AGENT" "BRANCH" "PATH"
221
+ echo "────────────────────────────────────────────────────────"
222
+ count=0
223
+ jq -r --arg pid "$resolvedId" '.workspaces[] | select(.project_id == $pid) |
224
+ [.id, (.status // "unknown"), (.agent_id // "(none)"), (.branch // "?"), (.worktree_path // "-")] | @tsv' \
225
+ "$wsFile" | while IFS=$'\t' read -r id st ag br path; do
226
+ printf "%-20s %-12s %-18s %-8s %s\n" "$id" "$st" "$ag" "$br" "$path"
227
+ count=$((count + 1))
228
+ done
229
+ fi
230
+ ```
231
+
232
+ ---
233
+
234
+ ## Step 3 — Return Output
235
+
236
+ ```yaml
237
+ domain: ops
238
+ status: complete
239
+ action: <action>
240
+ org: <org_name>
241
+ project_id: <project_id>
242
+ project_status: <status>
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Step 4 — Brain Write (standalone only)
248
+
249
+ If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.