monomind 2.1.0 → 2.1.4

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 (57) hide show
  1. package/README.md +77 -94
  2. package/package.json +3 -3
  3. package/packages/@monomind/cli/.claude/commands/mastermind/createorg.md +8 -9
  4. package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +24 -10
  5. package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +2 -2
  6. package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +29 -0
  7. package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +35 -23
  8. package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +21 -0
  9. package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
  10. package/packages/@monomind/cli/.claude/skills/mastermind-skills/createorg.md +91 -701
  11. package/packages/@monomind/cli/.claude/skills/mastermind-skills/org-settings.md +46 -47
  12. package/packages/@monomind/cli/.claude/skills/mastermind-skills/runorg.md +12 -1
  13. package/packages/@monomind/cli/README.md +77 -94
  14. package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
  15. package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
  16. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
  17. package/packages/@monomind/cli/dist/src/commands/org.js +46 -29
  18. package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
  19. package/packages/@monomind/cli/dist/src/init/executor.js +30 -6
  20. package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.d.ts +8 -8
  21. package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +31 -31
  22. package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +5 -1
  23. package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +28 -3
  24. package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
  25. package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
  26. package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
  27. package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
  28. package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +3 -1
  29. package/packages/@monomind/cli/dist/src/orgrt/broker.js +8 -3
  30. package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +5 -1
  31. package/packages/@monomind/cli/dist/src/orgrt/bus.js +5 -1
  32. package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +35 -1
  33. package/packages/@monomind/cli/dist/src/orgrt/daemon.js +190 -21
  34. package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +47 -10
  35. package/packages/@monomind/cli/dist/src/orgrt/inbox.d.ts +11 -0
  36. package/packages/@monomind/cli/dist/src/orgrt/inbox.js +56 -0
  37. package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +5 -1
  38. package/packages/@monomind/cli/dist/src/orgrt/policy.js +58 -5
  39. package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +3 -2
  40. package/packages/@monomind/cli/dist/src/orgrt/server.js +31 -40
  41. package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +11 -1
  42. package/packages/@monomind/cli/dist/src/orgrt/session.js +32 -1
  43. package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +8 -8
  44. package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +53 -53
  45. package/packages/@monomind/cli/dist/src/output.d.ts +29 -29
  46. package/packages/@monomind/cli/dist/src/output.js +10 -2
  47. package/packages/@monomind/cli/dist/src/pricing/model-pricing.d.ts +1 -1
  48. package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
  49. package/packages/@monomind/cli/dist/src/ui/collector.mjs +20 -5
  50. package/packages/@monomind/cli/dist/src/ui/dashboard.html +465 -500
  51. package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
  52. package/packages/@monomind/cli/dist/src/ui/orgs.html +21 -52
  53. package/packages/@monomind/cli/dist/src/ui/server.mjs +174 -164
  54. package/packages/@monomind/cli/package.json +12 -16
  55. package/packages/@monomind/cli/scripts/publish.sh +6 -0
  56. package/scripts/generate-agent-avatars.mjs +3 -3
  57. package/packages/@monomind/cli/dist/src/orgrt/live.html +0 -56
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mastermind-createorg
3
- description: Mastermind createorg — design, configure, and persist an autonomous agent organization with named roles, hierarchy, and communication topology. Supports optional --schedule flag for self-scheduling loop orgs.
3
+ description: Mastermind createorg — design and persist an autonomous agent organization (Org Runtime v2) as a `.monomind/orgs/<name>.json` config that `monomind org run/serve` loads directly. Supports optional --schedule flag for daemon-scheduled orgs.
4
4
  type: domain-skill
5
5
  default_mode: confirm
6
6
  ---
@@ -9,6 +9,8 @@ default_mode: confirm
9
9
 
10
10
  This skill is invoked by `mastermind:createorg` or directly via `/mastermind:createorg`.
11
11
 
12
+ Org Runtime v2 (`packages/@monomind/cli/src/orgrt/`) is a Node daemon, not a Task-tool-spawned boss agent. Every role in the config becomes a live SDK agent session (`@anthropic-ai/claude-agent-sdk` `query()`) the moment the org starts — there is no task board, no per-role generated `.claude/agents/*.md` file, and no communication-topology array. Roles address each other directly with the `org_send` tool using their `id` (or `<org>:<id>` cross-org). This skill's only job is to produce a config that validates against `OrgDefSchema` (`packages/@monomind/cli/src/orgrt/types.ts`).
13
+
12
14
  ---
13
15
 
14
16
  ## Inputs
