@mu-crew/mu 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/AGENTS.md +208 -599
  2. package/README.md +125 -329
  3. package/dist/cli.js +108 -78
  4. package/dist/cli.js.map +1 -1
  5. package/dist/extension/mu-pi.js +421 -56
  6. package/dist/extension/mu-pi.js.map +1 -1
  7. package/dist/index.d.ts +36 -10
  8. package/dist/index.js +89 -67
  9. package/dist/index.js.map +1 -1
  10. package/docs/ARCHITECTURE.md +176 -1072
  11. package/docs/ROADMAP.md +88 -169
  12. package/docs/VISION.md +205 -415
  13. package/docs/VOCABULARY.md +204 -466
  14. package/docs/architecture/control-socket.md +133 -0
  15. package/docs/architecture/dag.md +113 -0
  16. package/docs/architecture/mux.md +162 -0
  17. package/docs/architecture/ops-log.md +140 -0
  18. package/docs/architecture/sdk.md +185 -0
  19. package/docs/architecture/sync.md +129 -0
  20. package/docs/architecture/tui.md +146 -0
  21. package/docs/guide/README.md +30 -0
  22. package/docs/guide/backends.md +61 -0
  23. package/docs/guide/cleanup.md +74 -0
  24. package/docs/guide/delegate.md +87 -0
  25. package/docs/guide/dispatch.md +144 -0
  26. package/docs/guide/getting-started.md +180 -0
  27. package/docs/guide/recovery.md +135 -0
  28. package/docs/guide/remote.md +74 -0
  29. package/docs/guide/sql.md +76 -0
  30. package/docs/guide/stop-a-worker.md +64 -0
  31. package/docs/guide/sync.md +78 -0
  32. package/docs/guide/tui.md +98 -0
  33. package/docs/guide/upgrade.md +76 -0
  34. package/docs/history/CHANGELOG-pre-3.md +4866 -0
  35. package/docs/reference/env.md +87 -0
  36. package/docs/reference/naming.md +82 -0
  37. package/docs/specs/2026-09-28-agent-state-from-murmur.md +1 -1
  38. package/docs/specs/2026-09-29-task-substates.md +1 -1
  39. package/docs/specs/2026-10-03-keep-driving-nudge.md +142 -0
  40. package/package.json +2 -1
  41. package/prompts/mu-refute.md +8 -0
  42. package/prompts/mu-research.md +8 -0
  43. package/prompts/mu-review.md +8 -0
  44. package/prompts/mu-rules-audit.md +8 -0
  45. package/prompts/mu-tournament.md +9 -0
  46. package/prompts/ultrathink.md +9 -0
  47. package/skills/mu/SKILL.md +126 -255
  48. package/skills/mu/recipes/adversarial-review.md +83 -0
  49. package/skills/mu/recipes/brief.md +53 -0
  50. package/skills/mu/recipes/codemode-driver.md +54 -0
  51. package/skills/mu/recipes/deep-research.md +52 -0
  52. package/skills/mu/recipes/fan-out.md +36 -0
  53. package/skills/mu/recipes/hypothesis-panel.md +40 -0
  54. package/skills/mu/recipes/long-run.md +20 -0
  55. package/skills/mu/recipes/loop-until-done.md +38 -0
  56. package/skills/mu/recipes/orchestrator-loop.md +87 -0
  57. package/skills/mu/recipes/plan.md +54 -0
  58. package/skills/mu/recipes/recovery.md +26 -0
  59. package/skills/mu/recipes/refute.md +49 -0
  60. package/skills/mu/recipes/remote-workers.md +292 -0
  61. package/skills/mu/recipes/review-panel.md +57 -0
  62. package/skills/mu/recipes/rules-audit.md +70 -0
  63. package/skills/mu/recipes/tournament.md +37 -0
  64. package/skills/mu/recipes/triage.md +38 -0
  65. package/skills/mu/recipes/ultrathink.md +73 -0
  66. package/skills/mu/recipes/watcher.md +16 -0
  67. package/skills/mu/recipes/waves.md +19 -0
  68. package/skills/mu/recipes/worker.md +24 -0
  69. package/docs/HANDOVER.md +0 -486
  70. package/docs/USAGE_GUIDE.md +0 -2738
  71. package/skills/mu/REMOTE_WORKERS.md +0 -617
package/docs/VISION.md CHANGED
@@ -1,18 +1,14 @@
1
1
  # VISION: A persistent crew of agents
2
2
 
3
- > Terminology used in this doc is canonical. See
4
- > [VOCABULARY.md](VOCABULARY.md) for definitions of *workstream*,
5
- > *agent*, *task DAG*, *crew*, *track*, *claim*, *free*, *workspace*,
6
- > and the rest.
3
+ Terms are defined in [VOCABULARY.md](VOCABULARY.md).
7
4
 
8
- ## What This Is
5
+ ## What mu is
9
6
 
10
- mu is a small, durable **control plane** for a persistent crew of AI
11
- agents in multiplexer panes. Agents have names, roles, and status; they live
12
- across sessions; they work on a built-in task graph with VCS
13
- workspace isolation; humans and other agents drive them through one
14
- CLI. State lives in one SQLite file; every mu feature is a typed verb
15
- over that state or a reconciled view of reality.
7
+ mu is a small, durable control plane for a persistent crew of AI agents
8
+ in multiplexer panes. Agents have names and roles, outlive sessions, and
9
+ work on a built-in task graph, each in its own VCS workspace. Humans and
10
+ agents drive them through one CLI. State lives in one SQLite file. Every
11
+ feature is a typed verb over that state or a reconciled view of reality.
16
12
 
