@martintrojer/mu 0.3.2 → 0.4.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 +181 -42
- package/README.md +63 -22
- package/dist/cli.js +13348 -5236
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1428 -1369
- package/dist/index.js +4002 -3110
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +296 -56
- package/docs/HANDOVER.md +461 -0
- package/docs/ROADMAP.md +120 -498
- package/docs/USAGE_GUIDE.md +445 -143
- package/docs/VISION.md +48 -4
- package/docs/VOCABULARY.md +18 -5
- package/docs/img/tui-dashboard.png +0 -0
- package/package.json +12 -6
- package/skills/mu/SKILL.md +273 -469
package/AGENTS.md
CHANGED
|
@@ -13,8 +13,9 @@ write code. Follow the conventions below.
|
|
|
13
13
|
|
|
14
14
|
1. **[docs/USAGE_GUIDE.md](docs/USAGE_GUIDE.md)** — what mu does
|
|
15
15
|
from a user's perspective. ~10 minutes.
|
|
16
|
-
2. **[CHANGELOG.md](CHANGELOG.md)** — the
|
|
17
|
-
|
|
16
|
+
2. **[CHANGELOG.md](CHANGELOG.md)** — the upcoming version's
|
|
17
|
+
entry (currently `[0.4.0] — unreleased`). Single source of truth
|
|
18
|
+
for the verb list, schema, env vars.
|
|
18
19
|
3. **[docs/VISION.md](docs/VISION.md)** — the load-bearing pillars.
|
|
19
20
|
The design principles you must not violate.
|
|
20
21
|
4. **[docs/ROADMAP.md](docs/ROADMAP.md)** — what's next, with
|
|
@@ -24,13 +25,22 @@ write code. Follow the conventions below.
|
|
|
24
25
|
**Source of truth for every word** in code, docs, and error
|
|
25
26
|
messages. If you use a term not defined there, fix the docs first.
|
|
26
27
|
6. **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** — module layout,
|
|
27
|
-
reconciliation algorithm, key seams.
|
|
28
|
+
reconciliation algorithm, TUI architecture, key seams.
|
|
28
29
|
|
|
29
30
|
Design rationale for rejected and unbuilt features (DSL, snapshots,
|
|
30
31
|
task_artifacts, ...) is now folded into
|
|
31
32
|
[docs/ROADMAP.md](docs/ROADMAP.md) per item, alongside its
|
|
32
33
|
promotion criteria.
|
|
33
34
|
|
|
35
|
+
> **If you are an orchestrator** — a coding agent driving a crew of
|
|
36
|
+
> pi worker agents on this repo via `mu` — read
|
|
37
|
+
> **[docs/HANDOVER.md](docs/HANDOVER.md)** instead of the order
|
|
38
|
+
> above. It is the goto reset doc for orchestrators: onboarding
|
|
39
|
+
> steps, the 8-phase dispatch loop, conflict-resolution playbook,
|
|
40
|
+
> known gotchas, and end-of-session checklist. AGENTS.md is for
|
|
41
|
+
> workers (and humans editing the repo directly); HANDOVER.md is for
|
|
42
|
+
> orchestrators.
|
|
43
|
+
|
|
34
44
|
---
|
|
35
45
|
|
|
36
46
|
## Repo layout
|
|
@@ -41,39 +51,52 @@ mu/
|
|
|
41
51
|
├── AGENTS.md # this file
|
|
42
52
|
├── CHANGELOG.md # release notes
|
|
43
53
|
├── docs/ # everything else
|
|
44
|
-
│ ├── USAGE_GUIDE.md
|
|
45
|
-
│ ├──
|
|
46
|
-
│ ├──
|
|
47
|
-
│ ├──
|
|
48
|
-
│
|
|
54
|
+
│ ├── USAGE_GUIDE.md # user-facing tour (§ 5b is the TUI reference)
|
|
55
|
+
│ ├── HANDOVER.md # orchestrator goto reset doc (8-phase loop + gotchas)
|
|
56
|
+
│ ├── ROADMAP.md # what's next; promotion criteria; anti-feature pledges
|
|
57
|
+
│ ├── VISION.md # load-bearing pillars
|
|
58
|
+
│ ├── VOCABULARY.md # canonical terms (single source of truth)
|
|
59
|
+
│ └── ARCHITECTURE.md # module layout, TUI architecture, key seams
|
|
49
60
|
├── src/ # all source (root files: SDK + shared infra; one
|
|
50
61
|
│ # level of subdirs OK for cohesive clusters — see
|
|
51
62
|
│ # `src/cli/`, `src/agents/`, `src/tasks/` below)
|
|
52
|
-
│ ├── db.ts # SQLite schema + openDb (single CREATE-IF-NOT-EXISTS block)
|
|
63
|
+
│ ├── db.ts # SQLite schema + openDb (single CREATE-IF-NOT-EXISTS block; v7)
|
|
53
64
|
│ ├── tmux.ts # tmux wrapper, send protocol, pane validation
|
|
54
|
-
│ ├── detect.ts # pi
|
|
65
|
+
│ ├── detect.ts # pi status detector + Braille-spinner fallback for other CLIs
|
|
55
66
|
│ ├── reconcile.ts # ghost prune + status detect + orphan surface
|
|
56
67
|
│ ├── agents.ts # CRUD + send/read/list/close/free + liveness + reaper hub (re-exports src/agents/*)
|
|
57
68
|
│ ├── agents/ # cohesive cluster of agent-lifecycle internals
|
|
58
69
|
│ │ ├── spawn.ts # spawnAgent + resolveCliCommand / awaitSpawnLiveness / pane create-or-reuse / prestage / rollback
|
|
70
|
+
│ │ ├── kick.ts # reaper events + cleanup of dead agent rows
|
|
59
71
|
│ │ ├── adopt.ts # adoptAgent: register an existing tmux pane as a managed agent
|
|
60
72
|
│ │ └── errors.ts # typed agent error classes (AgentNotFoundError, AgentDiedOnSpawnError, …)
|
|
61
|
-
│ ├── tasks.ts # task SDK hub (re-exports src/tasks/*
|
|
73
|
+
│ ├── tasks.ts # task SDK hub (re-exports src/tasks/*)
|
|
62
74
|
│ ├── tasks/ # cohesive cluster of task-graph internals
|
|
63
|
-
│ │ ├── status.ts # TaskStatus enum + helpers
|
|
64
|
-
│ │ ├──
|
|
75
|
+
│ │ ├── status.ts # TaskStatus enum + helpers
|
|
76
|
+
│ │ ├── core.ts # core SDK funcs reused across cluster files
|
|
77
|
+
│ │ ├── id.ts # tryResolveTaskId / qualified-id helpers
|
|
78
|
+
│ │ ├── queries.ts # listTasks / nextTasks / owned-by
|
|
79
|
+
│ │ ├── edit.ts # addTask / setTaskTitle / etc (no edges)
|
|
80
|
+
│ │ ├── edges.ts # block / unblock / reparent / delete + dedupe
|
|
81
|
+
│ │ ├── claim.ts # claim / release + resolveActorIdentity (atomic CAS)
|
|
65
82
|
│ │ ├── lifecycle.ts # setTaskStatus / closeTask / openTask / rejectTask / deferTask + cascade
|
|
66
83
|
│ │ ├── wait.ts # waitForTasks: block until tasks reach a target status
|
|
84
|
+
│ │ ├── sort.ts # sortTasks (roi / recency / age / id)
|
|
67
85
|
│ │ └── errors.ts # typed task error classes (TaskAlreadyOwnedError, CycleError, …)
|
|
68
86
|
│ ├── tracks.ts # parallel-tracks union-find with diamond merge
|
|
69
87
|
│ ├── workstream.ts # ensureWorkstream / list / summarize / destroy / export
|
|
70
|
-
│ ├── archives.ts # cross-workstream archive
|
|
88
|
+
│ ├── archives.ts # cross-workstream archive bucket SDK hub (re-exports src/archives/*)
|
|
71
89
|
│ ├── exporting.ts # unified bucket renderer (workstream + archive export)
|
|
72
|
-
│ ├── importing.ts # inverse of exporting.ts: parse a
|
|
90
|
+
│ ├── importing.ts # inverse of exporting.ts: parse a bucket dir → live DB rows
|
|
73
91
|
│ ├── logs.ts # agent_logs SDK (append, list, latestSeq, emitEvent)
|
|
74
|
-
│ ├── vcs.ts # VcsBackend
|
|
75
|
-
│ ├── workspace.ts # per-agent VCS workspaces (
|
|
76
|
-
│ ├── snapshots.ts # whole-DB snapshots (
|
|
92
|
+
│ ├── vcs.ts # VcsBackend hub (re-exports src/vcs/*: jj/sl/git/none impls)
|
|
93
|
+
│ ├── workspace.ts # per-agent VCS workspaces hub (re-exports src/workspace/*)
|
|
94
|
+
│ ├── snapshots.ts # whole-DB snapshots hub (re-exports src/snapshots/*)
|
|
95
|
+
│ ├── dag.ts # full-DAG forest builder (loadFullDag for `mu task tree` + DAG popup)
|
|
96
|
+
│ ├── state.ts # SDK seam for `mu state` (fast SQL tier + slow subprocess tier + merge)
|
|
97
|
+
│ ├── staleness.ts # WORKSPACE_STALE_THRESHOLD + isStaleWorkspace
|
|
98
|
+
│ ├── project-root.ts # detectProjectRoot for the TUI launch cwd ladder
|
|
99
|
+
│ ├── doctor-summary.ts # TUI-friendly slice of `mu doctor` checks + remediation helpers
|
|
77
100
|
│ ├── output.ts # NextStep type + printNextSteps / errorNextSteps
|
|
78
101
|
│ ├── cli.ts # commander wiring (buildProgram); re-exports format/handle for back-compat
|
|
79
102
|
│ ├── cli/ # one file per verb-namespace; thin wrappers over the SDK
|
|
@@ -88,17 +111,51 @@ mu/
|
|
|
88
111
|
│ │ │ ├── claim.ts # claim / release / wait
|
|
89
112
|
│ │ │ ├── tree.ts # tree rendering
|
|
90
113
|
│ │ │ └── wire.ts # Commander glue
|
|
91
|
-
│ │ ├── workspace.ts # workspace create / list / free / path / orphans
|
|
114
|
+
│ │ ├── workspace.ts # workspace create / list / free / path / orphans / refresh / commits
|
|
92
115
|
│ │ ├── log.ts # log read / write / tail
|
|
93
116
|
│ │ ├── archive.ts # archive create / list / show / add / remove / delete
|
|
94
|
-
│ │ ├── state.ts # `mu state` (canonical state card)
|
|
117
|
+
│ │ ├── state.ts # `mu state` (canonical state card); --tui dispatches to src/cli/tui/
|
|
118
|
+
│ │ ├── staleness.ts # shared workspace-staleness CLI helpers + warn formatter
|
|
119
|
+
│ │ ├── tui-launch-focus.ts # initial-tab focus ladder for bare `mu` and `mu state --tui`
|
|
120
|
+
│ │ ├── tui/ # interactive ink-based TUI cluster; ONLY place ink/react are imported
|
|
121
|
+
│ │ │ ├── index.ts # runTui entrypoint; alt-screen + mouse-mode lifecycle
|
|
122
|
+
│ │ │ ├── escapes.ts # pure ANSI escape constants (ALT_SCREEN_*, mouse-mode bytes) — no ink imports
|
|
123
|
+
│ │ │ ├── app.tsx # <App> root (popup state machine + global keymap + footer + tick + tabs)
|
|
124
|
+
│ │ │ ├── state.ts # poll-loop hook (useDashboardSnapshot; fast/slow tick split)
|
|
125
|
+
│ │ │ ├── keys.ts # pure dispatchGlobalKey + dispatchPopupKey + shouldSwallowGlobalKey
|
|
126
|
+
│ │ │ ├── keymap-spec.ts # canonical keymap source-of-truth (drives help overlay + dispatch)
|
|
127
|
+
│ │ │ ├── yank.ts # clipboard probe + write (pbcopy/wl-copy/xclip/xsel/clip.exe + OSC-52)
|
|
128
|
+
│ │ │ ├── mouse.ts # vendored SGR mouse layer (parser + double-click + useMouse hook)
|
|
129
|
+
│ │ │ ├── layout.ts # responsive multi-column dashboard + per-card row budgets
|
|
130
|
+
│ │ │ ├── columns.ts # column-aligned row layout with protect/clip clipping
|
|
131
|
+
│ │ │ ├── wrap-ansi.ts # ANSI-aware visual-width line wrapper + SGR close-on-end
|
|
132
|
+
│ │ │ ├── glyphs.ts # superscript digit + status glyphs
|
|
133
|
+
│ │ │ ├── format-helpers.ts # shared TUI formatters (relTime, sinceClaim, ROI, etc.)
|
|
134
|
+
│ │ │ ├── titled-box.tsx # rounded border with section header inset into top border + bottomLabel
|
|
135
|
+
│ │ │ ├── popup-shell.tsx # popup outer chrome (cyan TitledBox)
|
|
136
|
+
│ │ │ ├── list-row.tsx # centralised non-selected row primitive (width pin + gutter + truncate)
|
|
137
|
+
│ │ │ ├── padded-rows.tsx # per-card body padder
|
|
138
|
+
│ │ │ ├── help.tsx # ?/F1 keymap overlay (scrollable on short panes)
|
|
139
|
+
│ │ │ ├── status-bar.tsx # bottom status bar (mode + active ws + tick + footer flash)
|
|
140
|
+
│ │ │ ├── tab-strip.tsx # multi-workstream tab switcher (N≥2)
|
|
141
|
+
│ │ │ ├── tab-strip-layout.ts # pure window-around-active layout helper for the tab strip
|
|
142
|
+
│ │ │ ├── tuicr.ts # `t` shortcut: alt-screen handoff to tuicr -r <sha>
|
|
143
|
+
│ │ │ ├── use-popup-filter.tsx # shared '/' substring filter hook + applyFilter + FilterPrompt
|
|
144
|
+
│ │ │ ├── use-status-filter.tsx # task-status toggles for task-list popups (o/i/c/r/d)
|
|
145
|
+
│ │ │ ├── use-notes-drill.ts # shared notes-drill memo (5 task popups consume it)
|
|
146
|
+
│ │ │ ├── use-popup-action-queue.ts # consume mouse PopupAction queue once per render
|
|
147
|
+
│ │ │ ├── cards/{agents,tracks,ready,log,workspaces,inprogress,blocked,recent,commits,doctor}.tsx + _placeholder.tsx
|
|
148
|
+
│ │ │ └── popups/{agents,tracks,ready,log,workspaces,inprogress,blocked,recent,commits,doctor,dag,all-tasks}.tsx
|
|
149
|
+
│ │ │ # plus drill.tsx (DrillScrollView), task-detail.tsx (TaskDetailDrill),
|
|
150
|
+
│ │ │ # cursor-row.tsx, scroll.ts (applyCursor/applyScroll), viewport.ts,
|
|
151
|
+
│ │ │ # show-loader.ts (shared subprocess-preserving loader)
|
|
95
152
|
│ │ ├── snapshot.ts # undo / snapshot list / snapshot show
|
|
96
153
|
│ │ ├── sql.ts # sql escape hatch
|
|
97
154
|
│ │ ├── doctor.ts # doctor diagnostic
|
|
98
155
|
│ │ ├── format.ts # pure rendering helpers (table renderers, status colourers, truncate/relTime)
|
|
99
156
|
│ │ └── handle.ts # typed-error → exit-code map + handle() wrapper
|
|
100
157
|
│ └── index.ts # SDK entrypoint (re-exports)
|
|
101
|
-
├── test/ #
|
|
158
|
+
├── test/ # ~165 *.test.ts files / ~2000 it()/test() calls; many use real tmux/git/jj/sl
|
|
102
159
|
├── skills/mu/SKILL.md # what the LLM running inside an agent pane sees
|
|
103
160
|
├── package.json # bin: { mu: ./dist/cli.js }, type: module
|
|
104
161
|
├── tsconfig.json # strict + noUncheckedIndexedAccess + verbatimModuleSyntax
|
|
@@ -116,15 +173,20 @@ mu/
|
|
|
116
173
|
```bash
|
|
117
174
|
npm install
|
|
118
175
|
npm run build # tsup → dist/
|
|
119
|
-
npm run typecheck #
|
|
176
|
+
npm run typecheck # source + test TypeScript checks
|
|
120
177
|
npm run lint # biome check src test
|
|
121
|
-
npm run test
|
|
178
|
+
npm run test:fast # fast unit/dev-loop tier (excludes *.integration.test.ts / *.smoke.test.ts)
|
|
179
|
+
npm run test # full vitest suite, including integration tests
|
|
122
180
|
npm run test:watch # vitest in watch mode
|
|
181
|
+
npm run test:watch:fast # fast-tier watch mode
|
|
123
182
|
```
|
|
124
183
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
184
|
+
Use `npm run test:fast` for the inner dev loop and concurrent
|
|
185
|
+
worker checks; it is the concurrency-safe tier that avoids real
|
|
186
|
+
tmux/VCS subprocess integration fixtures. All four green gates still
|
|
187
|
+
include `npm run test` (the full suite) before any commit. Full tests
|
|
188
|
+
include real-tmux integration tests that need `$TMUX` set. If you're
|
|
189
|
+
not in tmux, those tests skip themselves; CI runs inside tmux.
|
|
128
190
|
|
|
129
191
|
### Commits
|
|
130
192
|
|
|
@@ -170,17 +232,74 @@ those tests skip themselves; CI runs inside tmux.
|
|
|
170
232
|
|
|
171
233
|
- Unit tests: real SQLite (in-temp-dir), mocked tmux executor via
|
|
172
234
|
`setTmuxExecutor()`. Fast, deterministic.
|
|
173
|
-
-
|
|
174
|
-
|
|
175
|
-
|
|
235
|
+
- TUI popup/card behaviour tests should follow `test/README.md`:
|
|
236
|
+
prefer the `test/_ink-render.ts` CaptureStream seam over
|
|
237
|
+
`readFileSync` source-greps except for narrow structural guards.
|
|
238
|
+
- Fast tier: `npm run test:fast` runs `test/**/*.test.ts` while
|
|
239
|
+
excluding `*.integration.test.ts` and `*.smoke.test.ts`. Keep this
|
|
240
|
+
tier pure/in-process: mocked tmux/VCS, real SQLite only in per-test
|
|
241
|
+
temp DBs, no real tmux/git/jj/sl subprocess fixtures, no
|
|
242
|
+
filesystem-heavy export/import/snapshot paths, and no fixed sleeps
|
|
243
|
+
above 50ms.
|
|
244
|
+
- Integration tests: full-only tests use the `.integration.test.ts`
|
|
245
|
+
suffix (e.g. `tmux.integration.test.ts`). They may touch real tmux
|
|
246
|
+
servers, git/jj/sl fixture repos, subprocess-backed smoke paths,
|
|
247
|
+
filesystem-heavy export/import/snapshot flows, or intentionally
|
|
248
|
+
slower in-process CLI flows. Real-tmux tests are skipped when
|
|
249
|
+
`$TMUX` is unset. These tests typically opt out of the spawn
|
|
176
250
|
liveness check via `process.env.MU_SPAWN_LIVENESS_MS = "0"` in
|
|
177
251
|
`beforeEach` since the long-running sh subprocesses they spawn are
|
|
178
252
|
intentionally alive.
|
|
179
253
|
- Each test gets its own temp DB and (for integration) a unique
|
|
180
254
|
tmux session like `mu-test-<pid>-<ts>-<rand>` to avoid colliding
|
|
181
255
|
with the user's panes or with parallel test runs.
|
|
182
|
-
-
|
|
256
|
+
- Dogfood reality: multiple pi worker agents often run `npm run test`
|
|
257
|
+
concurrently on the same machine from different workspaces. Treat
|
|
258
|
+
flakes that pass in isolation but fail under load as concurrency
|
|
259
|
+
bugs first (shared `/tmp` cleanup, tmux socket/session collisions,
|
|
260
|
+
leaked subprocesses, VCS background file activity). Use
|
|
261
|
+
`npm run test:stress` for the pre-release/stability gate; it runs
|
|
262
|
+
the suite repeatedly with a per-run timeout and can simulate
|
|
263
|
+
parallel full-suite runs via
|
|
264
|
+
`MU_TEST_STRESS_MODE=parallel MU_TEST_STRESS_PARALLEL=2`.
|
|
265
|
+
- The acceptance test in `test/acceptance.integration.test.ts` is the
|
|
183
266
|
"everything works" gate. Keep it passing.
|
|
267
|
+
- **DB baseline**: `openDb()` refuses to open the user's REAL
|
|
268
|
+
default DB (`<HOME or XDG_STATE_HOME>/mu/mu.db`) when
|
|
269
|
+
`process.env.VITEST` is set or `NODE_ENV === "test"`. Tests
|
|
270
|
+
MUST use a per-test temp DB — either via MU_DB_PATH (which
|
|
271
|
+
`test/_runCli.ts` sets automatically) or an explicit `{ path }`
|
|
272
|
+
argument to `openDb`. A regression that forgets either one
|
|
273
|
+
fails loudly at the offending openDb() call site instead of
|
|
274
|
+
silently writing to the dev box's live state. Production never
|
|
275
|
+
sets VITEST, so the guard is a no-op outside the test runner.
|
|
276
|
+
- **Env baseline**: `test/_setup.ts` (vitest `setupFiles`) clears
|
|
277
|
+
every `MU_*` env var inherited from the parent shell at the start
|
|
278
|
+
of each fork, so SDK-level overrides (`MU_PI_COMMAND`,
|
|
279
|
+
`MU_IDLE_THRESHOLD_MS`, `MU_SEND_DELAY_MS`, …) can't silently
|
|
280
|
+
change behaviour underneath tests. Allowlist: `MU_TMUX_SOCKET`
|
|
281
|
+
(set by `_global-teardown.ts` at MODULE LOAD time — BEFORE vitest
|
|
282
|
+
spawns the worker pool — for Layer-3 isolation; see round-3
|
|
283
|
+
Part A in the file's header comment for why module-load not
|
|
284
|
+
setup()). Tests that need a specific value opt IN per-test via
|
|
285
|
+
`process.env.X = "..."` or `withEnv()` from `test/_env.ts`.
|
|
286
|
+
- **Default-socket sweep philosophy**: `_global-teardown.ts` runs
|
|
287
|
+
an ALLOWLIST sweep of `mu-*` sessions on the user's default tmux
|
|
288
|
+
socket at suite setup AND teardown. The allowlist is DB-rooted:
|
|
289
|
+
(1) `mu-<name>` for every workstream in the user's REAL DB
|
|
290
|
+
(read-only via better-sqlite3, bypassing the `openDb()` test
|
|
291
|
+
guard) and (2) `mu-$MU_SESSION` if the orchestrator runs the suite
|
|
292
|
+
inside a tmux pane. Anything else is, by elimination, test residue
|
|
293
|
+
and is killed. Replaces the old regex-prefix sweep that missed
|
|
294
|
+
bare-name leftovers like `mu-alpha` / `mu-demo` / `mu-ws`. Round-4
|
|
295
|
+
removed the previous "pre-existing sessions snapshot" source
|
|
296
|
+
(`bug_test_flake_round_4_self_heal`): leftover test residue at
|
|
297
|
+
module-load time was getting grandfathered in as protected forever,
|
|
298
|
+
defeating the self-healing intent. Cost: an ad-hoc
|
|
299
|
+
`tmux new-session -t mu-foo` with no DB row gets killed; workaround
|
|
300
|
+
is `mu workstream init foo` first. New tests can hardcode any
|
|
301
|
+
workstream name they want — if they accidentally bypass the
|
|
302
|
+
private socket the sweep catches them by default.
|
|
184
303
|
|
|
185
304
|
### When you change behaviour, update VOCABULARY first
|
|
186
305
|
|
|
@@ -208,12 +327,18 @@ meeting these criteria, **stop**. Add an entry to
|
|
|
208
327
|
The "anti-feature pledges" in ROADMAP.md are firm:
|
|
209
328
|
|
|
210
329
|
- No config file
|
|
211
|
-
- No daemon
|
|
330
|
+
- No daemon / background process beyond what tmux + SQLite give us
|
|
212
331
|
- No anticipatory abstractions (no traits with zero implementors)
|
|
213
332
|
- No wrappers around wrappers
|
|
214
|
-
- No codegen
|
|
215
|
-
-
|
|
216
|
-
|
|
333
|
+
- No codegen / embedded JS engine / workflow DSL
|
|
334
|
+
- No template/discovery system for agent roles (spawn flags + first
|
|
335
|
+
message ARE the definition)
|
|
336
|
+
- No render layer beyond `cli-table3` + `picocolors`, EXCEPT `ink`
|
|
337
|
+
confined to `src/cli/tui/`. NO second TUI stack alongside `ink`
|
|
338
|
+
(no `blessed` / `terminal-kit` etc.); if `ink` ever stops paying
|
|
339
|
+
off, REPLACE it, don't stack stacks.
|
|
340
|
+
- No plugin runtime, web UI, RPC, chat/docs integrations, memory
|
|
341
|
+
system, workflow engine
|
|
217
342
|
- Don't bundle pi (it's a peer dep)
|
|
218
343
|
|
|
219
344
|
### When in doubt: be small
|
|
@@ -252,11 +377,24 @@ real friction proves itself.
|
|
|
252
377
|
|
|
253
378
|
### "Update the schema"
|
|
254
379
|
|
|
255
|
-
1.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
380
|
+
1. Current schema version is **v7** (see `CURRENT_SCHEMA_VERSION`
|
|
381
|
+
in `src/db.ts`). The schema lives in `src/db.ts` as the
|
|
382
|
+
`applySchema(db)` block, which is idempotent CREATE-IF-NOT-EXISTS
|
|
383
|
+
plus targeted `DROP TABLE IF EXISTS` for retired tables
|
|
384
|
+
(e.g. v7's `DROP TABLE IF EXISTS approvals`). `openDb` rejects
|
|
385
|
+
pre-current DBs with `SchemaTooOldError` (exit 4) and a
|
|
386
|
+
migration hint.
|
|
387
|
+
2. Bump `CURRENT_SCHEMA_VERSION` in `src/db.ts` and mirror the new
|
|
388
|
+
shape in `CURRENT_SCHEMA`. Two of the last three bumps were
|
|
389
|
+
script-free: v5 → v6 was purely additive (existing
|
|
390
|
+
CREATE-TABLE-IF-NOT-EXISTS picked up new tables); v6 → v7 was a
|
|
391
|
+
destructive-but-idempotent `DROP TABLE` block. Reach for a
|
|
392
|
+
one-shot migration script only when the change can't be
|
|
393
|
+
expressed that way (the v4 → v5 surrogate-PK substrate switch
|
|
394
|
+
was the canonical example).
|
|
395
|
+
3. Update tests that exercise the schema (`test/db.test.ts`).
|
|
396
|
+
4. Update [CHANGELOG.md](CHANGELOG.md) under the upcoming version's
|
|
397
|
+
`### Changed` section.
|
|
260
398
|
|
|
261
399
|
### "Add a new tmux operation"
|
|
262
400
|
|
|
@@ -322,11 +460,12 @@ processes need time to settle. Use:
|
|
|
322
460
|
Before opening a PR or marking a task complete:
|
|
323
461
|
|
|
324
462
|
```bash
|
|
325
|
-
npm run typecheck && npm run lint && npm run test && npm run build
|
|
463
|
+
npm run typecheck && npm run lint && npm run test:fast && npm run test && npm run build
|
|
326
464
|
```
|
|
327
465
|
|
|
328
|
-
All four green. The acceptance
|
|
329
|
-
must pass — it's the
|
|
466
|
+
All four green gates, plus the fast dev-loop tier. The acceptance
|
|
467
|
+
test (`test/acceptance.integration.test.ts`) must pass — it's the
|
|
468
|
+
"end-to-end works" gate.
|
|
330
469
|
|
|
331
470
|
Checklist for any non-trivial change:
|
|
332
471
|
|
package/README.md
CHANGED
|
@@ -2,28 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
**A small, opinionated control plane for a crew of AI coding agents
|
|
4
4
|
working in parallel.** One tmux session, a typed task DAG, isolated
|
|
5
|
-
VCS workspaces per agent, an audit log — and a
|
|
6
|
-
|
|
5
|
+
VCS workspaces per agent, an audit log — and a dashboard for seeing
|
|
6
|
+
what the crew is doing right now.
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
*`mu` (no args) — read-only dashboard: agents, tracks, ready /
|
|
11
|
+
in-progress / blocked tasks, log tail, workspaces, doctor.*
|
|
7
12
|
|
|
8
13
|
```bash
|
|
9
14
|
mu workstream init auth-refactor
|
|
10
15
|
mu task add --title "Design auth" --impact 80 --effort-days 2
|
|
11
|
-
mu task add --title "Build auth" --impact 80 --effort-days 5 --
|
|
12
|
-
mu task add --title "Review auth" --impact 60 --effort-days 1 --
|
|
16
|
+
mu task add --title "Build auth" --impact 80 --effort-days 5 --blocked-by design_auth
|
|
17
|
+
mu task add --title "Review auth" --impact 60 --effort-days 1 --blocked-by build_auth
|
|
13
18
|
|
|
14
19
|
mu agent spawn worker-1 --workspace
|
|
15
20
|
mu agent spawn reviewer-1 --workspace --role read-only
|
|
16
21
|
mu agent send worker-1 "Pick up the next ready task and design the auth module."
|
|
17
22
|
|
|
18
23
|
tmux a -t mu-auth-refactor # watch the whole crew live
|
|
19
|
-
mu #
|
|
24
|
+
mu # human home base: TUI with every workstream loaded
|
|
25
|
+
mu state -w auth-refactor --json # agent/script API: typed static state for jq
|
|
20
26
|
mu log --tail # subscribe to every state change
|
|
21
27
|
```
|
|
22
28
|
|
|
23
29
|
The crew is real (tmux panes you can attach to), the work graph is
|
|
24
30
|
real (SQLite + a parallel-tracks algorithm with diamond-merge), the
|
|
25
31
|
workspaces are real (jj workspace / sl share / git worktree), and
|
|
26
|
-
**mu
|
|
32
|
+
**mu stays out of the model's way.** Tasks, workspaces, panes, notes,
|
|
33
|
+
and logs persist state and coordinate handoffs; the model still
|
|
34
|
+
decides what to do. Workers use the bundled
|
|
35
|
+
[SKILL.md](skills/mu/SKILL.md) when they need the full in-pane ground
|
|
36
|
+
truth. Bare `mu` is the human front door when stdout is attached to a
|
|
37
|
+
TTY: it launches the read-only TUI with every workstream loaded.
|
|
38
|
+
Piped/scripted calls print help instead; use typed verbs plus `--json`
|
|
39
|
+
(or `MU_NO_TUI=1`) for agent/API flows.
|
|
27
40
|
|
|
28
41
|
---
|
|
29
42
|
|
|
@@ -34,17 +47,16 @@ workspaces are real (jj workspace / sl share / git worktree), and
|
|
|
34
47
|
task DAG with **deterministic parallel-track detection +
|
|
35
48
|
diamond-merge** so two agents are never assigned tasks that share
|
|
36
49
|
a prerequisite.
|
|
37
|
-
- **
|
|
38
|
-
not
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- **A
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
not an oversight.
|
|
50
|
+
- **Stay out of the model's way.** Mu coordinates handoffs; it does
|
|
51
|
+
not make choices on behalf of the model. `--cli <key>` uppercases
|
|
52
|
+
to `$MU_<KEY>_COMMAND`, so your shell rc owns model/provider
|
|
53
|
+
selection and thinking-effort flags. The orchestrator and workers
|
|
54
|
+
drive; mu records, scopes, and yanks the next command.
|
|
55
|
+
- **A local typed state surface.** One CLI, one SQLite registry,
|
|
56
|
+
typed verbs, `--json` everywhere useful, and a read-only dashboard
|
|
57
|
+
for humans. Contributor-facing boundaries and rejected ideas live
|
|
58
|
+
in [ROADMAP.md](docs/ROADMAP.md); the README stays focused on how
|
|
59
|
+
mu feels to use.
|
|
48
60
|
|
|
49
61
|
## What mu is NOT
|
|
50
62
|
|
|
@@ -110,7 +122,31 @@ npx skills add ./skills/mu # local-path source format
|
|
|
110
122
|
```
|
|
111
123
|
|
|
112
124
|
More install patterns (alias-to-dist for fastest dev iteration) in
|
|
113
|
-
[docs/USAGE_GUIDE.md § 1 Setup](docs/USAGE_GUIDE.md#1-setup).
|
|
125
|
+
[docs/USAGE_GUIDE.md § 1 Setup](docs/USAGE_GUIDE.md#1-setup). After
|
|
126
|
+
installing, run bare `mu` (or `mu state --tui`) for the dashboard tour.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## TUI dashboard
|
|
131
|
+
|
|
132
|
+
Bare `mu` in a TTY launches the flagship read-only dashboard across
|
|
133
|
+
all workstreams; `mu state --tui -w <workstream>` is the explicit
|
|
134
|
+
single/multi-workstream form. Non-TTY callers and scripts keep the
|
|
135
|
+
static/help path, and `mu state --json` is the API.
|
|
136
|
+
|
|
137
|
+
The dashboard has ten cards: Commits, Agents, Tracks, Ready, Activity
|
|
138
|
+
log, Workspaces, In-progress, Blocked, Recent, and Doctor. Drill into
|
|
139
|
+
any numbered card fullscreen with `Shift+0`-`Shift+9`; `g` opens the
|
|
140
|
+
full DAG and `t` opens the all-tasks list. `?` shows the complete
|
|
141
|
+
keymap. Keyboard and mouse both work: navigate with keys, double-click
|
|
142
|
+
cards or rows to drill, and scroll popup bodies with the mouse wheel.
|
|
143
|
+
|
|
144
|
+
The TUI is read-only by design. `y` yanks the canonical `mu` command
|
|
145
|
+
for the focused row to your clipboard; you run it in a shell, so every
|
|
146
|
+
mutation still goes through a short-lived typed CLI invocation. The
|
|
147
|
+
one exception is user-driven: `t` inside a commit/show drill suspends
|
|
148
|
+
mu's alt-screen and hands off to `tuicr -r <sha>`, then restores the
|
|
149
|
+
dashboard when tuicr exits.
|
|
114
150
|
|
|
115
151
|
---
|
|
116
152
|
|
|
@@ -125,16 +161,20 @@ mu workstream init auth-refactor
|
|
|
125
161
|
|
|
126
162
|
# Plan the work as a DAG. IDs auto-derive from titles.
|
|
127
163
|
mu task add --title "Design auth module" --impact 80 --effort-days 2
|
|
128
|
-
mu task add --title "Build auth" --impact 80 --effort-days 5 --
|
|
129
|
-
mu task add --title "Review auth" --impact 60 --effort-days 1 --
|
|
164
|
+
mu task add --title "Build auth" --impact 80 --effort-days 5 --blocked-by design_auth_module
|
|
165
|
+
mu task add --title "Review auth" --impact 60 --effort-days 1 --blocked-by build_auth
|
|
130
166
|
|
|
131
167
|
# Spawn a crew with isolated workspaces.
|
|
132
168
|
mu agent spawn worker-1 --workspace
|
|
133
169
|
mu agent spawn reviewer-1 --workspace --role read-only
|
|
134
170
|
|
|
135
|
-
#
|
|
171
|
+
# Human home base: interactive read-only TUI across every workstream
|
|
172
|
+
# (same dashboard is explicit with: mu state --tui -w auth-refactor).
|
|
136
173
|
mu
|
|
137
174
|
|
|
175
|
+
# Agent/script API: static state stays explicit and JSON-friendly.
|
|
176
|
+
mu state -w auth-refactor --json
|
|
177
|
+
|
|
138
178
|
# Inside an agent's pane, the agent claims and closes tasks
|
|
139
179
|
# without ever knowing its own name (mu reads $TMUX_PANE).
|
|
140
180
|
mu task claim design_auth_module
|
|
@@ -148,7 +188,8 @@ mu log --tail
|
|
|
148
188
|
mu workstream destroy --yes
|
|
149
189
|
```
|
|
150
190
|
|
|
151
|
-
Full tour: [docs/USAGE_GUIDE.md](docs/USAGE_GUIDE.md)
|
|
191
|
+
Full tour: [docs/USAGE_GUIDE.md](docs/USAGE_GUIDE.md), including the
|
|
192
|
+
expanded [dashboard/state guide](docs/USAGE_GUIDE.md#5-see-the-graph-dashboard--state-api).
|
|
152
193
|
|
|
153
194
|
---
|
|
154
195
|
|