@mutmutco/opencode-mmi 2.56.0 → 2.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -8,7 +8,9 @@ type Config = {
8
8
  description?: string;
9
9
  agent?: string;
10
10
  }>;
11
+ agent?: Record<string, Record<string, unknown>>;
11
12
  permission?: Record<string, unknown> | string;
13
+ shell?: string;
12
14
  };
13
15
  type HookOutput = {
14
16
  env?: Record<string, string>;
@@ -21,6 +23,7 @@ type ToolInput = {
21
23
  type MmiOptions = {
22
24
  skillsPath?: string;
23
25
  commandAgent?: string;
26
+ platform?: NodeJS.Platform | string;
24
27
  };
25
28
  declare function beforeTool(input: ToolInput, output: HookOutput): Promise<void>;
26
29
  declare function shellEnv(_input: unknown, output: HookOutput): Promise<void>;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { readFileSync } from 'node:fs';
2
+ import { isAbsolute, resolve } from 'node:path';
2
3
  import { fileURLToPath } from 'node:url';
3
4
  const WORKFLOW_SKILLS = [
4
5
  'mmi',
@@ -17,6 +18,8 @@ const WORKFLOW_SKILLS = [
17
18
  ];
18
19
  const DEFAULT_SKILLS_PATH = fileURLToPath(new URL('../skills', import.meta.url));
19
20
  const DEFAULT_COMMAND_AGENT = 'build';
21
+ const OVERLORD_CONSULT_AGENT = 'mmi-overlord-consult';
22
+ const OVERLORD_IMPLEMENT_AGENT = 'mmi-overlord-implement';
20
23
  // The adapter knows its own version at load (it IS the installed npm package), which is the reliable
21
24
  // "installed opencode plugin version" signal doctor reads back via MMI_OPENCODE_PLUGIN_VERSION. Resolve
22
25
  // the package's own package.json relative to this compiled module; on any failure return undefined so the
@@ -40,6 +43,76 @@ function addSkillPermission(cfg) {
40
43
  cfg.permission.skill = cfg.permission.skill ?? { '*': 'allow' };
41
44
  }
42
45
  }
46
+ function nativeShell(platform) {
47
+ if (platform === 'win32')
48
+ return 'pwsh';
49
+ if (platform === 'darwin')
50
+ return 'zsh';
51
+ return 'bash';
52
+ }
53
+ function isLegacyWindowsPowerShell(shell) {
54
+ return Boolean(shell && /(?:^|[\\/])powershell(?:\.exe)?$/i.test(shell.trim()));
55
+ }
56
+ function ensureNativeShell(cfg, platform) {
57
+ if (!cfg.shell || (platform === 'win32' && isLegacyWindowsPowerShell(cfg.shell))) {
58
+ cfg.shell = nativeShell(platform);
59
+ }
60
+ }
61
+ function ensureOverlordAgents(cfg) {
62
+ cfg.agent = cfg.agent ?? {};
63
+ cfg.agent[OVERLORD_CONSULT_AGENT] = {
64
+ description: 'MMI Overlord read-only consultation servant.',
65
+ mode: 'primary',
66
+ permission: {
67
+ read: 'allow',
68
+ list: 'allow',
69
+ glob: 'allow',
70
+ grep: 'allow',
71
+ lsp: 'allow',
72
+ edit: 'deny',
73
+ bash: 'deny',
74
+ task: 'deny',
75
+ external_directory: 'deny',
76
+ todowrite: 'deny',
77
+ question: 'deny',
78
+ webfetch: 'ask',
79
+ websearch: 'ask',
80
+ skill: { '*': 'allow' },
81
+ },
82
+ };
83
+ cfg.agent[OVERLORD_IMPLEMENT_AGENT] = {
84
+ description: 'MMI Overlord bounded implementation servant.',
85
+ mode: 'primary',
86
+ permission: {
87
+ read: 'allow',
88
+ list: 'allow',
89
+ glob: 'allow',
90
+ grep: 'allow',
91
+ lsp: 'allow',
92
+ edit: 'allow',
93
+ bash: {
94
+ '*': 'ask',
95
+ 'git status*': 'allow',
96
+ 'git diff*': 'allow',
97
+ 'git show*': 'allow',
98
+ 'git log*': 'allow',
99
+ 'rg *': 'allow',
100
+ 'npm test*': 'allow',
101
+ 'npm run test*': 'allow',
102
+ 'npm --prefix * test*': 'allow',
103
+ 'npm --prefix * run typecheck*': 'allow',
104
+ 'node *': 'allow',
105
+ },
106
+ task: 'deny',
107
+ external_directory: 'deny',
108
+ todowrite: 'allow',
109
+ question: 'ask',
110
+ webfetch: 'ask',
111
+ websearch: 'ask',
112
+ skill: { '*': 'allow' },
113
+ },
114
+ };
115
+ }
43
116
  function uniqueAppend(values, value) {
44
117
  return Array.from(new Set([...(values ?? []), value]));
45
118
  }
@@ -69,6 +142,8 @@ function ensureConfig(cfg, options) {
69
142
  };
70
143
  }
71
144
  addSkillPermission(cfg);
145
+ ensureNativeShell(cfg, options.platform);
146
+ ensureOverlordAgents(cfg);
72
147
  }
73
148
  function normalizeToolName(name) {
74
149
  return String(name ?? '').trim().toLowerCase();
@@ -85,6 +160,15 @@ function isRealEnvPath(filePath) {
85
160
  return false;
86
161
  return true;
87
162
  }
163
+ function normalizePathForCompare(filePath) {
164
+ return filePath.replace(/\\/g, '/').replace(/\/+$/, '').toLowerCase();
165
+ }
166
+ function isInsidePath(root, filePath) {
167
+ const resolved = isAbsolute(filePath) ? filePath : resolve(root, filePath);
168
+ const rootNorm = normalizePathForCompare(root);
169
+ const pathNorm = normalizePathForCompare(resolved);
170
+ return pathNorm === rootNorm || pathNorm.startsWith(`${rootNorm}/`);
171
+ }
88
172
  function stripQuoted(command) {
89
173
  return command.replace(/'[^']*'/g, ' ').replace(/"[^"]*"/g, ' ');
90
174
  }
@@ -175,9 +259,44 @@ function shellBlockReason(command) {
175
259
  }
176
260
  return undefined;
177
261
  }
