@mu-crew/mu 1.6.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/AGENTS.md +611 -0
- package/README.md +328 -0
- package/dist/cli.js +22146 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +4853 -0
- package/dist/index.js +9740 -0
- package/dist/index.js.map +1 -0
- package/docs/.m-reflow-5f7exa_b.md +509 -0
- package/docs/.m-reflow-5v_034rw.md +545 -0
- package/docs/.m-reflow-7yaw8ubc.md +513 -0
- package/docs/ARCHITECTURE.md +997 -0
- package/docs/HANDOVER.md +486 -0
- package/docs/ROADMAP.md +277 -0
- package/docs/USAGE_GUIDE.md +2615 -0
- package/docs/VISION.md +487 -0
- package/docs/VOCABULARY.md +481 -0
- package/docs/img/tui-dashboard.png +0 -0
- package/package.json +87 -0
- package/skills/mu/REMOTE_WORKERS.md +604 -0
- package/skills/mu/SKILL.md +369 -0
package/docs/ROADMAP.md
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Roadmap
|
|
2
|
+
|
|
3
|
+
The single forward-looking doc. If a feature isn't here, it isn't
|
|
4
|
+
planned.
|
|
5
|
+
|
|
6
|
+
Canonical terms: [VOCABULARY.md](VOCABULARY.md). Pillars:
|
|
7
|
+
[VISION.md](VISION.md). Module layout:
|
|
8
|
+
[ARCHITECTURE.md](ARCHITECTURE.md). Shipped history:
|
|
9
|
+
[CHANGELOG.md](../CHANGELOG.md).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Promotion criteria
|
|
14
|
+
|
|
15
|
+
A roadmap item earns implementation when **all three** are true:
|
|
16
|
+
|
|
17
|
+
1. **Proven friction.** A real user hits the missing feature in a
|
|
18
|
+
real workflow at least twice. Imagined polish doesn't count.
|
|
19
|
+
2. **No pillar refactor.** Fits the current substrate without
|
|
20
|
+
bending any pillar in [VISION.md](VISION.md).
|
|
21
|
+
3. **Bounded scope.** Fits in <300 LOC or has a clear smaller
|
|
22
|
+
subset that does.
|
|
23
|
+
|
|
24
|
+
**Exceptions.** Data-loss footguns (silent destruction of user
|
|
25
|
+
artifacts) ship on the *first* occurrence. Polish — bug fixes,
|
|
26
|
+
ergonomic tweaks, error-message wording, doc tightening — doesn't
|
|
27
|
+
need promotion at all; just ship clean (typecheck + lint + tests +
|
|
28
|
+
build).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Anti-feature pledges
|
|
33
|
+
|
|
34
|
+
We will NOT, until each one earns its way back via the criteria
|
|
35
|
+
above:
|
|
36
|
+
|
|
37
|
+
- **Config file.** All config is CLI flags or env vars.
|
|
38
|
+
- **Daemon / watcher / background process** beyond what tmux and
|
|
39
|
+
SQLite give us.
|
|
40
|
+
- **Anticipatory abstractions** with zero current consumer (the
|
|
41
|
+
cautionary tale: a `RunContext` trait with no implementor).
|
|
42
|
+
- **Wrappers around wrappers** (cautionary tale:
|
|
43
|
+
`TextStream`/`TextState`/`StreamResult`).
|
|
44
|
+
- **Codegen, embedded JS engine, macros, decorators** beyond
|
|
45
|
+
TypeScript itself. No workflow DSL.
|
|
46
|
+
- **Template/definition system for agent roles.** Spawn flags +
|
|
47
|
+
the orchestrator's first message ARE the definition.
|
|
48
|
+
- **Render layers beyond `cli-table3` + `picocolors`**, except
|
|
49
|
+
`ink` confined to `src/cli/tui/`. No second TUI stack alongside
|
|
50
|
+
`ink` — if `ink` ever stops paying off, *replace* it; don't
|
|
51
|
+
stack stacks.
|
|
52
|
+
- **Bundle pi.** It's a peer dep.
|
|
53
|
+
- **Plugin runtime, web UI, RPC, chat/docs integrations, memory
|
|
54
|
+
system, workflow engine.** Rejected as a class — these are
|
|
55
|
+
exactly the accumulations a prior internal multi-agent runtime
|
|
56
|
+
collected, and not inheriting them is the point.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Rejected sync substrates
|
|
61
|
+
|
|
62
|
+
Recorded so we don't relitigate them. mu syncs through an ops log in
|
|
63
|
+
SQLite plus append-only JSONL **segments**; every alternative below
|
|
64
|
+
was considered and rejected for the reason given.
|
|
65
|
+
|
|
66
|
+
| Substrate | Why not |
|
|
67
|
+
| --------- | ------- |
|
|
68
|
+
| **Litestream** | Daemon; single-writer; one-way to object storage; `restore` is a whole-file clobber. Solves disaster recovery, not laptop↔devserver. No answer for "I added 3 tasks on the devserver while the laptop was offline." |
|
|
69
|
+
| **LiteFS** | FUSE. On macOS that means macFUSE — a kernel extension needing SIP gymnastics on Apple Silicon. Dead on arrival for a mixed-OS fleet. |
|
|
70
|
+
| **rqlite / dqlite / Marmot** | Raft or NATS clusters. A consensus cluster to sync a task graph between two machines that are usually not both awake. Requires daemons (anti-feature pledge). |
|
|
71
|
+
| **cr-sqlite** | Merges rows by primary key, and every mu entity table is `INTEGER PRIMARY KEY AUTOINCREMENT` — laptop's task `id=5` and devserver's *different* task `id=5` merge into one row, column-by-column. Silent data loss. Fixing it means UUID PKs, i.e. tearing out the surrogate-PK substrate. Also: upstream still says WIP, DDL doesn't sync, and it's a native extension needing a darwin/linux × arm/x64 × glibc/musl build matrix. |
|
|
72
|
+
| **RocksDB / LMDB for the op log** | No triggers, so capture becomes a convention every future call site must remember — and a forgotten op is now silent corruption of undo *and* sync. Single-process-exclusive, so it forces a daemon. mu's read side is ~96 prepared statements, ~70 JOINs, 3 views and recursive CTEs — all hand-rolled. Loses `mu sql`. |
|
|
73
|
+
| **SQLite file per peer (instead of JSONL)** | A torn transfer makes the *whole* file unopenable, versus losing one JSONL line. `-wal`/`-shm` sidecars in a synced folder are the canonical way to corrupt a DB. Page churn defeats rsync/Syncthing delta transfer, where append-only files are the best case. |
|
|
74
|
+
| **`MU_SYNC_PEERS` membership list** | A config file with extra steps, and it would have to be kept consistent across every machine — the drift problem it appears to solve. Peers are discovered from segment filenames instead. |
|
|
75
|
+
| **`mu sync --push/--pull <host>` <!-- doc-cli-drift:skip -->** | Would make mu shell out to ssh/scp — its first network egress — dragging in ssh config, jump hosts, ProxyCommand, ports, identity files, interactive prompts, and network-vs-auth error mapping. A remote backend wearing a small hat. mu prints a copy-pasteable rsync line instead. |
|
|
76
|
+
|
|
77
|
+
The chosen design's net dependency change is **zero**: still just
|
|
78
|
+
`better-sqlite3`.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Possible — small additions with an obvious shape
|
|
83
|
+
|
|
84
|
+
These have a clear design but haven't yet hit promotion criterion
|
|
85
|
+
1 (friction in ≥2 real workflows). They earn implementation when
|
|
86
|
+
real use surfaces them.
|
|
87
|
+
|
|
88
|
+
### Per-CLI status detection (claude, codex, …)
|
|
89
|
+
|
|
90
|
+
**Partly superseded on the herdr backend**, which classifies panes
|
|
91
|
+
natively across the agent kinds it knows — mu takes its word there and
|
|
92
|
+
skips scrollback scraping entirely. This item stays live for the tmux
|
|
93
|
+
backend, where mu has to do its own detecting.
|
|
94
|
+
|
|
95
|
+
mu is a pi orchestrator. The Braille-spinner fallback catches every
|
|
96
|
+
TUI wrapper using standard spinner glyphs (U+2800–U+28FF), so
|
|
97
|
+
pi-meta + solo + many vanilla TUIs (claude, codex) work without a
|
|
98
|
+
per-CLI detector.
|
|
99
|
+
|
|
100
|
+
For patterns the spinner fallback misses (permission prompts,
|
|
101
|
+
specific busy markers), a per-CLI `Detector` registry keyed by
|
|
102
|
+
CLI name (~50 LOC per CLI) is the obvious shape. Promote when a
|
|
103
|
+
real specific-prompt-misclassification surfaces.
|
|
104
|
+
|
|
105
|
+
Pattern sketch:
|
|
106
|
+
|
|
107
|
+
| CLI | Busy patterns | Permission patterns |
|
|
108
|
+
| ------ | -------------------------------------- | --------------------------------------------------------- |
|
|
109
|
+
| Claude | `to interrupt`, `\(.*[↑↓].*tokens\)` | `Allow once`, `Allow for this session`, `Esc to cancel` |
|
|
110
|
+
| Codex | `esc to interrupt)`, `to cancel` | `enter to confirm`, `enter to submit \| esc to cancel` |
|
|
111
|
+
| Pi | (well-known mu-defined marker) | (well-known mu-defined marker) — shipped |
|
|
112
|
+
|
|
113
|
+
Critical subtleties any new detector must keep:
|
|
114
|
+
|
|
115
|
+
- **Tail-window extraction**: take last ~100 lines, strip trailing
|
|
116
|
+
blanks, then take last ~20. Already implemented for pi in
|
|
117
|
+
`src/detect.ts`; the registry version factors it out.
|
|
118
|
+
- **Permission detection uses a narrower window than busy
|
|
119
|
+
detection** to prevent already-answered prompts re-triggering.
|
|
120
|
+
- **Permission overrides busy** — if a permission prompt is
|
|
121
|
+
visible, agent is `NeedsPermission`, not `Busy`.
|
|
122
|
+
|
|
123
|
+
### A third mux backend (zellij, wezterm, kitty)
|
|
124
|
+
|
|
125
|
+
**Not promoted.** tmux and herdr are two real implementations, which
|
|
126
|
+
is what justifies `MuxBackend` existing at all — the interface was
|
|
127
|
+
extracted to serve a concrete second case, not in anticipation of an
|
|
128
|
+
nth. A third backend needs its own friction evidence under the
|
|
129
|
+
[promotion criteria](#promotion-criteria) like anything else. "The
|
|
130
|
+
abstraction already exists" is not evidence.
|
|
131
|
+
|
|
132
|
+
### Subscription-based wakeups
|
|
133
|
+
|
|
134
|
+
`mu log --tail` polls SQLite once per second. SQLite update hooks
|
|
135
|
+
(via better-sqlite3) or `fs.watch` on the WAL would drop latency
|
|
136
|
+
at the cost of more machinery. Promote when someone hits the
|
|
137
|
+
cliff.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Open questions
|
|
142
|
+
|
|
143
|
+
Listed so we don't pretend they're settled.
|
|
144
|
+
|
|
145
|
+
- **Capability tags on operations.** mu's only authorization
|
|
146
|
+
surface today is "the agent ran the verb." Promote capability
|
|
147
|
+
enforcement when an agent actually does damage.
|
|
148
|
+
- **Per-workstream config.** Resisted (anti-feature pledge). "This
|
|
149
|
+
workstream uses one pi binary, that one uses another" is a real
|
|
150
|
+
gap env vars don't solve cleanly. Revisit when a second user
|
|
151
|
+
hits it.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## murmur, and remote agents (noted 2026-08-28, revised 2026-09-02)
|
|
156
|
+
|
|
157
|
+
[murmur](https://github.com/mu-crew/murmur) is a sibling tool at
|
|
158
|
+
`~/hacking/murmur`, on npm as `@mu-crew/murmur`: every coding
|
|
159
|
+
agent on every machine in one attention-sorted list you can jump
|
|
160
|
+
from. It is **built and in daily use** — the original note here
|
|
161
|
+
described it as four design documents, and two of its conclusions
|
|
162
|
+
moved since:
|
|
163
|
+
|
|
164
|
+
- **Current state only, not an event log.** Each node publishes one
|
|
165
|
+
complete snapshot; a peer's answer is replaced in one write and
|
|
166
|
+
absence means absence. No history, watermarks or HLC. murmur's own
|
|
167
|
+
architecture says a generic `put`/`del` op-log "would simply *be*
|
|
168
|
+
`mu`" — so the two differ in substrate now, not just scope.
|
|
169
|
+
- **No control channel, ever.** murmur observes and jumps; "not a
|
|
170
|
+
remote terminal" is a stated non-goal. The phase-2 prompt/abort
|
|
171
|
+
surface this note once counted on will not come from there.
|
|
172
|
+
|
|
173
|
+
**What it would give mu**, both prerequisites for `mu spawn --on
|
|
174
|
+
<host>`: **global agent addressing** (`agents.pane_id` is
|
|
175
|
+
machine-local; murmur's `(host_id, agent_id)` is not, and identity is
|
|
176
|
+
kept separate from `session/window/pane` so it survives a move), and
|
|
177
|
+
**remote observation** (read the fold, get agents on other machines
|
|
178
|
+
for free — including ones mu never spawned). It would not give mu the
|
|
179
|
+
control channel; remote *driving* is unbuilt in both tools.
|
|
180
|
+
|
|
181
|
+
**The cheap seam already works.** murmur's pi extension reads
|
|
182
|
+
`MU_MANAGED_AGENT` / `MU_AGENT_NAME` / `MU_WORKSTREAM` / `MU_ROLE`
|
|
183
|
+
off the pane and marks such agents `orchestrated` — "crew" — hidden
|
|
184
|
+
unless `blocked` or `crashed`, since a supervisor consumes anything
|
|
185
|
+
else. mu already exports the first three (`src/agents/spawn.ts`,
|
|
186
|
+
`paneEnv`) and did nothing. Zero lines: the baseline any tighter
|
|
187
|
+
coupling has to beat. `MU_ROLE` is the one murmur reads and mu does
|
|
188
|
+
NOT set, so a crew row's role column is always null — a one-line fix
|
|
189
|
+
if that column ever proves useful, not a reason to couple further.
|
|
190
|
+
|
|
191
|
+
**No conflict with the sync design.** § Rejected sync substrates and
|
|
192
|
+
§ Explicitly rejected both stand: murmur is a **separate binary**
|
|
193
|
+
owning the ssh egress, and if mu ever consumes it, it does so by
|
|
194
|
+
reading a local store, never by growing a network stack. A merge must
|
|
195
|
+
keep the mu half transport-free. murmur independently reached mu's
|
|
196
|
+
two conclusions from mu's own code: ambient rather than daemon (a
|
|
197
|
+
collect rides ordinary invocations, rate-limited with jitter so the
|
|
198
|
+
status bar cannot drive an ssh fan-out) and sync must never fail a
|
|
199
|
+
command (every peer error caught and categorised).
|
|
200
|
+
|
|
201
|
+
**Why not merge now.** Remote observation is the easy half and is now
|
|
202
|
+
shipped; orchestration is the hard half and murmur removes none of
|
|
203
|
+
it. Repos and credentials must exist on the target, worktree setup is
|
|
204
|
+
a local filesystem operation, cherry-pick handoff assumes artifacts
|
|
205
|
+
move between machines, and "which node runs this task" is a scheduler
|
|
206
|
+
question mu does not have.
|
|
207
|
+
|
|
208
|
+
**The step that tests it** is now available, not scheduled: make mu a
|
|
209
|
+
*client* — drop its own status tracking and read murmur's snapshot.
|
|
210
|
+
Small change, real experiment. But `paneStatus()` / `src/detect.ts`
|
|
211
|
+
is not hurting, and trading a working local detector for a
|
|
212
|
+
cross-machine dependency needs a reason from real use (promotion
|
|
213
|
+
criterion 1), not the mere existence of the alternative. Keep the
|
|
214
|
+
*observe* vs *orchestrate* seam in mind even then — it is what lets
|
|
215
|
+
murmur watch agents mu never spawned, and a merge should say why it
|
|
216
|
+
beats that.
|
|
217
|
+
|
|
218
|
+
**Doors already open**, free: same language and runtime (TypeScript
|
|
219
|
+
on npm, since pi is an npm package), `(host_id, agent_id)` addressing
|
|
220
|
+
mu would need anyway, and the `MU_*` env contract.
|
|
221
|
+
|
|
222
|
+
**Do not** start the merge, add ssh to mu, or fold murmur's schema
|
|
223
|
+
into `mu.db` on the strength of this note. It records an intention
|
|
224
|
+
and its preconditions.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Pi extension and the three rules
|
|
229
|
+
|
|
230
|
+
If a pi extension lands (typed `mu_*` tools, HUD widget, wakeups)
|
|
231
|
+
bundled in this same npm package, three rules stay non-negotiable:
|
|
232
|
+
|
|
233
|
+
1. **The DB is canonical.** All state in `<state-dir>/mu.db`.
|
|
234
|
+
Extension reads/writes through the same modules the CLI uses.
|
|
235
|
+
No extension-only state.
|
|
236
|
+
2. **Every operation works from the CLI.** No tool registered in
|
|
237
|
+
the extension has logic that doesn't exist in the CLI.
|
|
238
|
+
3. **The skill teaches the CLI.** Pi sessions without the
|
|
239
|
+
extension still get a working mu by following
|
|
240
|
+
[skills/mu/SKILL.md](../skills/mu/SKILL.md).
|
|
241
|
+
|
|
242
|
+
If those three rules hold, mu stays driveable from a shell forever
|
|
243
|
+
and the extension stays thin.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Explicitly rejected (one-liners)
|
|
248
|
+
|
|
249
|
+
Listed so we don't rediscover them.
|
|
250
|
+
|
|
251
|
+
- **JS / Lisp DSL** (`mu run` / `mu eval` / `mu repl`) <!-- doc-cli-drift:skip --> — bash +
|
|
252
|
+
jq + `--json` covers the gap. A workflow DSL is a maintenance
|
|
253
|
+
liability.
|
|
254
|
+
- **`defineOperation()` registry framework** — no consumer left
|
|
255
|
+
after the DSL was rejected.
|
|
256
|
+
- **Markdown agent-definition discovery** — spawn flags + first
|
|
257
|
+
message already are the definition.
|
|
258
|
+
- **mu as a pi extension only (no CLI)** — children couldn't drive
|
|
259
|
+
mu; humans couldn't debug from a shell.
|
|
260
|
+
- **mu as a library only (no CLI)** — multiple processes would
|
|
261
|
+
fight over the DB.
|
|
262
|
+
- **Two binaries (`mu-agents` + `mu-tasks`)** — agent ↔ task
|
|
263
|
+
integration needs one transactional surface.
|
|
264
|
+
- **`TaskSurface` adapter abstraction** — the built-in graph IS
|
|
265
|
+
the killer feature.
|
|
266
|
+
- **Live cross-machine state sync via a daemon or remote backend** —
|
|
267
|
+
local-first SQLite. The ops-log sync is ambient but daemon-free
|
|
268
|
+
(flush/ingest ride on ordinary mu invocations) and transport-free
|
|
269
|
+
(mu reads and writes files; the user moves them). Rejected
|
|
270
|
+
storage/replication substrates are in
|
|
271
|
+
[§ Rejected sync substrates](#rejected-sync-substrates).
|
|
272
|
+
- **Network-opening remote verbs (`mu remote check`, `mu sync --push/--pull`)** <!-- doc-cli-drift:skip --> — mu manages panes and a task graph on one machine; every network hop is an operator-owned command, either passed through `agent spawn --command` for the mux to run or printed as a copy-pasteable next step. Keeping mu's own process ssh-free avoids an ssh config/auth/host/error model. Spawn does not violate this boundary: the mux, not mu, runs the operator's string.
|
|
273
|
+
- **HTTP API on top of SQLite** — write your own RPC if you need
|
|
274
|
+
one.
|
|
275
|
+
- **A "hosted" mu** — your machine is the deployment.
|
|
276
|
+
- **Anthropomorphic agent names (`alice`, `bob`)** — use
|
|
277
|
+
role-based names (`worker-1`, `reviewer-1`).
|