@@ -16,33 +18,13 @@ This skill is invoked by `mastermind:createorg` or directly via `/mastermind:cre
16
18
  - `brain_context`: BRAIN CONTEXT block (injected by command, or loaded below if standalone)
17
19
  - `prompt`: goal and/or role description for this org
18
20
  - `org_name`: desired name for the org (slug, e.g. `content-team`); constrained to `[a-z0-9-]`
19
- - `roles_desc`: optional explicit role list from user (e.g. "boss, content writer, reviewer, marketer, designer, middle manager")
20
- - `schedule`: optional schedule string, e.g. `"every 30 minutes"`, `"every hour"`, `"every 2 hours"`, `"daily"`. When provided, generates a self-scheduling loop org.
21
+ - `roles_desc`: optional explicit role list from user (e.g. "boss, content writer, reviewer, marketer, designer")
22
+ - `schedule`: optional schedule string in daemon format — `"<N>s"`, `"<N>m"`, or `"<N>h"` (e.g. `"30m"`, `"2h"`). When provided, the org is picked up by `monomind org serve` on its own interval; omit for a one-shot `monomind org run`.
23
+ - `budget_tokens`: optional total token budget for the org run (default 1,000,000 — split evenly across roles by the daemon)
21
24
  - `mode`: auto | confirm
22
25
  - `session_id`: session ID passed by command wrapper (snake_case input)
23
26
  - `caller`: command | master
24
27
 
25
- ### Schedule parsing (when `--schedule` is present)
26
-
27
- Convert the schedule string to `poll_interval_minutes`:
28
-
29
- | Schedule string | Minutes |
30
- |---|---|
31
- | `every N minutes` | N |
32
- | `every minute` | 1 |
33
- | `every hour` | 60 |
34
- | `every N hours` | N × 60 |
35
- | `daily` / `every day` | 1440 |
36
- | `every N days` | N × 1440 |
37
-
38
- ```bash
39
- # Example: "every 30 minutes" → poll_interval_minutes=30
40
- # "every 2 hours" → poll_interval_minutes=120
41
- # "daily" → poll_interval_minutes=1440
42
- ```
43
-
44
- Store the parsed value as `poll_interval_minutes` for use in Steps 4 and 6.7.
45
-
46
28
  ---
47
29
 
48
30
  ## Step 0 — Brain Load (standalone only)
@@ -59,7 +41,7 @@ Run intake from `_intake.md` if `prompt` is vague (stop at Q3, domain is `ops`).
59
41
 
60
42
  If `org_name` is not provided, extract the most prominent product/team noun from `prompt`, slugify it (lowercase, spaces → hyphens, strip non-`[a-z0-9-]` chars), and confirm with the user. Fallback: `org-<YYYYMMDD>`.
61
43
 
62
- Reject any `org_name` that does not match `^[a-z0-9][a-z0-9-]{0,63}$`.
44
+ Reject any `org_name` that does not match `^[a-z0-9][a-z0-9-]{0,63}$` (the CLI's own `ORG_NAME_RE` in `org.ts` is slightly looser — `^[a-z0-9][a-z0-9_-]*$/i` — but this skill's stricter slug is always a valid subset).
63
45
 
64
46
  ---
65
47
 
@@ -67,330 +49,77 @@ Reject any `org_name` that does not match `^[a-z0-9][a-z0-9-]{0,63}$`.
67
49
 
68
50
  Parse `roles_desc` (if provided) into a list of role titles. If not provided, derive a set of roles from `prompt` by identifying the human functions needed to achieve the goal.
69
51
 
70
- **Required roles to include when deriving roles from the prompt** (**skip this rule for persona-based orgs** where the characters themselves define the structure; do not inject a generic coordinator into a celebrity panel):
71
- - A coordinator/boss role that owns the goal and makes final decisions
52
+ **Required roles to include when deriving roles from the prompt** (**skip this rule for persona-based orgs**, see below, where the characters themselves define the structure):
53
+ - A coordinator/boss role that owns the goal exactly one role with `reports_to: null`
72
54
  - At least one executor role that does the primary work
73
- - A reviewer or QA role if quality output is implied
74
- - A communication layer (middle manager) if team size ≥ 4
75
-
76
- **If the user provided an explicit `roles_desc`, their list is authoritative — never silently inject roles into it.** If a structural role above is missing (e.g. no coordinator, or ≥4 roles with no middle manager), in confirm mode note the gap in the Step 5 plan as a one-line suggestion ("Suggestion: add a coordinator — none in your list; reply 'add it' or 'go' to keep as-is"); in auto mode, create exactly the roles listed.
77
-
78
- **Step 2.2 — Detect the org's domain.** From the goal/prompt, classify the org's domain in one or two words (e.g. `software-engineering`, `content-marketing`, `sports-analytics`, `legal`, `medical`, `finance`). This drives agent-type resolution below.
55
+ - A reviewer role if quality output is implied
79
56
 
80
- > **Check Step 2.3 (Persona / Character Detection) BEFORE resolving agent types.** If the org is persona-based (roles are named real people, celebrities, or fictional characters), skip the roster below for those roles and follow Step 2.3 instead.
57
+ **If the user provided an explicit `roles_desc`, their list is authoritative never silently inject roles into it.** If a structural role above is missing (e.g. no coordinator), in confirm mode note the gap in the Step 4 plan as a one-line suggestion; in auto mode, create exactly the roles listed and let the first one default to boss (Step 2.2).
81
58
 
82
- **Step 2.4Resolve each role's `agent_type` (domain-fit first).**
59
+ **Step 2.1Assign `id`, `title`, `type`, `reports_to`.**
83
60
 
84
- The premade roster below is a set of **candidates, not defaults**. Every premade agent is domain-scoped `reviewer` reviews *code*, `tester` tests *software*, `Content Creator` writes *marketing content*. A keyword match alone is never enough to use one; the agent's domain must also match the role's actual job in this org.
61
+ - `id`: slug derived from title (`Content Writer` `content-writer`)
62
+ - `title`: display title, as given
63
+ - `type`: `"boss"` for the single root role (the daemon looks for `type === 'boss' || reports_to === null`, falling back to `roles[0]` if neither matches), `"specialist"` for everyone else — or a domain-fit synonym like `"reviewer"` / `"researcher"` purely for readability; the runtime treats `type` as free text except for the `"boss"` match
64
+ - `reports_to`: the boss's `id` for direct reports, `null` only for the boss; for larger teams a middle layer can report to another non-boss role — the runtime does not enforce a shape beyond "each role's `reports_to` must be another role's `id` or null"
85
65
 
86
- | Premade agent slug | Its domain | Candidate for role keywords |
87
- |---|---|---|
88
- | `coordinator` | any (domain-neutral orchestration) | boss / ceo / director / lead / chief |
89
- | `Project Shepherd` | any (domain-neutral coordination) | middle manager / manager |
90
- | `researcher` | general research | researcher (broad research roles only) |
91
- | `coder` | software | engineer / developer / coder / dev |
92
- | `reviewer` | software — code review | code reviewer |
93
- | `tester` | software — QA/testing | qa / tester (of software) |
94
- | `Content Creator` | content/marketing | content writer / copywriter |
95
- | `Growth Hacker` | marketing | marketer / growth |
96
- | `SEO Specialist` | search marketing | seo / search |
97
- | `Social Media Strategist` | social marketing | social media / social |
98
- | `Product Manager` | product/software | product / product manager |
99
- | `Monodesign` | design/UI/brand | designer / ui / ux / visual |
66
+ Exactly one role must have `reports_to: null`. If the user's role list has none, promote the first/most senior-sounding role. If it has more than one, ask which is the root (confirm mode) or promote the first one listed (auto mode).
100
67
 
101
- **Resolution procedureapply to each role in order:**
68
+ **Step 2.2Persona / Character Detection.**
102
69
 
103
- 1. **Persona role** (Step 2.3) coin the character slug; skip the roster.
104
- 2. Find a roster candidate by role keyword.
105
- 3. **Domain-fit gate:** accept the candidate ONLY if its domain column matches what this role actually does in *this org's* domain (Step 2.2). A "reviewer" in a football-analysis org reviews match analyses, not code — `reviewer` fails the gate. An "analyst" there analyzes matches, not general research — `researcher` fails too. When in doubt, the gate fails.
106
- 4. **Gate passed, generic role** → reuse the premade slug as-is.
107
- 5. **Gate passed, use-case-specific role** (e.g. a content writer for a niche audience) → still reuse the premade slug; put the specialization into the role's `responsibilities` and the org goal (runorg passes both to the agent). Do not fork the definition for mere topical focus.
108
- 6. **No candidate, or gate failed** → coin a role-specific slug from the role title (`Football Analyst` → `football-analyst`, `Court Reporter` → `court-reporter`, `Churn Analyst` → `churn-analyst`, devbot `Orchestrator` → `devbot-orchestrator`) and fully generate its definition in Step 2.5 — skills, instructions, and I/O contracts all authored for this role in this org's domain. If a rejected candidate was structurally close, its definition may seed the *shape* of the generated one, but every line must be rewritten for the actual domain.
109
- 7. `general-purpose` is a last resort, only when no sensible slug applies. Never map an editor/content-reviewer role to `reviewer` — that agent is code review; coin `content-editor` (or similar) and generate.
70
+ A role is **persona-based** if its title is a named real person, a well-known fictional character, or a celebrity/historical figure referred to by name. An org is persona-based if ≥50% of its roles are character names, or the goal/prompt contains `panel`, `debate`, `simulation`, `roleplay`, `celebrity`, `character`, `virtual [name]`, `impersonate`, `as [name]`.
110
71
 
111
- **A coined slug + generated definition always beats a premade agent whose system prompt describes a different job.** runorg and the dashboard load whatever definition matches `agent_type` — a football org whose analyst is `researcher` or whose reviewer is `reviewer` gets the wrong instructions at run time. That is a bug, not a fallback.
72
+ Persona roles work the same as any other role in v2 there is no separate `agent_type`/subagent registry to resolve against. Put the character depth directly into `responsibilities` (the only field `buildRolePrompt` — `orgrt/session.ts:27-39` actually feeds into the agent's role briefing): write 3-6 specific, voice-defining responsibilities drawn from the character's known career, positions, and communication style, not generic duties. For a living public figure, base it on documented public behavior — do not invent positions they haven't taken.
112
73
 
113
74
  ---
114
75
 
115
- ## Step 2.3 — Persona / Character Detection (run BEFORE the Step 2.4 resolution above)
76
+ ## Step 2.3 — Optional Per-Role Settings
116
77
 
117
- **Before resolving agent types via Step 2.4, detect whether this org is persona-based:**
78
+ For any role that needs non-default behavior, set (all optional omit to inherit defaults):
118
79
 
119
- A role is **persona-based** if its title is:
120
- - A named real person (e.g. "Donald Trump", "Elon Musk", "Steve Jobs")
121
- - A well-known fictional character (e.g. "Sherlock Holmes", "Tony Stark")
122
- - A celebrity, historical figure, or public persona referred to by name
80
+ - `adapter_config.model`: a model id (e.g. `"claude-opus-4-7"`) default is `"claude-sonnet-4-5"` (`orgrt/types.ts:33`)
81
+ - `provider`: `{ kind: "subscription" | "api-key" | "base-url" | "bedrock" | "vertex", apiKeyEnv?, baseUrl?, authTokenEnv? }` — default `subscription` (local Claude Code login); only set this if the role needs a different provider/credential
82
+ - `policy`: `{ allowTools?, denyTools?, fileWrite?, fileRead?, webAllow?, maxTokens? }` — glob-based tool/file/web restrictions for that role; leave unset unless the user asked for sandboxing
123
83
 
124
- An org is **persona-based** if 50% of its roles are character names, OR the goal/prompt contains keywords like: `panel`, `debate`, `simulation`, `roleplay`, `celebrity`, `character`, `virtual [name]`, `impersonate`, `as [name]`.
125
-
126
- **If persona-based:**
127
-
128
- 1. **Ignore the premade roster entirely for these roles.** Do NOT map "Donald Trump" → `coder`, "Elon Musk" → `researcher`, etc.
129
-
130
- 2. **Coin a character-specific `agent_type` slug** from the character's name:
131
- - `Donald Trump` → `donald-trump`
132
- - `Sherlock Holmes` → `sherlock-holmes`
133
- - `Steve Jobs` → `steve-jobs`
134
-
135
- 3. **Derive skills and expertise from what is publicly known about that person**, not from generic software roles. Use your knowledge of the person's career, public persona, communication style, known positions, and characteristic behaviors. For example:
136
- - Donald Trump: negotiation, real-estate dealmaking, brand promotion, confrontational rhetoric, media manipulation, self-promotion, political populism
137
- - Elon Musk: first-principles engineering, disruptive product vision, risk-taking, rapid iteration, social media provocation, space/EV technology
138
- - A fictional detective: deductive reasoning, observation, criminal psychology, pattern recognition
139
-
140
- 4. **The generated agent definition** (written in Step 2.5) must read as that character — their voice, stance, known views, communication style. It is a character simulation, not a generic role.
141
-
142
- 5. **Non-character roles in the same org** (e.g. "Moderator", "Audience") go through the normal Step 2.4 resolution (roster + domain-fit gate, or a role-coined slug).
143
-
144
- **If NOT persona-based:** proceed normally with Step 2.4.
84
+ Do not invent values for these only populate a field the user actually specified or clearly implied (e.g. "the researcher should use Opus" that role's `adapter_config.model`).
145
85
 
146
86
  ---
147
87
 
148
- ## Step 2.5Complete Every Agent's Specification (generate what's missing)
149
-
150
- **This is the step that makes each created agent actually work.** A role is only usable if it has: skills, an instruction document (system prompt), an input contract, and an output contract. Most of these are missing from a bare role description — **generate them, tailored to the specific agent, rather than leaving them blank.**
151
-
152
- **For persona/character roles** (identified in Step 2.3): the generated definition must embody the character. The system prompt should open with "You are [Character Name]" and describe their personality, known views, communication style, and behavioral quirks drawn from public knowledge. Skills must reflect their real-world expertise and traits, not generic software capabilities. If the character is a living public figure, base the portrayal on documented public behavior and statements — do not invent positions they haven't taken.
153
-
154
- For **each** role, do the following:
88
+ ## Step 3Build Org Config
155
89
 
156
- **1. Check whether a usable agent definition already exists.**
157
- ```bash
158
- # Match by frontmatter `name:` first, then by filename slug, anywhere under .claude/agents
159
- at="<agent_type>"
160
- existing=$(grep -rils "^name:[[:space:]]*${at}\$" .claude/agents 2>/dev/null | head -1)
161
- [ -z "$existing" ] && existing=$(find .claude/agents -iname "${at}.md" 2>/dev/null | head -1)
162
- ```
163
- A definition is **usable** only if it exists AND it passed the Step 2.4 domain-fit gate (its instructions describe this role's actual job in this org's domain). A curated def about a different domain (e.g. `reviewer.md` = code review, applied to a "Court Reporter" or "Match Reviewer") does **not** count as usable — treat it as missing, coin a role-specific `agent_type` per Step 2.4 rule 6, and generate.
164
-
165
- **2. If no usable definition exists, generate one** at `.claude/agents/generated/<agent_type>.md`. Author it specifically for this role and this org's goal — never a generic stub. Use this shape:
166
-
167
- ```markdown
168
- ---
169
- name: <agent_type>
170
- description: <one line — who this agent is and what it does>
171
- capability:
172
- role: <agent_type>
173
- goal: <one sentence: the agent's standing objective in this org>
174
- version: "1.0.0"
175
- expertise: # 4–6 concrete SKILLS this role needs to do its job well
176
- - <skill>
177
- - <skill>
178
- task_types: # 3–5 kinds of work it performs
179
- - <task-type>
180
- input_type: <what this agent consumes — who/what it receives, derived from its inbound communication edges + responsibilities>
181
- output_type: <what this agent produces — the artifact it hands off or reports, derived from its outbound edges + responsibilities>
182
- model_preference: sonnet
183
- termination: <the condition under which this agent's job is done>
184
- ---
185
-
186
- # <Role Title>
187
-
188
- <1–2 sentences: the agent's identity and stance.>
189
-
190
- ## Core Responsibilities
191
- <the role's responsibilities, expanded into numbered, actionable duties>
192
-
193
- ## Operating Guidelines
194
- <3–6 concrete rules that keep this agent doing the right thing for its domain — what to always do, what never to do, how to handle missing inputs>
195
-
196
- ## Communication
197
- - **Receives (input)**: <sources + what, from the inbound edges in Step 3>
198
- - **Sends (output)**: <targets + what, from the outbound edges in Step 3>
199
- - **Protocol**: <direct / via manager; who it reports to>
200
-
201
- ## Quality Bar
202
- <one sentence defining "good output" for this role, so the agent can self-check>
203
- ```
204
-
205
- Generate this content with real domain reasoning — the `expertise`, `input_type`, `output_type`, and instruction body must be specific to *this* agent (a prosecutor's skills are not a judge's). Reuse a generated def across roles of the same `agent_type` (don't regenerate if you just created it this run).
206
-
207
- **3. Populate the org role.** Set the role's `skills` array to the def's `expertise` list (so the org config is self-describing), and keep `agent_type` pointing at the (possibly newly coined) type. Never leave `skills: []` when expertise was generated.
208
-
209
- **4. Note generated files** for the Step 8 artifacts list.
210
-
211
- The dashboard agent drawer and `runorg` both read these definitions (matched by `agent_type`), so generating them here is what makes the Roles/Skills/instructions show up *and* what gives each spawned agent its real instructions at run time.
212
-
213
- ---
214
-
215
- ## Step 2.6 — COMPLETENESS GATE (BLOCKING — do not proceed to Step 3 until all checks pass)
216
-
217
- This gate prevents saving an org where the dashboard will show "No instruction document" or blank skills. **Run these checks now — one Bash call per role:**
218
-
219
- **Check 0 — domain fit (judgment, per role using a premade slug):** for every role whose `agent_type` comes from the Step 2.4 roster, re-confirm the gate: the premade agent's definition describes this role's actual job in *this org's* domain. If not, go back to Step 2.4 rule 6 — coin a slug and generate. An org outside the roster's domains (sports, legal, medical, etc.) should have **zero domain-scoped** roster slugs (`coder`, `reviewer`, `tester`, `researcher`, etc.); domain-neutral slugs (`coordinator`, `Project Shepherd`) and roles whose *function itself* matches a premade (e.g. a content writer publishing that org's output → `Content Creator`, per rule 5) remain valid reuses.
220
-
221
- For each role in the org:
222
-
223
- ```bash
224
- # Check 1 — agent_type is set
225
- role_id="<role_id>"
226
- agent_type="<agent_type>"
227
- [ -z "$agent_type" ] && echo "FAIL: role '$role_id' has no agent_type" && exit 1
228
-
229
- # Check 2 — definition file exists on disk
230
- def_file=".claude/agents/generated/${agent_type}.md"
231
- # Also check non-generated paths
232
- fallback=$(find .claude/agents -iname "${agent_type}.md" 2>/dev/null | head -1)
233
- if [ ! -f "$def_file" ] && [ -z "$fallback" ]; then
234
- echo "FAIL: no agent definition file for '$agent_type' — generate it now before continuing"
235
- exit 1
236
- fi
237
- echo "OK: $role_id → $agent_type ✓"
238
- ```
239
-
240
- If any check fails: go back to Step 2.5 and generate the missing file before proceeding. Do not skip this check.
241
-
242
- **Also verify the `skills` array for each role is non-empty (≥3 items).** If `skills: []` for any role, pull the expertise from the generated definition file and populate it now.
243
-
244
- ---
245
-
246
- ## Step 3 — Suggest Communication Topology
247
-
248
- Determine topology from team size:
249
- - 1–3 roles → `mesh` (all communicate directly)
250
- - 4–6 roles → `star` (boss at center, all report to boss)
251
- - 7+ roles → `hierarchical` (boss → middle manager(s) → executors)
252
-
253
- Build directed communication edges:
254
-
255
- **Communication edge types:**
256
- - `command`: top-down direction of work
257
- - `report`: bottom-up status / output delivery
258
- - `feedback`: peer review or critique
259
- - `handoff`: one role passes output directly to next role in sequence
260
-
261
- **Default edges for a 6-role org (boss, content writer, content reviewer, marketer, designer, middle manager):**
262
- ```
263
- boss → middle_manager (command)
264
- middle_manager → content_writer (command)
265
- middle_manager → designer (command)
266
- middle_manager → marketer (command)
267
- content_writer → content_reviewer (handoff)
268
- content_reviewer → middle_manager (report)
269
- designer → middle_manager (report)
270
- marketer → middle_manager (report)
271
- middle_manager → boss (report)
272
- boss → middle_manager (feedback)
273
- ```
274
-
275
- Adjust for the actual roles in this run. Assign `reports_to` on each role using the derived topology.
276
-
277
- **Completeness rules (every role must be properly wired — no orphans):**
278
- - Every executor role has **≥1 inbound edge** (how work reaches it — usually a `command`) and **≥1 outbound edge** (how its output leaves — usually a `report` or `handoff`).
279
- - Where one role's output is another's input, connect them with a `handoff` in that direction (e.g. clerk → counsel; writer → editor). Make sequential producer→consumer chains explicit.
280
- - The coordinator/boss has an inbound `report` from each role it commands, so results flow back up.
281
- - Peer roles that critique each other get `feedback` edges; adversarial pairs (e.g. prosecutor ↔ defender) get reciprocal `handoff` edges.
282
- - After building edges, **derive each role's input/output contract from them**: a role's `input_type` summarizes who/what its inbound edges deliver; its `output_type` summarizes what its outbound edges carry. Feed these into the generated definition from Step 2.5 so the spec and the topology agree.
283
-
284
- A role that ends up with no inbound or no outbound edge is a bug — re-examine the topology before saving.
285
-
286
- ---
287
-
288
- ## Step 3.5 — TOPOLOGY VALIDATION GATE (BLOCKING — do not proceed to Step 4 until all checks pass)
289
-
290
- Build the communication array now, then validate it with these checks:
291
-
292
- ```bash
293
- # Check 1 — at least one edge exists
294
- edges='<communication_json_array>'
295
- edge_count=$(echo "$edges" | jq 'length')
296
- [ "$edge_count" -eq 0 ] && echo "FAIL: communication array is empty — define edges now" && exit 1
297
-
298
- # Check 2 — every role has at least one inbound OR outbound edge
299
- role_ids=("<id1>" "<id2>" ... ) # all role IDs
300
- for rid in "${role_ids[@]}"; do
301
- has_edge=$(echo "$edges" | jq --arg r "$rid" '[.[] | select(.from==$r or .to==$r)] | length')
302
- [ "$has_edge" -eq 0 ] && echo "FAIL: role '$rid' has no communication edges — it is an orphan" && exit 1
303
- done
304
-
305
- # Check 3 — every non-boss executor role has at least one inbound edge (receives work)
306
- # and at least one outbound edge (delivers output)
307
- echo "OK: topology validated — $edge_count edges, all roles wired"
308
- ```
309
-
310
- If any check fails: go back to Step 3 and add the missing edges. **The `communication` array must be non-empty in the saved JSON** — the dashboard Chart tab draws its arrows from this array; an empty array means a blank chart with isolated nodes and no connection lines.
311
-
312
- ---
313
-
314
- ## Step 4 — Build Org Config
315
-
316
- Produce an org config object using the resolved topology (not hardcoded to `hierarchical`).
317
-
318
- Ask the user (or infer from prompt) for the optional Paperclip-style fields:
319
- - **Budget**: max token budget for this org run (e.g. 500000 tokens). Use `unlimited` if not specified.
320
- - **Governance**: approval policy — `auto` (agents act freely) | `board` (sensitive actions require `/mastermind:approve`) | `strict` (all external actions need approval)
321
- - **Adapter**: which AI model/adapter the CEO agent should use (e.g. `claude-sonnet-4-6`, `claude-opus-4-7`). Default: `claude-sonnet-4-6`.
90
+ Produce an org config object matching `OrgDefSchema` exactly:
322
91
 
323
92
  ```json