262
+ function overlordScopeBlockReason(tool, args) {
263
+ const profile = process.env.MMI_OVERLORD_SERVANT_PROFILE;
264
+ if (!profile)
265
+ return undefined;
266
+ const worktree = process.env.MMI_OVERLORD_WORKTREE;
267
+ if (!worktree)
268
+ return 'Overlord servant scope missing MMI_OVERLORD_WORKTREE; refusing tool call.';
269
+ const mutatingTool = tool === 'write' || tool === 'edit' || tool === 'apply_patch';
270
+ if (mutatingTool && profile === 'consultation') {
271
+ return 'Overlord consultation servants are read-only; edits are coordinator-owned.';
272
+ }
273
+ const filePath = toolFilePath(args);
274
+ if (mutatingTool && !filePath)
275
+ return 'Overlord servant edit target path is missing; refusing tool call.';
276
+ if (mutatingTool && !isInsidePath(worktree, filePath)) {
277
+ return `Overlord servant edit outside assigned worktree is refused: ${filePath}`;
278
+ }
279
+ if (tool === 'bash') {
280
+ const command = stripQuoted(String(args.command ?? '')).trim();
281
+ if (profile === 'consultation')
282
+ return 'Overlord consultation servants cannot run shell commands; the coordinator supplies bounded evidence.';
283
+ if (/\bmmi-cli\s+(?:stage|pr|rcand|release|hotfix)\b/i.test(command))
284
+ return 'Overlord servants cannot own stage, PR, promotion, release, or hotfix commands.';
285
+ if (/\bgh\s+pr\s+(?:create|merge|close|reopen|ready|review)\b/i.test(command))
286
+ return 'Overlord servants cannot own PR lifecycle commands.';
287
+ if (/\b(?:playwright|chrome|chromium|msedge)\b/i.test(command))
288
+ return 'Overlord servants cannot own browser or Playwright resources.';
289
+ if (/\b(?:vite|next|npm\s+run\s+(?:dev|start|preview))\b/i.test(command))
290
+ return 'Overlord servants cannot own shared dev servers.';
291
+ }
292
+ return undefined;
293
+ }
178
294
  async function beforeTool(input, output) {
179
295
  const args = (output.args ?? {});
180
296
  const tool = normalizeToolName(input.tool);
297
+ const overlordReason = overlordScopeBlockReason(tool, args);
298
+ if (overlordReason)
299
+ throw new Error(overlordReason);
181
300
  if ((tool === 'write' || tool === 'edit' || tool === 'apply_patch') && isRealEnvPath(toolFilePath(args))) {
182
301
  throw new Error('Vault only: do not edit or write .env files. Use /secrets for runtime config.');
183
302
  }
@@ -196,12 +315,13 @@ async function shellEnv(_input, output) {
196
315
  }
197
316
  async function compacting(_input, output) {
198
317
  output.context = output.context ?? [];
199
- output.context.push('MMI continuity: preserve issue/PR refs, saga and North Star anchors, blockers, decisions, verification state, and NEXT.');
318
+ output.context.push('MMI continuity: preserve issue/PR refs, blockers, decisions, verification state, and NEXT. Saga/North Star anchors are Jervaise-only.');
200
319
  }
201
320
  async function MmiOpenCodePlugin(_ctx, rawOptions) {
202
321
  const options = {
203
322
  skillsPath: rawOptions?.skillsPath ?? DEFAULT_SKILLS_PATH,
204
323
  commandAgent: rawOptions?.commandAgent ?? DEFAULT_COMMAND_AGENT,
324
+ platform: rawOptions?.platform ?? process.platform,
205
325
  };
206
326
  return {
207
327
  config: (cfg) => ensureConfig(cfg, options),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mutmutco/opencode-mmi",
3
- "version": "2.56.0",
4
- "description": "MMI Future OpenCode adapter — registers mmi, secrets, stage, rcand, release, hotfix, bootstrap, grind, overlord, build, handoff, coop, and browser-automation skills, workflow commands, and deterministic guardrail hooks.",
3
+ "version": "2.58.0",
4
+ "description": "MMI Future OpenCode adapter — registers mmi, secrets, stage, rcand, release, hotfix, bootstrap, grind, overlord, build, coop, browser-automation, and Jervaise-only continuity/handoff skills, workflow commands, and deterministic guardrail hooks.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "license": "UNLICENSED",
@@ -19,14 +19,14 @@ Hard rules:
19
19
  - **Verifier (or judge) is never the builder.** Hard lenses run at verifier tier minimum.
20
20
  - When the host exposes multiple vendors, prefer maximum spread on each fusion round. Document any gap honestly — never claim fusion ran cross-vendor when only one vendor was available.
21
21
  - Invoking `/grind`, `/grind --auto`, or `/build` authorizes the planner, verifier, judge, and synthesizer panels those skills require, within their normal bounds. On Codex, use `multi_agent_v1` for standard panels when that tool is available.
22
- - A single-vendor host degrades gracefully: different temperatures or repeat passes; still run the synthesizer. Note degradation in saga and halt/end-of-grind reports.
22
+ - A single-vendor host degrades gracefully: different temperatures or repeat passes; still run the synthesizer. For `jervaise`, note degradation in saga and halt/end-of-grind reports; for every other login, note it in the halt/end-of-grind report and the issue/PR record (saga is Jervaise-only).
23
23
 
24
24
  Use fusion on the hard parts — plan choices, ambiguous specs, security-critical surfaces, verification rounds at checkpoints. Do not spend fusion tokens on trivial slices.
25
25
 
26
26
  ## Panel evidence contract
27
27
 
28
28
  - Use the host's multi-agent panel mechanism when it is available. Degrade only when the tool is unavailable, a spawn is denied/null, or the user explicitly disables delegation/panels.
29
- - State degraded fallback explicitly in saga notes and final reports. A degraded round is evidence with a ceiling, not a normal clean panel.
29
+ - State degraded fallback explicitly: for `jervaise` in saga notes + final reports; for every other login in the final report + issue/PR record (saga is Jervaise-only). A degraded round is evidence with a ceiling, not a normal clean panel.
30
30
  - `mmi-cli verify synthesize` is a reconciliation helper for real verifier lane JSON. It must not replace an available host panel, and it must not be fed empty input or controller-authored all-pass stubs.
31
31
  - Two stable clean rounds count only when the required verifier process actually produced the lens outputs. Empty, missing, or self-authored pass JSON is invalid fresh-eyes evidence.
32
32
 
@@ -56,9 +56,9 @@ Both `/grind` and `/build` self-select one of four effort tiers — **`light` ·
56
56
 
57
57
  **Prefer the lightest model that clears the bar.** Reach for a heavier model only when the work needs it — a hard plan, an ambiguous spec, a security-critical lens, a failing verify round. Routine builder turns, mechanical edits, and light-tier slices run on a lighter model. Reserve top-tier models for fusion planners, hard lenses, and `ultra`-tier sites. Spending a frontier model on a one-liner is waste, not rigor.
58
58
 
59
- **Fusion single-API models (opencode `fugu` / `fugu-ultra`, `codex-fugu`):** these already integrate multiple models behind one API, so the cross-vendor panel the skills would otherwise spawn is **built into the model**. On a fusion model:
59
+ **Fusion single-API models (opencode `fugu` / `fugu-ultra`):** these already integrate multiple models behind one API, so the cross-vendor panel the skills would otherwise spawn is **built into the model**. On a fusion model:
60
60
 
61
- - **Cap the tier at `light`** — never run higher (`capTierForModel` in `build-policy.ts`). For now only `fugu`, `fugu-ultra` (opencode) and `codex-fugu` are fusion models.
61
+ - **Cap the tier at `light`** — never run higher (`capTierForModel` in `build-policy.ts`). For now only OpenCode `fugu` and `fugu-ultra` are fusion models.
62
62
  - **Give them the most straightforward method** — single straight-through pass, **no** multi-agent planner/lens fan-out. The fusion is internal; an external panel is redundant cost.
63
63
  - Detect by active model id, or let the opencode plugin pass the signal explicitly when it lands.
64
64
 
@@ -74,7 +74,7 @@ Claude Code **2.1.181** hard-caps subagents at **5 levels of nesting depth**; fo
74
74
 
75
75
  Concrete ownership: only the top-level orchestrator (the skill invoker) launches fusion planners and verify lenses. Sub-agents return JSON or markdown; they do **not** spawn their own sub-panels unless the skill explicitly says otherwise for that one role.
76
76
 
77
- **Sub-agent continuation is host-scoped (#1943/#1956).** `SendMessage` can continue a previously-spawned agent only on hosts that expose it to the top-level orchestrator; it is **not** in a sub-agent's toolset, and Claude Code has surfaced misleading Agent-tool footers for a continuation tool that is not callable there. So a sub-agent never messages or continues a peer. It **returns its result** and the orchestrator either uses a host-exposed continuation tool or re-spawns a fresh sub-agent with a compact handoff packet: issue/PR refs, branch/worktree, changed files, objective, what passed/failed, and exact NEXT. Cross-agent / cross-PC coordination is **`/coop`**, never `SendMessage` or ad-hoc messaging. Keep this narration out of user-facing output — a one-line `saga note` at most.
77
+ **Sub-agent continuation is host-scoped (#1943/#1956).** `SendMessage` can continue a previously-spawned agent only on hosts that expose it to the top-level orchestrator; it is **not** in a sub-agent's toolset, and Claude Code has surfaced misleading Agent-tool footers for a continuation tool that is not callable there. So a sub-agent never messages or continues a peer. It **returns its result** and the orchestrator either uses a host-exposed continuation tool or re-spawns a fresh sub-agent with a compact handoff packet: issue/PR refs, branch/worktree, changed files, objective, what passed/failed, and exact NEXT. Cross-agent / cross-PC coordination is **`/coop`**, never `SendMessage` or ad-hoc messaging. Keep this narration out of user-facing output — for `jervaise`, a one-line `saga note` at most; for every other login, keep it out of user-facing output entirely (saga is Jervaise-only).
78
78
 
79
79
  ## Classifier-denied spawn handling
80
80
 
@@ -83,7 +83,7 @@ Claude Code **2.1.178**: in auto mode, subagent spawns are evaluated by a classi
83
83
  **Degraded round — not clean:**
84
84
 
85
85
  - A denied, null, or missing planner/lens/research sub-agent is a **gap**, not a pass.
86
- - Log the gap: `mmi-cli saga note "spawn-denied role=<planner|lens|research> round=<n>"`.
86
+ - Log the gap: for `jervaise`, `mmi-cli saga note "spawn-denied role=<planner|lens|research> round=<n>"`; for every other login, record the gap in the halt/end-of-grind report + issue/PR record (saga is Jervaise-only).
87
87
  - Surface gaps in halt reports, end-of-grind summaries, and build halt reports.
88
88
  - A round with any denied/null spawn does **not** count toward **two synthesis-stable clean rounds**.
89
89
  - When aggregating parallel results, use explicit null handling — `.filter(Boolean)` alone is insufficient unless paired with a gap count check; a denied spawn must never inflate a clean count.
@@ -147,7 +147,7 @@ Org-wide session doctrine lives in **`AGENTS.md` § Session workflow** — grind
147
147
  - Branch from latest `origin/development` into `../mmi-worktrees/<branch>` — **never edit the main checkout** during grind/build runs.
148
148
  - If a generic/native worktree helper would create `.claude/worktrees/`, `.worktrees/`, or another non-Hub path, skip it for MMI org repos and use `mmi-cli worktree create` / `setup`.
149
149
  - One worktree per grind/build run until integration boundary; multi-worktree waves merge via `mmi-cli wave land`.
150
- - Return to the main checkout mid-run only for a new unrelated branch, real base drift, final integrated validation, cleanup after merge, explicit user request, or a broken/unsafe worktree. Otherwise keep implementation, verification, commits, PR prep, saga, and North Star updates in the active worktree.
150
+ - Return to the main checkout mid-run only for a new unrelated branch, real base drift, final integrated validation, cleanup after merge, explicit user request, or a broken/unsafe worktree. Otherwise keep implementation, verification, commits, PR prep, and any allowed continuity updates in the active worktree.
151
151
  - A local `/stage` belongs to the active worktree that started it. Do not disrupt a running stage for git bookkeeping alone. Before moving to a different worktree, stop/destroy the stage and recreate it from the new worktree, or warn first when the user's intent is unclear. Linked worktrees share stage state through the git common dir, so a new worktree can still stop the previous local stage.
152
152
  - Give each worktree its **own** `node_modules` via clean `npm ci` — never symlink/junction into the main checkout's `node_modules` (junctions can be followed by teardown and destroy the main checkout).
153
153
  - **Cross-platform lockfile — validate on the CI OS, not the build OS (#1840).** When a build/grind on **Windows** regenerates `package-lock.json` (any `npm install` — e.g. adding a workspace or devDep), npm 11 **prunes Linux-only optional deps** (`@emnapi/*`, the `@node-rs/argon2` / `@tailwindcss/oxide` `*-wasm32-wasi` fallbacks). Local `npm ci` + the gate then pass on Windows while the Linux CI runner's `npm ci` dies `EUSAGE` (`Missing: @emnapi/core@… from lock file`) in ~11s — **local-OS green never proves a cross-platform lockfile.** Before merge, regenerate **and** validate the lock in a Linux container matching CI's Node (`node:24` at present): `docker run --rm -v "${PWD}:/app" -w /app node:<ci-node> npm install --package-lock-only --ignore-scripts`, then validate with `node_modules`-shadowed anonymous volumes — `docker run --rm -v "${PWD}:/app" -v /app/node_modules -w /app node:<ci-node> sh -c "npm ci && npm run check"`. The container lock is a win32+linux+wasm **superset** that satisfies Linux CI (local Windows `npm ci` may then reject it on an npm-minor mismatch — CI is the gate).
@@ -168,11 +168,13 @@ Until repro proves otherwise:
168
168
 
169
169
  ## Saga snapshot / resume
170
170
 
171
- Loop memory composes with saga HEAD — enforced via **`mmi-cli saga snapshot`**.
171
+ Loop memory composes with saga HEAD for `jervaise` — enforced via **`mmi-cli saga snapshot`**.
172
172
 
173
- - **Read-first on resume:** `mmi-cli saga snapshot show --kind <grind|build>` (`--json` for machine use). Reconcile with diff + `PanelReport` — never collapsed chat.
174
- - **Write-last each phase:** one-line `mmi-cli saga note "<audit>"` **plus** `mmi-cli saga snapshot set --kind <grind|build>` (or `--json-file`).
175
- - **Hygiene:** bounded summary only; one-line phase notes = append-only trail beneath HEAD.
173
+ - **For `jervaise`:**
174
+ - **Read-first on resume:** `mmi-cli saga snapshot show --kind <grind|build>` (`--json` for machine use). Reconcile with diff + `PanelReport` — never collapsed chat.
175
+ - **Write-last each phase:** one-line `mmi-cli saga note "<audit>"` **plus** `mmi-cli saga snapshot set --kind <grind|build>` (or `--json-file`).
176
+ - **Hygiene:** bounded summary only; one-line phase notes = append-only trail beneath HEAD.
177
+ - **For every other login:** skip Saga/North Star commands (they are Jervaise-only); use the issue/PR record + git history as the durable resume surface — re-read the issue body and the merged PRs, not a continuity snapshot.
176
178
 
177
179
  Grind schema: `skills/grind/templates/saga-snapshot.md`. Build uses `--kind build`.
178
180
 
@@ -223,10 +223,10 @@ known. Going forward the thin Lambda adds each new issue to that project on `iss
223
223
  `Status: Todo`.
224
224
 
225
225
  **Register the project for cloud agents.** The same registry META row carries `{name, slug, projectId,
226
- wikiRepo, repos[]}`; do not append to a committed `projects.json`. This is what makes `wiki-keeper` run for
227
- the project (the launcher fans one run per registered project, generating its wiki + refreshing its board).
228
- `kb-keeper`, `saga-keeper`, and `northstar-keeper` are org-wide and need no per-project entry. If attaching this repo to an
229
- existing project, merge this repo into that project's `repos[]` instead of creating a new project.
226
+ wikiRepo, repos[]}`; do not append to a committed `projects.json`. Repo wikis and doc freshness are owned by
227
+ the repo itself. Saga/North Star maintenance and KB sync are Hub workflows, not per-project agents. If
228
+ attaching this repo to an existing project, merge this repo into that project's `repos[]` instead of creating a
229
+ new project.
230
230
 
231
231
  ## Step 4 — vault tiers + deploy substrate
232
232
 
@@ -338,7 +338,7 @@ collaborator list + the per-branch allowlist are the record — no separate rost
338
338
  `.claude/settings.local.json` is local-only.
339
339
  - **Reserve the spine filenames.** `AGENTS.md` / `CLAUDE.md` are the org spine — never repo-specific. Seed
340
340
  `.cursor/rules/<repo-slug>.mdc` (frontmatter `alwaysApply: true`) with repo-specific agent guidance (what
341
- the repo is, services/deps, build/test, conventions). Include the saga startup pattern for non-Claude
341
+ the repo is, services/deps, build/test, conventions). For `jervaise`, include the saga startup pattern for non-Claude
342
342
  agents: `mmi-cli saga health --json`, `mmi-cli saga show`, then explicit `mmi-cli saga note` at handoff or
343
343
  meaningful checkpoints. This gives Cursor's setup agent a home so it does not hijack `AGENTS.md`; Cursor
344
344
  cloud agents read `.cursor/rules` automatically.
@@ -7,7 +7,9 @@ description: Drive a milestone from a finished foundation to merged PRs, autonom
7
7
 
8
8
  **Shared doctrine:** Read `skills/_shared/doctrine.md` at session start and on resume. Fusion, parallelism, flat fan-out, classifier-denied spawns, blocker tiers, worktree hygiene, #1595 verify+commit, enforcement matrix — single source; do not duplicate here.
9
9
 
10
- You own a milestone or capability from a finished foundation to merged PRs, autonomously. Auto is the default mode and the framing interview is the one routine human touchpoint. After the interview locks decisions to the board and the North Star, you run gateless: fan out parallel sites, raise the effort tier per part, fuse cross-vendor planners on the hard parts, verify in nested sub-loops, and auto-merge each PR into `development` until the frontier is exhausted or a hard-decision blocker parks a site.
10
+ You own a milestone or capability from a finished foundation to merged PRs, autonomously. Auto is the default mode and the framing interview is the one routine human touchpoint. After the interview locks decisions to the board, and to North Star only when the current login is `jervaise`, you run gateless: fan out parallel sites, raise the effort tier per part, fuse cross-vendor planners on the hard parts, verify in nested sub-loops, and auto-merge each PR into `development` until the frontier is exhausted or a hard-decision blocker parks a site.
11
+
12
+ **Continuity access:** Saga and North Star are Jervaise-only. If the current login is not `jervaise`, skip all `saga`, `northstar`, `plan`, and `/handoff` steps; keep durable state in the board issue, PR body/comments, verification logs, and final halt report.
11
13
 
12
14
  ## Core idea
13
15
 
@@ -61,9 +63,9 @@ Heuristics:
61
63
 
62
64
  **Flags force a tier:** `--light`, `--standard`, `--deep`, `--ultra` override auto-selection for the whole run (explicit override always wins, per `pickEffortTier`).
63
65
 
64
- **Fusion-model cap:** on opencode `fugu` / `fugu-ultra` or `codex-fugu`, cap at `light` and run the straightforward single-pass method — no planner/lens fan-out. See doctrine § Model economy.
66
+ **Fusion-model cap:** on OpenCode `fugu` / `fugu-ultra`, cap at `light` and run the straightforward single-pass method — no planner/lens fan-out. See doctrine § Model economy.
65
67
 
66
- **Announce + log every tier choice.** Print the tier, the signals that drove it, and a one-line "why" before construction starts; `mmi-cli saga note "build tier=<tier> site=<slug> signals=<…> reason=<…>"`. The heuristics are encoded testably in `build-policy.ts` (fixtures lock signals -> tier/parallelism/planner-count/reasoning).
68
+ **Announce + log every tier choice.** Print the tier, the signals that drove it, and a one-line "why" before construction starts. For `jervaise`, `mmi-cli saga note "build tier=<tier> site=<slug> signals=<…> reason=<…>"`; for every other login, record the tier choice in the issue/PR record (saga is Jervaise-only). The heuristics are encoded testably in `build-policy.ts` (fixtures lock signals -> tier/parallelism/planner-count/reasoning).
67
69
 
68
70
  The tier is the **concurrency ceiling** and the **verification depth floor** for that site. **Fill the cap** — batch independent sites up to it rather than serializing (doctrine § Parallelism). The tier raises the ceiling; it does not lower the parallel bias.
69
71
 
@@ -93,28 +95,30 @@ Cover:
93
95
 
94
96
  **Lock the decisions in:**
95
97
 
96
- 1. `mmi-cli northstar push <slug>` with the milestone body + criteria.
98
+ 1. For `jervaise`, `mmi-cli northstar push <slug>` with the milestone body + criteria. For everyone else, put the criteria in the issue/PR record.
97
99
  2. File or update the umbrella issue for the milestone and any known child issues; **batch-claim everything build will work in ONE call** — `mmi-cli board claim <ref> <ref> … --for <login>` (dedupes + claims in parallel; never one-by-one). (Set urgency with `--priority` — the board Priority **field**, never a `priority:*` label; #416.)
98
- 3. `mmi-cli saga note "build framing: milestone=<…> criteria=<…> out-of-scope=<…> hard-decisions=<…>"`.
99
- 4. **Cost estimate (measure-first).** Run `mmi-cli build estimate` (or `build tier` + mental math) and print the worst-case **agent-call proxy** + ceiling. If projected exceed → lower tier or halt-and-report before going gateless; log `saga note "build cost-estimate units=<n> ceiling=<n> action=<ok|lower-tier|halt>"`. Phase 0 may override `CAMPAIGN_ITERATION_CAP` (~15 orients default) with explicit human approval — log to saga.
100
- 5. Initialize the **in-hand North Star** from `templates/campaign-northstar.md` via `northstar push` — this is campaign SSOT; saga is session handoff.
100
+ 3. For `jervaise`, `mmi-cli saga note "build framing: milestone=<…> criteria=<…> out-of-scope=<…> hard-decisions=<…>"`.
101
+ 4. **Cost estimate (measure-first).** Run `mmi-cli build estimate` (or `build tier` + mental math) and print the worst-case **agent-call proxy** + ceiling. If projected exceed → lower tier or halt-and-report before going gateless; for `jervaise`, log `saga note "build cost-estimate units=<n> ceiling=<n> action=<ok|lower-tier|halt>"`. Phase 0 may override `CAMPAIGN_ITERATION_CAP` (~15 orients default) with explicit human approval.
102
+ 5. For `jervaise`, initialize the **in-hand North Star** from `templates/campaign-northstar.md` via `northstar push` — this is campaign SSOT; saga is session handoff. For everyone else, use the issue/PR as campaign SSOT.
101
103
 
102
104
  After Phase 0 the loop runs gateless. If the milestone genuinely shifts mid-run, re-interview — do not let the loop redefine the milestone on its own.
103
105
 
104
106
  ## Loop memory — North Star in hand
105
107
 
106
- **Two-store rule:** North Star (`plans/<slug>.md`) = campaign position; saga = session audit trail. Halt report = projection of the in-hand North Star, not a third source of truth.
108
+ **Two-store rule for `jervaise`:** North Star (`plans/<slug>.md`) = campaign position; saga = session audit trail. Halt report = projection of the in-hand North Star, not a third source of truth. For everyone else, the issue/PR record carries campaign position and audit trail.
107
109
 
108
110
  The North Star is **campaign working memory**, not a doc read once. **Read → act → write-back** every state transition:
109
111
 
110
- - **Read first:** L0 orient starts with `mmi-cli northstar show <slug>` (or `northstar relevant`), then `mmi-cli saga snapshot show --kind build` for session handoff.
111
- - **Write last:** after site enter/exit, tier choice, park, solvable-clear, merge, re-frame — `mmi-cli northstar push <slug>` with the canonical structure in `templates/campaign-northstar.md`, then `mmi-cli saga snapshot set --kind build` for session handoff.
112
+ - **For `jervaise`:**
113
+ - **Read first:** L0 orient starts with `mmi-cli northstar show <slug>` (or `northstar relevant`), then `mmi-cli saga snapshot show --kind build` for session handoff.
114
+ - **Write last:** after site enter/exit, tier choice, park, solvable-clear, merge, re-frame — `mmi-cli northstar push <slug>` with the canonical structure in `templates/campaign-northstar.md`, then `mmi-cli saga snapshot set --kind build` for session handoff.
115
+ - **For every other login:** campaign position lives in the issue/PR record — re-read the milestone issue + linked PRs at orient, and write state transitions back as issue comments / PR descriptions (saga + North Star are Jervaise-only).
112
116
 
113
117
  Canonical sections: Milestone + slug; Criteria; Done last turn / In progress / Blocked / Next frontier; Tier ledger; Verification ceiling per site.
114
118
 
115
119
  **Hygiene:** short + structured. If state outgrows a scannable snapshot, graduate or split the milestone — do not grow the file.
116
120
 
117
- **Re-frame:** North Star edit first, then `saga note --decision`, then continue. When a halt fires (iteration cap, cost ceiling, hard-decision), record the reason in Blocked / Next frontier before the halt report.
121
+ **Re-frame:** for `jervaise`, North Star edit first, then `saga note --decision`, then continue; for every other login, edit the milestone issue first, then note the decision in the issue/PR record. When a halt fires (iteration cap, cost ceiling, hard-decision), record the reason in Blocked / Next frontier before the halt report.
118
122
 
119
123
  **Re-interview triggers** (always pause for these; never let the loop absorb them):
120
124
 
@@ -129,7 +133,7 @@ Build is loops inside loops. **Every loop must improve understanding** of the pr
129
133
 
130
134
  The nesting:
131
135
 
132
- - **L0 — Campaign loop (frontier).** Read the in-hand North Star **first**; orient on board + research; select the unblocked frontier; pick a site; construct; learn; write North Star back; re-orient. Runs until **externally confirmed** frontier exhaustion or a halt condition (iteration cap, cost ceiling, hard-decision). Default **~15** L0 orients (`CAMPAIGN_ITERATION_CAP`); on cap without external exhaustion → halt-and-report (honest halt ≠ failure).
136
+ - **L0 — Campaign loop (frontier).** For `jervaise`, read the in-hand North Star **first**; for every other login, re-read the milestone issue + linked PRs. Orient on board + research; select the unblocked frontier; pick a site; construct; learn; write the campaign position back (North Star for `jervaise`, issue/PR record for everyone else); re-orient. Runs until **externally confirmed** frontier exhaustion or a halt condition (iteration cap, cost ceiling, hard-decision). Default **~15** L0 orients (`CAMPAIGN_ITERATION_CAP`); on cap without external exhaustion → halt-and-report (honest halt ≠ failure).
133
137
  - **L1 — Site loop (slice -> merge).** For one site: plan, build, checkpoint-verify in sub-loops, fix, re-verify, open PR, watch CI, merge into `development`, then tick the site's line in the milestone umbrella (`mmi-cli issue check <umbrella> --item "<text>"`; native sub-issues auto-tick on close) so it doesn't read 0% after slices shipped (#1796). Each L1 turn rolls back into L0.
134
138
  - **L2 — Checkpoint verification sub-loops.** Inside a site, at each meaningful increment (not just at the end), spin a verification sub-loop. The effort tier sets how many checkpoints and how deep each one runs.
135
139
  - **L3 — Fusion-panel rounds.** Inside a checkpoint, use the host multi-agent panel mechanism when available, then run parallel lenses -> synthesizer -> triage; repeat until **two consecutive synthesis-stable clean rounds** (identical blocker `id` sets; an empty blocker set counts as stable). Degraded fallback follows shared doctrine and must be reported. Empty or controller-authored all-pass lens stubs are invalid evidence. Each blocker/clean verdict must cite an **objective signal** when one exists (failing test, typecheck error, sandbox repro, cited source) — not bare judgment. **Terminal done hierarchy:** (1) repo checks / CI green, (2) two stable clean rounds, (3) merge authority — never skip layer 1.
@@ -146,17 +150,18 @@ packages, plugin bundles, seeds) need a **consumer-path checkpoint**, not just a
146
150
  **Worktree tests:** see shared doctrine — tests must run with `cwd` set to the worktree; orchestrator reproduces subagent green before merge.
147
151
 
148
152
  **Stay in the active worktree.** For a coherent build site or same-repo wave, keep implementation,
149
- verification, commits, PR prep, saga, and North Star updates in the selected feature worktree until
150
- the site/wave reaches its integration boundary. Do not bounce to the main checkout for routine status,
151
- fast-forward, or reorientation work. Switch mid-run only for a new unrelated branch, real base drift,
153
+ verification, commits, PR prep, and (for `jervaise`) saga + North Star updates in the selected feature
154
+ worktree until the site/wave reaches its integration boundary. For every other login, the issue/PR
155
+ record carries campaign position keep that current instead. Do not bounce to the main checkout for
156
+ routine status, fast-forward, or reorientation work. Switch mid-run only for a new unrelated branch, real base drift,
152
157
  final integrated validation, cleanup after merge, explicit user request, or a broken/unsafe worktree.
153
158
  Keep any local `/stage` attached to the active worktree; do not disrupt it for git bookkeeping alone.
154
159
 
155
160
  **Delegated verify+commit:** see shared doctrine § Delegated verify+commit (#1595).
156
161
 
157
- **Re-framing rule:** when L0 orient detects that the problem has shifted under you (a dependency landed differently, a spec was wrong, a downstream effect was missed), **North Star edit first**, then `saga note --decision`, then update the board, then continue. Never let the loop quietly redefine the milestone.
162
+ **Re-framing rule:** when L0 orient detects that the problem has shifted under you (a dependency landed differently, a spec was wrong, a downstream effect was missed), **North Star edit first** (or, for non-`jervaise`, the milestone issue first), then for `jervaise` `saga note --decision`, then update the board, then continue. Never let the loop quietly redefine the milestone.
158
163
 
159
- **Ralph Wiggum guard:** distrust the loop's own "I'm done" signal. **Frontier exhausted** requires external confirmation: in-hand North Star shows empty next frontier, no open unblocked board claims, no in-flight PRs for this milestone, no unresolved parked sites — checked via `mmi-cli board` / `gh` and `mmi-cli build frontier`, not self-belief. Same orient picture twice = stall signal (counts toward stale orients).
164
+ **Ralph Wiggum guard:** distrust the loop's own "I'm done" signal. **Frontier exhausted** requires external confirmation: for `jervaise`, the in-hand North Star shows an empty next frontier; for every other login, the milestone issue shows no open unblocked sub-items. Either way, no open unblocked board claims, no in-flight PRs for this milestone, no unresolved parked sites — checked via `mmi-cli board` / `gh` and `mmi-cli build frontier`, not self-belief. Same orient picture twice = stall signal (counts toward stale orients).
160
165
 
161
166
  ## Research is first-class
162
167
 
@@ -164,7 +169,7 @@ When a decision needs grounding — an API contract, a third-party behavior, a s
164
169
 
165
170
  - Research is **not a detour from building** — it is part of building.
166
171
  - Default research budget: 3 queries per spike, hard cap on round trips, allow/deny lists honored (no benchmark-leak domains in verify-time search).
167
- - Saga-log every spike: `mmi-cli saga note "build research spike=<…> sources=<…> conclusion=<…>"`.
172
+ - Saga-log every spike (for `jervaise`): `mmi-cli saga note "build research spike=<…> sources=<…> conclusion=<…>"`. For every other login, record the spike conclusion in the issue/PR record (saga is Jervaise-only).
168
173
 
169
174
  ## Authority + guardrails
170
175
 
@@ -174,8 +179,8 @@ Non-negotiable, in priority order:
174
179
  - **No-CI repos (#1432).** Run `mmi-cli pr ci-policy --json` before polling. When `policy` is `no-ci`, local verify satisfies terminal layer 1 — merge after local verify. **`(Recommended)` `mmi-cli pr land <n>`** runs the full path. After land, that branch's worktree + branch cleanup is automatic (#1606); for serialized same-repo waves, do not land every issue separately if the active shared worktree is meant to continue. When the user explicitly wants the linked worktree/stage to continue across a same-session batch boundary, use `mmi-cli pr land <n> --preserve-worktree` and clean up the local branch/worktree/stage at the batch end (#1888).
175
180
  - **Worktree / node_modules:** see shared doctrine.
176
181
  - **Claim `--for <login>`.** Resolve the human from `mmi-cli whoami` or the session banner. Never claim as the bot.
177
- - **Saga note every phase.** Drop a one-line `mmi-cli saga note "<…>"` after Phase 0, each L0 orient, each tier choice, each L1 site enters/exits, every parked site, and at the halt report.
178
- - **North Star in hand each L0 turn.** `mmi-cli northstar show <slug>` first; `mmi-cli saga snapshot show --kind build` for handoff; write back via `northstar push` + `saga snapshot set --kind build`.
182
+ - **Saga note every phase (for `jervaise`).** Drop a one-line `mmi-cli saga note "<…>"` after Phase 0, each L0 orient, each tier choice, each L1 site enters/exits, every parked site, and at the halt report. For every other login, record these transitions in the issue/PR record (saga is Jervaise-only).
183
+ - **North Star in hand each L0 turn (for `jervaise`).** `mmi-cli northstar show <slug>` first; `mmi-cli saga snapshot show --kind build` for handoff; write back via `northstar push` + `saga snapshot set --kind build`. For every other login, re-read the milestone issue + linked PRs at each orient (North Star is Jervaise-only).
179
184
  - **Two-tier vault only.** `/secrets` — never env files. Harness: `vault-edit-gate.mjs` on Claude Code (see enforcement matrix).
180
185
  - **No self-escalation.** Privileged ops → board issue for master.
181
186
  - **No fabrication.** Source-of-truth links, paths, CLI flags only.
@@ -10,4 +10,4 @@ file holds the per-level "deepened understanding" tests and the distribution-chu
10
10
  - **L2** — the checkpoint exposed something the plan missed (a coupling, a contract, a perf cliff, a failure mode). A checkpoint that just confirms "no blockers found" without surfacing one new fact is suspect — widen the next L2.
11
11
  - **L3** — the fusion-panel round produced a `PanelReport` whose `consensus`, `contradictions`, `blind_spots`, and `unique_insights` actually move the model of the change. Two clean rounds with identical empty blocker sets prove stability; two clean rounds with the same shallow lens write-ups prove only that the panel is asleep.
12
12
 
13
- **Distribution chunks need consumer verification.** When any site, slice, or task ships an artifact consumed outside its source repo — shadcn registry items, npm packages, generated plugin bundles, scaffold seeds, or any publish/install surface — an in-repo build is not enough. Add a checkpoint that simulates the consumer path (`shadcn add`, `npm pack` + install, scaffold into a scratch app, or equivalent) and typechecks/runs the consumer. If a full simulation is unavailable, do both of these before merge: research the installer's rewrite/resolution rules, and verify every runtime dependency is declared, including CSS/token/theme layers. Log the exact consumer lens and its ceiling in the saga.
13
+ **Distribution chunks need consumer verification.** When any site, slice, or task ships an artifact consumed outside its source repo — shadcn registry items, npm packages, generated plugin bundles, scaffold seeds, or any publish/install surface — an in-repo build is not enough. Add a checkpoint that simulates the consumer path (`shadcn add`, `npm pack` + install, scaffold into a scratch app, or equivalent) and typechecks/runs the consumer. If a full simulation is unavailable, do both of these before merge: research the installer's rewrite/resolution rules, and verify every runtime dependency is declared, including CSS/token/theme layers. For `jervaise`, log the exact consumer lens and its ceiling in the saga; for every other login, log it in the issue/PR record (saga is Jervaise-only).
@@ -4,8 +4,8 @@ Illustrative walkthrough of how the `/build` loop chews through one real milesto
4
4
  autopilot. The slice names and issue refs are illustrative; the real ones belong to the milestone's
5
5
  own North Star.
6
6
 
7
- - **Phase 0 — Framing.** Lock the milestone: "ship the Katip v1.0 pipeline body end-to-end on top of the finished foundation." Criteria: every slice green to `development`; vocab pack landed; live-Recall integration scoped (not done). Hard-decision territory: slice-B (`#192`) depends on `#156` ratify + a live-Recall field that needs a human call. North Star push; saga note; out-of-scope = the live-Recall integration itself.
8
- - **L0 orient (first turn).** Read North Star, scan the board for unblocked items, run a brief research spike on the `#156` ratify state. Inventory: slice-F machinery is the foundation; slices C/D/E run on default choices; vocab pack is parallel-safe; slice-B is blocked on a hard decision.
7
+ - **Phase 0 — Framing.** Lock the milestone: "ship the Katip v1.0 pipeline body end-to-end on top of the finished foundation." Criteria: every slice green to `development`; vocab pack landed; live-Recall integration scoped (not done). Hard-decision territory: slice-B (`#192`) depends on `#156` ratify + a live-Recall field that needs a human call. For `jervaise`: North Star push + saga note; for every other login, record the framing in the issue/PR record (saga + North Star are Jervaise-only). Out-of-scope = the live-Recall integration itself.
8
+ - **L0 orient (first turn).** For `jervaise`, read the in-hand North Star (`northstar show`); for every other login, re-read the milestone issue + linked PRs. Scan the board for unblocked items, run a brief research spike on the `#156` ratify state. Inventory: slice-F machinery is the foundation; slices C/D/E run on default choices; vocab pack is parallel-safe; slice-B is blocked on a hard decision.
9
9
  - **Partition the frontier (buildability + effort tier).** Three groups fall out:
10
10
  - **Group 1 — foundational, buildable.** owner_email machinery, `#159`, slice-F machinery. Effort tier **deep**: foundational, one wrong call cascades.
11
11
  - **Group 2 — slices on default choices, buildable.** Slices C, D, E. Effort tier **standard**: bounded risk, real but not architectural.
@@ -1,5 +1,7 @@
1
1
  # Campaign North Star — in-hand template
2
2
 
3
+ **Jervaise-only artifact.** This template is for `jervaise` (saga + North Star are Jervaise-only continuity tools). For every other login, campaign position lives in the issue/PR record — do not use this template or `mmi-cli northstar`.
4
+
3
5
  Short, structured campaign working memory. Keep scannable; if this outgrows one screen, graduate or split the milestone.
4
6
 
5
7
  ```markdown
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: coop
3
- description: Cross-repo, cross-PC multi-agent coordination through the #mmi-agents Slack channel, with a GitHub proof issue and Hub wake. Use instead of send_message or ad-hoc Slack MCP in unsupervised mode.
3
+ description: Cross-repo, cross-PC multi-agent coordination through the #mmi-agents Slack channel, Hub open-session discovery, bounded polling, and a GitHub proof issue. Use instead of send_message or ad-hoc Slack MCP.
4
4
  ---
5
5
 
6
6
  # /coop — agent coordination
7
7
 
8
- Slack-first coordination for parallel agents in different worktrees, IDEs, PCs, or repos.
8
+ Join-or-create coordination for humans, backed by join-or-start primitives for agents in different worktrees, IDEs, PCs, or repos.
9
9
  `#mmi-agents` is the live coordination surface. The GitHub issue is the proof/context record.
10
10
 
11
11
  ## When to use
@@ -17,21 +17,93 @@ Slack-first coordination for parallel agents in different worktrees, IDEs, PCs,
17
17
  ## When not to use
18
18
 
19
19
  - Serial merge train → use `wave land`
20
- - Session transfer → use `/handoff`
20
+ - Session transfer → `jervaise` can use `/handoff`; everyone else uses the issue/PR handoff record
21
21
  - General Slack chat → not chatops; `#mmi-agents` is only for the `COOP_*` protocol
22
22
 
23
- ## Quick start
23
+ ## Human flow
24
24
 
25
- **Coordinator** (creates proof issue + posts `COOP_START` in `#mmi-agents`):
25
+ When the human types `/coop`, make the command feel like a small wizard.
26
+
27
+ 1. Run discovery:
28
+
29
+ ```bash
30
+ mmi-cli coop pending
31
+ mmi-cli coop open
32
+ ```
33
+
34
+ 2. Show joinable sessions by category:
35
+
36
+ - Invited to me
37
+ - My agents
38
+ - This repo
39
+ - Internal / other repos
40
+
41
+ 3. Ask whether to join one or create one.
42
+
43
+ 4. If joining:
44
+
45
+ ```bash
46
+ mmi-cli coop join <sessionCode-or-coopId>
47
+ mmi-cli coop wait <sessionCode-or-coopId>
48
+ ```
49
+
50
+ 5. If creating, ask the topic first.
51
+
52
+ 6. Then ask the target:
53
+
54
+ - Own agents
55
+ - A specific human / their agents
56
+ - Open internal session
57
+
58
+ 7. Start the session with topic and target metadata:
59
+
60
+ ```bash
61
+ mmi-cli coop start --repo mutmutco/MyRepo --topic "<topic>" --target own-agents --message-file tmp/coop-open.md
62
+ mmi-cli coop start --repo mutmutco/MyRepo --topic "<topic>" --target user --target-users oguz-mut --message-file tmp/coop-open.md
63
+ mmi-cli coop start --repo mutmutco/MyRepo --topic "<topic>" --target internal --message-file tmp/coop-open.md
64
+ ```
65
+
66
+ 8. Tell the human the returned session code.
67
+
68
+ 9. For a specific target human, offer to DM them through the MMI Future Slack app. If they approve and a Slack target is known, run:
69
+
70
+ ```bash
71
+ mmi-cli coop invite <coopId> --target-user oguz-mut --dm --slack-user U123
72
+ ```
73
+
74
+ If no Slack user id or DM channel is available, still post the visible invite:
75
+
76
+ ```bash
77
+ mmi-cli coop invite <coopId> --target-user oguz-mut
78
+ ```
79
+
80
+ 10. Enter bounded wait:
81
+
82
+ ```bash
83
+ mmi-cli coop wait <coopId>
84
+ ```
85
+
86
+ ## CLI primitives
87
+
88
+ **Check pending and open sessions first:**
89
+
90
+ ```bash
91
+ mmi-cli coop pending
92
+ mmi-cli coop open
93
+ ```
94
+
95
+ **Join an open session when one matches:**
26
96
 
27
97
  ```bash
28
- mmi-cli coop start --repo mutmutco/MyRepo --message-file tmp/coop-open.md
98
+ mmi-cli coop join <coopId>
99
+ mmi-cli coop wait <coopId>
29
100
  ```
30
101
 
31
- **Joiner** (joins the `#mmi-agents` coordination chat):
102
+ **Start only when no relevant session is open:**
32
103
 
33
104
  ```bash
34
- mmi-cli coop join <coopId> [--cloud]
105
+ mmi-cli coop start --repo mutmutco/MyRepo --topic "<topic>" --target internal --message-file tmp/coop-open.md
106
+ mmi-cli coop wait <coopId>
35
107
  ```
36
108
 
37
109
  **Handshake and information exchange** (substance in `#mmi-agents`; GitHub gets proof/context only):
@@ -42,21 +114,19 @@ mmi-cli coop say <coopId> --phase ACK --message-file tmp/ack.md
42
114
  mmi-cli coop say <coopId> --phase SHOOK --message-file tmp/shook.md
43
115
  ```
44
116
 
45
- **End** (coordinator, after user confirms):
117
+ `SHOOK` ends the coop session. Use `COOP_END` / `coop end` for explicit abort or close:
46
118
 
47
119
  ```bash
48
120
  mmi-cli coop end <coopId>
49
121
  ```
50
122
 
51
- ## Wake (primary path)
123
+ ## Bounded wait
52
124
 
53
- Hub dispatches wake on every coop message targeting joiners:
125
+ Use `mmi-cli coop wait <coopId>` after join/start/say. It polls after `1m`, `2m`, `3m`, `5m`, `10m`, and `30m`, prints only new messages, then stops waiting.
54
126
 
55
- 1. **SessionStart** `coop pending` banner + detached `coop deliver`
56
- 2. **Cursor cloud** — when joiner used `--cloud`
57
- 3. **Slack Events** — inbound `#mmi-agents` coop messages re-trigger wake
127
+ Timeout does **not** close the session. The coop remains open and can be joined later.
58
128
 
59
- **Do not** rely on `coop watch` unless wake is broken it is degraded poll only.
129
+ `coop watch` remains an unbounded manual diagnostic only.
60
130
 
61
131
  ## Rules
62
132
 
@@ -64,7 +134,12 @@ Hub dispatches wake on every coop message targeting joiners:
64
134
  - Use `#mmi-agents` for the live handshake, questions, counters, constraints, and shared facts
65
135
  - Use the GitHub issue for start context, proof links, decisions reached, and final outcome
66
136
  - Any **mutmutco org member** with a Hub session may join
67
- - Coordinator drives until `SHOOK` or explicit abort
137
+ - Check open sessions before starting a new one
138
+ - For humans, `/coop` is join-or-create: list categories first, ask topic/target only when creating
139
+ - A returned `sessionCode` is the human-shareable join code
140
+ - Specific-human creation stores `targetLogins` so the invite appears under "Invited to me"
141
+ - DM invites are opt-in; visible `#mmi-agents` invite is always available
142
+ - `SHOOK` and `COOP_END` close the session; `ACK` and `COUNTER` keep it open
68
143
 
69
144
  ## Reference
70
145