17
13
  ```bash
18
14
  mu agent spawn worker-1 --tab Backend --workspace
@@ -24,233 +20,178 @@ mu state # canonical state card
24
20
  mu log --tail # subscribe to every state change
25
21
  ```
26
22
 
27
- That's the whole product. Everything else makes those few lines work,
28
- recover from failure, and scale to dozens of agents and hundreds of
29
- tasks.
23
+ Everything else makes those lines recover from failure and scale to
24
+ dozens of agents and hundreds of tasks.
30
25
 
31
- ---
32
-
33
- ## Why It Exists
26
+ ## Why it exists
34
27
 
35
28
  Existing tools force a choice:
36
29
 
37
30
  - **Hidden subagents** (pi-subagents, the Claude Code and Codex task
38
- tools) delegate one-shot work to a child you cannot see, steer, or
39
- keep talking to; its transcript collapses into a result.
40
- - **Tmux-orchestration tools** spawn agents in panes but leave
31
+ tools) hand one-shot work to a child you cannot see, steer, or keep
32
+ talking to. Its transcript collapses into a result.
33
+ - **tmux orchestration tools** spawn agents in panes but leave
41
34
  coordination to chat transcripts or filesystem conventions.
42
- - **Task trackers** (GitHub Issues, Linear, even tg) model the work but
43
- don't run the agents.
44
- - **Bigger orchestration platforms** carry the coordination state but
45
- have accumulated breadth that costs more in maintenance than it
46
- pays for. See
47
- [§ What looking at a prior multi-agent runtime taught us](#what-looking-at-a-prior-multi-agent-runtime-taught-us).
48
-
49
- mu unifies the first three without becoming the fourth: persistent
50
- pi agents, a structured work graph, per-agent VCS isolation, one
51
- CLI, one SQLite file. "What should this agent do next?" becomes:
52
-
53
- ```bash
54
- mu task next # top ready task by ROI
55
- mu state # full picture as a JSON state card
56
- ```
35
+ - **Task trackers** (GitHub Issues, Linear) model the work but do not
36
+ run the agents.
37
+ - **Large orchestration platforms** hold the coordination state but
38
+ carry breadth that costs more to maintain than it returns. See
39
+ [What a prior runtime taught us](#what-a-prior-runtime-taught-us).
57
40
 
58
- ---
41
+ mu joins the first three without becoming the fourth.
59
42
 
60
- ## Design Principles
43
+ ## Design principles
61
44
 
62
45
  ### 1. The CLI is the product
63
46
 
64
- The pi extension is a UX skin. Everything mu does must work from a
65
- shell with no pi anywhere. A feature that requires the extension
66
- doesn't ship.
47
+ Everything mu does works from a shell with no pi extension loaded. A
48
+ feature that needs the extension does not ship. The pi extension
49
+ (`mu link pi`) serves the control socket and the `mu_delegate` tool, and
50
+ three rules keep it thin:
67
51
 
68
- Delegation is CLI: `mu agent spawn -w scratch` + `mu agent send` +
69
- `mu agent wait --json`. The `mu_delegate` tool adds only the callback
70
- that puts the answer into the parent conversation, and that is
71
- presentation.
52
+ 1. **The DB is canonical.** The extension reads and writes through the
53
+ same modules as the CLI. It keeps no state of its own.
54
+ 2. **Every operation works from the CLI.** No extension tool has logic
55
+ the CLI lacks.
56
+ 3. **The skill teaches the CLI.** A pi session without the extension
57
+ still gets a working mu from [skills/mu/SKILL.md](../skills/mu/SKILL.md).
58
+
59
+ Delegation is CLI: `mu agent spawn -w scratch`, `mu agent send`, and
60
+ `mu agent wait --json`. `mu_delegate` only adds the callback that puts
61
+ the answer into the parent conversation.
72
62
 
73
63
  ### 2. One DB is canonical
74
64
 
75
- All state lives in `~/.local/state/mu/mu.db`. SQLite WAL; multiple
76
- processes share it safely. The DB is the source of truth; in-memory
77
- state is a cache. The extension and the CLI go through the same DB,
78
- so they never diverge.
65
+ All state lives in `~/.local/state/mu/mu.db` (SQLite WAL, safe for
66
+ concurrent processes). In-memory state is a cache. The extension and the
67
+ CLI share the DB, so they cannot diverge.
79
68
 
80
69
  ### 2b. One log records every change
81
70
 
82
- There is exactly **one** record of change: the `ops` table, written by
83
- SQLite triggers inside the same transaction as the mutation they
84
- record. Same file, same transaction — so capture cannot be forgotten
85
- and cannot drift from the data, even on power loss.
86
-
87
- **Sync, undo, rebuild, and history are all queries or replays over
88
- that one log.**
71
+ The `ops` table is the only change record. SQLite triggers write it in
72
+ the same transaction as the mutation, so capture cannot be forgotten or
73
+ drift from the data. Sync, undo, rebuild, and history are queries or
74
+ replays over that log.
89
75
 
90
- The tables stay canonical for **reads** — this is not an event-sourced
91
- system that replays to answer a query. Ops are the durable change
92
- record; the tables are the materialized view; triggers keep them in
93
- lockstep. `mu doctor` rebuilds into a temp DB and diffs, so the
94
- lockstep is verified rather than assumed.
95
-
96
- The cost: a capture bug is not "sync is broken", it is "undo and
97
- rebuild are also broken". The drift check is load-bearing.
76
+ Reads still go to the tables. mu is not event-sourced: the tables are
77
+ the materialized view and triggers keep them in step with the ops.
78
+ `mu doctor` rebuilds into a temp DB and diffs, so that is verified, not
79
+ assumed. A capture bug therefore breaks sync, undo, and rebuild at once,
80
+ which is why the drift check is load-bearing.
98
81
 
99
82
  ### 2c. Local-first, transport-agnostic
100
83
 
101
- Every machine keeps its own complete DB. Machines exchange
102
- append-only JSONL **segments** — one per machine, single-writer, so no
103
- file is ever contended and any file-mover (Syncthing, rsync, scp,
104
- git, a USB stick) is adequate transport. mu reads and writes files;
105
- **the user owns transport**. mu has no network code, no daemon, and
106
- no membership config — peers are discovered from the segment files
107
- present.
84
+ Every machine keeps a complete DB. Machines exchange append-only JSONL
85
+ segments, one per machine with a single writer, so no file is contended
86
+ and any file mover works (Syncthing, rsync, scp, git, a USB stick). mu
87
+ reads and writes files. The user owns transport. mu has no network
88
+ code, no daemon, and no membership config: peers are found from the
89
+ segment files present.
108
90
 
109
91
  ### 3. Reality wins reconciliation
110
92
 
111
- `mu agent list` queries the mux, prunes ghosts, surfaces orphans. The DB
112
- records what we last observed, not what we wish were true. If
113
- worker-1's pane crashed, the next `mu agent list` notices.
93
+ `mu agent list` queries the mux, prunes ghosts, and surfaces orphans.
94
+ The DB records what mu last observed.
114
95
 
115
96
  ### 4. Agents are dumb workers; the task graph is the brain
116
97
 
117
- The **task DAG is the central organizing primitive**, not a sidecar
118
- feature. Tasks have mandatory `impact` and `effort_days`; edges are
119
- `blocks` relationships; `ready`/`blocked`/`goals` are SQL views; the
120
- parallel-track detector runs union-find with automatic diamond-merge
121
- so two agents never collide on a shared dependency.
98
+ The task DAG is the center of mu, not a sidecar. Tasks require `impact`
99
+ and `effort_days`. Edges are `blocks` relations. `ready`, `blocked`, and
100
+ `goals` are SQL views. The parallel-track detector runs union-find and
101
+ merges diamonds, so two agents never collide on a shared dependency.
122
102
 
123
- "What should this agent do next?" and "can we parallelize?" are
124
- deterministic queries against the graph, not LLM judgment calls. The
125
- LLM decides *what to type to the agent*; the graph decides *which
126
- agent gets which task*.
103
+ "What next?" and "can we parallelize?" are deterministic queries. The
104
+ LLM decides what to type to an agent. The graph decides which agent gets
105
+ which task.
127
106
 
128
107
  ### 5. One workstream per mux session
129
108
 
130
- A mu workstream is a **mux session** — a tmux session on the tmux
131
- backend, a herdr workspace on the herdr backend. All its agents are
132
- panes/windows inside that session. `tmux a -t mu-<workstream>` shows
133
- the whole crew live. Multiple workstreams on one machine are multiple
134
- isolated mux sessions, partitioned in the DB by `session_id`. Detach
135
- and reattach as you would any tmux session — the crew survives.
136
-
137
- The multiplexer is a **backend**, chosen by detection
138
- (`MU_MUX` → `HERDR_ENV` → `$TMUX` → `PATH`), the same shape as the
139
- VCS backend. Everything backend-specific — topology, the send
140
- protocol, scrollback capture, pane-id validation, identity fallback —
141
- lives behind `MuxBackend` in `src/mux/`. Two implementations, not an
142
- anticipatory abstraction: a third earns its way in on its own
143
- friction evidence.
109
+ A workstream is a mux session: a tmux session on tmux, a herdr workspace
110
+ on herdr. Its agents are panes in that session, so
111
+ `tmux a -t mu-<workstream>` shows the whole crew. Workstreams on one
112
+ machine are separate sessions, partitioned in the DB by `session_id`.
113
+ The crew survives detach and reattach.
114
+
115
+ The multiplexer is a backend chosen by detection
116
+ (`MU_MUX` → `HERDR_ENV` → `$TMUX` → `PATH`), like the VCS backend.
117
+ Topology, the paste protocol, scrollback capture, pane-id validation,
118
+ and identity fallback live behind `MuxBackend` in `src/mux/`. There are
119
+ two implementations. A third needs its own friction evidence.
144
120
 
145
121
  ### 6. Pi-first, with reported agent state
146
122
 
147
- mu does not infer agent state from pane text. The herdr backend reports
148
- state through the mux. On tmux, murmur's pi extension reports state from
149
- inside the agent process; without murmur, state is `unknown` with a reason.
123
+ mu never infers agent state from pane text. Each state source reports it:
150
124
 
151
- `--cli` and `MU_<UPPER_CLI>_COMMAND` stay useful for swapping the pi
152
- binary: set `MU_PI_COMMAND=<name>` once and every spawn picks it up.
153
- Multi-word commands work: `MU_PI_COMMAND="pi-alt --some-flag"`.
125
+ | Agent | Send, abort, wait | State |
126
+ | --- | --- | --- |
127
+ | pi (any backend, local or remote over `ssh -L`) | control socket, exact | control socket |
128
+ | other CLI on herdr | mux | herdr |
129
+ | other CLI on tmux | mux (bracketed paste) | murmur |
154
130
 
155
- Multi-CLI support (claude / codex with real detection) is not
156
- planned. The substrate is ready if it earns promotion per the
157
- [ROADMAP](ROADMAP.md) criteria: spawn accepts arbitrary commands and
158
- the schema's `cli` column is TEXT.
131
+ With no source, state is `unknown` with a reason. A pi agent whose
132
+ socket does not answer fails loudly; mu never falls back to pasting.
133
+ murmur is optional for pi agents.
134
+
135
+ `MU_PI_COMMAND="pi-alt --some-flag"` swaps the pi command for every
136
+ spawn. First-class support for other CLIs is not planned. It can earn promotion
137
+ under the [ROADMAP](ROADMAP.md) criteria: spawn accepts any command and
138
+ `agents.cli` is TEXT.
159
139
 
160
140
  ### 7. TypeScript on Node
161
141
 
162
- Mu is TypeScript on Node, with a small set of well-established
163
- npm deps (`commander`, `better-sqlite3`, `cli-table3`, `picocolors`,
164
- `execa`). No native code we maintain, no build matrix. Anyone
165
- reading `package.json` should recognize every name.
166
-
167
- The choice earns its keep on four axes:
168
-
169
- - **The type system pays.** The `AgentNotFoundError` /
170
- `TaskNotFoundError` / `TaskNotInWorkstreamError` / `CycleError`
171
- hierarchy maps to exit codes via `handle()`; the
172
- `assertXInWorkstream` family stays type-safe across every
173
- namespace; `noUncheckedIndexedAccess` has caught real bugs. Go
174
- loses the discriminated unions, Python's checker is too weak,
175
- Rust costs 2–3× the LOC.
176
- - **JSON-first surface fits TS.** Every read verb's `--json` output
177
- is `JSON.stringify(value)` straight from a typed shape.
178
- - **`better-sqlite3` fits the shape.** Synchronous
179
- request/response matches the CLI invocation model; WAL correct out
180
- of the box; `db.transaction()` is the right shape.
181
- - **Iteration speed.** ~60 typed verbs / 10 tables / ~2900 tests
182
- (`npm run test`) in ~95k LOC src+tests (`wc -l` over `src/` and
183
- `test/`), with multiple substantive changes per day. That cadence
184
- in an equivalent Rust codebase would be 2–3× slower.
185
-
186
- **Where it's weak: cold start.** Node's V8 init is ~30–50ms even
187
- after tsup bundles (Rust ~5ms, Go ~10–15ms). That would matter if
188
- mu were called in tight loops, but the docs steer operators away
189
- from polling toward `mu log --tail`. If that stops being true, Rust
190
- is the natural port target.
191
-
192
- **Native dep:** `better-sqlite3` requires prebuilds or a C++
193
- toolchain. Prebuilds cover darwin-arm64/x64, linux-x64/arm64,
194
- win32-x64 — every dev workstation we care about. Acceptable.
195
-
196
- ### 8. Schema-first; typed verbs over read views; SQL as escape hatch
197
-
198
- The product surface is:
199
-
200
- - **Read views** (the `ready` / `blocked` / `goals` SQL views; `mu
201
- state` as the curated state card) for inspection.
202
- - **Typed verbs** that map cleanly to resource transitions for action
203
- (`task add`, `task claim`, `task close`, `agent spawn --workspace`,
204
- `workstream init`, `workstream destroy`, ...).
205
- - **`--json` on every read verb** so scripts pipe through `jq`
206
- instead of parsing tables.
207
- - **`mu sql`** as the explicit escape hatch underneath.
208
-
209
- There is no DSL, no plugin system, no workflow engine, no
210
- `defineOperation` registry generating verbs from declarations. The
211
- commander wiring in `src/cli.ts` is the single source of truth for
212
- the verb surface. Adding a new verb is one SDK function plus one
213
- commander block.
142
+ mu uses a few well-known npm dependencies (`commander`,
143
+ `better-sqlite3`, `cli-table3`, `picocolors`, `execa`, and `ink` for the
144
+ TUI). There is no native code to maintain and no build matrix.
145
+
146
+ - **Types pay.** The typed error classes map to exit codes in
147
+ `handle()`. The `assertXInWorkstream` family stays type-safe across
148
+ namespaces. `noUncheckedIndexedAccess` has caught real bugs.
149
+ - **`better-sqlite3` fits.** Synchronous calls match a short-lived CLI,
150
+ and `db.transaction()` is the right shape.
151
+ - **Iteration is fast.** Several substantive changes a day land in
152
+ about 99k lines of `src/` and `test/`.
153
+
154
+ The weak spot is cold start: Node takes 30–50 ms to boot, which matters
155
+ only in tight loops. If that changes, Rust is the port target.
156
+ `better-sqlite3` needs prebuilds (darwin-arm64/x64, linux-x64/arm64,
157
+ win32-x64) or a C++ toolchain.
158
+
159
+ ### 8. Schema-first: typed verbs over read views, SQL as escape hatch
160
+
161
+ - **Read views**: the `ready`, `blocked`, and `goals` views, and
162
+ `mu state` as the state card.
163
+ - **Typed verbs** that map to resource transitions (`task claim`,
164
+ `task close`, `agent spawn --workspace`, `workstream destroy`).
165
+ - **`--json` on every read verb**, so scripts use `jq`, not table parsing.
166
+ - **`mu sql`** underneath, as the explicit escape hatch.
167
+
168
+ There is no DSL, no plugin system, no workflow engine, and no verb
169
+ registry. The commander wiring in `src/cli.ts` is the verb surface. A new
170
+ verb is one SDK function plus one commander block.
214
171
 
215
172
  ### 9. Observed vs claimed
216
173
 
217
- When a verb mutates state, the audit trail records what the caller
218
- said it relied on. `mu task close design --evidence "tests pass:
219
- npm test exit 0"` lands in the ops log as
220
- `task status design (IN_PROGRESS → CLOSED) evidence="..."`. The verb
221
- still trusts the caller — mu doesn't run tests for you — but the
222
- grounding for every state change is searchable via `mu log`.
174
+ A mutating verb records what the caller said it relied on.
175
+ `mu task close design --evidence "npm test exit 0"` lands in the ops log
176
+ with the evidence. mu does not run the tests, but `mu log` can search
177
+ the grounding for every change.
223
178
 
224
179
  ### 10. Get out of the model's way
225
180
 
226
- Mu coordinates agents; it does not reason about them. Specifically,
227
- mu does not own:
228
-
229
- - **Model selection.** No tier abstraction, no provider matrix, no
230
- vendor-name mapping. Pi already speaks `--model sonnet:high` and
231
- `--provider openai`. Inventing tier names would mean owning a
232
- vendor matrix that goes stale every quarter.
233
- - **Effort / thinking levels.** Pi has
234
- `--thinking off|minimal|low|medium|high|xhigh`. Mu doesn't wrap
235
- it, doesn't normalise it, doesn't second-guess it. Pass-through
236
- via `--command` or the `MU_<UPPER_CLI>_COMMAND` env var, full stop.
237
- - **Prompt engineering.** Mu has no system-prompt templating, no
238
- role injection beyond the agent name and `--role`, no "agent
239
- template" registry. The system prompt is whatever you put in the
240
- spawn command and the first message you send.
241
- - **Tool routing decisions.** Pi (and any other CLI you spawn) owns
242
- tool allowlists, MCP servers, extensions. Mu doesn't proxy or
243
- inspect them.
244
- - **Output interpretation.** Mu does not parse pane contents for agent
245
- state, facts, claims, or tool calls. murmur or herdr reports runtime
246
- agent state.
247
- The `--evidence` payload is whatever the agent says it is; mu
248
- records it without interpretation.
249
-
250
- The full mechanism is one function: `--cli <key>` uppercases the
251
- key and looks up `$MU_<KEY>_COMMAND`. That's mu's entire vendor
252
- surface. The operator pattern when you want different models per
253
- role is just convention on top:
181
+ mu coordinates agents and does not reason about them. It does not own:
182
+
183
+ - **Model selection or thinking levels.** No tiers, no provider matrix.
184
+ pi already takes `--model` and `--thinking`. Pass them through the
185
+ spawn command.
186
+ - **Prompts.** No system-prompt templates and no role registry. The
187
+ prompt is the spawn command plus the first message.
188
+ - **Tool routing.** The agent CLI owns tool allowlists, MCP servers, and
189
+ extensions.
190
+ - **Output interpretation.** mu does not parse panes for state, facts,
191
+ or tool calls. `--evidence` is recorded as given.
192
+
193
+ The whole vendor surface is one lookup: `--cli <key>` reads
194
+ `$MU_<KEY>_COMMAND`. Per-role models are a convention in your shell rc:
254
195
 
255
196
  ```bash
256
197
  export MU_PI_MINI_COMMAND="pi --model haiku:off" # → --cli pi_mini
@@ -260,227 +201,76 @@ mu agent spawn worker-1 --cli pi_mini
260
201
  mu agent spawn reviewer-1 --cli pi_big
261
202
  ```
262
203
 
263
- Your shell rc owns the mapping. The names `pi_mini` / `pi_big` are
264
- operator convention — mu doesn't know about "tiers," it just looks
265
- up whatever env var the uppercased key produces. Swap the whole
266
- matrix in one line; per-machine, per-workstream, per project —
267
- wherever you set the env. The substrate stays small; the
268
- orchestrator stays in charge.
269
-
270
- ---
271
-
272
- ## What It Enables
273
-
274
- - **Persistent crews in one place** — Spawn worker-1/worker-2/reviewer-1
275
- once, send them work all day. `tmux a -t mu-<workstream>` shows
276
- the whole crew: each agent in its own pane, observable, detachable.
277
- - **Graph-driven coordination** — The task DAG answers "what's ready?",
278
- "what blocks what?", "what can be parallelized?" with SQL queries
279
- and union-find, not LLM guesses. Task notes accumulate durable
280
- context that outlives any single agent or session.
281
- - **Deterministic parallelization** — Diamond patterns (shared
282
- prerequisites) get merged automatically so two agents never collide
283
- on a shared dependency. The orchestrator follows the algorithm; it
284
- doesn't have to be smart enough to spot the trap.
285
- - **VCS workspace isolation** — Each agent gets its own jj workspace,
286
- sl clone, git worktree, or `cp -a` snapshot, auto-detected.
287
- `mu agent spawn --workspace` creates and mounts; `mu agent close`
288
- auto-frees. Two parallel agents in the same project never trample
289
- each other's working tree.
290
- - **Async coordination via `mu log`** — Every state-changing verb
291
- writes an op. Subscribers `mu log --tail` instead of polling.
292
- Wakeups without a daemon.
293
- - **Audit trail with grounding** — `--evidence` on lifecycle verbs
294
- records what the caller observed, searchable via `mu log`.
295
- - **Crash recovery** — Reconciliation prunes ghost agents; the reaper
296
- reverts their IN_PROGRESS tasks to OPEN with an explanatory note;
297
- no manual cleanup.
298
- - **Human-driveable** — Anything mu can do, you can do from a shell.
299
- Debug, recover, script, cron.
300
-
301
- ---
302
-
303
- ## What It Is NOT
304
-
305
- - **Not an orchestrator.** mu provides primitives. The orchestration
306
- *policy* (when to spawn, what to assign, when to free) is yours —
307
- expressed as bash scripts, jq pipelines over `--json` output, or
308
- driven by an LLM through the bundled skill. There is no JS DSL,
309
- no workflow engine, no `mu run script.ts`. <!-- doc-cli-drift:skip --> (See
310
- [§ What looking at a prior multi-agent runtime taught us](#what-looking-at-a-prior-multi-agent-runtime-taught-us).)
311
- - **Not a build tool.** mu doesn't compile, test, or deploy your code.
312
- It runs agents that do those things.
313
- - **Not a chat protocol.** Agents communicate through the work graph
314
- (notes, claim, status) and the **ops log** read through `mu log`.
315
- - **Not a hidden-subagent runner.** A one-shot **delegate** is an
316
- ordinary agent in a visible pane: attach, steer, abort, or keep
317
- talking to it. The cost is one pane and one pi process per delegate;
318
- a hidden subagent is lighter for many tiny calls. mu bets that
319
- visibility and steering are worth that for agent work. No agent
320
- types: the brief is ad-hoc text.
321
- - **Not a hosted service.** Local-first SQLite. Zero ops, no accounts.
322
- Your machine is the deployment.
323
- - **Not a verifier.** The verbs trust the caller. `task close
324
- --evidence "tests pass"` records the claim; mu doesn't run the
325
- tests. Verification is the caller's job. (mu may grow optional
326
- verifying-runners later if friction surfaces; today it's an
327
- audit-trail discipline, not enforcement.)
204
+ ## What it enables
205
+
206
+ - **Visible crews.** Spawn agents once and send them work all day. Each
207
+ sits in a pane you can attach to.
208
+ - **Isolation.** Each agent gets a jj workspace, sl clone, git worktree,
209
+ or `cp -a` copy, detected automatically and freed by `mu agent close`.
210
+ - **Wakeups without a daemon.** `mu log --tail` and event-driven
211
+ `mu agent wait` replace polling.
212
+ - **Crash recovery.** The reaper reopens a dead agent's IN_PROGRESS
213
+ tasks with a note.
214
+
215
+ ## What it is not
216
+
217
+ - **Not an orchestrator.** mu provides primitives. The policy (when to
218
+ spawn, what to assign, when to free) is yours: bash, `jq` over
219
+ `--json`, or an LLM following the bundled skill. There is no workflow
220
+ engine and no `mu run script.ts`. <!-- doc-cli-drift:skip -->
221
+ - **Not a chat protocol.** Agents communicate through notes, claims, and
222
+ the ops log.
223
+ - **Not a hidden-subagent runner.** A delegate is an ordinary agent in a
224
+ visible pane: attach, steer, abort, or keep talking to it. It costs one
225
+ pane and one pi process. A hidden subagent is lighter for many tiny
226
+ calls. mu bets that visibility and steering are worth the cost. There
227
+ are no agent types: the brief is plain text.
328
228
  - **DB-undoable, not substrate-undoable.** `mu undo <group> --yes`
329
- emits inverse ops for one action and restores the rows. It does not
330
- replay killed mux panes or recreate freed workspace directories;
331
- after an undo, reconciliation reports ghosts/orphans and the caller
332
- decides what to re-spawn or adopt.
333
-
334
- ---
335
-
336
- ## Key Constraints
337
-
338
- 1. **A multiplexer is required.** The substrate is mux panes — tmux or
339
- herdr. No multiplexer, no agents. `mu doctor` reports the resolved
340
- backend and its version; verbs that touch the agent layer fail with
341
- exit 5 when none is reachable.
342
-
343
- 2. **Local-first persistence.** SQLite file at
344
- `~/.local/state/mu/mu.db`. Cross-machine state moves as
345
- append-only JSONL segments in a shared folder; you own transport.
346
-
347
- 3. **Pi-first.** `--cli pi` is the meaningful default; `--cli` accepts
348
- other strings as a key for the `MU_<UPPER_CLI>_COMMAND` env var
349
- resolver. Agent state comes from murmur on tmux and herdr on herdr;
350
- absence is `unknown` rather than an inferred value.
351
-
352
- 4. **Send is delivered, not acknowledged.** `mu agent send` gets the
353
- text into the pane and warns loudly when it cannot confirm
354
- submission, but the AGENT never acknowledges receipt.
355
- Orchestrators poll status or subscribe to
356
- `mu log --tail` for confirmation. This is by design — the
357
- alternative requires a protocol every CLI would have to speak.
358
-
359
- 5. **Recursion is opt-in.** The `mu_delegate` tool is hidden in
360
- agents mu spawned (`MU_MANAGED_AGENT`), so a delegate cannot spawn
361
- delegates through it. Agents get the `mu` binary on PATH, but the
362
- bundled skill says "you are not the orchestrator."
363
-
364
- 6. **Subscriptions are polling-based.** `mu log --tail` polls
365
- SQLite once per second. SQLite handles the concurrency; latency
366
- is bounded by the poll interval. Real subscription mechanisms
367
- (SQLite hooks, fs.watch) are a future ask if anyone hits the
368
- latency cliff.
369
-
370
- 7. **Every invocation is short-lived — except for two named
371
- interactive readers.** mu is a CLI: each verb starts, mutates
372
- or reads, prints, and exits. There is no daemon, no resident
373
- state outside SQLite, no background process. Two verbs are
374
- exempt, narrowly, because they are interactive *readers* rather
375
- than background workers:
376
-
377
- - `mu log --tail` — polls SQLite once per second; emits NDJSON
378
- until SIGINT or the parent closes stdin.
379
- - the TUI dashboard — rendered by `mu state --tui` explicitly or
380
- by bare `mu` when stdout is attached to a TTY, until the user
381
- quits with `q`/`Ctrl-C`. Plain `mu state` keeps the static-card
382
- behaviour; non-TTY bare `mu` prints help instead of entering Ink.
383
-
384
- Both share the same shape, and the shape is the predicate that
385
- bounds the exception:
386
-
387
- - **Interactive, not a daemon.** The process is owned by a
388
- human (or a parent script) and dies the moment that owner
389
- ends it. Nothing keeps it alive across sessions; nothing
390
- restarts it.
391
- - **Read-only against SQLite.** Neither verb writes. The TUI's
392
- act-intents (claim, close, send, ...) yank the canonical
393
- `mu <verb>` command into the clipboard and exit the
394
- dashboard; every mutation still lands through a fresh
395
- short-lived CLI invocation.
396
- - **No resources beyond stdout, stdin, and a poll timer.** No
397
- sockets, no file watches, no subscriptions to external
398
- services, no spawned subprocesses, no inter-process state
399
- beyond the SQLite reads any other CLI invocation already
400
- does.
401
- - **Human-TTY gated, with static/script fallbacks.** The TUI mode
402
- activates when `--tui` is passed to `mu state` or when bare `mu`
403
- sees `process.stdout.isTTY === true`. Default `mu state` prints
404
- the static card. Non-interactive callers (pipes, CI, `--json`, or
405
- `MU_NO_TUI=1`) never enter the TUI.
406
-
407
- This is not a precedent for any other long-lived process. The
408
- anti-feature pledges in [ROADMAP.md](ROADMAP.md) remain in force;
409
- a third member of this exception class needs its own promotion.
410
-
411
- ---
412
-
413
- ## What looking at a prior multi-agent runtime taught us
414
-
415
- A five-role council critique of a prior internal multi-agent runtime
416
- — mu's design ancestor — converged on a sharp central claim:
417
-
418
- > [The runtime] is not justified as a better general coding harness.
419
- > [The runtime] is justified only when it becomes a durable
420
- > coordination/control plane for work that outgrows a thin harness
421
- > plus manually managed tmux.
422
-
423
- And a sharper recommendation for what such a control plane should
424
- look like:
425
-
426
- > A minimal defensible core would be: durable sessions/transcripts;
427
- > agent registry; task records / task graph; workspace and checkout
428
- > ownership/leases; event log; wakeups/timers; human approvals/input;
429
- > typed control API; read-only views/state cards; recovery/orphan
430
- > detection.
431
- >
432
- > Everything else — chat, docs, IDE assist, incident-triage,
433
- > mobile-agent, end-to-end workflows, memory policy, rich
434
- > dashboards, workflow DSLs — should be optional layers that prove
435
- > they strengthen the supervision loop.
436
-
437
- Nine of the ten items in that minimal core ship in mu; almost every
438
- item the council criticised is something mu does not have.
439
-
440
- ### The council's criticisms → mu's design choices
441
-
442
- | Council critique of the prior runtime | mu's stance |
443
- | ------------------------------------------------------------- | -------------------------------------------------------------------------- |
444
- | "Sprawling product identities (TUI + web + Thrift + plugin host + workflow engine + chat + docs + memory + ...)" | One CLI, one SQLite file, no plugins, no web UI, no Thrift, no chat/docs integrations. |
445
- | "Workflow DSL is mostly liability" | Rejected outright. No `mu run`/`eval`/`repl`. <!-- doc-cli-drift:skip --> `--json` + bash + jq cover the scripting story. |
446
- | "defineOperation/verb-registry adds entropy without consumers" | Rejected. The commander wiring in `src/cli.ts` is the verb surface; one place. |
447
- | "Plugin sprawl with hidden state and lifecycle bugs" | No plugins. Adding behaviour is a typed verb in `src/cli.ts`. |
448
- | "CLI verbs as a primary model surface vs. typed mutations" | mu's verbs *are* the typed mutations. CLI is a thin wrapper over a typed SDK with idempotency, validation, exit-code-mapped errors. |
449
- | "Raw SQL as the only inspection surface is too low-level" | `mu state` is the canonical state card. `--json` everywhere. `mu sql` is the escape hatch beneath, not the cockpit. |
450
- | "Distinguish observed from claimed state" | `--evidence` on lifecycle verbs (first inch). The verb still trusts the caller; the audit trail records grounding. |
451
- | "Approval primitives belong in the core" | Not in mu: dogfood across 200+ tasks produced zero calls for them. Anti-anticipatory pruning per "no traits with zero implementors". May earn promotion when a real implementor surfaces (e.g. an unattended pi-orchestrator running mu). |
452
- | "Reads must distinguish provenance (process telemetry vs agent self-report)" | event `source` field attributes events to actor (claiming agent / decider / 'system'). |
453
- | "State must be authoritative and recoverable, not just durable" | Reconciliation runs on read paths; reaper recovers stuck IN_PROGRESS automatically. |
454
-
455
- ### What this validates
456
-
457
- 1. **The anti-feature pledges hold.** No DSL, no plugins,
458
- no daemon, no config file, no web UI. Each is a failure mode the
459
- prior runtime exhibited and mu chose not to inherit.
460
-
461
- 2. **"Pi+tmux is the benchmark" is the right comparison.** mu only
462
- earns its complexity above the threshold where coordination
463
- itself is the work — multiple agents, multiple checkouts, delayed
464
- wakeups, recovery, approvals. Below that, a thin harness with
465
- manual tmux is more transparent.
466
-
467
- 3. **Schema-first + typed verbs + state cards is the right model UX
468
- shape** — independent reasoning from operators, engineers,
469
- architects, and model-UX specialists converges on it.
470
-
471
- ### What this still flags as gaps
472
-
473
- The critique cuts mu too:
474
-
475
- - **Wakeups are polling-based.** `mu log --tail` polls every 1s.
476
- Real subscriptions (SQLite update hooks) are deferred.
477
- - **`--evidence` is grounding, not verification.** mu doesn't run the
478
- tests. A future `--verify-by` mode that runs a command and records
479
- its exit could deepen this; not built yet.
480
- - **No idempotency keys on mutations.** Most ops are idempotent by
481
- happenstance; not declared as part of the API contract.
482
- - **No dry-run on most mutations.** `workstream destroy`, `task delete`, and `undo` have it; most other mutating verbs apply immediately.
483
- - **No capability model.** The `role` field is stored on agent rows
484
- but unused. No "reviewer-1 cannot delete tasks" enforcement.
485
-
486
- Each is a known gap with a clear shape; none has earned promotion.
229
+ restores rows. It does not revive killed panes or freed workspace
230
+ directories. Reconciliation then reports ghosts and orphans.
231
+
232
+ ## Key constraints
233
+
234
+ 1. **A multiplexer is required** (tmux or herdr). `mu doctor` reports
235
+ the backend. Agent verbs exit 5 when none is reachable.
236
+ 2. **The agent never acknowledges a send.** For pi, the control socket
237
+ confirms that pi accepted the message. On the mux path, mu confirms
238
+ only that the text reached the pane and warns when it cannot confirm
239
+ submission. Use `mu agent wait` or `mu log --tail` to see the effect.
240
+ 3. **Recursion is opt-in.** `mu_delegate` is hidden in agents mu spawned
241
+ (`MU_MANAGED_AGENT`). Agents have `mu` on PATH, but the skill tells
242
+ them they are not the orchestrator.
243
+ 4. **Every invocation is short-lived, except two interactive readers.**
244
+ No daemon, no resident state outside SQLite, no background process.
245
+ The exceptions are `mu log --tail` and the TUI (`mu state --tui`, or
246
+ bare `mu` on a TTY). Both are:
247
+ - owned by a human or parent script and gone when it ends;
248
+ - read-only: TUI actions copy the `mu <verb>` command to the
249
+ clipboard and exit, so every write is a fresh CLI call;
250
+ - limited to stdin, stdout, and a poll timer: no sockets, watches, or
251
+ subprocesses;
252
+ - TTY-gated: pipes, CI, `--json`, and `MU_NO_TUI=1` never enter the
253
+ TUI, and plain `mu state` prints the static card.
254
+
255
+ The control socket is not a third exception. The pi process serves it
256
+ and it dies with that process. Any other long-lived process needs its
257
+ own promotion; the [anti-feature pledges](ROADMAP.md#anti-feature-pledges)
258
+ stand.
259
+
260
+ ## What a prior runtime taught us
261
+
262
+ A council review of mu's design ancestor, a larger internal multi-agent
263
+ runtime, found it justified only as a durable coordination control
264
+ plane. Its minimal core: sessions, an agent registry, a task graph,
265
+ workspace ownership, an event log, wakeups, human approvals, a typed
266
+ control API, read-only state cards, and orphan recovery. Everything else
267
+ (chat, workflow DSLs, memory, dashboards) had to prove its worth.
268
+
269
+ mu ships nine of the ten. Approvals are missing because 200+ dogfooded
270
+ tasks never needed them. Below the point where coordination is itself
271
+ the work, pi plus manual tmux is more transparent than mu.
272
+
273
+ Known gaps, none promoted yet: `--evidence` grounds but does not verify,
274
+ mutations have no declared idempotency keys, most mutations have no dry
275
+ run (`workstream destroy`, `task delete`, and `undo` do), and the `role`
276
+ field is stored but not enforced.