324
93
  {
325
94
  "name": "<org_name>",
326
95
  "goal": "<the goal the org exists to achieve>",
327
- "created_at": "<ISO8601>",
328
- "mode": "daemon",
329
- "topology": "<mesh | star | hierarchical — from Step 3>",
330
- "status": "<'stopped' if --schedule provided; 'active' otherwise>",
96
+ "status": "stopped",
97
+ "schedule": "<'<N>m' | '<N>h' | '<N>s' from Step 0 input, or null for a one-shot org>",
98
+ "run_config": {
99
+ "max_concurrent_agents": 4,
100
+ "budget_tokens": "<budget_tokens input, or 1000000 default>",
101
+ "memory_namespace": "org:<org_name>",
102
+ "max_turns_per_message": 30
103
+ },
331
104
  "roles": [
332
105
  {
333
106
  "id": "<slug>",
334
107
  "title": "<display title>",
335
- "agent_type": "<subagent_type slug from Step 2.3 character slug for persona roles, or from the Step 2.4 resolution (reused premade or coined+generated) for functional roles>",
336
- "responsibilities": ["<1-3 bullet responsibilities>"],
337
- "reports_to": "<role id or null>",
338
- "skills": ["<populated from the generated def's expertise in Step 2.5 — never left empty>"],
339
- "adapter_config": {
340
- "model": "<claude model id>",
341
- "max_tokens": 8192
342
- }
108
+ "type": "boss | specialist | <domain synonym>",
109
+ "reports_to": "<role id, or null for the single boss>",
110
+ "responsibilities": ["<3-6 specific duties — this text becomes part of the agent's role briefing>"]
343
111
  }
344
- ],
345
- "communication": [
346
- {
347
- "from": "<role_id>",
348
- "to": "<role_id>",
349
- "type": "command | report | feedback | handoff",
350
- "protocol": "direct"
351
- }
352
- ],
353
- "governance": {
354
- "policy": "auto | board | strict",
355
- "approvals_file": ".monomind/orgs/<org_name>-approvals.json"
356
- },
357
- "board_id": "<uuid — filled in Step 6 after board creation>",
358
- "todo_col_id": "<uuid — filled in Step 6>",
359
- "doing_col_id": "<uuid — filled in Step 6>",
360
- "done_col_id": "<uuid — filled in Step 6>",
361
- "board_space": "<org_name>",
362
- "board_name": "org-tasks",
363
- "run_config": {
364
- "checkpoint_interval_min": 30,
365
- "max_concurrent_agents": 6,
366
- "memory_namespace": "org:<org_name>",
367
- "budget_tokens": "<number or 0 for unlimited>",
368
- "alert_threshold": 0.8,
369
- "ceo_adapter": "<model id>"
370
- },
371
- "loop": "<only included when --schedule was provided; see below>"
112
+ ]
372
113
  }
