@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 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 v0.1.0 release entry.
17
- Single source of truth for the verb list, schema, env vars.
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
- │ ├── ROADMAP.md # what's next; promotion criteria
46
- │ ├── VISION.md
47
- │ ├── VOCABULARY.md
48
- └── ARCHITECTURE.md
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-only status detector
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/* + edit/edges/queries verbs)
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 (single source of truth for statuses)
64
- │ │ ├── claim.ts # claim/release + resolveActorIdentity (atomic CAS)
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 buckets (create / add / remove / restore)
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 v0.3 bucket dir → live DB rows
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 interface + jj/sl/git/none impls
75
- │ ├── workspace.ts # per-agent VCS workspaces (CRUD over vcs_workspaces)
76
- │ ├── snapshots.ts # whole-DB snapshots (VACUUM INTO) + auto-capture hook
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) + bare `mu` (mission control / hud render mode)
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/ # 60 files / 57 *.test.ts / ~996 it()/test() calls; many use real tmux/git/jj/sl
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 # tsc --noEmit
176
+ npm run typecheck # source + test TypeScript checks
120
177
  npm run lint # biome check src test
121
- npm run test # vitest run
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
- All four must pass before any commit. Tests include real-tmux
126
- integration tests that need `$TMUX` set. If you're not in tmux,
127
- those tests skip themselves; CI runs inside tmux.
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
- - Integration tests: real tmux server. File suffix
174
- `.integration.test.ts` (e.g. `tmux.integration.test.ts`). Skipped
175
- when `$TMUX` is unset. These tests typically opt out of the spawn
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
- - The acceptance test in `test/acceptance.test.ts` is the
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
- - An agent template/discovery system requires explicit promotion
216
- - No render layer beyond `cli-table3` + `picocolors`
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. 0.1.0 has no migration layer. Schema lives in `src/db.ts` as a
256
- single CREATE-IF-NOT-EXISTS block. The first non-additive
257
- change should land alongside a `schema_version` table.
258
- 2. Update tests that exercise the schema (`test/db.test.ts`).
259
- 3. Update [CHANGELOG.md](CHANGELOG.md) §"Schema" snapshot.
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 test (`test/acceptance.test.ts`)
329
- must pass — it's the "end-to-end works" gate.
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 hard refusal to
6
- grow into another bloated agent framework.
5
+ VCS workspaces per agent, an audit log — and a dashboard for seeing
6
+ what the crew is doing right now.
7
+
8
+ ![mu dashboard](docs/img/tui-dashboard.png)
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 --blocks design_auth
12
- mu task add --title "Review auth" --impact 60 --effort-days 1 --blocks build_auth
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 # mission control: ready tasks, parallel tracks, agent status
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 does not get in your model's way.**
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
- - **Get out of the model's way.** Mu coordinates agents; it does
38
- not reason about them. No model selection, no thinking-effort
39
- knobs, no system-prompt templating, no tool routing. `--cli <key>`
40
- uppercases to `$MU_<KEY>_COMMAND` your shell rc owns the
41
- mapping. Swap your whole stack in one line.
42
- - **A deliberate refusal to over-engineer.** One CLI. One SQLite
43
- file. ~60 typed verbs. No daemon, no config file, no plugin
44
- runtime, no DSL, no codegen, no web UI, no chat integration, no
45
- hosted service. Each missing piece is an
46
- **[anti-feature pledge](docs/ROADMAP.md#anti-feature-pledges-still-in-force-reinforced-by-an-internal-critique)**,
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 --blocks design_auth_module
129
- mu task add --title "Review auth" --impact 60 --effort-days 1 --blocks build_auth
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
- # Mission control: parallel tracks, ready tasks, agent status.
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