@mu-crew/mu 1.6.0 → 3.0.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 +6 -5
- package/README.md +31 -17
- package/dist/cli.js +3582 -2633
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +265 -137
- package/dist/index.js +3128 -2486
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +71 -45
- package/docs/ROADMAP.md +20 -105
- package/docs/USAGE_GUIDE.md +62 -41
- package/docs/VISION.md +11 -21
- package/docs/VOCABULARY.md +33 -40
- package/docs/img/tui-dashboard.png +0 -0
- package/docs/specs/2026-09-28-agent-state-from-murmur.md +333 -0
- package/docs/specs/2026-09-29-task-substates.md +247 -0
- package/package.json +1 -1
- package/skills/mu/REMOTE_WORKERS.md +31 -38
- package/skills/mu/SKILL.md +26 -25
- package/docs/.m-reflow-5f7exa_b.md +0 -509
- package/docs/.m-reflow-5v_034rw.md +0 -545
- package/docs/.m-reflow-7yaw8ubc.md +0 -513
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -31,8 +31,8 @@ programmatic SDK are thin facades over the same core modules.
|
|
|
31
31
|
│ │ mux/ │ │ schema │ │ jj │ │ capture │ │
|
|
32
32
|
│ │ tmux │ │ queries │ │ sapling │ │ apply/sync │ │
|
|
33
33
|
│ │ herdr │ │ tracks │ │ git │ │ doctor │ │
|
|
34
|
-
│ │
|
|
35
|
-
│ │
|
|
34
|
+
│ │ state │ │ claim │ │ none │ │ │ │
|
|
35
|
+
│ │ sources │ │ │ │ │ │ │ │
|
|
36
36
|
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────────┬────────┘ │
|
|
37
37
|
└───────┼─────────────┼─────────────┼─────────────────┼───────────┘
|
|
38
38
|
▼ ▼ ▼ ▼
|
|
@@ -111,8 +111,38 @@ it mu is just an agent runner.
|
|
|
111
111
|
`ROI = impact / effort` drives prioritization.
|
|
112
112
|
- **One edge type**: `blocks`. `A → B` means A must close before B can
|
|
113
113
|
start. Multiple edge types create ambiguity that defeats the purpose.
|
|
114
|
-
- **Status lifecycle**: `OPEN → IN_PROGRESS → CLOSED`.
|
|
115
|
-
|
|
114
|
+
- **Status lifecycle**: `OPEN → IN_PROGRESS → CLOSED`. Status alone
|
|
115
|
+
decides edge satisfaction: any `CLOSED` task satisfies its blockers.
|
|
116
|
+
- **Substate** qualifies status and never touches edges:
|
|
117
|
+
`OPEN/todo|parked`, `IN_PROGRESS/active`,
|
|
118
|
+
`CLOSED/done|wontfix|duplicate|superseded`. Rule: **store intent,
|
|
119
|
+
derive graph facts** — ready and blocked stay derived from edges.
|
|
120
|
+
`OPEN/parked` is excluded from `ready` but stays in `goals`.
|
|
121
|
+
|
|
122
|
+
#### Substate integrity: deferred FK + apply-time pair repair
|
|
123
|
+
|
|
124
|
+
The legal pairs live in the `task_substates` lookup table, seeded from
|
|
125
|
+
code on every open (machine-local, never synced). `tasks` has a
|
|
126
|
+
composite FK `(status, substate) → task_substates`,
|
|
127
|
+
`DEFERRABLE INITIALLY DEFERRED`, which is the only guard on the pair.
|
|
128
|
+
It is checked at COMMIT, so apply's one-field-at-a-time UPDATEs pass as
|
|
129
|
+
long as the pair is legal when the transaction ends. That is why
|
|
130
|
+
`applyOp` wraps each task put in `db.transaction` (and undo already runs
|
|
131
|
+
in one): in autocommit the first per-field UPDATE would fail the FK.
|
|
132
|
+
|
|
133
|
+
Every lifecycle write sets `status` and `substate` in one UPDATE, so
|
|
134
|
+
one op carries both under one HLC. A pair can still split across ops:
|
|
135
|
+
a status-only op from a v10 peer, an unknown substate from a newer
|
|
136
|
+
peer, or a concurrent close and park on two machines. Before commit,
|
|
137
|
+
`repairTaskPair` (`src/apply.ts`) sets the substate to the one implied
|
|
138
|
+
by the newest op in the LOG that writes a substate, resolved against
|
|
139
|
+
the row's current status, and falls back to the status default when
|
|
140
|
+
that pair is illegal. Substate is therefore NOT per-field LWW.
|
|
141
|
+
Reading the log instead of the row makes the result a pure function of
|
|
142
|
+
the op set plus the row's status, so every peer converges on the same
|
|
143
|
+
row whatever the arrival order. For the same reason the repair records
|
|
144
|
+
**no op**: each peer computes the identical repair from the identical
|
|
145
|
+
log. Recording one would only add a second writer racing the first.
|
|
116
146
|
- **Notes** are append-only per task; survive across LLM sessions and
|
|
117
147
|
agent restarts. The fix for context loss at the *task* level rather
|
|
118
148
|
than the agent level.
|
|
@@ -121,7 +151,7 @@ it mu is just an agent runner.
|
|
|
121
151
|
|
|
122
152
|
| View | Returns |
|
|
123
153
|
| --------- | ---------------------------------------------------------------------- |
|
|
124
|
-
| `ready` | OPEN tasks with no unresolved blockers — work that can start *now*
|
|
154
|
+
| `ready` | `OPEN/todo` tasks with no unresolved blockers — work that can start *now* |
|
|
125
155
|
| `blocked` | OPEN tasks waiting on something |
|
|
126
156
|
| `goals` | Tasks with no dependents — graph endpoints |
|
|
127
157
|
|
|
@@ -291,17 +321,16 @@ That difference is expressed as a **capability**, not a name check:
|
|
|
291
321
|
| --- | --- | --- |
|
|
292
322
|
| `NewWindowOptions.command` etc. | carries the command | **refused** if non-empty |
|
|
293
323
|
| `startAgentInPane()` | not implemented | implemented |
|
|
294
|
-
| liveness / readiness wait | mu
|
|
324
|
+
| liveness / readiness wait | mu checks pane life, startup errors, then murmur readiness when available | the mux blocks until ready |
|
|
295
325
|
|
|
296
326
|
`spawnAgent` branches on `mux.startAgentInPane !== undefined`. When it
|
|
297
|
-
is absent (tmux) the command rides along on the creation verb
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
tmux-tier knobs.
|
|
327
|
+
is absent (tmux), the command rides along on the creation verb. The
|
|
328
|
+
liveness check verifies that the pane survived and scans for startup
|
|
329
|
+
errors; when murmur is available, readiness also waits for the pane's
|
|
330
|
+
`@murmur_pane_state`. Without murmur, readiness is skipped and the first
|
|
331
|
+
send uses its input-timing checks. When `startAgentInPane` is present,
|
|
332
|
+
mu creates the pane bare, calls it, and skips the tmux checks because
|
|
333
|
+
the backend returns only after the agent is ready.
|
|
305
334
|
|
|
306
335
|
The creation verbs **refuse** a non-empty command on a backend that
|
|
307
336
|
cannot honour it rather than dropping it silently: a dropped command
|
|
@@ -407,7 +436,7 @@ src/cli/tui/
|
|
|
407
436
|
├── tab-strip-layout.ts # pure window-around-active layout helper
|
|
408
437
|
├── help.tsx # ?/F1 keymap overlay (scrollable on short panes)
|
|
409
438
|
├── use-popup-filter.tsx # shared '/' substring filter hook + applyFilter + FilterPrompt
|
|
410
|
-
├── use-status-filter.tsx #
|
|
439
|
+
├── use-status-filter.tsx # status toggles (o/i/c) + substate toggles (p/w) for task-list popups
|
|
411
440
|
├── use-notes-drill.ts # shared notes-drill memo (5 task popups consume it)
|
|
412
441
|
├── use-popup-action-queue.ts # consume mouse PopupAction queue once per render
|
|
413
442
|
├── cards/ # 10 dashboard glance cards (one slot each)
|
|
@@ -579,15 +608,12 @@ surrogate INTEGER ids once and then stay on ids. See
|
|
|
579
608
|
|
|
580
609
|
## Reconciliation
|
|
581
610
|
|
|
582
|
-
`mu agent list` always reconciles the registry against
|
|
583
|
-
returning.
|
|
611
|
+
`mu agent list` always reconciles the registry against mux reality before
|
|
612
|
+
returning. Two steps, in order:
|
|
584
613
|
|
|
585
614
|
1. **Prune ghosts.** For each `agents` row, if its `pane_id` no longer
|
|
586
|
-
exists in
|
|
587
|
-
2. **
|
|
588
|
-
the pane and run the per-CLI detector. Update `agents.status` if
|
|
589
|
-
the detected value differs from the stored one.
|
|
590
|
-
3. **Surface orphans.** For each tmux pane in the workstream's session
|
|
615
|
+
exists in the mux, delete the row.
|
|
616
|
+
2. **Surface orphans.** For each pane in the workstream's mux session
|
|
591
617
|
that has no matching `agents` row but whose pane title looks like
|
|
592
618
|
an agent name, add it to the orphans list. **Do not auto-adopt** —
|
|
593
619
|
`mu agent list` shows orphans under a separate "(orphans)" section and
|
|
@@ -596,19 +622,21 @@ returning. Three steps, in order:
|
|
|
596
622
|
`src/reconcile.ts` is the only implementation. Key properties:
|
|
597
623
|
|
|
598
624
|
- **Reality wins**: the mux is the source of truth for what panes
|
|
599
|
-
exist.
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
`
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
`
|
|
611
|
-
|
|
625
|
+
exist. Reconciliation closes the gap on every `mu agent list`.
|
|
626
|
+
- **Agent state is reported, not scraped or persisted.** `src/agent-state.ts`
|
|
627
|
+
reads herdr's `paneStatus()` on herdr. On tmux, one `list-panes -a`
|
|
628
|
+
reads `@murmur_pane_state` and `@murmur_pane_since` for every local
|
|
629
|
+
agent. Only agents without a local option use `murmur status --json`;
|
|
630
|
+
that result is cached for 10 seconds. See murmur's
|
|
631
|
+
[stable contract](https://github.com/mu-crew/murmur/blob/main/ARCHITECTURE.md#contract).
|
|
632
|
+
- **Mapping:** murmur `working` → `busy`, `blocked` →
|
|
633
|
+
`needs_permission`, and `idle` / `done` / `crashed` → `needs_input`.
|
|
634
|
+
herdr supplies mu's runtime states directly.
|
|
635
|
+
- **Absence is `unknown`.** Readings carry reasons such as `murmur not
|
|
636
|
+
installed`, `murmur pi extension not linked`, `murmur has no row`,
|
|
637
|
+
`ambiguous: N hosts`, `remote snapshot stale`, and `pane gone`.
|
|
638
|
+
- **`agents.status` is deprecated.** Inserts write `spawning` to satisfy
|
|
639
|
+
the schema. No code updates or reads the column as runtime state.
|
|
612
640
|
- **No silent adoption**: orphans are reported, never claimed.
|
|
613
641
|
- **`mu doctor` calls the same routine** and reports counts.
|
|
614
642
|
|
|
@@ -627,7 +655,7 @@ separately below.
|
|
|
627
655
|
|
|
628
656
|
| Module | Responsibility |
|
|
629
657
|
| --------------------- | ----------------------------------------------------------------------------------------- |
|
|
630
|
-
| `src/db.ts` | Connection (better-sqlite3, WAL), **schema
|
|
658
|
+
| `src/db.ts` | Connection (better-sqlite3, WAL), **schema v11** (11 tables incl. the `task_substates` lookup + 3 views), `resolveWorkstreamId`. Installs capture on every writable open. Owns `SYNCED_ENTITIES` / `MACHINE_LOCAL_ENTITIES` / `PORTABLE_TABLES` / `MACHINE_LOCAL_TABLES`. Refuses a pre-v11 DB (`SchemaTooOldError`) or a newer one (`SchemaTooNewError`), both exit 4. |
|
|
631
659
|
| `src/hlc.ts` | The **HLC** (VOCABULARY § HLC), serialized as sortable TEXT `<wall_ms:15>.<counter:6>.<machine_id>`. `nextHlc` / `receiveHlc` / `compareHlc` / `parseHlc` / `formatHlc`. Clock state lives in `machine_identity`. |
|
|
632
660
|
| `src/capture.ts` | **Op capture**: builds the triggers that record every write to a portable table as an op in the same transaction. |
|
|
633
661
|
| `src/apply.ts` | **The apply path** — capture's counterpart: given one op, local or from a peer, make the tables reflect it. Also owns `reprojectDeferredOps` ([§ ambient sync hook](#the-ambient-sync-hook)). |
|
|
@@ -645,10 +673,10 @@ separately below.
|
|
|
645
673
|
| `src/disk-recon.ts` | **Disk↔DB reconciliation** — the only module that reads the STATE DIR and compares it to the DB, in both directions: a `vcs_workspaces` row whose path is gone (`ws-rows`), a dir with no row (`ws-dirs`, reusing `listAllOrphanWorkspaces`), plus residue nothing references (`ws-empty` / `db-copies` / `exports` / `locks`). Emits `FleetHazard` so doctor's renderer, `--json` and the TUI card need no new shape. Default tier is `readdir` + `stat` at depth 2 (~1ms); `measureWorkspaceUsage` recurses for bytes and is `--disk` only, because its cost scales with the checkouts. **Report-only by construction** — every finding carries its cleanup command and the module runs none of them. |
|
|
646
674
|
| `src/op-context.ts` | The **op context** seam: `withOpContext(db, {intent, actor, group}, fn)` labels every op in a scope, restored in a `finally`. Nested scopes inherit the group, which puts a cascade under one `mu undo`. `withCaptureSuppressed` is the echo guard. |
|
|
647
675
|
| `src/mux.ts` | **Mux backend hub** — re-exports `src/mux/*`, same shape as `src/vcs.ts`. The public `MuxBackend` surface every call site imports. |
|
|
648
|
-
| `src/mux/*.ts` | **Multiplexer backends**: `types.ts` (the `MuxBackend` interface + `MuxError` / `PaneNotFoundError`), `detect.ts` (`MU_MUX` → `HERDR_ENV` → `$TMUX` → `PATH` ladder + test seam), `tmux.ts`, `herdr.ts`. The backend owns topology,
|
|
676
|
+
| `src/mux/*.ts` | **Multiplexer backends**: `types.ts` (the `MuxBackend` interface + `MuxError` / `PaneNotFoundError`), `detect.ts` (`MU_MUX` → `HERDR_ENV` → `$TMUX` → `PATH` ladder + test seam), `tmux.ts`, `herdr.ts`, and `input-timing.ts`. The backend owns topology, capture, **pane id** validation (tmux `%15` vs herdr `w1:p1`), identity fallback, and optional native agent state (`paneStatus?()`) and agent start (`startAgentInPane?()`). `input-timing.ts` reads pane text only to decide when tmux input can be submitted; it does not report agent state. |
|
|
649
677
|
| `src/tmux.ts` | Re-export of the tmux backend, kept for genuinely tmux-only concerns: the `MU_TMUX_SOCKET` test seam and the shared `sleep` / `setSleepForTests` poll seam. Everything else imports `src/mux.ts` and goes through `activeMux()`. |
|
|
650
|
-
| `src/
|
|
651
|
-
| `src/reconcile.ts` | Ghost prune +
|
|
678
|
+
| `src/agent-state.ts` | Runtime agent-state resolver. Reads herdr's native state or murmur's local pane options and remote JSON; maps source states, returns `unknown` with a reason, and caches remote murmur reads for 10 seconds. |
|
|
679
|
+
| `src/reconcile.ts` | Ghost prune + orphan surface; "reality wins" |
|
|
652
680
|
| `src/agents.ts` | Hub: CRUD + send / read / list / close + liveness + reaper. Re-exports `src/agents/*`; pane-title composition (`composeAgentTitle`) lives here. |
|
|
653
681
|
| `src/agents/*.ts` | Agent-lifecycle internals: `spawn.ts` (spawn, CLI resolution, liveness wait *or* backend `startAgentInPane`, pane create-or-reuse, rollback), `spawn-lock.ts` (per-session lock around topology+finalize), `wait.ts`, `adopt.ts`, `kick.ts` (signal a wedged pane's pgid), `errors.ts`. |
|
|
654
682
|
| `src/dag.ts` | Shared DAG read/render helpers: `loadFullDag` plus pure `renderForest` / `renderTaskTree`, reused by `mu task tree` and the TUI DAG popup. |
|
|
@@ -660,7 +688,7 @@ separately below.
|
|
|
660
688
|
| `src/log-render.ts` | **The ONE op → prose formatter.** `renderOp` maps an intent (+ key + payload fields) to `{verb, subject, detail}`; plus `renderOpLine`, `opSubject`, `parseOpKey`. Pure and colour-free, so CLI and TUI share one phrasing. |
|
|
661
689
|
| `src/vcs/*.ts` | One backend per file (`git.ts`, `jj.ts`, `sl.ts`, `none.ts`) plus `types.ts` (the `VcsBackend` interface), `helpers.ts`, and `index.ts` (detection precedence `jj` → `sl` → `git` → none; `backendByName`). |
|
|
662
690
|
| `src/workspace/*.ts` | Per-agent VCS workspaces, a registry on top of `vcs.ts`: `core.ts` (row shapes, paths, errors), `crud.ts`, `decorate.ts` (staleness + dirty), `orphans.ts`. |
|
|
663
|
-
| `src/glyphs.ts` | **The ONE glyph vocabulary.** `
|
|
691
|
+
| `src/glyphs.ts` | **The ONE glyph vocabulary.** `AGENT_STATE_GLYPH` + `agentStateGlyph()` for runtime agent state, the `GLYPH` record for every other state symbol (blocked, dirty, stale, ok/warn/fail, filter toggles), and `superscriptDigit` for TUI card-header keys. All classic Nerd Font `nf-fa-*` — single-codepoint and one cell wide, so `cli-table3` columns line up. |
|
|
664
692
|
| `src/output.ts` | NextStep type + `printNextSteps` + `errorNextSteps` plumbing for self-documenting output |
|
|
665
693
|
| `src/shell-quote.ts` | `shellQuote` — POSIX single-quoting for tokens interpolated into copy-pasteable next-step hints. |
|
|
666
694
|
| `src/state.ts` | SDK seam for `mu state`: `loadWorkstreamSnapshotFast` (pure SQL, TUI 1s tick), `loadWorkstreamSnapshotSlow` (subprocesses), `mergeSnapshotFastSlow`, `loadWorkstreamSnapshot`. Also parses exact `REMOTE:` task-note inventory and `REMOTE_BASE:` dispatch metadata. Opt-in: `withDirty`, `withDoctor`, `withRecentCommits`, `withAllTasks`. |
|
|
@@ -670,7 +698,7 @@ separately below.
|
|
|
670
698
|
| `src/cli/tui/*.tsx` | The interactive ink TUI, lazy-imported by `src/cli/state.ts`. **The only place ink/react are imported** — a ROADMAP pledge. Per-file roles: [§ TUI architecture](#tui-architecture). |
|
|
671
699
|
| `src/cli/tasks/*.ts` | Sub-cluster of the `mu task` namespace: `queries.ts` (list/next/owned-by + `mu me tasks` / `mu me next`), `lifecycle.ts` (close/open), `edit.ts`, `edges.ts` (+ delete cascade preview), `claim.ts`, `tree.ts`, `wire.ts` (Commander glue). |
|
|
672
700
|
| `src/index.ts` | SDK entrypoint (re-exports) |
|
|
673
|
-
| `skills/mu/SKILL.md` | Bundled skill teaching the LLM the model
|
|
701
|
+
| `skills/mu/SKILL.md` | Bundled skill teaching the LLM the orchestration model and operational traps; `mu --help` owns the verb reference. |
|
|
674
702
|
|
|
675
703
|
### What the rows above leave out
|
|
676
704
|
|
|
@@ -756,9 +784,8 @@ DB must never sit in `MU_SYNC_DIR`:
|
|
|
756
784
|
better-sqlite3's `db.transaction(fn)()` wrapper.
|
|
757
785
|
4. **Executes the operation** — agent ops shell out to tmux (and to
|
|
758
786
|
jj/sl/git for workspaces); task ops are pure SQL.
|
|
759
|
-
5. **Reconciles with reality** —
|
|
760
|
-
|
|
761
|
-
state and updates the DB (ghost prune + status detect).
|
|
787
|
+
5. **Reconciles with reality** — read paths prune ghosts and surface
|
|
788
|
+
orphans; runtime agent state is read from murmur or herdr without a DB write.
|
|
762
789
|
6. **Records ops** — automatically, per [§ The ops log](#the-ops-log-read-this-first);
|
|
763
790
|
machine-local changes go through `emitEvent`. `mu log --tail`
|
|
764
791
|
subscribers see the new ops on the next 1-second poll.
|
|
@@ -773,7 +800,6 @@ The extension points. A new impl of each is small.
|
|
|
773
800
|
| Seam | Add a new impl by... |
|
|
774
801
|
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
775
802
|
| `VcsBackend` | Implementing `detect / createWorkspace / freeWorkspace / isClean / commitsBehind / rebaseTo / commitsSinceBase / recentCommits / showCommit` (~80–150 LOC; jj/sl/git/none are working examples) |
|
|
776
|
-
| Per-CLI `Detector` | Adding patterns to `detectPiStatus` (vanilla pi `to interrupt)`; pi-meta + every TUI wrapper covered by Braille spinner glyph fallback `[\u2800-\u28FF]`) |
|
|
777
803
|
| New typed verb | An SDK function in the relevant `src/*.ts`; a `cmd<Verb>` in the matching `src/cli/<namespace>.ts`; one commander block in `buildProgram()`, wrapped in `handle()` and routed through `printNextSteps` |
|
|
778
804
|
| New schema migration| Bump `CURRENT_SCHEMA_VERSION` in `src/db.ts` and mirror the shape in `CURRENT_SCHEMA`. Keep startup migration-free; extend the retained fresh-target sidecar only when an old released schema needs a bridge. Recipe: [scripts/README.md](../scripts/README.md) |
|
|
779
805
|
| New syncable field | Add the column to a portable table, extend the capture trigger's changed-column comparison, confirm the apply path writes it. The UPDATE trigger MUST emit only changed columns — a full-row payload silently regresses field merge to row-level LWW |
|
package/docs/ROADMAP.md
CHANGED
|
@@ -85,41 +85,6 @@ These have a clear design but haven't yet hit promotion criterion
|
|
|
85
85
|
1 (friction in ≥2 real workflows). They earn implementation when
|
|
86
86
|
real use surfaces them.
|
|
87
87
|
|
|
88
|
-
### Per-CLI status detection (claude, codex, …)
|
|
89
|
-
|
|
90
|
-
**Partly superseded on the herdr backend**, which classifies panes
|
|
91
|
-
natively across the agent kinds it knows — mu takes its word there and
|
|
92
|
-
skips scrollback scraping entirely. This item stays live for the tmux
|
|
93
|
-
backend, where mu has to do its own detecting.
|
|
94
|
-
|
|
95
|
-
mu is a pi orchestrator. The Braille-spinner fallback catches every
|
|
96
|
-
TUI wrapper using standard spinner glyphs (U+2800–U+28FF), so
|
|
97
|
-
pi-meta + solo + many vanilla TUIs (claude, codex) work without a
|
|
98
|
-
per-CLI detector.
|
|
99
|
-
|
|
100
|
-
For patterns the spinner fallback misses (permission prompts,
|
|
101
|
-
specific busy markers), a per-CLI `Detector` registry keyed by
|
|
102
|
-
CLI name (~50 LOC per CLI) is the obvious shape. Promote when a
|
|
103
|
-
real specific-prompt-misclassification surfaces.
|
|
104
|
-
|
|
105
|
-
Pattern sketch:
|
|
106
|
-
|
|
107
|
-
| CLI | Busy patterns | Permission patterns |
|
|
108
|
-
| ------ | -------------------------------------- | --------------------------------------------------------- |
|
|
109
|
-
| Claude | `to interrupt`, `\(.*[↑↓].*tokens\)` | `Allow once`, `Allow for this session`, `Esc to cancel` |
|
|
110
|
-
| Codex | `esc to interrupt)`, `to cancel` | `enter to confirm`, `enter to submit \| esc to cancel` |
|
|
111
|
-
| Pi | (well-known mu-defined marker) | (well-known mu-defined marker) — shipped |
|
|
112
|
-
|
|
113
|
-
Critical subtleties any new detector must keep:
|
|
114
|
-
|
|
115
|
-
- **Tail-window extraction**: take last ~100 lines, strip trailing
|
|
116
|
-
blanks, then take last ~20. Already implemented for pi in
|
|
117
|
-
`src/detect.ts`; the registry version factors it out.
|
|
118
|
-
- **Permission detection uses a narrower window than busy
|
|
119
|
-
detection** to prevent already-answered prompts re-triggering.
|
|
120
|
-
- **Permission overrides busy** — if a permission prompt is
|
|
121
|
-
visible, agent is `NeedsPermission`, not `Busy`.
|
|
122
|
-
|
|
123
88
|
### A third mux backend (zellij, wezterm, kitty)
|
|
124
89
|
|
|
125
90
|
**Not promoted.** tmux and herdr are two real implementations, which
|
|
@@ -152,76 +117,22 @@ Listed so we don't pretend they're settled.
|
|
|
152
117
|
|
|
153
118
|
---
|
|
154
119
|
|
|
155
|
-
## murmur
|
|
156
|
-
|
|
157
|
-
[murmur](https://github.com/mu-crew/murmur) is a
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
surface this note once counted on will not come from there.
|
|
172
|
-
|
|
173
|
-
**What it would give mu**, both prerequisites for `mu spawn --on
|
|
174
|
-
<host>`: **global agent addressing** (`agents.pane_id` is
|
|
175
|
-
machine-local; murmur's `(host_id, agent_id)` is not, and identity is
|
|
176
|
-
kept separate from `session/window/pane` so it survives a move), and
|
|
177
|
-
**remote observation** (read the fold, get agents on other machines
|
|
178
|
-
for free — including ones mu never spawned). It would not give mu the
|
|
179
|
-
control channel; remote *driving* is unbuilt in both tools.
|
|
180
|
-
|
|
181
|
-
**The cheap seam already works.** murmur's pi extension reads
|
|
182
|
-
`MU_MANAGED_AGENT` / `MU_AGENT_NAME` / `MU_WORKSTREAM` / `MU_ROLE`
|
|
183
|
-
off the pane and marks such agents `orchestrated` — "crew" — hidden
|
|
184
|
-
unless `blocked` or `crashed`, since a supervisor consumes anything
|
|
185
|
-
else. mu already exports the first three (`src/agents/spawn.ts`,
|
|
186
|
-
`paneEnv`) and did nothing. Zero lines: the baseline any tighter
|
|
187
|
-
coupling has to beat. `MU_ROLE` is the one murmur reads and mu does
|
|
188
|
-
NOT set, so a crew row's role column is always null — a one-line fix
|
|
189
|
-
if that column ever proves useful, not a reason to couple further.
|
|
190
|
-
|
|
191
|
-
**No conflict with the sync design.** § Rejected sync substrates and
|
|
192
|
-
§ Explicitly rejected both stand: murmur is a **separate binary**
|
|
193
|
-
owning the ssh egress, and if mu ever consumes it, it does so by
|
|
194
|
-
reading a local store, never by growing a network stack. A merge must
|
|
195
|
-
keep the mu half transport-free. murmur independently reached mu's
|
|
196
|
-
two conclusions from mu's own code: ambient rather than daemon (a
|
|
197
|
-
collect rides ordinary invocations, rate-limited with jitter so the
|
|
198
|
-
status bar cannot drive an ssh fan-out) and sync must never fail a
|
|
199
|
-
command (every peer error caught and categorised).
|
|
200
|
-
|
|
201
|
-
**Why not merge now.** Remote observation is the easy half and is now
|
|
202
|
-
shipped; orchestration is the hard half and murmur removes none of
|
|
203
|
-
it. Repos and credentials must exist on the target, worktree setup is
|
|
204
|
-
a local filesystem operation, cherry-pick handoff assumes artifacts
|
|
205
|
-
move between machines, and "which node runs this task" is a scheduler
|
|
206
|
-
question mu does not have.
|
|
207
|
-
|
|
208
|
-
**The step that tests it** is now available, not scheduled: make mu a
|
|
209
|
-
*client* — drop its own status tracking and read murmur's snapshot.
|
|
210
|
-
Small change, real experiment. But `paneStatus()` / `src/detect.ts`
|
|
211
|
-
is not hurting, and trading a working local detector for a
|
|
212
|
-
cross-machine dependency needs a reason from real use (promotion
|
|
213
|
-
criterion 1), not the mere existence of the alternative. Keep the
|
|
214
|
-
*observe* vs *orchestrate* seam in mind even then — it is what lets
|
|
215
|
-
murmur watch agents mu never spawned, and a merge should say why it
|
|
216
|
-
beats that.
|
|
217
|
-
|
|
218
|
-
**Doors already open**, free: same language and runtime (TypeScript
|
|
219
|
-
on npm, since pi is an npm package), `(host_id, agent_id)` addressing
|
|
220
|
-
mu would need anyway, and the `MU_*` env contract.
|
|
221
|
-
|
|
222
|
-
**Do not** start the merge, add ssh to mu, or fold murmur's schema
|
|
223
|
-
into `mu.db` on the strength of this note. It records an intention
|
|
224
|
-
and its preconditions.
|
|
120
|
+
## murmur and remote agents
|
|
121
|
+
|
|
122
|
+
[murmur](https://github.com/mu-crew/murmur) is a separate binary for
|
|
123
|
+
current agent state across machines. It owns collection and ssh egress;
|
|
124
|
+
mu remains transport-free and owns the task DAG, claims, workspaces, and
|
|
125
|
+
panes.
|
|
126
|
+
|
|
127
|
+
**Done in 2.0:** mu reads murmur for agent state. See
|
|
128
|
+
[Agent state from murmur](specs/2026-09-28-agent-state-from-murmur.md).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### Next schema change
|
|
133
|
+
|
|
134
|
+
Drop the deprecated `agents.status` column at the first v11 migration.
|
|
135
|
+
In 2.0 it remains for schema compatibility and always contains `spawning`.
|
|
225
136
|
|
|
226
137
|
---
|
|
227
138
|
|
|
@@ -275,3 +186,7 @@ Listed so we don't rediscover them.
|
|
|
275
186
|
- **A "hosted" mu** — your machine is the deployment.
|
|
276
187
|
- **Anthropomorphic agent names (`alice`, `bob`)** — use
|
|
277
188
|
role-based names (`worker-1`, `reviewer-1`).
|
|
189
|
+
- **Pane scraping as an agent-state fallback** — absence of a state source is `unknown`, not a guessed state.
|
|
190
|
+
- **Storing runtime agent state in `mu.db`** — the copy goes stale; murmur or herdr owns the current reading.
|
|
191
|
+
- **Reading murmur's `state.db`** — use murmur's stable public contract, not its private schema.
|
|
192
|
+
- **murmur as a hard dependency** — installs that only use the task graph do not need murmur or its native dependencies.
|
package/docs/USAGE_GUIDE.md
CHANGED
|
@@ -8,7 +8,7 @@ A practical, copy-pasteable tour of mu. Terms are canonical — see
|
|
|
8
8
|
> **Status:** 1.0 (pre-release). Typed verbs span 7 namespaces
|
|
9
9
|
> (`workstream`, `agent`, `task`, `workspace`, `log`, `me`, `db`) plus
|
|
10
10
|
> bare top-level verbs (`state`, `doctor`, `sql`, `undo`, `sync`,
|
|
11
|
-
> `rebuild`). Every verb accepts `--json`. Schema
|
|
11
|
+
> `rebuild`). Every verb accepts `--json`. Schema v11. See
|
|
12
12
|
> [CHANGELOG.md](../CHANGELOG.md).
|
|
13
13
|
|
|
14
14
|
**In a hurry? Start at [§ 0. Common scenarios](#0-common-scenarios).**
|
|
@@ -240,6 +240,7 @@ environment
|
|
|
240
240
|
$TMUX : set
|
|
241
241
|
$TMUX_PANE : %21
|
|
242
242
|
$MU_SESSION : auth
|
|
243
|
+
agent state : ok agent state from murmur 1.0.0
|
|
243
244
|
|
|
244
245
|
db
|
|
245
246
|
path : /tmp/mu-play.db
|
|
@@ -385,11 +386,12 @@ table/key/field is the reproduction. See
|
|
|
385
386
|
|
|
386
387
|
### 0.6 Upgrading an older DB
|
|
387
388
|
|
|
388
|
-
`mu` refuses to open a pre-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
389
|
+
`mu` refuses to open a pre-v11 DB (`SchemaTooOldError`, exit 4) or a DB
|
|
390
|
+
newer than it understands (`SchemaTooNewError`, exit 4) and leaves the
|
|
391
|
+
file alone. The retained `scripts/migrate.ts` sidecar auto-detects v7,
|
|
392
|
+
v8, v9, or v10 and writes a fresh v11 DB. It never migrates in place.
|
|
393
|
+
Legacy `REJECTED` tasks become `CLOSED/wontfix` and `DEFERRED` tasks
|
|
394
|
+
become `OPEN/parked`; their original op payloads remain unchanged.
|
|
393
395
|
Pre-1.0 archives restore as live workstreams under their original
|
|
394
396
|
`source_workstream` names unless you pass `--drop-archives`.
|
|
395
397
|
|
|
@@ -469,11 +471,11 @@ alias mu="node $PWD/dist/cli.js"
|
|
|
469
471
|
See [README.md § Install](../README.md#install) for the full set of
|
|
470
472
|
install patterns.
|
|
471
473
|
|
|
472
|
-
mu requires a terminal multiplexer. tmux ≥ 3.0 is the
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
474
|
+
mu requires a terminal multiplexer. tmux ≥ 3.0 is the backend the rest
|
|
475
|
+
of this guide assumes; herdr also supports spawn, send, and read (see
|
|
476
|
+
[§ 20](#20-multiplexer-backends-tmux-and-herdr)). On tmux, install
|
|
477
|
+
murmur for runtime agent state. Make sure you're inside a session before
|
|
478
|
+
proceeding:
|
|
477
479
|
|
|
478
480
|
```bash
|
|
479
481
|
tmux # if you're not already in one
|
|
@@ -1042,7 +1044,7 @@ convention):
|
|
|
1042
1044
|
| Slot | Card | Toggle | Popup | Content |
|
|
1043
1045
|
| ---- | ------------- | ------ | --------- | ---------------------------------------------------- |
|
|
1044
1046
|
| 0 | Commits | `0` | `Shift+0` | Recent project-root commits (git / jj / sl) |
|
|
1045
|
-
| 1 | Agents | `1` | `Shift+1` | Active agents +
|
|
1047
|
+
| 1 | Agents | `1` | `Shift+1` | Active agents + runtime state + cli + role |
|
|
1046
1048
|
| 2 | Tracks | `2` | `Shift+2` | Parallel tracks (union-find clusters) |
|
|
1047
1049
|
| 3 | Ready (Tasks) | `3` | `Shift+3` | Ready-to-claim tasks (no open blockers) |
|
|
1048
1050
|
| 4 | Activity log | `4` | `Shift+4` | Recent ops rendered as prose |
|
|
@@ -1207,6 +1209,7 @@ for the newly active workstream.
|
|
|
1207
1209
|
| filter | `Esc` | cancel (clear query) |
|
|
1208
1210
|
| filter | `Enter` | commit (keep filter, return to nav) |
|
|
1209
1211
|
| task popup| `o` / `i` / `c` | toggle OPEN / IN_PROGRESS / CLOSED |
|
|
1212
|
+
| task popup| `p` / `w` | toggle OPEN/parked / closed-not-done (DAG + All-tasks) |
|
|
1210
1213
|
| All-tasks | `b` | blocked filter cycle (all → only → hide) |
|
|
1211
1214
|
| All-tasks | `s` | cycle sort key (roi → recency → age → id) |
|
|
1212
1215
|
| git-show | `t` | launch `tuicr -r <sha>` (alt-screen handoff) |
|
|
@@ -1226,7 +1229,7 @@ and recoverable from any shell.
|
|
|
1226
1229
|
|
|
1227
1230
|
## 6. Spawn a crew
|
|
1228
1231
|
|
|
1229
|
-
For a demo with live
|
|
1232
|
+
For a demo with live agent state, install and link murmur, then spawn pi agents:
|
|
1230
1233
|
|
|
1231
1234
|
```bash
|
|
1232
1235
|
mu agent spawn worker-1 --workstream auth-refactor # default --cli is pi
|
|
@@ -1250,7 +1253,7 @@ What just happened:
|
|
|
1250
1253
|
session
|
|
1251
1254
|
3. mu set the pane title to `worker-1` via `tmux select-pane -T worker-1`
|
|
1252
1255
|
— **this is the claim protocol identity**
|
|
1253
|
-
4. mu inserted a row in `agents` with `pane_id=%15
|
|
1256
|
+
4. mu inserted a row in `agents` with `pane_id=%15`; the deprecated `status` column remains `spawning`
|
|
1254
1257
|
|
|
1255
1258
|
If the DB insert fails after the pane was created, mu kills the pane
|
|
1256
1259
|
to avoid leaking. If the same name was already taken, mu rejects
|
|
@@ -1615,13 +1618,30 @@ enforce these — they're for the agents reading them.
|
|
|
1615
1618
|
## 12. Close out a task
|
|
1616
1619
|
|
|
1617
1620
|
```bash
|
|
1618
|
-
mu task close design # OPEN/IN_PROGRESS → CLOSED
|
|
1621
|
+
mu task close design # OPEN/IN_PROGRESS → CLOSED/done
|
|
1619
1622
|
mu task close umbrella --if-ready # close ONLY if every blocker
|
|
1620
1623
|
# is CLOSED; else no-op + list
|
|
1621
1624
|
# the still-blocking ids
|
|
1625
|
+
mu task close spike --as wontfix --why "superseded by the v2 design"
|
|
1622
1626
|
mu task open design # CLOSED → OPEN (e.g. closed by mistake)
|
|
1627
|
+
mu task park polish --why "after the release" # OPEN → OPEN/parked
|
|
1628
|
+
mu task unpark polish # OPEN/parked → OPEN/todo
|
|
1623
1629
|
```
|
|
1624
1630
|
|
|
1631
|
+
Every task carries a **substate** next to its status, rendered as a pair.
|
|
1632
|
+
`OPEN` is `todo` or `parked`; `IN_PROGRESS` is `active`; `CLOSED` is
|
|
1633
|
+
`done`, `wontfix`, `duplicate`, or `superseded`. `--as` picks the closed
|
|
1634
|
+
substate. Anything but `done` requires `--why`, stored as a note in the
|
|
1635
|
+
same transaction. Any `CLOSED/*` satisfies a blocker, so a non-`done`
|
|
1636
|
+
close prints the dependents it unblocked.
|
|
1637
|
+
|
|
1638
|
+
To keep dependents waiting, park the task instead of closing it. A
|
|
1639
|
+
parked task leaves `mu task next` and the ready set, and `mu task claim`
|
|
1640
|
+
refuses it without `--force`. It stays in goals, and a track whose non-closed
|
|
1641
|
+
tasks are all parked is marked `(parked)`. Park refuses `IN_PROGRESS`
|
|
1642
|
+
(release first) and `CLOSED` (open first). Filter with
|
|
1643
|
+
`mu task list --substate parked`.
|
|
1644
|
+
|
|
1625
1645
|
Both are idempotent (closing an already-CLOSED task prints a no-op and
|
|
1626
1646
|
exits 0). Owner is left intact — use `mu task release <id>` to clear
|
|
1627
1647
|
ownership when an agent bails mid-flight. `IN_PROGRESS` flips back to
|
|
@@ -1703,7 +1723,7 @@ mu sql "SELECT name FROM sqlite_master WHERE type IN ('table','view') ORDER BY t
|
|
|
1703
1723
|
### `mu agent wait`: the task-less counterpart to `mu task wait`
|
|
1704
1724
|
|
|
1705
1725
|
Scratch helpers usually own no task, so `mu task wait` has nothing to
|
|
1706
|
-
watch. `mu agent wait` blocks on the agent's runtime
|
|
1726
|
+
watch. `mu agent wait` blocks on the agent's runtime state: an agent
|
|
1707
1727
|
**fires** when it goes **busy → any other state**. It must be observed
|
|
1708
1728
|
busy first, so an already-idle agent does NOT fire instantly — you're
|
|
1709
1729
|
waiting for *this* work to finish. Replaces `sleep` polling loops.
|
|
@@ -1719,8 +1739,8 @@ Mirrors `mu task wait`'s shape: `--any`/`--first` fire on the first
|
|
|
1719
1739
|
agent (default: all must finish); `--first` prints the firing agent's
|
|
1720
1740
|
ref; `--json` carries `nextSteps`; refs may be qualified
|
|
1721
1741
|
`<workstream>/<name>`. Exit codes: `0` met, `5` timeout, `6` a watched
|
|
1722
|
-
agent's pane died.
|
|
1723
|
-
|
|
1742
|
+
agent's pane died. On tmux, murmur supplies the state. `unknown` never
|
|
1743
|
+
fires the wait; run `mu doctor` for the missing-source reason.
|
|
1724
1744
|
|
|
1725
1745
|
**Don't reach for this verb to catch a worker that asked a question.**
|
|
1726
1746
|
It fires on `busy → needs_input`, so it does detect the case — but it
|
|
@@ -1843,9 +1863,10 @@ For unattended waits, always pass `--on-stall exit`; otherwise the default
|
|
|
1843
1863
|
warning leaves the wait polling. Two orthogonal flags govern the behaviour:
|
|
1844
1864
|
|
|
1845
1865
|
* `--stuck-after <seconds>` — the **trigger**. An IN_PROGRESS task
|
|
1846
|
-
whose owner has been in `needs_input` for `>= N` seconds
|
|
1847
|
-
|
|
1848
|
-
|
|
1866
|
+
whose owner has been in `needs_input` for `>= N` seconds according
|
|
1867
|
+
to the state source is marked as needing attention. `unknown` never
|
|
1868
|
+
counts. Default `300` (5 min); pass `0` to disable detection entirely
|
|
1869
|
+
(no warn AND no exit).
|
|
1849
1870
|
* `--on-stall <action>` — the **action** when the trigger fires.
|
|
1850
1871
|
Two values:
|
|
1851
1872
|
* `warn` (default) — yellow attention warning to stderr (deduped per
|
|
@@ -1954,14 +1975,11 @@ You killed it from another tmux client, or its CLI crashed:
|
|
|
1954
1975
|
mu agent list # worker-1's row prunes itself (ghost detected)
|
|
1955
1976
|
```
|
|
1956
1977
|
|
|
1957
|
-
Reconciliation runs on every `mu agent list` / `mu`.
|
|
1978
|
+
Reconciliation runs on every `mu agent list` / `mu`. Two steps:
|
|
1958
1979
|
|
|
1959
1980
|
1. **Prune ghost rows** — DB row whose `pane_id` no longer exists in
|
|
1960
|
-
|
|
1961
|
-
2. **
|
|
1962
|
-
pane and re-derive status (busy / needs_input / needs_permission /
|
|
1963
|
-
spawning) per the pi-status detector
|
|
1964
|
-
3. **Surface orphan panes** — panes in the workstream's session whose
|
|
1981
|
+
the mux gets deleted
|
|
1982
|
+
2. **Surface orphan panes** — panes in the workstream's session whose
|
|
1965
1983
|
`pane.command` looks like an agent CLI but that aren't in the
|
|
1966
1984
|
registry. **Not** auto-adopted; mu lists them under "Orphan panes"
|
|
1967
1985
|
with the `mu agent adopt <pane-id>` hint
|
|
@@ -2367,26 +2385,29 @@ winner, and the newer HLC takes it.
|
|
|
2367
2385
|
|
|
2368
2386
|
---
|
|
2369
2387
|
|
|
2370
|
-
## 15.7 Upgrading a v7, v8, or
|
|
2388
|
+
## 15.7 Upgrading a v7, v8, v9, or v10 DB
|
|
2371
2389
|
|
|
2372
|
-
`mu` refuses to write a pre-
|
|
2390
|
+
`mu` refuses to write a pre-v11 DB and leaves it untouched. Use the
|
|
2373
2391
|
single retained sidecar against a backup:
|
|
2374
2392
|
|
|
2375
2393
|
```bash
|
|
2376
2394
|
DB=${MU_DB_PATH:-$HOME/.local/state/mu/mu.db}
|
|
2377
2395
|
BACKUP="$HOME/mu-old-backup-$(date +%Y%m%d-%H%M%S).db"
|
|
2378
2396
|
sqlite3 "$DB" ".backup '$BACKUP'"
|
|
2379
|
-
npx tsx scripts/migrate.ts "$BACKUP" --out "${DB}.
|
|
2380
|
-
MU_DB_PATH="${DB}.
|
|
2381
|
-
mv "$DB" "${DB}.old-kept" && mv "${DB}.
|
|
2397
|
+
npx tsx scripts/migrate.ts "$BACKUP" --out "${DB}.v11"
|
|
2398
|
+
MU_DB_PATH="${DB}.v11" mu doctor --deep
|
|
2399
|
+
mv "$DB" "${DB}.old-kept" && mv "${DB}.v11" "$DB"
|
|
2382
2400
|
mu doctor
|
|
2383
2401
|
```
|
|
2384
2402
|
|
|
2385
|
-
The script auto-detects v7, v8, or
|
|
2386
|
-
SHA-256 before and after, and never overwrites a target unless
|
|
2387
|
-
is explicit. v9 history is retained unchanged; legacy
|
|
2388
|
-
|
|
2389
|
-
|
|
2403
|
+
The script auto-detects v7, v8, v9, or v10, opens it read-only, compares
|
|
2404
|
+
its SHA-256 before and after, and never overwrites a target unless
|
|
2405
|
+
`--force` is explicit. v9/v10 history is retained unchanged; legacy
|
|
2406
|
+
statuses map onto substates (`REJECTED` → `CLOSED/wontfix`, `DEFERRED` →
|
|
2407
|
+
`OPEN/parked`) while projecting into v11, and no migration notes are
|
|
2408
|
+
written. Where an undo or a note hid the legacy status, the script
|
|
2409
|
+
records a `migrate.substate` op; `--recover <db>` reruns that recovery
|
|
2410
|
+
on an already-migrated DB. Valid v9 agents, workspaces, owners, peer
|
|
2390
2411
|
watermarks, and machine identity carry across, but pane ids and absolute
|
|
2391
2412
|
workspace paths cannot be proven live until `mu doctor` reconciles them.
|
|
2392
2413
|
The v7/v8 path keeps the older conservative omissions for agents and
|
|
@@ -2449,7 +2470,7 @@ rm -f /tmp/mu-demo.db
|
|
|
2449
2470
|
set on spawn. Two agents cannot claim the same task.
|
|
2450
2471
|
|
|
2451
2472
|
Everything else (`mu sql`, send/read, the bracketed-paste protocol,
|
|
2452
|
-
ghost reconciliation) is plumbing in service of those three.
|
|
2473
|
+
agent-state sources, ghost reconciliation) is plumbing in service of those three.
|
|
2453
2474
|
|
|
2454
2475
|
---
|
|
2455
2476
|
|
|
@@ -2461,7 +2482,6 @@ in real use:
|
|
|
2461
2482
|
|
|
2462
2483
|
| Want | Workaround | Status |
|
|
2463
2484
|
| --------------------------------------------- | ----------------------------------------------------------------------- | ------------- |
|
|
2464
|
-
| Multi-CLI status detection (per-CLI prompts) | Braille spinner fallback covers pi/pi-meta + every TUI wrapper using standard spinner glyphs. Per-CLI permission-prompt patterns are pi-only. | partially shipped |
|
|
2465
2485
|
| 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 |
|
|
2466
2486
|
| Markdown agent-definition discovery | Spawn accepts `--cli` and `--command` directly; no template registry | dropped |
|
|
2467
2487
|
<!-- doc-cli-drift:skip-start -->
|
|
@@ -2504,7 +2524,8 @@ your platform.
|
|
|
2504
2524
|
|
|
2505
2525
|
mu drives exactly one multiplexer per invocation. tmux is the
|
|
2506
2526
|
incumbent; [herdr](https://github.com/herdrdev/herdr) is the second
|
|
2507
|
-
backend
|
|
2527
|
+
backend. Spawn, send, and read work on both; agent state comes from herdr
|
|
2528
|
+
on herdr and from murmur on tmux. The
|
|
2508
2529
|
remaining gaps are narrow and listed under
|
|
2509
2530
|
[Known limits on herdr](#known-limits-on-herdr) — the notable one is
|
|
2510
2531
|
that `mu agent kick` is Linux-only there.
|
|
@@ -2554,7 +2575,7 @@ The backend is resolved once per process and cached.
|
|
|
2554
2575
|
| Attach hint | `tmux a -t mu-<ws>` | `herdr session attach mu-<ws>` |
|
|
2555
2576
|
| Pane borders | 4-side border showing agent name + status glyph | no-op — herdr owns its pane chrome; mu-managed panes carry the label instead |
|
|
2556
2577
|
| Layout | `select-layout` | no-op — herdr splits are explicit, geometry is yours |
|
|
2557
|
-
|
|
|
2578
|
+
| Agent state | murmur pane options for local agents; `murmur status --json` for remote agents | herdr reports state via `paneStatus()` |
|
|
2558
2579
|
| Focus | mu creates detached | `--no-focus` on every mutating call, always. `detached: false` still gets you a detached workspace; run `herdr workspace focus` yourself. |
|
|
2559
2580
|
| Isolation seam | `MU_TMUX_SOCKET` (`-L <name>`) | `MU_HERDR_SESSION` (`--session <name>`, its own socket) |
|
|
2560
2581
|
| `mu agent send` / `read` | six-step paste/Enter protocol | one atomic `agent prompt --wait` |
|