373
114
  ```
374
115
 
375
- **If `--schedule` was provided**, include these two additional top-level fields in the org config:
116
+ `status` starts `"stopped"` regardless of whether `schedule` is set the org does not run until `monomind org run <name>` (one-shot) or `monomind org serve` (picks up any org whose `schedule` is set) is invoked.
376
117
 
377
- ```json
378
- {
379
- "status": "stopped",
380
- "loop": {
381
- "poll_interval_minutes": "<parsed from schedule string>",
382
- "last_run": null,
383
- "next_run": null,
384
- "run_prompt_file": ".monomind/loops/<org_name>.md"
385
- }
386
- }
387
- ```
388
-
389
- `status` starts as `"stopped"`. The org does not run until `/mastermind:runorg --org <org_name>` is called (which transitions it to `"active"`).
118
+ Only include `adapter_config`, `provider`, or `policy` on a role when Step 2.3 populated them for it — leave them out entirely rather than writing empty objects.
390
119
 
391
120
  ---
392
121
 
393
- ## Step 5 — Show Plan and Confirm (confirm mode)
122
+ ## Step 4 — Show Plan and Confirm (confirm mode)
394
123
 
395
124
  Render the org plan in a clear human-readable format:
396
125
 
@@ -400,40 +129,21 @@ Render the org plan in a clear human-readable format:
400
129
  ║ GOAL: <goal> ║
401
130
  ╚══════════════════════════════════════════════════╝
402
131
 
403
- ROLES (N roles — all must have agent_type + skills before "go")
132
+ ROLES (N roles — exactly one boss, every reports_to resolves to a real role id)
404
133
  ─────
405
- • [boss] CEO / Boss
406
- Agent type: coordinator
407
- Skills: strategic oversight, decision-making, org management
408
- Reports to: (none top of hierarchy)
409
- Responsibilities: Strategic oversight, final approval
410
- Definition file: .claude/agents/coordinator.md ✓
411
-
412
- • [middle_manager] Middle Manager
413
- Agent type: project-shepherd
414
- Skills: sprint planning, cross-team coordination, status tracking
415
- Reports to: boss
416
- Responsibilities: Sprint planning, cross-team coordination
417
- Definition file: .claude/agents/generated/project-shepherd.md ✓
418
-
419
- ... (all roles — each showing agent_type, skills, and definition file status)
420
-
421
- COMMUNICATION TOPOLOGY (N edges — must be non-zero)
422
- ──────────────────────
423
- boss → middle_manager (command)
424
- middle_manager → content_writer (command)
425
- content_writer → content_reviewer (handoff)
426
- content_reviewer → middle_manager (report)
427
- middle_manager → boss (report)
428
- ... (all edges — every role must appear here at least once)
134
+ • [boss] CEO / Boss (type: boss, reports_to: none)
135
+ Responsibilities: Strategic oversight, final decisions, coordinates the team via org_send
136
+
137
+ [content_writer] Content Writer (type: specialist, reports_to: boss)
138
+ Responsibilities: Draft posts per the content calendar, hand off to content_reviewer
139
+
140
+ ... (all roles)
429
141
 
430
142
  SETTINGS
431
143
  ────────
432
- Topology: <derived> | Mode: persistent daemon
433
- Memory: org:<org_name> | Board: <org_name>/org-tasks
434
- Checkpoint every: 30 min | Max agents: 6
435
- Schedule: <"every <poll_interval_minutes> minutes" if --schedule; otherwise "manual (no auto-schedule)">
436
- Status: <"stopped (run /mastermind:runorg --org <org_name> to activate)" if --schedule; otherwise "—">
144
+ Budget: <run_config.budget_tokens> tokens (split evenly across N roles)
145
+ Memory namespace: org:<org_name>
146
+ Schedule: <"every <N> <unit>" if schedule set; otherwise "manual — run with `monomind org run <org_name>`">
437
147
 
438
148
  Type "go" to save this org, or describe changes.
439
149
  ```
