@martintrojer/mu 0.3.1 → 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 +14143 -5403
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1779 -1287
- package/dist/index.js +4339 -2943
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +298 -58
- package/docs/HANDOVER.md +461 -0
- package/docs/ROADMAP.md +120 -496
- package/docs/USAGE_GUIDE.md +518 -152
- package/docs/VISION.md +48 -4
- package/docs/VOCABULARY.md +24 -8
- package/docs/img/tui-dashboard.png +0 -0
- package/package.json +12 -6
- package/skills/mu/SKILL.md +274 -443
package/docs/USAGE_GUIDE.md
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
# mu — Usage Guide
|
|
2
2
|
|
|
3
|
-
A practical, copy-pasteable tour of mu (current main; v0.
|
|
3
|
+
A practical, copy-pasteable tour of mu (current main; v0.4-track).
|
|
4
4
|
Everything below works against the built CLI. Terms are canonical
|
|
5
5
|
— see [VOCABULARY.md](VOCABULARY.md) for definitions; the complete
|
|
6
6
|
current verb list is in `## CLI — complete verb list` of
|
|
7
7
|
[skills/mu/SKILL.md](../skills/mu/SKILL.md).
|
|
8
8
|
|
|
9
|
-
> **Status:** v0.
|
|
9
|
+
> **Status:** v0.4 wave (pre-1.0). ~60 typed verbs across 8
|
|
10
10
|
> namespaces (`workstream`, `agent`, `task`, `workspace`, `log`,
|
|
11
11
|
> `snapshot`, `archive`, `me`) plus bare top-level verbs
|
|
12
12
|
> (`state`, `doctor`, `sql`, `undo`, `adopt`). Every verb accepts
|
|
13
13
|
> `--json` (one allow-listed exception, `mu agent attach`),
|
|
14
14
|
> per-agent VCS workspaces (jj/sl/git/none), activity log with
|
|
15
|
-
> `--tail` subscription,
|
|
16
|
-
>
|
|
15
|
+
> `--tail` subscription, bare `mu` TTY dashboard, canonical static
|
|
16
|
+
> state card (`mu state` default / `--tui` render modes), whole-DB
|
|
17
17
|
> snapshots auto-captured before destructive verbs +
|
|
18
18
|
> `mu undo` / `mu snapshot {list,show}`, evidence on lifecycle
|
|
19
19
|
> verbs, schema v7 (v5 surrogate INTEGER PKs + per-workstream
|
|
20
20
|
> UNIQUE on operator-facing names; v6 added the `archive_*`
|
|
21
21
|
> family additively; v7 dropped the dead `approvals` table).
|
|
22
22
|
> See [CHANGELOG.md](../CHANGELOG.md) for the release entry,
|
|
23
|
-
> and [§ Not in 0.
|
|
23
|
+
> and [§ Not in 0.4.0](#whats-not-in-040-and-how-to-work-around-it)
|
|
24
24
|
> at the bottom for the gaps that still need workarounds.
|
|
25
25
|
|
|
26
26
|
*If anything below disagrees with `mu --help`, trust `mu --help`.*
|
|
@@ -33,7 +33,8 @@ current verb list is in `## CLI — complete verb list` of
|
|
|
33
33
|
2. [Get oriented (`mu doctor`)](#2-get-oriented)
|
|
34
34
|
3. [Create a workstream (`mu workstream init`)](#3-create-a-workstream)
|
|
35
35
|
4. [Plan some work as a DAG (`mu task add`)](#4-plan-some-work-as-a-dag)
|
|
36
|
-
5. [See the graph (
|
|
36
|
+
5. [See the graph (dashboard + state API)](#5-see-the-graph-dashboard--state-api)
|
|
37
|
+
5b. [The TUI dashboard (interactive)](#5b-the-tui-dashboard-interactive)
|
|
37
38
|
6. [Spawn a crew (`mu agent spawn`)](#6-spawn-a-crew)
|
|
38
39
|
7. [Watch the crew live (`tmux attach`)](#7-watch-the-crew-live)
|
|
39
40
|
8. [Send work to an agent (`mu agent send`)](#8-send-work-to-an-agent)
|
|
@@ -47,7 +48,7 @@ current verb list is in `## CLI — complete verb list` of
|
|
|
47
48
|
15.5. [Archives — cross-workstream preservation](#155-archives--cross-workstream-preservation-of-task-graphs)
|
|
48
49
|
16. [One-shot demo script](#16-one-shot-demo-script)
|
|
49
50
|
17. [Mental model in three sentences](#mental-model-in-three-sentences)
|
|
50
|
-
18. [What's NOT in 0.
|
|
51
|
+
18. [What's NOT in 0.4.0](#whats-not-in-040-and-how-to-work-around-it)
|
|
51
52
|
19. [Where to go from here](#where-to-go-from-here)
|
|
52
53
|
|
|
53
54
|
---
|
|
@@ -140,6 +141,32 @@ tmux # if you're not already in one
|
|
|
140
141
|
|
|
141
142
|
## 2. Get oriented
|
|
142
143
|
|
|
144
|
+
For a human at an interactive terminal, bare `mu` is the home base:
|
|
145
|
+
it launches the read-only TUI with every workstream on the machine
|
|
146
|
+
loaded as tabs. Initial tab focus uses this ladder: `$MU_SESSION` when
|
|
147
|
+
it names a loaded workstream; then the current tmux session name when
|
|
148
|
+
it is `mu-<workstream>`; then best-effort cwd detection against
|
|
149
|
+
registered workspace paths; then cwd equal to the VCS-derived project
|
|
150
|
+
root of any loaded workstream's workspaces (ties broken by most-recent
|
|
151
|
+
workstream activity); then tab 0. If no workstream exists yet, it
|
|
152
|
+
prints help plus the one-paste start command:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
mu
|
|
156
|
+
# Get started: mu workstream init <name>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
For scripts, agents, CI, and pipes, bare `mu` deliberately does NOT
|
|
160
|
+
enter the TUI: when stdout is not a TTY it prints `mu --help`. Use
|
|
161
|
+
explicit typed verbs and `--json` for the API surface:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
mu state -w <workstream> --json
|
|
165
|
+
MU_NO_TUI=1 mu # force the non-TTY/help path even in a terminal
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Run the diagnostic once to check tmux + DB health:
|
|
169
|
+
|
|
143
170
|
```bash
|
|
144
171
|
mu doctor
|
|
145
172
|
```
|
|
@@ -222,9 +249,10 @@ $ mu task list -w foo --json
|
|
|
222
249
|
```
|
|
223
250
|
|
|
224
251
|
`count` is `items.length` pre-computed so `jq '.count'` is one less
|
|
225
|
-
hop than `jq '.items | length'`. Future siblings
|
|
226
|
-
|
|
227
|
-
|
|
252
|
+
hop than `jq '.items | length'`. Future siblings layer on without
|
|
253
|
+
breaking the existing two fields. Today `mu workspace commits --json`
|
|
254
|
+
also includes `vcs`, `baseRef`, and `workspacePath` siblings because
|
|
255
|
+
that verb already computes the workspace's fork metadata.
|
|
228
256
|
|
|
229
257
|
Applies to: `mu task list / next / owned-by / notes`,
|
|
230
258
|
`mu workstream list`, `mu workstream destroy --empty` (dry-run),
|
|
@@ -329,8 +357,8 @@ Tasks have **mandatory** `impact` (1–100) and `effort-days` (>0).
|
|
|
329
357
|
Edges are blocks-relationships, modelled as **`--blocked-by`** on `mu
|
|
330
358
|
task add` (and `mu task reparent`): `--blocked-by design` means "this
|
|
331
359
|
task is blocked by `design`; it can't start until `design` closes."
|
|
332
|
-
Tasks are **scoped to a workstream** —
|
|
333
|
-
tasks for the workstream you're
|
|
360
|
+
Tasks are **scoped to a workstream** — the dashboard and state views only show
|
|
361
|
+
tasks for the workstream you're viewing.
|
|
334
362
|
|
|
335
363
|
```bash
|
|
336
364
|
# --workstream can be omitted if you're inside the workstream's tmux
|
|
@@ -357,112 +385,299 @@ Each task validates its id (`/^[a-z][a-z0-9_-]{0,63}$/`) and rejects
|
|
|
357
385
|
duplicates. If you tried `mu task add x --blocked-by y` while `y`
|
|
358
386
|
already transitively depended on `x`, mu would refuse with a `CycleError`.
|
|
359
387
|
|
|
360
|
-
**Task ids are
|
|
361
|
-
|
|
362
|
-
|
|
388
|
+
**Task ids are per-workstream unique.** The same local id can exist in
|
|
389
|
+
multiple workstreams, so cross-workstream references use the qualified
|
|
390
|
+
form `<workstream>/<id>` when a global scope is needed. Blocks-edges
|
|
391
|
+
are always same-workstream — if a blocker resolves outside the target
|
|
363
392
|
workstream, mu refuses with a `CrossWorkstreamEdgeError`.
|
|
364
393
|
|
|
365
394
|
---
|
|
366
395
|
|
|
367
|
-
## 5. See the graph (
|
|
396
|
+
## 5. See the graph (dashboard + state API)
|
|
368
397
|
|
|
369
|
-
|
|
370
|
-
mu --workstream auth-refactor
|
|
371
|
-
# or, if your tmux session is mu-auth-refactor:
|
|
372
|
-
mu
|
|
373
|
-
```
|
|
398
|
+
`mu` exposes one logical "what's going on?" view with two renderers:
|
|
374
399
|
|
|
375
|
-
|
|
376
|
-
|
|
400
|
+
| Surface | Use it for |
|
|
401
|
+
| -------------------- | --------------------------------------------------------------- |
|
|
402
|
+
| **bare `mu`** | A human at a terminal — launches the interactive TUI dashboard. |
|
|
403
|
+
| **`mu state --tui`** | Same TUI, explicitly opt-in. Useful in scripts / aliases. |
|
|
404
|
+
| **`mu state`** | Static text card. JSON-friendly; pipeable; `watch`-able. |
|
|
405
|
+
| **`mu state --json`** | The canonical full snapshot. Agents and scripts read this. |
|
|
377
406
|
|
|
378
|
-
|
|
379
|
-
|
|
407
|
+
The interactive surface is large enough to deserve its own section —
|
|
408
|
+
see [§ 5b. The TUI dashboard](#5b-the-tui-dashboard-interactive)
|
|
409
|
+
immediately below. The rest of this section is the static / JSON
|
|
410
|
+
contract.
|
|
380
411
|
|
|
381
|
-
|
|
382
|
-
Track 1: review (3 tasks, 1 ready, track)
|
|
412
|
+
### Static state card (`mu state`)
|
|
383
413
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
found. When two goals share a prerequisite, mu collapses them into
|
|
399
|
-
ONE track ("merged") so two agents are never assigned tasks that
|
|
400
|
-
share a dependency
|
|
401
|
-
- **Ready** — actionable now, sorted by ROI (impact / effort)
|
|
402
|
-
|
|
403
|
-
### `mu state` render modes (default, `--hud`, `--mission`)
|
|
404
|
-
|
|
405
|
-
`mu state` is one verb with three render modes — same data set,
|
|
406
|
-
different presentation strategy. The flag picks the renderer; the
|
|
407
|
-
JSON shape (`--json`) follows render mode (full vs stripped).
|
|
408
|
-
|
|
409
|
-
```bash
|
|
410
|
-
mu state # default: full top-to-bottom card
|
|
411
|
-
mu state --hud # dynamic-fit budget renderer (watch / popup / status-bar)
|
|
412
|
-
mu state --mission # stripped 5-col glance card
|
|
413
|
-
mu # bare alias for `mu state --mission`
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
- **default (full card)** — every section: agents + orphans + tracks +
|
|
417
|
-
ready / in-progress / blocked / recent-closed + workspaces + recent
|
|
418
|
-
events. JSON-first by design (per Ilya's council critique: state
|
|
419
|
-
cards as the default attention surface; SQL/raw verbs as the
|
|
420
|
-
escape hatch underneath).
|
|
421
|
-
|
|
422
|
-
- **`--hud`** — dynamic table layout that fills the terminal (or tmux
|
|
423
|
-
pane) height + width with as much useful data as fits.
|
|
424
|
-
`watch -n 5 mu state --hud -w X` for a refreshing pane;
|
|
425
|
-
`tmux display-popup -E 'mu state --hud -w X'` for an on-demand
|
|
426
|
-
popup; `#(mu state --hud -w X --json) | jq ...` for tmux
|
|
427
|
-
status-bar interpolation. Sections (priority order):
|
|
428
|
-
header / agents / ready / in-progress / tracks / recent-events.
|
|
429
|
-
Truncated tables get a `… +N more (<verb>)` footer; lower-priority
|
|
430
|
-
sections that can't fit are skipped entirely. Drops blocked /
|
|
431
|
-
recent-closed / workspaces (not glanceable); operator drops
|
|
432
|
-
`--hud` to see them.
|
|
433
|
-
|
|
434
|
-
- **`--mission`** — stripped 5-col glance card (agents + orphans +
|
|
435
|
-
tracks + ready). The bare-`mu` muscle-memory orient call
|
|
436
|
-
("what's going on?"). The full card with blocked / recent-closed /
|
|
437
|
-
workspaces is too much for that intent; `--mission` is the
|
|
438
|
-
intentional minimum-viable orient view.
|
|
439
|
-
|
|
440
|
-
`--hud` and `--mission` are mutually exclusive.
|
|
441
|
-
|
|
442
|
-
Multi-workstream: pass `-w` multiple values to render N workstreams
|
|
443
|
-
in one card. `-w a,b,c`, `-w a -w b`, or any mix all work — see
|
|
444
|
-
[CLI conventions](#cli-conventions-multi-value-flags). `--all` is
|
|
445
|
-
sugar for "every workstream on this machine" (mutually exclusive with
|
|
446
|
-
`-w`). N≥2 in `--hud` mode unions the per-ws sections with a leading
|
|
447
|
-
`workstream` column; in default + `--mission` modes N≥2 stacks one
|
|
448
|
-
per-workstream card after another. The `--json` envelope wraps in
|
|
449
|
-
`{ workstreams: [...] }` when N≥2.
|
|
450
|
-
|
|
451
|
-
JSON shapes (per render mode):
|
|
414
|
+
For an agent/script or a static capture, use explicit `mu state`:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
mu state -w auth-refactor # human-readable card
|
|
418
|
+
mu state -w auth-refactor --json # full snapshot
|
|
419
|
+
mu state --all --json # every workstream on this machine
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
The static card includes every section the TUI cards summarize:
|
|
423
|
+
agents + orphans + tracks + ready / in-progress / blocked /
|
|
424
|
+
recent-closed tasks + workspaces + recent events. `--json` emits the
|
|
425
|
+
same full snapshot shape regardless of `--tui`.
|
|
426
|
+
|
|
427
|
+
**JSON shapes**
|
|
452
428
|
|
|
453
429
|
- `mu state --json` (single-ws): flat `{ workstreamName, agents,
|
|
454
430
|
orphans, tracks, ready, blocked, inProgress, recentClosed,
|
|
455
431
|
workspaces, recent }`.
|
|
456
|
-
- `mu state --
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
432
|
+
- `mu state --json` (multi-ws): wrapped `{ workstreams: [{...}, ...] }`.
|
|
433
|
+
- bare `mu --json`: prints `--help` rather than entering the TUI;
|
|
434
|
+
use `mu state --json` for the full snapshot.
|
|
435
|
+
- `--tui` is render-only and incompatible with `--json` (the TUI
|
|
436
|
+
has no JSON shape).
|
|
437
|
+
|
|
438
|
+
**Multi-workstream**: pass `-w` multiple values, or `--all`. See
|
|
439
|
+
[CLI conventions](#cli-conventions-multi-value-flags). In static
|
|
440
|
+
mode N≥2 stacks one per-workstream card after another.
|
|
441
|
+
|
|
442
|
+
> **Migrating from old state surfaces**: `mu state --hud` and
|
|
443
|
+
> `mu state --mission` were removed in v0.4; use `mu state --tui`
|
|
444
|
+
> for the interactive surface and `mu state --json` for the full
|
|
445
|
+
> snapshot. `tmux display-popup -E 'mu state -w X'` keeps working
|
|
446
|
+
> unchanged for popup-card use.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 5b. The TUI dashboard (interactive)
|
|
451
|
+
|
|
452
|
+
The interactive TUI is mu's flagship human surface. It is **read-only
|
|
453
|
+
by design** — every act-intent `y`anks the canonical `mu` command to
|
|
454
|
+
your clipboard so you run mutations from your shell, with one
|
|
455
|
+
documented escape (`t` in git-show drills runs `tuicr` in the project
|
|
456
|
+
root, see below).
|
|
457
|
+
|
|
458
|
+
### Launch
|
|
461
459
|
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
460
|
+
```bash
|
|
461
|
+
mu # bare; opens the TUI when stdout is a TTY
|
|
462
|
+
mu state --tui # explicit; same surface
|
|
463
|
+
mu state --tui -w a,b # restrict to specific workstreams
|
|
464
|
+
mu state --tui --all # all workstreams (default for bare `mu`)
|
|
465
|
+
MU_NO_TUI=1 mu # force the help path even in a TTY
|
|
466
|
+
mu --json # also forces help; pipe `mu state --json`
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
Quit with `q` or `Ctrl-C`. The dashboard restores your scrollback
|
|
470
|
+
on exit (alt-screen).
|
|
471
|
+
|
|
472
|
+
**Initial active tab** is picked from this ladder:
|
|
473
|
+
`$MU_SESSION` → current tmux session name (`mu-<ws>`) → cwd inside a
|
|
474
|
+
registered workspace → cwd at the VCS-derived project root of any
|
|
475
|
+
workstream (newest activity wins ties) → tab 0.
|
|
476
|
+
|
|
477
|
+
### Layout: 10 cards, responsive columns
|
|
478
|
+
|
|
479
|
+
The dashboard renders 10 toggleable cards with rounded borders and
|
|
480
|
+
section headers inset into the top border line (lazygit / btop / k9s
|
|
481
|
+
convention):
|
|
482
|
+
|
|
483
|
+
| Slot | Card | Toggle | Popup | Content |
|
|
484
|
+
| ---- | ------------- | ------ | --------- | ---------------------------------------------------- |
|
|
485
|
+
| 0 | Commits | `0` | `Shift+0` | Recent project-root commits (git / jj / sl) |
|
|
486
|
+
| 1 | Agents | `1` | `Shift+1` | Active agents + status + cli + role |
|
|
487
|
+
| 2 | Tracks | `2` | `Shift+2` | Parallel tracks (union-find clusters) |
|
|
488
|
+
| 3 | Ready (Tasks) | `3` | `Shift+3` | Ready-to-claim tasks (no open blockers) |
|
|
489
|
+
| 4 | Activity log | `4` | `Shift+4` | Recent `agent_logs` events |
|
|
490
|
+
| 5 | Workspaces | `5` | `Shift+5` | Per-agent VCS workspaces + behind/dirty status |
|
|
491
|
+
| 6 | In-progress | `6` | `Shift+6` | IN_PROGRESS tasks owned by agents |
|
|
492
|
+
| 7 | Blocked | `7` | `Shift+7` | Tasks with at least one open blocker |
|
|
493
|
+
| 8 | Recent | `8` | `Shift+8` | Recently CLOSED tasks |
|
|
494
|
+
| 9 | Doctor | `9` | `Shift+9` | Cheap health checks (schema, ghosts, orphans, …) |
|
|
495
|
+
| — | DAG | — | `g` | Full task DAG forest (keybind-only) |
|
|
496
|
+
| — | All tasks | — | `t` | Sortable / filterable list of every task |
|
|
497
|
+
|
|
498
|
+
Digit toggles HIDE / SHOW the card on the dashboard; `Shift+digit`
|
|
499
|
+
opens the matching fullscreen popup. **Single-popup invariant**: only
|
|
500
|
+
one popup is visible at a time; `Esc` / `q` returns to the dashboard
|
|
501
|
+
with all toggles + tick rate preserved.
|
|
502
|
+
|
|
503
|
+
**Responsive layout**: cards stack below 120 cols, then reflow into
|
|
504
|
+
pair-aware 2 / 3 / 4-column layouts at 120 / 180 / 240 cols. Each
|
|
505
|
+
visible card gets a dynamic row budget so a noisy list cannot crowd
|
|
506
|
+
out its siblings; overflow shows as `+N more · Shift+N` inset into
|
|
507
|
+
the bottom border. On very short panes, the dashboard culls
|
|
508
|
+
low-priority cards (Doctor → Recent → Workspaces → …) and shows
|
|
509
|
+
`+N cards hidden · resize taller` until the surviving cards fit.
|
|
510
|
+
|
|
511
|
+
Dashboard ordering is slot-stable: within each rendered column,
|
|
512
|
+
non-stream cards are ordered by toggle digit ascending; stream cards
|
|
513
|
+
(Commits, Activity log) sit as natural trailers, with slot 0 trailing
|
|
514
|
+
last.
|
|
515
|
+
|
|
516
|
+
### Multi-workstream tabs
|
|
517
|
+
|
|
518
|
+
When the TUI is launched with N≥2 workstreams (e.g. bare `mu` on a
|
|
519
|
+
machine with multiple workstreams, or `mu state --tui -w a,b,c`),
|
|
520
|
+
a compact tab strip renders above the cards:
|
|
521
|
+
|
|
522
|
+
```
|
|
523
|
+
workstreams: ▸ auth-refactor · ui-rewrite · demo (Tab / Shift-Tab)
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
- `Tab` cycles forward, `Shift-Tab` backward (suppressed inside
|
|
527
|
+
popups so the same key still navigates inside popups that bind
|
|
528
|
+
it locally).
|
|
529
|
+
- The active tab name appears in the status bar's right zone next
|
|
530
|
+
to the tick rate.
|
|
531
|
+
- Cards / popups always operate on the active tab — there's no
|
|
532
|
+
per-row workstream column.
|
|
533
|
+
- For N=1 the strip renders nothing (frame is byte-identical to
|
|
534
|
+
single-ws TUI).
|
|
535
|
+
- When the workstream set is wider than the terminal, the strip
|
|
536
|
+
windows around the active tab and shows `‹N` / `›N` counters
|
|
537
|
+
for hidden workstreams.
|
|
538
|
+
|
|
539
|
+
### Popup drills
|
|
540
|
+
|
|
541
|
+
`Enter` in any list popup drills into the focused row. Where the
|
|
542
|
+
row is itself an entity (a task), a further `Enter` chains into the
|
|
543
|
+
shared read-only task-detail leaf (notes timeline):
|
|
544
|
+
|
|
545
|
+
- **Tracks popup (`Shift+2`)**: list of tracks → `Enter` opens the
|
|
546
|
+
track's task list → `Enter` opens that task's notes timeline.
|
|
547
|
+
- **Ready / In-progress / Blocked / Recent / All-tasks**:
|
|
548
|
+
list of tasks → `Enter` opens notes; `y` yanks `mu task show <id>`
|
|
549
|
+
(or `mu task claim` / `mu task close` / `mu task tree` depending
|
|
550
|
+
on popup).
|
|
551
|
+
- **Activity log popup (`Shift+4`)**: list of events → `Enter`
|
|
552
|
+
drills into the full untruncated payload of the focused event;
|
|
553
|
+
`y` yanks `mu log --since <seq-1> -n 1 -w <ws>`.
|
|
554
|
+
- **Workspaces popup (`Shift+5`)**: list of workspaces → `Enter`
|
|
555
|
+
opens the commits-since-fork list → `Enter` on a commit opens
|
|
556
|
+
the inline `git show <sha> --stat -p` view; `y` yanks `git show
|
|
557
|
+
<sha>`; `t` launches `tuicr -r <sha>`.
|
|
558
|
+
- **Commits popup (`Shift+0`)**: project-root recent commits →
|
|
559
|
+
`Enter` opens the backend's show view; `y` yanks the show
|
|
560
|
+
command; `t` launches `tuicr`.
|
|
561
|
+
- **Doctor popup (`Shift+9`)**: list of checks → `Enter` opens
|
|
562
|
+
the remediation paragraph for the focused check.
|
|
563
|
+
- **DAG popup (`g`)**: keybind-only; renders the active workstream's
|
|
564
|
+
full task DAG forest (one ASCII subtree per root, diamond-collapse
|
|
565
|
+
marker on repeated nodes).
|
|
566
|
+
|
|
567
|
+
One `Esc` / `q` backs out per recursion level. Drills auto-refresh
|
|
568
|
+
in step with the dashboard tick (fast 1s for SQL-derived bodies
|
|
569
|
+
like notes, slow 10s for subprocess git-show / scrollback). Scroll
|
|
570
|
+
position is preserved across refreshes; subprocess loaders keep the
|
|
571
|
+
prior body visible until the new one arrives so there's no
|
|
572
|
+
blank-flash mid-refetch.
|
|
573
|
+
|
|
574
|
+
### Search / filter
|
|
575
|
+
|
|
576
|
+
`/` inside any list popup enters an incremental case-insensitive
|
|
577
|
+
substring filter (lazygit / k9s convention):
|
|
578
|
+
|
|
579
|
+
- Every printable character appends to the query; `Backspace` pops
|
|
580
|
+
one.
|
|
581
|
+
- `Esc` cancels (clears the query); `Enter` commits (keeps the
|
|
582
|
+
filter applied while letting `j/k` resume normal navigation).
|
|
583
|
+
- Press `/` again on a committed filter to refine.
|
|
584
|
+
- The filter blob is per-popup: agent name + status + cli + role;
|
|
585
|
+
track head id + title; task name + title + status + owner; log
|
|
586
|
+
verb + payload + source.
|
|
587
|
+
- Filter state is per-popup and dies with the popup.
|
|
588
|
+
|
|
589
|
+
Task-list popups also expose **per-status toggles** (`o` / `i` / `c`
|
|
590
|
+
/ `r` / `d` toggle OPEN / IN_PROGRESS / CLOSED / REJECTED / DEFERRED
|
|
591
|
+
visibility; default all-on).
|
|
592
|
+
|
|
593
|
+
The All-tasks popup adds **sort cycle** on `s`: `roi` → `recency`
|
|
594
|
+
→ `age` → `id`.
|
|
595
|
+
|
|
596
|
+
### Mouse
|
|
597
|
+
|
|
598
|
+
Navigation-in only:
|
|
599
|
+
|
|
600
|
+
- Double-click a dashboard card → opens its popup.
|
|
601
|
+
- Scroll-wheel inside a popup list / drill body → moves the focused
|
|
602
|
+
cursor / scrolls the body.
|
|
603
|
+
- Double-click a popup row → drills one level deeper.
|
|
604
|
+
|
|
605
|
+
There is intentionally **no mouse back binding** — use `Esc` / `q`
|
|
606
|
+
to back out predictably.
|
|
607
|
+
|
|
608
|
+
### Yank contract (`y`) and the `tuicr` escape (`t`)
|
|
609
|
+
|
|
610
|
+
Every popup row exposes one canonical `mu` command via `y`. The
|
|
611
|
+
command goes to your system clipboard (pbcopy / wl-copy / xclip /
|
|
612
|
+
xsel / clip.exe with OSC-52 fallback). You run it in your shell.
|
|
613
|
+
The TUI never executes a mutation.
|
|
614
|
+
|
|
615
|
+
The one user-driven escape from the read-only pledge is **`t`**
|
|
616
|
+
inside any `git show` drill (Workspaces popup or Commits popup):
|
|
617
|
+
mu suspends its alt-screen, runs `tuicr -r <sha>` in the project
|
|
618
|
+
root / workspace cwd, then restores the dashboard when tuicr exits.
|
|
619
|
+
This is a deliberate handoff — the operator drives another TUI
|
|
620
|
+
tool, not mu performing the mutation.
|
|
621
|
+
|
|
622
|
+
Task-list cards and popups colour-code status cells consistently
|
|
623
|
+
with the static CLI tables: OPEN cyan, IN_PROGRESS yellow, CLOSED
|
|
624
|
+
green, REJECTED red, DEFERRED dim/gray.
|
|
625
|
+
|
|
626
|
+
### Polling tiers
|
|
627
|
+
|
|
628
|
+
The dashboard has two refresh tiers:
|
|
629
|
+
|
|
630
|
+
- **Fast tick** (default 1s, adjustable with `+` / `-` / `=` /
|
|
631
|
+
`0`): SQL-only. Refreshes tasks, tracks, workspace registry rows,
|
|
632
|
+
and the activity log.
|
|
633
|
+
- **Slow tick** (10s, fixed): subprocess-backed. Refreshes
|
|
634
|
+
tmux-derived agent liveness / orphans, workspace dirty flags,
|
|
635
|
+
recent project commits, and the Doctor summary.
|
|
636
|
+
|
|
637
|
+
The last slow-tier result is merged into every fast render so cards
|
|
638
|
+
do not flicker through a loading state. `r` / F5 refreshes both
|
|
639
|
+
tiers immediately. Tab / Shift-Tab triggers an eager slow refresh
|
|
640
|
+
for the newly active workstream.
|
|
641
|
+
|
|
642
|
+
### Keymap reference
|
|
643
|
+
|
|
644
|
+
| Mode | Keys | Action |
|
|
645
|
+
| --------- | ---------------------------- | -------------------------------------------------------------- |
|
|
646
|
+
| dashboard | `0`-`9` | toggle card visibility |
|
|
647
|
+
| dashboard | `Shift+0`-`Shift+9` | open the matching popup |
|
|
648
|
+
| dashboard | `g` | open DAG popup (keybind-only) |
|
|
649
|
+
| dashboard | `t` | open All-tasks popup (keybind-only) |
|
|
650
|
+
| dashboard | `Tab` / `Shift-Tab` | cycle workstream tabs (N≥2) |
|
|
651
|
+
| dashboard | `+` / `-` / `=` / `0` | adjust fast tick rate (faster / slower / default / pause) |
|
|
652
|
+
| dashboard | `r` / `F5` | force refresh both tiers |
|
|
653
|
+
| dashboard | `?` / `F1` | open help overlay |
|
|
654
|
+
| any | `q` / `Ctrl-C` | quit (or back out of popup; quits at dashboard) |
|
|
655
|
+
| popup | `j` / `k` | move cursor / scroll |
|
|
656
|
+
| popup | `g` / `G` | jump top / bottom |
|
|
657
|
+
| popup | `Ctrl-D` / `Ctrl-U` | half-page down / up |
|
|
658
|
+
| popup | `PgDn` / `PgUp` | full page |
|
|
659
|
+
| popup | `Enter` | drill into focused row |
|
|
660
|
+
| popup | `Esc` / `q` | back out one level |
|
|
661
|
+
| popup | `y` | yank canonical `mu` command for focused row |
|
|
662
|
+
| popup | `/` | enter filter mode |
|
|
663
|
+
| filter | (printable) / `Backspace` | edit query |
|
|
664
|
+
| filter | `Esc` | cancel (clear query) |
|
|
665
|
+
| filter | `Enter` | commit (keep filter, return to nav) |
|
|
666
|
+
| task popup| `o` / `i` / `c` / `r` / `d` | toggle OPEN / IN_PROGRESS / CLOSED / REJECTED / DEFERRED |
|
|
667
|
+
| All-tasks | `s` | cycle sort key (roi → recency → age → id) |
|
|
668
|
+
| git-show | `t` | launch `tuicr -r <sha>` (alt-screen handoff) |
|
|
669
|
+
|
|
670
|
+
`?` shows the same table as a scrollable overlay (j/k/Ctrl-D/U/g/G
|
|
671
|
+
also work inside the overlay).
|
|
672
|
+
|
|
673
|
+
### Read-only invariant
|
|
674
|
+
|
|
675
|
+
The TUI never executes a mutation. This is not a feature of the
|
|
676
|
+
implementation; it's a load-bearing pledge in `docs/ROADMAP.md`. If
|
|
677
|
+
a future TUI gesture tempts you to call into the SDK to mutate
|
|
678
|
+
state, file a roadmap entry first — the yank-and-run pattern is the
|
|
679
|
+
intentional cost we pay to keep the TUI inspectable, scriptable, and
|
|
680
|
+
recoverable from any shell.
|
|
466
681
|
|
|
467
682
|
---
|
|
468
683
|
|
|
@@ -561,9 +776,9 @@ mu agent list -w auth-refactor # surfaces orphans at the bottom
|
|
|
561
776
|
# Orphan panes (1)
|
|
562
777
|
# %15 title=worker-2 cli=pi
|
|
563
778
|
|
|
564
|
-
mu adopt %15 -w auth-refactor # adopt by pane id
|
|
565
|
-
mu adopt worker-2 -w auth-refactor # adopt by pane title (same effect)
|
|
566
|
-
mu adopt %15 --name investigator -w auth-refactor # adopt and rename the pane
|
|
779
|
+
mu agent adopt %15 -w auth-refactor # adopt by pane id
|
|
780
|
+
mu agent adopt worker-2 -w auth-refactor # adopt by pane title (same effect)
|
|
781
|
+
mu agent adopt %15 --name investigator -w auth-refactor # adopt and rename the pane
|
|
567
782
|
```
|
|
568
783
|
|
|
569
784
|
The pane title becomes the agent name (`mu`'s claim protocol
|
|
@@ -630,6 +845,28 @@ MU_SEND_DELAY_MS=300 mu agent send worker-1 "..." # faster, less safe
|
|
|
630
845
|
MU_SEND_DELAY_MS=1000 mu agent send worker-1 "..." # slow remote
|
|
631
846
|
```
|
|
632
847
|
|
|
848
|
+
If the target agent has a workspace that is **stale** (≥10 commits
|
|
849
|
+
behind main — the same red bucket shown in `mu workspace list` and the
|
|
850
|
+
TUI Workspaces card), `mu agent send` prints a yellow stderr warning
|
|
851
|
+
but still sends by default:
|
|
852
|
+
|
|
853
|
+
```bash
|
|
854
|
+
WARN: worker-1 workspace is 14 commits behind main (≥10 = stale)
|
|
855
|
+
Next:
|
|
856
|
+
Refresh first : mu workspace refresh worker-1 -w auth-refactor
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
Use `--strict-staleness` when a wrapper should refuse instead of
|
|
860
|
+
warning:
|
|
861
|
+
|
|
862
|
+
```bash
|
|
863
|
+
mu agent send worker-1 "..." -w auth-refactor --strict-staleness
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
Agents without workspaces are skipped (common for read-only roles).
|
|
867
|
+
`--json` output includes `staleness: null` or `{agentName,
|
|
868
|
+
workstreamName, commitsBehindMain, isStale}`.
|
|
869
|
+
|
|
633
870
|
---
|
|
634
871
|
|
|
635
872
|
## 9. Read what an agent did
|
|
@@ -714,6 +951,29 @@ workstream prefix, `AgentNotFoundError` (exit 3, message names the
|
|
|
714
951
|
workstream) when the named worker doesn't live there. Nothing is
|
|
715
952
|
written on either failure.
|
|
716
953
|
|
|
954
|
+
When `--for` targets an agent with a stale workspace (≥10 commits
|
|
955
|
+
behind main), `mu task claim` warns on stderr and appends a refresh
|
|
956
|
+
hint, but the claim still succeeds by default:
|
|
957
|
+
|
|
958
|
+
```bash
|
|
959
|
+
mu task claim build -w auth-refactor --for worker-2
|
|
960
|
+
# stderr: WARN: worker-2 workspace is 14 commits behind main (≥10 = stale)
|
|
961
|
+
# Next: Refresh first : mu workspace refresh worker-2 -w auth-refactor
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
Pass `--strict-staleness` to refuse the claim instead with typed
|
|
965
|
+
`TaskClaimStaleWorkspaceError` (exit 4). This is useful for scripts
|
|
966
|
+
that should never dispatch work onto a stale parent:
|
|
967
|
+
|
|
968
|
+
```bash
|
|
969
|
+
mu task claim build -w auth-refactor --for worker-2 --strict-staleness
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
`--json` output includes `staleness: null` or `{agentName,
|
|
973
|
+
workstreamName, commitsBehindMain, isStale}`. Bare in-pane claims and
|
|
974
|
+
`--self` claims do not run this check because they do not assign work
|
|
975
|
+
to a named agent via `--for`.
|
|
976
|
+
|
|
717
977
|
### The orchestrator pattern: `--self`
|
|
718
978
|
|
|
719
979
|
Not every action comes from a registered worker pane. Often the
|
|
@@ -723,7 +983,7 @@ a worker pane just for a 5-minute job. Two patterns split here:
|
|
|
723
983
|
|
|
724
984
|
- **Worker** — a pane mu spawned (or you adopted). Has a row in the
|
|
725
985
|
`agents` table. Identity = pane title. Claims with bare
|
|
726
|
-
`mu task claim <id>`. `tasks.
|
|
986
|
+
`mu task claim <id>`. `tasks.owner_id` points at the worker row.
|
|
727
987
|
|
|
728
988
|
- **Actor** — anything that *causes* a state change. Includes
|
|
729
989
|
workers, but also includes the orchestrator. May or may not have
|
|
@@ -737,7 +997,7 @@ If the orchestrator tries `mu task claim some-task` directly:
|
|
|
737
997
|
conflict: claimer 'pi-mu' (pane %6441) is not a registered mu agent.
|
|
738
998
|
Working directly? Pass --self to attribute via log instead.
|
|
739
999
|
Dispatching to a worker? Pass --for <worker> to assign.
|
|
740
|
-
Want full registration? Run: mu adopt %6441
|
|
1000
|
+
Want full registration? Run: mu agent adopt %6441
|
|
741
1001
|
```
|
|
742
1002
|
|
|
743
1003
|
Three actionable next steps. Pick one based on intent:
|
|
@@ -745,16 +1005,16 @@ Three actionable next steps. Pick one based on intent:
|
|
|
745
1005
|
```bash
|
|
746
1006
|
# Orchestrator does the work itself (most common):
|
|
747
1007
|
mu task claim some-task --self --evidence "trivial 5-line fix"
|
|
748
|
-
# -> tasks.
|
|
1008
|
+
# -> tasks.owner_id stays NULL
|
|
749
1009
|
# -> agent_logs records 'task claim some-task by pi-mu --self (anonymous)'
|
|
750
1010
|
# -> mu task show surfaces it as 'owner: (self: pi-mu)'
|
|
751
1011
|
|
|
752
1012
|
# Orchestrator dispatches to a worker:
|
|
753
1013
|
mu task claim some-task --for worker-1
|
|
754
|
-
# -> tasks.
|
|
1014
|
+
# -> tasks.owner_id points at worker-1
|
|
755
1015
|
|
|
756
1016
|
# Orchestrator wants to BE a registered worker (rare):
|
|
757
|
-
mu adopt %6441 -w <ws>
|
|
1017
|
+
mu agent adopt %6441 -w <ws> # only if pane is in mu-<ws> session
|
|
758
1018
|
mu task claim some-task # now works as a normal worker claim
|
|
759
1019
|
```
|
|
760
1020
|
|
|
@@ -767,7 +1027,7 @@ to pane title, or `$USER`, or `unknown`):
|
|
|
767
1027
|
mu task claim deploy --self --actor deploy-bot --evidence "prod release"
|
|
768
1028
|
```
|
|
769
1029
|
|
|
770
|
-
When `tasks.
|
|
1030
|
+
When `tasks.owner_id IS NULL` because of `--self`, `mu task show` looks
|
|
771
1031
|
up the most recent `task claim` event for that task and surfaces it:
|
|
772
1032
|
|
|
773
1033
|
```
|
|
@@ -790,10 +1050,39 @@ mu task note design "DECISION: JWT, 24h expiry, refresh via cookie"
|
|
|
790
1050
|
mu task note design "FILES: src/auth.rs:45-120"
|
|
791
1051
|
```
|
|
792
1052
|
|
|
793
|
-
Read them via the
|
|
1053
|
+
Read them via the typed verb:
|
|
1054
|
+
|
|
1055
|
+
```bash
|
|
1056
|
+
mu task notes design # all notes, oldest first
|
|
1057
|
+
mu task notes design --tail 3 # only the last 3 (alias --last)
|
|
1058
|
+
mu task notes design --since 2026-01-01 # only notes after an ISO 8601 cutoff
|
|
1059
|
+
mu task notes design --since-claim # only notes since the most recent
|
|
1060
|
+
# 'task claim' event for this task
|
|
1061
|
+
# (auto-resolved from agent_logs)
|
|
1062
|
+
mu task notes design --tail 5 --json # collection envelope {items, count}
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
Filters compose: `--tail` slices the last N of whatever survived
|
|
1066
|
+
the timestamp filter. `--since` and `--since-claim` are mutually
|
|
1067
|
+
exclusive (both define a cutoff) — pick one. With no filters the
|
|
1068
|
+
output is unchanged from prior versions (every note, oldest-first).
|
|
1069
|
+
|
|
1070
|
+
`--since-claim` is the orchestrator-friendly form: dispatch flows
|
|
1071
|
+
often drop a multi-screen SPEC note BEFORE claiming, then the
|
|
1072
|
+
worker appends progress notes AFTER the claim. `--since-claim`
|
|
1073
|
+
slices off the SPEC so you see only the worker's reports. If no
|
|
1074
|
+
claim event exists for the task, it degrades to no filter (so the
|
|
1075
|
+
verb stays useful on un-claimed tasks).
|
|
1076
|
+
|
|
1077
|
+
Or, for ad-hoc shape, the SQL escape hatch:
|
|
794
1078
|
|
|
795
1079
|
```bash
|
|
796
|
-
mu sql "SELECT author, content, created_at
|
|
1080
|
+
mu sql "SELECT n.author, n.content, n.created_at
|
|
1081
|
+
FROM task_notes n
|
|
1082
|
+
JOIN tasks t ON t.id = n.task_id
|
|
1083
|
+
JOIN workstreams w ON w.id = t.workstream_id
|
|
1084
|
+
WHERE t.local_id='design' AND w.name='auth-refactor'
|
|
1085
|
+
ORDER BY n.id"
|
|
797
1086
|
```
|
|
798
1087
|
|
|
799
1088
|
Convention for note content: `KEY: value` lines. Common keys are
|
|
@@ -821,6 +1110,18 @@ task re-enters the ready set (the canonical "hand it back to the
|
|
|
821
1110
|
pool" workflow). `--reopen` is the escape hatch for forcing `OPEN`
|
|
822
1111
|
from `CLOSED` / `REJECTED` / `DEFERRED`.
|
|
823
1112
|
|
|
1113
|
+
When the closing actor has a per-agent workspace and that workspace
|
|
1114
|
+
has uncommitted edits, a successful close adds one extra `Next:` hint
|
|
1115
|
+
reminding the actor to commit before the next wave:
|
|
1116
|
+
|
|
1117
|
+
```bash
|
|
1118
|
+
cd $(mu workspace path worker-1 -w auth-refactor) && git commit -am 'Design auth module'
|
|
1119
|
+
```
|
|
1120
|
+
|
|
1121
|
+
The hint is best-effort: no workspace, a clean workspace, the `none`
|
|
1122
|
+
backend, or a failed VCS dirty check simply omit it. The same
|
|
1123
|
+
`nextSteps` entry is present in `--json` output.
|
|
1124
|
+
|
|
824
1125
|
`--if-ready` is the umbrella-on-wave-done shape: an orchestrator
|
|
825
1126
|
fires `mu task close <umbrella> --if-ready` after each wave-task
|
|
826
1127
|
finishes (or unconditionally as a final action). It's a no-op while
|
|
@@ -912,21 +1213,29 @@ one verify, one workspace recycle:
|
|
|
912
1213
|
# The dispatch-pipeline recipe: cycle until in_flight is empty.
|
|
913
1214
|
in_flight=( mufeedback-v03/foo mufeedback-v03/bar roadmap-v0-3/baz )
|
|
914
1215
|
while (( ${#in_flight[@]} > 0 )); do
|
|
915
|
-
|
|
916
|
-
|
|
1216
|
+
res=$(mu task wait "${in_flight[@]}" --first --timeout 90 --json)
|
|
1217
|
+
closed=$(jq -r '.firing.qualifiedId // empty' <<<"$res")
|
|
917
1218
|
if [[ -z "$closed" ]]; then break; fi # timeout or exit 6 — see below
|
|
918
1219
|
|
|
919
|
-
|
|
920
|
-
# nextSteps array — or use `mu task show` to look up).
|
|
921
|
-
worker=$(mu task show "${closed##*/}" -w "${closed%%/*}" --json | jq -r .ownerName)
|
|
1220
|
+
worker=$(jq -r '.firing.owner // empty' <<<"$res")
|
|
922
1221
|
ws=${closed%%/*}
|
|
923
|
-
|
|
924
|
-
#
|
|
925
|
-
|
|
926
|
-
git cherry-pick
|
|
1222
|
+
|
|
1223
|
+
# 1. Inspect, then run, the sha-pinned apply hint from nextSteps.
|
|
1224
|
+
# When the worker has commits since its fork point, the command is
|
|
1225
|
+
# `git cherry-pick <sha>` (or `<first>^..<last>` for multiple
|
|
1226
|
+
# commits). When the worker closed without committing, nextSteps
|
|
1227
|
+
# says so and points at manual `git diff` / `git apply` rescue.
|
|
1228
|
+
apply=$(jq -r '.nextSteps[0].command' <<<"$res")
|
|
1229
|
+
printf 'apply hint: %s\n' "$apply"
|
|
1230
|
+
if [[ "$apply" == git\ cherry-pick* ]]; then
|
|
1231
|
+
eval "$apply"
|
|
1232
|
+
else
|
|
1233
|
+
echo "manual rescue required; inspect the worker workspace before continuing"
|
|
1234
|
+
break
|
|
1235
|
+
fi
|
|
927
1236
|
|
|
928
1237
|
# 2. Verify
|
|
929
|
-
npm run typecheck && npm run lint && npm run test && npm run build
|
|
1238
|
+
npm run typecheck && npm run lint && npm run test:fast && npm run test && npm run build
|
|
930
1239
|
|
|
931
1240
|
# 3. Refresh the workspace for the next dispatch (rebases onto
|
|
932
1241
|
# fresh main WITHOUT killing the worker's LLM context). Default
|
|
@@ -934,6 +1243,10 @@ while (( ${#in_flight[@]} > 0 )); do
|
|
|
934
1243
|
# overrides. Refuses on dirty WC; conflicts exit 5 with a `cd`
|
|
935
1244
|
# hint to resolve in-place.
|
|
936
1245
|
mu workspace refresh "$worker" -w "$ws"
|
|
1246
|
+
# Alt: `mu workspace recreate "$worker" -w "$ws"` does free + create
|
|
1247
|
+
# atomically — same shortcut, but throws away the worker's local
|
|
1248
|
+
# changes (the lossy escape: requires --force on a dirty WC).
|
|
1249
|
+
# Use when you don't care about replaying the worker's commits.
|
|
937
1250
|
|
|
938
1251
|
# 4. Drop $closed from in_flight, dispatch the next task, repeat.
|
|
939
1252
|
in_flight=( "${in_flight[@]/$closed}" )
|
|
@@ -1030,12 +1343,14 @@ mu sql "UPDATE tasks SET status='IN_PROGRESS'
|
|
|
1030
1343
|
|
|
1031
1344
|
# What's blocking what (open tasks only) — same data as `mu task tree`
|
|
1032
1345
|
# but as a flat join when you want a wider report. task_edges is keyed
|
|
1033
|
-
# by tasks.id, not local_id.
|
|
1346
|
+
# by tasks.id, not local_id; join workstreams to scope the report.
|
|
1034
1347
|
mu sql "SELECT b.local_id AS blocked, t.local_id AS by_task
|
|
1035
1348
|
FROM tasks b
|
|
1349
|
+
JOIN workstreams w ON w.id = b.workstream_id
|
|
1036
1350
|
JOIN task_edges e ON e.to_task_id = b.id
|
|
1037
1351
|
JOIN tasks t ON t.id = e.from_task_id
|
|
1038
|
-
WHERE
|
|
1352
|
+
WHERE w.name='mufeedback-v03'
|
|
1353
|
+
AND t.status != 'CLOSED' AND b.status = 'OPEN'"
|
|
1039
1354
|
|
|
1040
1355
|
# Recursive CTE: every task that transitively blocks `launch` in a
|
|
1041
1356
|
# given workstream (or use `mu task tree launch --json` for the same
|
|
@@ -1078,7 +1393,32 @@ Reconciliation runs on every `mu agent list` / `mu`. Three steps:
|
|
|
1078
1393
|
3. **Surface orphan panes** — panes in the workstream's tmux session
|
|
1079
1394
|
whose `pane.command` looks like an agent CLI (pi) but
|
|
1080
1395
|
that aren't in the registry. **Not** auto-adopted; mu shows them
|
|
1081
|
-
under "Orphan panes" and tells you `mu adopt <pane-id>` to register
|
|
1396
|
+
under "Orphan panes" and tells you `mu agent adopt <pane-id>` to register
|
|
1397
|
+
|
|
1398
|
+
### A worker is wedged on an unbounded tool subprocess
|
|
1399
|
+
|
|
1400
|
+
A worker ran `find / -maxdepth 6 ...` (30-60 minutes on a populated
|
|
1401
|
+
home directory) or a busy-wait loop. `mu agent send` queues steering
|
|
1402
|
+
messages until the tool returns; `tmux send-keys C-c` against the
|
|
1403
|
+
pane doesn't propagate (the wrapping pi/claude/codex CLI catches it
|
|
1404
|
+
as TUI input). The escape hatch:
|
|
1405
|
+
|
|
1406
|
+
```bash
|
|
1407
|
+
mu agent kick worker-1 # SIGINT (graceful, default)
|
|
1408
|
+
mu agent kick worker-1 --signal SIGTERM # polite escalation
|
|
1409
|
+
mu agent kick worker-1 --signal SIGKILL # hammer
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1412
|
+
`mu agent kick` looks up the pane's TTY via `tmux display-message
|
|
1413
|
+
-p '#{pane_tty}'`, asks `ps -t <tty>` for the foreground process
|
|
1414
|
+
group (the row whose `stat` field contains `+`), and signals the
|
|
1415
|
+
whole pgrp directly. Refuses with `NoForegroundProcessError` when
|
|
1416
|
+
the foreground IS the wrapping CLI itself — use `mu agent close`
|
|
1417
|
+
to close the agent.
|
|
1418
|
+
|
|
1419
|
+
Prevention: don't prompt workers to run filesystem-wide `find`,
|
|
1420
|
+
broad `grep -r /`, or unbounded busy-wait loops. Pass paths
|
|
1421
|
+
explicitly or scope to `$WORKSPACE`.
|
|
1082
1422
|
|
|
1083
1423
|
### You closed your terminal session
|
|
1084
1424
|
|
|
@@ -1219,6 +1559,19 @@ mu agent close reviewer-1
|
|
|
1219
1559
|
`mu agent close` is idempotent: `killPane` swallows "pane already gone"
|
|
1220
1560
|
errors; `deleteAgent` returns false (not throws) on a missing row.
|
|
1221
1561
|
|
|
1562
|
+
If the agent has a workspace, behaviour depends on its state:
|
|
1563
|
+
|
|
1564
|
+
- **Clean** (no uncommitted changes AND no commits since fork) — the
|
|
1565
|
+
workspace is silently auto-freed alongside the close, so a
|
|
1566
|
+
`--workspace` spawn that did no real work doesn't make you type
|
|
1567
|
+
`--discard-workspace` just to clean up.
|
|
1568
|
+
- **Dirty** (uncommitted changes OR commits since fork) — close refuses
|
|
1569
|
+
with `WorkspacePreservedError` (exit 4). Two resolutions: (a) `mu
|
|
1570
|
+
workspace free <agent>` first (optionally with `--commit` to capture
|
|
1571
|
+
pending changes), then `mu agent close <agent>`; or (b) `mu agent
|
|
1572
|
+
close <agent> --discard-workspace` to free both in one shot (lossy:
|
|
1573
|
+
any work in the workspace is gone).
|
|
1574
|
+
|
|
1222
1575
|
### Tear down the whole workstream
|
|
1223
1576
|
|
|
1224
1577
|
`mu workstream destroy` is the symmetric counterpart of `mu workstream init`: it kills the
|
|
@@ -1282,8 +1635,10 @@ failure leaves the registry intact (you can retry); if you only want
|
|
|
1282
1635
|
the DB cleared, use `mu sql` directly:
|
|
1283
1636
|
|
|
1284
1637
|
```bash
|
|
1285
|
-
mu sql "DELETE FROM tasks
|
|
1286
|
-
|
|
1638
|
+
mu sql "DELETE FROM tasks
|
|
1639
|
+
WHERE workstream_id=(SELECT id FROM workstreams WHERE name='auth-refactor')" # cascades
|
|
1640
|
+
mu sql "DELETE FROM agents
|
|
1641
|
+
WHERE workstream_id=(SELECT id FROM workstreams WHERE name='auth-refactor')"
|
|
1287
1642
|
```
|
|
1288
1643
|
|
|
1289
1644
|
Or nuke the entire DB:
|
|
@@ -1310,7 +1665,7 @@ subdirectory per source workstream:
|
|
|
1310
1665
|
<bucket>/
|
|
1311
1666
|
README.md # bucket-level summary (every source-ws + dates + totals)
|
|
1312
1667
|
INDEX.md # union of all task tables; first column = source-ws
|
|
1313
|
-
manifest.json # bucketVersion: 2
|
|
1668
|
+
manifest.json # bucketVersion: 2, manifest_version: 2, per-source-ws task summaries + sha256s
|
|
1314
1669
|
<source-ws>/
|
|
1315
1670
|
README.md # per-source-ws (counts)
|
|
1316
1671
|
INDEX.md # per-source-ws (table of every task)
|
|
@@ -1320,12 +1675,21 @@ subdirectory per source workstream:
|
|
|
1320
1675
|
Bucket exports are **additive**: `mu workstream export -w X --out
|
|
1321
1676
|
<bucket>` creates the bucket scaffolding plus `X/` on first use,
|
|
1322
1677
|
and a follow-up call with `-w Y --out <same-bucket>` appends a
|
|
1323
|
-
sibling `Y/` subdirectory without touching `X/`.
|
|
1678
|
+
sibling `Y/` subdirectory without touching `X/`. The top-level
|
|
1679
|
+
`INDEX.md` is always the union from `manifest.sources`, so a later
|
|
1680
|
+
single-workstream refresh does not drop sibling workstreams from the
|
|
1681
|
+
bucket-wide task table. Re-running with
|
|
1324
1682
|
the same `-w` is sha256-idempotent: only changed task files are
|
|
1325
1683
|
rewritten (mtime preserved on identical files); tasks added since
|
|
1326
1684
|
the previous export get fresh files; tasks deleted from the DB
|
|
1327
1685
|
STAY on disk with a `> **Deleted from DB on <ts>**` banner so you
|
|
1328
|
-
never lose context that may already be git-blamed.
|
|
1686
|
+
never lose context that may already be git-blamed. `manifest_version:
|
|
1687
|
+
2` stores compact task summaries (`name`/`title`/`status`/`impact`/
|
|
1688
|
+
`effortDays`) beside the per-file sha256s; older v1 manifests are
|
|
1689
|
+
accepted on re-export; mu infers the missing summaries from existing
|
|
1690
|
+
per-task markdown when possible, falling back to placeholder values
|
|
1691
|
+
only if a task file is missing or unreadable, so the bucket remains
|
|
1692
|
+
appendable.
|
|
1329
1693
|
|
|
1330
1694
|
```bash
|
|
1331
1695
|
# One-shot dump (bucket happens to contain just one source-ws)
|
|
@@ -1399,7 +1763,7 @@ Key properties:
|
|
|
1399
1763
|
imported in its own SQLite transaction. A failure in source A
|
|
1400
1764
|
rolls back A; sibling source B is unaffected.
|
|
1401
1765
|
- **Refuses silent merges.** If the target workstream already
|
|
1402
|
-
exists in the DB
|
|
1766
|
+
exists in the DB, the import errors with
|
|
1403
1767
|
`WorkstreamAlreadyExistsError`. Recourse:
|
|
1404
1768
|
`--workstream <new-name>` (single-source buckets only) or
|
|
1405
1769
|
destroy the existing workstream first.
|
|
@@ -1413,8 +1777,6 @@ Key properties:
|
|
|
1413
1777
|
- **Forward edge refs are deferred.** `blocked_by` / `blocks`
|
|
1414
1778
|
arrays are validated against the bucket's id-set up front, then
|
|
1415
1779
|
inserted after every task in the source-ws is created.
|
|
1416
|
-
- **Pre-0.3 layouts refuse.** Buckets without a `bucketVersion: 2`
|
|
1417
|
-
manifest throw `ImportLegacyLayoutError` with a re-export hint.
|
|
1418
1780
|
- **Partial import.** Multi-source buckets accept either a
|
|
1419
1781
|
per-source-ws subdir path (auto-detected via
|
|
1420
1782
|
`README.md` + `INDEX.md` + `tasks/` + a parent
|
|
@@ -1462,12 +1824,16 @@ Key properties:
|
|
|
1462
1824
|
- **Globally-unique labels.** Archive labels live in their own
|
|
1463
1825
|
namespace (separate from workstream names). Pick once, reuse
|
|
1464
1826
|
across years.
|
|
1465
|
-
- **
|
|
1466
|
-
idempotent at the (archive, source workstream) granularity
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1827
|
+
- **Snapshot-only accumulation.** `mu archive add <label> -w <ws>` is
|
|
1828
|
+
idempotent at the (archive, source workstream) granularity and is
|
|
1829
|
+
designed for end-of-milestone snapshot-and-destroy flows. Re-running
|
|
1830
|
+
on the same workstream is task-incremental: newly-created tasks are
|
|
1831
|
+
added, but notes and events for already-archived tasks stay pinned
|
|
1832
|
+
to the original snapshot and are NOT refreshed. If you need a full
|
|
1833
|
+
event-stream refresh for a source workstream, remove that source (or
|
|
1834
|
+
delete/re-create the archive label) and add it again. Two different
|
|
1835
|
+
workstreams under the same label coexist as separate
|
|
1836
|
+
`(source_workstream, original_local_id)` rows.
|
|
1471
1837
|
- **Outlives the source.** `archived_tasks.source_workstream` is
|
|
1472
1838
|
TEXT (not an FK), so the source workstream can be destroyed and
|
|
1473
1839
|
the archive's snapshot of it stays queryable forever.
|
|
@@ -1547,8 +1913,8 @@ mu agent spawn worker-1 --workstream demo --cli sh
|
|
|
1547
1913
|
mu agent spawn worker-2 --workstream demo --cli sh
|
|
1548
1914
|
|
|
1549
1915
|
# Assign + observe
|
|
1550
|
-
mu
|
|
1551
|
-
mu
|
|
1916
|
+
mu task claim design -w demo --for worker-1 --evidence "demo assignment"
|
|
1917
|
+
mu state -w demo
|
|
1552
1918
|
|
|
1553
1919
|
# Watch live (Ctrl+b d to detach)
|
|
1554
1920
|
tmux attach -t mu-demo
|
|
@@ -1574,8 +1940,8 @@ rm -f ~/.local/state/mu/mu.db
|
|
|
1574
1940
|
shared deps.
|
|
1575
1941
|
|
|
1576
1942
|
3. **Agents claim tasks via their pane title — zero config.**
|
|
1577
|
-
`mu task claim foo` from inside `worker-1`'s pane sets
|
|
1578
|
-
atomically. mu reads the pane title via
|
|
1943
|
+
`mu task claim foo` from inside `worker-1`'s pane sets the task's
|
|
1944
|
+
`owner_id` to the `worker-1` agent row atomically. mu reads the pane title via
|
|
1579
1945
|
`tmux display-message -t $TMUX_PANE -p '#{pane_title}'`, set on
|
|
1580
1946
|
spawn. Two agents cannot claim the same task.
|
|
1581
1947
|
|
|
@@ -1585,9 +1951,9 @@ service of those three.
|
|
|
1585
1951
|
|
|
1586
1952
|
---
|
|
1587
1953
|
|
|
1588
|
-
## What's NOT in 0.
|
|
1954
|
+
## What's NOT in 0.4.0 (and how to work around it)
|
|
1589
1955
|
|
|
1590
|
-
<a id="whats-not-in-
|
|
1956
|
+
<a id="whats-not-in-040-and-how-to-work-around-it"></a>
|
|
1591
1957
|
|
|
1592
1958
|
The full roadmap with promotion criteria lives in
|
|
1593
1959
|
[ROADMAP.md](ROADMAP.md). The short list of gaps you might hit
|
|
@@ -1596,13 +1962,13 @@ in real use:
|
|
|
1596
1962
|
| Want | Workaround | Status |
|
|
1597
1963
|
| --------------------------------------------- | ----------------------------------------------------------------------- | ------------- |
|
|
1598
1964
|
| Multi-CLI status detection (per-CLI prompts) | Braille spinner fallback (`f68838f`) covers pi/pi-meta + every TUI wrapper using standard spinner glyphs. Per-CLI permission-prompt patterns still pi-only. | partially shipped |
|
|
1599
|
-
| Pi extension (typed tools, HUD, wakeups) | `mu state --
|
|
1965
|
+
| Pi extension (typed tools, HUD, wakeups) | `mu state --tui` (interactive) covers the dashboard use-case; plain `mu state` (static) is the `watch` / `tmux display-popup` / `status-right` substrate. Other extension tools deferred. | partially shipped |
|
|
1600
1966
|
| Markdown agent-definition discovery | Spawn accepts `--cli` and `--command` directly; no template registry | dropped |
|
|
1601
1967
|
| `mu run script.ts` (JS DSL) | Use `--json` + bash + jq | rejected |
|
|
1602
1968
|
| Sync to GitHub Issues / Linear / Asana | Not in scope; explicitly rejected | — |
|
|
1603
|
-
| ~~`mu task blocked`~~ (removed; the `blocked` SQL view is the abstraction) | `mu sql "SELECT local_id, status, title FROM blocked WHERE
|
|
1604
|
-
| ~~`mu task goals`~~ (removed; same shape as `blocked` — view is the abstraction) | `mu sql "SELECT local_id, status, title FROM goals WHERE
|
|
1605
|
-
| ~~`mu task search <pat>`~~ (removed; case-insensitive LIKE is one SQL line) | `mu sql "SELECT local_id, status, title FROM tasks WHERE
|
|
1969
|
+
| ~~`mu task blocked`~~ (removed; the `blocked` SQL view is the abstraction) | `mu sql "SELECT b.local_id, b.status, b.title FROM blocked b JOIN workstreams w ON w.id=b.workstream_id WHERE w.name='X'"` | removed-with-recipe |
|
|
1970
|
+
| ~~`mu task goals`~~ (removed; same shape as `blocked` — view is the abstraction) | `mu sql "SELECT g.local_id, g.status, g.title FROM goals g JOIN workstreams w ON w.id=g.workstream_id WHERE w.name='X'"` | removed-with-recipe |
|
|
1971
|
+
| ~~`mu task search <pat>`~~ (removed; case-insensitive LIKE is one SQL line) | `mu sql "SELECT t.local_id, t.status, t.title FROM tasks t JOIN workstreams w ON w.id=t.workstream_id WHERE w.name='X' AND LOWER(t.title) LIKE '%pat%'"` (add `LEFT JOIN task_notes` for the old `--in-notes`; drop the workstream join/filter for the old `--all`) | removed-with-recipe |
|
|
1606
1972
|
|
|
1607
1973
|
Anything in this table that bites you in real use is a candidate
|
|
1608
1974
|
for **promotion**. Criteria: proven friction in ≥2 real workflows +
|