@@ -444,13 +154,10 @@ If the user requests changes, apply them and re-render. Repeat until confirmed.
444
154
 
445
155
  ---
446
156
 
447
- ## Step 6 — Save Org Config
448
-
449
- Set shell variables from the resolved inputs (use the actual `org_name` value from Step 1 and `session_id` input):
157
+ ## Step 5 — Save Org Config
450
158
 
451
159
  ```bash
452
- org_name="<resolved org name from Step 1>" # e.g. "content-team"
453
- session_id="<session_id input>" # passed by command wrapper
160
+ org_name="<resolved org name from Step 1>"
454
161
  orgJson=".monomind/orgs/${org_name}.json"
455
162
  mkdir -p .monomind/orgs
456
163
  ```
@@ -458,355 +165,53 @@ mkdir -p .monomind/orgs
458
165
  Write the confirmed org config as JSON using `jq` to guarantee valid encoding:
459
166
 
460
167
  ```bash
461
- # Build the config JSON from the confirmed org plan and write atomically.
462
168
  # Set shell variables from the confirmed plan before running this block:
463
- # governance_policy — "auto" | "board" | "strict" (from Step 4)
464
- # budget_tokens_val — integer or 0 for unlimited (from Step 4)
465
- # ceo_adapter — model id string (from Step 4)
466
- # poll_interval_minutes — integer (from --schedule), or "" if no schedule
169
+ # goal, schedule_val ("" if none), budget_tokens_val, roles_json (JSON array matching the role shape above)
467
170
  jq -n \
468
171
  --arg name "$org_name" \
469
172
  --arg goal "$goal" \
470
- --arg topology "$topology" \
173
+ --arg schedule "${schedule_val:-}" \
174
+ --argjson budget_tokens "${budget_tokens_val:-1000000}" \
471
175
  --argjson roles "$roles_json" \
472
- --argjson communication "$communication_json" \
473
- --arg gov_policy "${governance_policy:-auto}" \
474
- --argjson budget_tokens "${budget_tokens_val:-0}" \
475
- --arg ceo_adapter "${ceo_adapter:-claude-sonnet-4-6}" \
476
- '{name:$name,goal:$goal,mode:"daemon",topology:$topology,status:"active",
477
- created_at:(now|todate),roles:$roles,communication:$communication,
478
- governance:{policy:$gov_policy,approvals_file:(".monomind/orgs/"+$name+"-approvals.json")},
479
- board_space:$name,board_name:"org-tasks",
480
- run_config:{
481
- checkpoint_interval_min:30,
482
- max_concurrent_agents:6,
483
- memory_namespace:("org:"+$name),
484
- budget_tokens:$budget_tokens,
485
- alert_threshold:0.8,
486
- ceo_adapter:$ceo_adapter
487
- }}' \
176
+ '{name:$name,goal:$goal,status:"stopped",
177
+ schedule:(if $schedule=="" then null else $schedule end),
178
+ run_config:{max_concurrent_agents:4,budget_tokens:$budget_tokens,
179
+ memory_namespace:("org:"+$name),max_turns_per_message:30},
180
+ roles:$roles}' \
488
181
  > "${orgJson}.tmp" && mv "${orgJson}.tmp" "$orgJson"
489
182
  ```
490
183
 
491
- **If `--schedule` was provided**, patch the saved config with `status` and `loop`:
492
-
493
- ```bash
494
- # Only run this block when poll_interval_minutes is set (i.e. --schedule was used)
495
- tmp="${orgJson}.tmp"
496
- jq \
497
- --argjson interval "$poll_interval_minutes" \
498
- --arg run_prompt_file ".monomind/loops/${org_name}.md" \
499
- '. + {
500
- status: "stopped",
501
- loop: {
502
- poll_interval_minutes: $interval,
503
- last_run: null,
504
- next_run: null,
505
- run_prompt_file: $run_prompt_file
506
- }
507
- }' \
508
- "$orgJson" > "$tmp" && mv "$tmp" "$orgJson"
509
- ```
510
-
511
- Create the monotask space, board, and default columns (space is required — abort before creating board if space fails):
512
- ```bash
513
- # Step 1 — Space (required first)
514
- space_id=$(monotask space list 2>/dev/null | awk -F' \| ' -v n="$org_name" '$2==n{print $1}' | head -1)
515
- [ -z "$space_id" ] && space_id=$(monotask space create "$org_name" 2>&1 | grep -oE '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
516
- [ -z "$space_id" ] && { echo "ERROR: Could not find or create space '$org_name' — verify monotask is installed (run: monotask --version)"; exit 1; }
517
-
518
- # Step 2 — Board (created only after space is confirmed)
519
- board_id=$(monotask board create "org-tasks" --json | jq -r '.id // empty')
520
- [ -z "$board_id" ] && { echo "ERROR: Failed to create monotask board"; exit 1; }
521
-
522
- # Step 3 — Link board to space immediately
523
- monotask space boards add "$space_id" "$board_id" >/dev/null 2>&1 || true
524
-
525
- # Step 4 — Columns
526
- todo_col_id=$(monotask column create "$board_id" "Todo" --json | jq -r '.id // empty')
527
- doing_col_id=$(monotask column create "$board_id" "Doing" --json | jq -r '.id // empty')
528
- done_col_id=$(monotask column create "$board_id" "Done" --json | jq -r '.id // empty')
529
- [ -z "$todo_col_id" ] && { echo "ERROR: Failed to create 'Todo' column on board $board_id"; exit 1; }
530
- [ -z "$doing_col_id" ] && { echo "ERROR: Failed to create 'Doing' column on board $board_id"; exit 1; }
531
- [ -z "$done_col_id" ] && { echo "ERROR: Failed to create 'Done' column on board $board_id"; exit 1; }
532
- ```
533
-
534
- Patch the saved org config with the board and column IDs:
535
- ```bash
536
- tmp="${orgJson}.tmp"
537
- jq --arg board_id "$board_id" \
538
- --arg todo_col_id "$todo_col_id" \
539
- --arg doing_col_id "$doing_col_id" \
540
- --arg done_col_id "$done_col_id" \
541
- '. + {board_id:$board_id,todo_col_id:$todo_col_id,doing_col_id:$doing_col_id,done_col_id:$done_col_id}' \
542
- "$orgJson" > "$tmp" && mv "$tmp" "$orgJson"
543
- ```
544
-
545
- **POST-SAVE VALIDATION (run immediately after saving — abort if either check fails):**
184
+ **POST-SAVE VALIDATION (run immediately after saving abort if any check fails):**
546
185
 
547
186
  ```bash
548
- # Check 1 — communication array is non-empty (dashboard Chart tab requires this for arrows)
549
- comm_count=$(jq '.communication | length' "$orgJson" 2>/dev/null || echo 0)
550
- if [ "$comm_count" -eq 0 ]; then
551
- echo "ERROR: Saved org has empty communication array dashboard Chart will show isolated nodes with no arrows."
552
- echo "Fix: go back to Step 3 and Step 3.5, define edges, then re-save."
187
+ # Check 1 — exactly one root role (reports_to null)
188
+ root_count=$(jq '[.roles[] | select(.reports_to == null)] | length' "$orgJson")
189
+ if [ "$root_count" -ne 1 ]; then
190
+ echo "ERROR: expected exactly one role with reports_to: null, found $root_count fix the roles array and re-save."
553
191
  exit 1
554
192
  fi
555
- echo "✓ Communication: $comm_count edges saved"
556
-
557
- # Check 2 — every role has agent_type set
558
- bad_roles=$(jq -r '.roles[] | select((.agent_type // "") == "") | .id' "$orgJson" 2>/dev/null)
559
- if [ -n "$bad_roles" ]; then
560
- echo "ERROR: These roles have no agent_type dashboard will show '?' for each:"
561
- echo "$bad_roles"
562
- echo "Fix: go back to Step 2 / Step 2.5 and set agent_type for each role, then re-save."
193
+ echo "✓ Exactly one root role"
194
+
195
+ # Check 2 — every non-root role's reports_to resolves to a real role id
196
+ bad_reports=$(jq -r '
197
+ ([.roles[].id]) as $ids |
198
+ [.roles[] | select(.reports_to != null and (.reports_to as $r | $ids | index($r) | not)) | .id]
199
+ | join(", ")' "$orgJson")
200
+ if [ -n "$bad_reports" ]; then
201
+ echo "ERROR: these roles have a reports_to that doesn't match any role id: $bad_reports"
563
202
  exit 1
564
203
  fi
565
- echo "✓ All roles have agent_type set"
566
-
567
- # Check 3 — every role has skills (non-empty array)
568
- empty_skills=$(jq -r '.roles[] | select((.skills // []) | length == 0) | .id' "$orgJson" 2>/dev/null)
569
- if [ -n "$empty_skills" ]; then
570
- echo "WARNING: These roles have empty skills arrays — dashboard Skills tab will show nothing:"
571
- echo "$empty_skills"
572
- echo "Fix: populate skills from each role's generated agent definition."
573
- fi
574
-
575
- echo "✓ Org config validated — org is ready to run"
576
- ```
577
-
578
- ---
579
-
580
- ## Step 6.7 — Generate Loop Prompt File (scheduled orgs only)
581
-
582
- **Skip this step if `--schedule` was NOT provided.**
583
-
584
- If `poll_interval_minutes` is set, generate the self-scheduling loop prompt at `.monomind/loops/<org_name>.md`.
585
-
586
- This file is the single source of truth for one scheduled iteration. It is passed verbatim as the `prompt` argument to `ScheduleWakeup` at the end of every iteration — the loop is self-perpetuating as long as `status == "active"`.
587
-
588
- **Loop prompt structure:**
204
+ echo "✓ All reports_to values resolve"
589
205
 
590
- The file must follow this exact template (substitute actual values for all `<placeholders>`):
206
+ # Check 3 schema sanity check via the CLI itself (parses with OrgDefSchema, same code path org run/serve use)
207
+ npx monomind@latest org list >/dev/null 2>&1 || echo "WARNING: could not verify via CLI — check .monomind/orgs manually"
591
208
 
592
- ````markdown
593
- # <org_name> — Loop Prompt
594
-
595
- **Controlled by:** `.monomind/orgs/<org_name>.json` → `status` field
596
- **Start:** `/mastermind:runorg --org <org_name>` (sets `status: "active"` and runs first iteration)
597
- **Stop:** `/mastermind:stoporg --org <org_name>` (sets `status: "stopped"` — next wakeup exits without rescheduling)
598
- **Pause (HIL):** set `status: "paused"` in `.monomind/orgs/<org_name>.json` — loop keeps waking up but skips work until status returns to `"active"`
599
-
600
- ---
601
-
602
- ## Step 0 — Status Gate (REQUIRED FIRST — do not skip)
603
-
604
- ```bash
605
- ORG_FILE=".monomind/orgs/<org_name>.json"
606
- LOOP_STATUS=$(jq -r '.status // "stopped"' "$ORG_FILE" 2>/dev/null || echo "stopped")
607
- ```
608
-
609
- - If `LOOP_STATUS == "active"` → continue to Step 1.
610
- - If `LOOP_STATUS == "paused"` → print "Org '<org_name>' is paused — skipping iteration. Jump directly to Schedule Next." Do NOT run Steps 1–N.
611
- - If anything else (including `"stopped"`) → print "Org '<org_name>' status is '$LOOP_STATUS' — exiting loop. **Do NOT call ScheduleWakeup.**" and stop.
612
-
613
- ---
614
-
615
- ## Step 1 — Record Iteration Start
616
-
617
- ```bash
618
- ORG_FILE=".monomind/orgs/<org_name>.json"
619
- tmp="${ORG_FILE}.tmp"
620
- jq '.loop.last_run = (now|todate)' "$ORG_FILE" > "$tmp" && mv "$tmp" "$ORG_FILE"
621
- REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
622
- CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
623
- # Unique run ID — used to thread all events in the Chat tab under one session
624
- RUN_ID="run-$(date -u +%Y%m%dT%H%M%S)"
625
- # Capture Claude project dir for per-agent token tracking
626
- CLAUDE_PROJECT_DIR="$HOME/.claude/projects/$(echo "$REPO_ROOT" | tr '/' '-' | sed 's/^-//')"
627
-
628
- # Comm helper — emits org:comms so Chat tab shows agent-to-agent messages
629
- _comm() {
630
- local _from="$1" _to="$2" _msg="$3"
631
- curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
632
- -H "Content-Type: application/json" \
633
- -d "$(jq -cn \
634
- --arg org "<org_name>" \
635
- --arg runId "$RUN_ID" \
636
- --arg from "$_from" \
637
- --arg to "$_to" \
638
- --arg msg "$_msg" \
639
- '{type:"org:comms",org:$org,runId:$runId,from:$from,to:$to,msg:$msg,ts:(now*1000|floor)}')" || true
640
- }
641
-
642
- # Register this run with the server — creates run file and enables Chat tab dropdown
643
- curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
644
- -H "Content-Type: application/json" \
645
- -d "$(jq -cn \
646
- --arg org "<org_name>" \
647
- --arg runId "$RUN_ID" \
648
- --arg goal "<goal>" \
649
- '{type:"run:start",org:$org,runId:$runId,goal:$goal,ts:(now*1000|floor)}')" || true
650
- ```
651
-
652
- ---
653
-
654
- ## [Org-specific iteration steps]
655
-
656
- <IMPORTANT: Generate the actual work steps here from the org's goal and roles. These are NOT generic placeholders — write real, actionable steps derived from the org's goal, roles, and communication topology.>
657
-
658
- <For a GitHub issue-resolver org, these would be: find next issue, claim it, implement, test, deploy, report.>
659
- <For a content org, these would be: check content calendar, assign writers, review drafts, publish.>
660
- <Derive from orgConfig.goal and orgConfig.roles[].responsibilities — be specific.>
661
-
662
- **REQUIRED — include these patterns at every agent handoff:**
663
-
664
- 1. **Before spawning each agent**, snapshot the Claude project JSONL files and emit a `_comm` from the dispatching role to the receiving role describing the task:
665
- ```bash
666
- JSONL_SNAP_<N>=$(ls -t "$CLAUDE_PROJECT_DIR"/*.jsonl 2>/dev/null | head -20 | sort)
667
- _comm "<dispatcher-role-id>" "<agent-role-id>" "Task: <what the agent is being asked to do>"
668
- ```
669
-
670
- 2. **After the agent returns**, emit a `_comm` from that agent back to its caller with the result summary, then emit its token usage:
671
- ```bash
672
- JSONL_SNAP_<N+1>=$(ls -t "$CLAUDE_PROJECT_DIR"/*.jsonl 2>/dev/null | head -20 | sort)
673
- NEW_JSONL=$(comm -13 <(echo "$JSONL_SNAP_<N>") <(echo "$JSONL_SNAP_<N+1>") | head -1)
674
- _comm "<agent-role-id>" "<dispatcher-role-id>" "Result: <one-sentence summary of what the agent returned>"
675
- if [ -n "$NEW_JSONL" ] && [ -f "$NEW_JSONL" ]; then
676
- USAGE=$(python3 -c "
677
- import json, sys
678
- tin=tout=0
679
- for l in open(sys.argv[1]):
680
- try:
681
- d=json.loads(l)
682
- u=d.get('message',{}).get('usage',{})
683
- tin+=u.get('input_tokens',0); tout+=u.get('output_tokens',0)
684
- except: pass
685
- cost=tin*3e-6+tout*15e-6
686
- print(json.dumps({'tokens_in':tin,'tokens_out':tout,'cost_usd':round(cost,6)}))
687
- " "$NEW_JSONL" 2>/dev/null || echo '{"tokens_in":0,"tokens_out":0,"cost_usd":0}')
688
- curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
689
- -H "Content-Type: application/json" \
690
- -d "$(echo "$USAGE" | jq \
691
- --arg org "<org_name>" \
692
- --arg role "<agent-role-id>" \
693
- --arg runId "$RUN_ID" \
694
- '. + {type:"agent:usage",org:$org,role:$role,runId:$runId,ts:(now*1000|floor|tostring|tonumber)}')" || true
695
- fi
696
- ```
697
-
698
- 3. Use the actual content from the agent's return value in the `_comm` `msg` field — not a generic placeholder. The Chat tab shows this text verbatim.
699
-
700
- 4. At cycle end (before Schedule Next), emit the completion comms and event:
701
- ```bash
702
- _comm "<boss-role-id>" "sys" "Cycle complete: <one-line summary of what was accomplished>"
703
- curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
704
- -H "Content-Type: application/json" \
705
- -d "$(jq -cn \
706
- --arg org "<org_name>" \
707
- --arg runId "$RUN_ID" \
708
- '{type:"org:cycle:complete",org:$org,runId:$runId,ts:(now*1000|floor)}')" || true
709
- ```
710
-
711
- ---
712
-
713
- ## Schedule Next (ONLY if status is active or paused)
714
-
715
- Re-check org status before rescheduling:
716
-
717
- ```bash
718
- ORG_FILE=".monomind/orgs/<org_name>.json"
719
- LOOP_STATUS=$(jq -r '.status // "stopped"' "$ORG_FILE" 2>/dev/null || echo "stopped")
720
- ```
721
-
722
- If `LOOP_STATUS == "active"` or `LOOP_STATUS == "paused"`:
723
-
724
- 1. Read this loop prompt file verbatim:
725
- ```bash
726
- LOOP_PROMPT=$(cat .monomind/loops/<org_name>.md)
727
- ```
728
-
729
- 2. Call `ScheduleWakeup` with:
730
- - `delaySeconds`: `<poll_interval_minutes * 60>`
731
- - `reason`: `"<org_name>: next scheduled poll (every <poll_interval_minutes> min)"`
732
- - `prompt`: the full contents of `$LOOP_PROMPT`
733
-
734
- 3. Update `next_run` in the org JSON:
735
- ```bash
736
- ORG_FILE=".monomind/orgs/<org_name>.json"
737
- tmp="${ORG_FILE}.tmp"
738
- next_ts=$(( $(date +%s) + <poll_interval_minutes * 60> ))
739
- next_iso=$(date -u -r "$next_ts" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
740
- || date -u -d "@$next_ts" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
741
- || python3 -c "import datetime; print(datetime.datetime.utcfromtimestamp($next_ts).strftime('%Y-%m-%dT%H:%M:%SZ'))")
742
- jq --arg next "$next_iso" '.loop.next_run = $next' "$ORG_FILE" > "$tmp" && mv "$tmp" "$ORG_FILE"
743
- ```
744
-
745
- 4. Emit `org:loop:scheduled` event:
746
- ```bash
747
- REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
748
- CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
749
- curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
750
- -H "Content-Type: application/json" \
751
- -d "$(jq -cn --arg org "<org_name>" --arg next "$next_iso" --arg proj "$REPO_ROOT" \
752
- '{type:"org:loop:scheduled",org:$org,next_run:$next,project:$proj,ts:(now*1000|floor)}')" || true
753
- ```
754
-
755
- If `LOOP_STATUS` is anything else (e.g. `"stopped"`) → print "Org '<org_name>' loop ended — not rescheduling." and exit.
756
- ````
757
-
758
- **Before writing: substitute ALL `<org_name>` tokens with the actual resolved org name string (the value from Step 1, e.g. `research-pod`), and all `<poll_interval_minutes>` tokens with the numeric value. These are template placeholders — the written file must contain no angle-bracket tokens. Every `ORG_FILE=".monomind/orgs/<org_name>.json"` becomes `ORG_FILE=".monomind/orgs/research-pod.json"`, every `cat .monomind/loops/<org_name>.md` becomes `cat .monomind/loops/research-pod.md`, etc. Leaving any `<...>` token unexpanded will cause shell failures at loop execution time.**
759
-
760
- **Write this file to disk:**
761
-
762
- ```bash
763
- mkdir -p .monomind/loops
764
- # Write the generated loop prompt (with all placeholders substituted)
765
- # to .monomind/loops/<org_name>.md (← substitute this path too)
766
- ```
767
-
768
- Use the Write tool (not Bash echo/cat) to write the file so the content is verbatim.
769
-
770
- The org-specific iteration steps (the block between Step 1 and "Schedule Next") must be **generated from the actual org** — goal, roles, responsibilities — not left as generic placeholders.
771
-
772
- ---
773
-
774
- ## Step 7 — Emit Dashboard Events
775
-
776
- Read values from the saved JSON file and emit two events: `domain:complete` (for the session stream) and `org:create` (so the dashboard Orgs panel registers the new org immediately):
777
-
778
- ```bash
779
- REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
780
- CTRL_URL=$(jq -r '.url // "http://localhost:4242"' "$REPO_ROOT/.monomind/control.json" 2>/dev/null || echo "http://localhost:4242")
781
- orgName=$(jq -r '.name' "$orgJson")
782
- goal_val=$(jq -r '.goal' "$orgJson")
783
- rolesCount=$(jq '.roles | length // 0' "$orgJson")
784
-
785
- # domain:complete — for session correlation
786
- curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
787
- -H "Content-Type: application/json" \
788
- -d "$(jq -cn \
789
- --arg session "$session_id" \
790
- --arg orgName "$orgName" \
791
- --arg goal "$goal_val" \
792
- --argjson rolesCount "$rolesCount" \
793
- '{type:"domain:complete",session:$session,domain:"ops",status:"complete",
794
- org:$orgName,goal:$goal,roles_count:$rolesCount,ts:(now*1000|floor)}')" || true
795
-
796
- # org:create — so handleOrgEvent routes it to the Orgs panel event log and SSE triggers list refresh
797
- curl -s -X POST "${CTRL_URL}/api/mastermind/event" \
798
- -H "Content-Type: application/json" \
799
- -d "$(jq -cn \
800
- --arg session "$session_id" \
801
- --arg org "$orgName" \
802
- --arg goal "$goal_val" \
803
- --arg proj "$(pwd)" \
804
- '{type:"org:create",session:$session,org:$org,goal:$goal,project:$proj,ts:(now*1000|floor)}')" || true
209
+ echo "✓ Org config validated — ready for: monomind org run ${org_name}"
805
210
  ```
806
211
 
807
212
  ---
808
213
 
809
- ## Step 8 — Return Output
214
+ ## Step 6 — Return Output
810
215
 
811
216
  ```yaml
812
217
  domain: ops
@@ -814,12 +219,6 @@ status: complete
814
219
  artifacts:
815
220
  - path: .monomind/orgs/<org_name>.json
816
221
  type: config
817
- - path: .claude/agents/generated/<agent_type>.md
818
- type: agent-definition
819
- note: "one per role whose agent_type lacked a usable definition (skills, instructions, input/output)"
820
- - path: .monomind/loops/<org_name>.md
821
- type: loop-prompt
822
- note: "only present when --schedule was used; omit otherwise"
823
222
  decisions:
824
223
  - what: "Org <org_name> created with N roles"
825
224
  why: "Role mapping derived from goal and user description"
@@ -829,34 +228,25 @@ lessons:
829
228
  - what_worked: "Auto-suggested roles matched user intent"
830
229
  - what_didnt: ""
831
230
  next_actions:
832
- - "Run /mastermind:runorg --org <org_name> to start the organization"
833
- - "Edit .monomind/orgs/<org_name>.json to customize roles or communication"
834
- - "[scheduled orgs only] Run /mastermind:stoporg --org <org_name> to stop the loop"
835
- - "[scheduled orgs only] Run /mastermind:orgs to see all org statuses"
836
- board_url: "monotask://<org_name>/org-tasks"
837
- run_id: "<current UTC datetime as ISO8601, e.g. via $(date -u +%Y-%m-%dT%H:%M:%SZ)>"
231
+ - "Run `monomind org run <org_name>` to start the organization in the foreground"
232
+ - "Or `monomind org serve` to host it (and any other scheduled orgs) as a background daemon"
233
+ - "Edit .monomind/orgs/<org_name>.json directly, or use /mastermind:org-settings, to change goal/budget/roles"
234
+ - "`monomind org status <org_name>` to check runtime state; `monomind org stop <org_name>` to stop a running org"
838
235
  ```
839
236
 
840
237
  Print confirmation:
841
238
  ```
842
239
  ✓ Org "<org_name>" saved to .monomind/orgs/<org_name>.json
843
- → Run: /mastermind:runorg --org <org_name>
240
+ → Run: monomind org run <org_name>
844
241
  ```
845
242
 
846
- If `--schedule` was provided, also print:
243
+ If `schedule` was set, also print:
847
244
  ```
848
- Loop prompt saved to .monomind/loops/<org_name>.md
849
- Schedule: every <poll_interval_minutes> minutes
850
- Status: stopped (org will not run until /mastermind:runorg --org <org_name>)
851
-
852
- Lifecycle:
853
- Start: /mastermind:runorg --org <org_name>
854
- Stop: /mastermind:stoporg --org <org_name>
855
- List: /mastermind:orgs
245
+ Schedule: every <N> <unit> pick it up with: monomind org serve
856
246
  ```
857
247
 
858
248
  ---
859
249
 
860
- ## Step 9 — Brain Write (standalone only)
250
+ ## Step 7 — Brain Write (standalone only)
861
251
 
862
252
  If `caller` is not "command", follow _protocol.md Brain Write Procedure for domain `ops`.