@mu-crew/mu 1.6.0 → 2.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/README.md +11 -15
- package/dist/cli.js +2603 -2283
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +97 -121
- package/dist/index.js +2677 -2425
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +36 -40
- package/docs/ROADMAP.md +20 -105
- package/docs/USAGE_GUIDE.md +23 -24
- package/docs/VISION.md +11 -21
- package/docs/VOCABULARY.md +22 -35
- package/docs/specs/2026-09-28-agent-state-from-murmur.md +333 -0
- package/package.json +1 -1
- package/skills/mu/REMOTE_WORKERS.md +31 -38
- package/skills/mu/SKILL.md +16 -21
- 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
|
▼ ▼ ▼ ▼
|
|
@@ -291,17 +291,16 @@ That difference is expressed as a **capability**, not a name check:
|
|
|
291
291
|
| --- | --- | --- |
|
|
292
292
|
| `NewWindowOptions.command` etc. | carries the command | **refused** if non-empty |
|
|
293
293
|
| `startAgentInPane()` | not implemented | implemented |
|
|
294
|
-
| liveness / readiness wait | mu
|
|
294
|
+
| liveness / readiness wait | mu checks pane life, startup errors, then murmur readiness when available | the mux blocks until ready |
|
|
295
295
|
|
|
296
296
|
`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.
|
|
297
|
+
is absent (tmux), the command rides along on the creation verb. The
|
|
298
|
+
liveness check verifies that the pane survived and scans for startup
|
|
299
|
+
errors; when murmur is available, readiness also waits for the pane's
|
|
300
|
+
`@murmur_pane_state`. Without murmur, readiness is skipped and the first
|
|
301
|
+
send uses its input-timing checks. When `startAgentInPane` is present,
|
|
302
|
+
mu creates the pane bare, calls it, and skips the tmux checks because
|
|
303
|
+
the backend returns only after the agent is ready.
|
|
305
304
|
|
|
306
305
|
The creation verbs **refuse** a non-empty command on a backend that
|
|
307
306
|
cannot honour it rather than dropping it silently: a dropped command
|
|
@@ -579,15 +578,12 @@ surrogate INTEGER ids once and then stay on ids. See
|
|
|
579
578
|
|
|
580
579
|
## Reconciliation
|
|
581
580
|
|
|
582
|
-
`mu agent list` always reconciles the registry against
|
|
583
|
-
returning.
|
|
581
|
+
`mu agent list` always reconciles the registry against mux reality before
|
|
582
|
+
returning. Two steps, in order:
|
|
584
583
|
|
|
585
584
|
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
|
|
585
|
+
exists in the mux, delete the row.
|
|
586
|
+
2. **Surface orphans.** For each pane in the workstream's mux session
|
|
591
587
|
that has no matching `agents` row but whose pane title looks like
|
|
592
588
|
an agent name, add it to the orphans list. **Do not auto-adopt** —
|
|
593
589
|
`mu agent list` shows orphans under a separate "(orphans)" section and
|
|
@@ -596,19 +592,21 @@ returning. Three steps, in order:
|
|
|
596
592
|
`src/reconcile.ts` is the only implementation. Key properties:
|
|
597
593
|
|
|
598
594
|
- **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
|
-
|
|
595
|
+
exist. Reconciliation closes the gap on every `mu agent list`.
|
|
596
|
+
- **Agent state is reported, not scraped or persisted.** `src/agent-state.ts`
|
|
597
|
+
reads herdr's `paneStatus()` on herdr. On tmux, one `list-panes -a`
|
|
598
|
+
reads `@murmur_pane_state` and `@murmur_pane_since` for every local
|
|
599
|
+
agent. Only agents without a local option use `murmur status --json`;
|
|
600
|
+
that result is cached for 10 seconds. See murmur's
|
|
601
|
+
[stable contract](https://github.com/mu-crew/murmur/blob/main/ARCHITECTURE.md#contract).
|
|
602
|
+
- **Mapping:** murmur `working` → `busy`, `blocked` →
|
|
603
|
+
`needs_permission`, and `idle` / `done` / `crashed` → `needs_input`.
|
|
604
|
+
herdr supplies mu's runtime states directly.
|
|
605
|
+
- **Absence is `unknown`.** Readings carry reasons such as `murmur not
|
|
606
|
+
installed`, `murmur pi extension not linked`, `murmur has no row`,
|
|
607
|
+
`ambiguous: N hosts`, `remote snapshot stale`, and `pane gone`.
|
|
608
|
+
- **`agents.status` is deprecated.** Inserts write `spawning` to satisfy
|
|
609
|
+
the v10 schema. No code updates or reads the column as runtime state.
|
|
612
610
|
- **No silent adoption**: orphans are reported, never claimed.
|
|
613
611
|
- **`mu doctor` calls the same routine** and reports counts.
|
|
614
612
|
|
|
@@ -645,10 +643,10 @@ separately below.
|
|
|
645
643
|
| `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
644
|
| `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
645
|
| `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,
|
|
646
|
+
| `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
647
|
| `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 +
|
|
648
|
+
| `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. |
|
|
649
|
+
| `src/reconcile.ts` | Ghost prune + orphan surface; "reality wins" |
|
|
652
650
|
| `src/agents.ts` | Hub: CRUD + send / read / list / close + liveness + reaper. Re-exports `src/agents/*`; pane-title composition (`composeAgentTitle`) lives here. |
|
|
653
651
|
| `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
652
|
| `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 +658,7 @@ separately below.
|
|
|
660
658
|
| `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
659
|
| `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
660
|
| `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.** `
|
|
661
|
+
| `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
662
|
| `src/output.ts` | NextStep type + `printNextSteps` + `errorNextSteps` plumbing for self-documenting output |
|
|
665
663
|
| `src/shell-quote.ts` | `shellQuote` — POSIX single-quoting for tokens interpolated into copy-pasteable next-step hints. |
|
|
666
664
|
| `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 +668,7 @@ separately below.
|
|
|
670
668
|
| `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
669
|
| `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
670
|
| `src/index.ts` | SDK entrypoint (re-exports) |
|
|
673
|
-
| `skills/mu/SKILL.md` | Bundled skill teaching the LLM the model
|
|
671
|
+
| `skills/mu/SKILL.md` | Bundled skill teaching the LLM the orchestration model and operational traps; `mu --help` owns the verb reference. |
|
|
674
672
|
|
|
675
673
|
### What the rows above leave out
|
|
676
674
|
|
|
@@ -756,9 +754,8 @@ DB must never sit in `MU_SYNC_DIR`:
|
|
|
756
754
|
better-sqlite3's `db.transaction(fn)()` wrapper.
|
|
757
755
|
4. **Executes the operation** — agent ops shell out to tmux (and to
|
|
758
756
|
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).
|
|
757
|
+
5. **Reconciles with reality** — read paths prune ghosts and surface
|
|
758
|
+
orphans; runtime agent state is read from murmur or herdr without a DB write.
|
|
762
759
|
6. **Records ops** — automatically, per [§ The ops log](#the-ops-log-read-this-first);
|
|
763
760
|
machine-local changes go through `emitEvent`. `mu log --tail`
|
|
764
761
|
subscribers see the new ops on the next 1-second poll.
|
|
@@ -773,7 +770,6 @@ The extension points. A new impl of each is small.
|
|
|
773
770
|
| Seam | Add a new impl by... |
|
|
774
771
|
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
775
772
|
| `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
773
|
| 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
774
|
| 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
775
|
| 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
|
@@ -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
|
|
@@ -469,11 +470,11 @@ alias mu="node $PWD/dist/cli.js"
|
|
|
469
470
|
See [README.md § Install](../README.md#install) for the full set of
|
|
470
471
|
install patterns.
|
|
471
472
|
|
|
472
|
-
mu requires a terminal multiplexer. tmux ≥ 3.0 is the
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
473
|
+
mu requires a terminal multiplexer. tmux ≥ 3.0 is the backend the rest
|
|
474
|
+
of this guide assumes; herdr also supports spawn, send, and read (see
|
|
475
|
+
[§ 20](#20-multiplexer-backends-tmux-and-herdr)). On tmux, install
|
|
476
|
+
murmur for runtime agent state. Make sure you're inside a session before
|
|
477
|
+
proceeding:
|
|
477
478
|
|
|
478
479
|
```bash
|
|
479
480
|
tmux # if you're not already in one
|
|
@@ -1042,7 +1043,7 @@ convention):
|
|
|
1042
1043
|
| Slot | Card | Toggle | Popup | Content |
|
|
1043
1044
|
| ---- | ------------- | ------ | --------- | ---------------------------------------------------- |
|
|
1044
1045
|
| 0 | Commits | `0` | `Shift+0` | Recent project-root commits (git / jj / sl) |
|
|
1045
|
-
| 1 | Agents | `1` | `Shift+1` | Active agents +
|
|
1046
|
+
| 1 | Agents | `1` | `Shift+1` | Active agents + runtime state + cli + role |
|
|
1046
1047
|
| 2 | Tracks | `2` | `Shift+2` | Parallel tracks (union-find clusters) |
|
|
1047
1048
|
| 3 | Ready (Tasks) | `3` | `Shift+3` | Ready-to-claim tasks (no open blockers) |
|
|
1048
1049
|
| 4 | Activity log | `4` | `Shift+4` | Recent ops rendered as prose |
|
|
@@ -1226,7 +1227,7 @@ and recoverable from any shell.
|
|
|
1226
1227
|
|
|
1227
1228
|
## 6. Spawn a crew
|
|
1228
1229
|
|
|
1229
|
-
For a demo with live
|
|
1230
|
+
For a demo with live agent state, install and link murmur, then spawn pi agents:
|
|
1230
1231
|
|
|
1231
1232
|
```bash
|
|
1232
1233
|
mu agent spawn worker-1 --workstream auth-refactor # default --cli is pi
|
|
@@ -1250,7 +1251,7 @@ What just happened:
|
|
|
1250
1251
|
session
|
|
1251
1252
|
3. mu set the pane title to `worker-1` via `tmux select-pane -T worker-1`
|
|
1252
1253
|
— **this is the claim protocol identity**
|
|
1253
|
-
4. mu inserted a row in `agents` with `pane_id=%15
|
|
1254
|
+
4. mu inserted a row in `agents` with `pane_id=%15`; the deprecated `status` column remains `spawning`
|
|
1254
1255
|
|
|
1255
1256
|
If the DB insert fails after the pane was created, mu kills the pane
|
|
1256
1257
|
to avoid leaking. If the same name was already taken, mu rejects
|
|
@@ -1703,7 +1704,7 @@ mu sql "SELECT name FROM sqlite_master WHERE type IN ('table','view') ORDER BY t
|
|
|
1703
1704
|
### `mu agent wait`: the task-less counterpart to `mu task wait`
|
|
1704
1705
|
|
|
1705
1706
|
Scratch helpers usually own no task, so `mu task wait` has nothing to
|
|
1706
|
-
watch. `mu agent wait` blocks on the agent's runtime
|
|
1707
|
+
watch. `mu agent wait` blocks on the agent's runtime state: an agent
|
|
1707
1708
|
**fires** when it goes **busy → any other state**. It must be observed
|
|
1708
1709
|
busy first, so an already-idle agent does NOT fire instantly — you're
|
|
1709
1710
|
waiting for *this* work to finish. Replaces `sleep` polling loops.
|
|
@@ -1719,8 +1720,8 @@ Mirrors `mu task wait`'s shape: `--any`/`--first` fire on the first
|
|
|
1719
1720
|
agent (default: all must finish); `--first` prints the firing agent's
|
|
1720
1721
|
ref; `--json` carries `nextSteps`; refs may be qualified
|
|
1721
1722
|
`<workstream>/<name>`. Exit codes: `0` met, `5` timeout, `6` a watched
|
|
1722
|
-
agent's pane died.
|
|
1723
|
-
|
|
1723
|
+
agent's pane died. On tmux, murmur supplies the state. `unknown` never
|
|
1724
|
+
fires the wait; run `mu doctor` for the missing-source reason.
|
|
1724
1725
|
|
|
1725
1726
|
**Don't reach for this verb to catch a worker that asked a question.**
|
|
1726
1727
|
It fires on `busy → needs_input`, so it does detect the case — but it
|
|
@@ -1843,9 +1844,10 @@ For unattended waits, always pass `--on-stall exit`; otherwise the default
|
|
|
1843
1844
|
warning leaves the wait polling. Two orthogonal flags govern the behaviour:
|
|
1844
1845
|
|
|
1845
1846
|
* `--stuck-after <seconds>` — the **trigger**. An IN_PROGRESS task
|
|
1846
|
-
whose owner has been in `needs_input` for `>= N` seconds
|
|
1847
|
-
|
|
1848
|
-
|
|
1847
|
+
whose owner has been in `needs_input` for `>= N` seconds according
|
|
1848
|
+
to the state source is marked as needing attention. `unknown` never
|
|
1849
|
+
counts. Default `300` (5 min); pass `0` to disable detection entirely
|
|
1850
|
+
(no warn AND no exit).
|
|
1849
1851
|
* `--on-stall <action>` — the **action** when the trigger fires.
|
|
1850
1852
|
Two values:
|
|
1851
1853
|
* `warn` (default) — yellow attention warning to stderr (deduped per
|
|
@@ -1954,14 +1956,11 @@ You killed it from another tmux client, or its CLI crashed:
|
|
|
1954
1956
|
mu agent list # worker-1's row prunes itself (ghost detected)
|
|
1955
1957
|
```
|
|
1956
1958
|
|
|
1957
|
-
Reconciliation runs on every `mu agent list` / `mu`.
|
|
1959
|
+
Reconciliation runs on every `mu agent list` / `mu`. Two steps:
|
|
1958
1960
|
|
|
1959
1961
|
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
|
|
1962
|
+
the mux gets deleted
|
|
1963
|
+
2. **Surface orphan panes** — panes in the workstream's session whose
|
|
1965
1964
|
`pane.command` looks like an agent CLI but that aren't in the
|
|
1966
1965
|
registry. **Not** auto-adopted; mu lists them under "Orphan panes"
|
|
1967
1966
|
with the `mu agent adopt <pane-id>` hint
|
|
@@ -2449,7 +2448,7 @@ rm -f /tmp/mu-demo.db
|
|
|
2449
2448
|
set on spawn. Two agents cannot claim the same task.
|
|
2450
2449
|
|
|
2451
2450
|
Everything else (`mu sql`, send/read, the bracketed-paste protocol,
|
|
2452
|
-
ghost reconciliation) is plumbing in service of those three.
|
|
2451
|
+
agent-state sources, ghost reconciliation) is plumbing in service of those three.
|
|
2453
2452
|
|
|
2454
2453
|
---
|
|
2455
2454
|
|
|
@@ -2461,7 +2460,6 @@ in real use:
|
|
|
2461
2460
|
|
|
2462
2461
|
| Want | Workaround | Status |
|
|
2463
2462
|
| --------------------------------------------- | ----------------------------------------------------------------------- | ------------- |
|
|
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
2463
|
| 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
2464
|
| Markdown agent-definition discovery | Spawn accepts `--cli` and `--command` directly; no template registry | dropped |
|
|
2467
2465
|
<!-- doc-cli-drift:skip-start -->
|
|
@@ -2504,7 +2502,8 @@ your platform.
|
|
|
2504
2502
|
|
|
2505
2503
|
mu drives exactly one multiplexer per invocation. tmux is the
|
|
2506
2504
|
incumbent; [herdr](https://github.com/herdrdev/herdr) is the second
|
|
2507
|
-
backend
|
|
2505
|
+
backend. Spawn, send, and read work on both; agent state comes from herdr
|
|
2506
|
+
on herdr and from murmur on tmux. The
|
|
2508
2507
|
remaining gaps are narrow and listed under
|
|
2509
2508
|
[Known limits on herdr](#known-limits-on-herdr) — the notable one is
|
|
2510
2509
|
that `mu agent kick` is Linux-only there.
|
|
@@ -2554,7 +2553,7 @@ The backend is resolved once per process and cached.
|
|
|
2554
2553
|
| Attach hint | `tmux a -t mu-<ws>` | `herdr session attach mu-<ws>` |
|
|
2555
2554
|
| 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
2555
|
| Layout | `select-layout` | no-op — herdr splits are explicit, geometry is yours |
|
|
2557
|
-
|
|
|
2556
|
+
| Agent state | murmur pane options for local agents; `murmur status --json` for remote agents | herdr reports state via `paneStatus()` |
|
|
2558
2557
|
| 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
2558
|
| Isolation seam | `MU_TMUX_SOCKET` (`-L <name>`) | `MU_HERDR_SESSION` (`--session <name>`, its own socket) |
|
|
2560
2559
|
| `mu agent send` / `read` | six-step paste/Enter protocol | one atomic `agent prompt --wait` |
|
package/docs/VISION.md
CHANGED
|
@@ -137,19 +137,11 @@ lives behind `MuxBackend` in `src/mux/`. Two implementations, not an
|
|
|
137
137
|
anticipatory abstraction: a third earns its way in on its own
|
|
138
138
|
friction evidence.
|
|
139
139
|
|
|
140
|
-
### 6. Pi-first,
|
|
140
|
+
### 6. Pi-first, with reported agent state
|
|
141
141
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
backend no other CLI ships with a detector, so an unrecognized pane
|
|
146
|
-
tends to read `needs_input`.
|
|
147
|
-
|
|
148
|
-
A mux that classifies panes itself changes this. The herdr backend
|
|
149
|
-
reports agent state natively across the agent kinds it knows, so on
|
|
150
|
-
that backend mu takes the mux's word and skips scrollback scraping
|
|
151
|
-
entirely. Detection is a property of the **mux backend**, not a fixed
|
|
152
|
-
property of mu.
|
|
142
|
+
mu does not infer agent state from pane text. The herdr backend reports
|
|
143
|
+
state through the mux. On tmux, murmur's pi extension reports state from
|
|
144
|
+
inside the agent process; without murmur, state is `unknown` with a reason.
|
|
153
145
|
|
|
154
146
|
`--cli` and `MU_<UPPER_CLI>_COMMAND` stay useful for swapping the pi
|
|
155
147
|
binary: set `MU_PI_COMMAND=<name>` once and every spawn picks it up.
|
|
@@ -244,9 +236,9 @@ mu does not own:
|
|
|
244
236
|
- **Tool routing decisions.** Pi (and any other CLI you spawn) owns
|
|
245
237
|
tool allowlists, MCP servers, extensions. Mu doesn't proxy or
|
|
246
238
|
inspect them.
|
|
247
|
-
- **Output interpretation.** Mu
|
|
248
|
-
|
|
249
|
-
|
|
239
|
+
- **Output interpretation.** Mu does not parse pane contents for agent
|
|
240
|
+
state, facts, claims, or tool calls. murmur or herdr reports runtime
|
|
241
|
+
agent state.
|
|
250
242
|
The `--evidence` payload is whatever the agent says it is; mu
|
|
251
243
|
records it without interpretation.
|
|
252
244
|
|
|
@@ -344,12 +336,10 @@ orchestrator stays in charge.
|
|
|
344
336
|
`~/.local/state/mu/mu.db`. Cross-machine state moves as
|
|
345
337
|
append-only JSONL segments in a shared folder; you own transport.
|
|
346
338
|
|
|
347
|
-
3. **Pi-first.**
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
mu defers to it. Either way we optimize for
|
|
352
|
-
false-negative-then-poll over false-positive-then-act.
|
|
339
|
+
3. **Pi-first.** `--cli pi` is the meaningful default; `--cli` accepts
|
|
340
|
+
other strings as a key for the `MU_<UPPER_CLI>_COMMAND` env var
|
|
341
|
+
resolver. Agent state comes from murmur on tmux and herdr on herdr;
|
|
342
|
+
absence is `unknown` rather than an inferred value.
|
|
353
343
|
|
|
354
344
|
4. **Send is delivered, not acknowledged.** `mu agent send` gets the
|
|
355
345
|
text into the pane and warns loudly when it cannot confirm
|
package/docs/VOCABULARY.md
CHANGED
|
@@ -46,16 +46,14 @@ defined here, fix the doc. If you need a new term, add it here first.
|
|
|
46
46
|
| **owner** | The **worker** name in `tasks.owner`. Set by claim. NULL when the task is unowned OR was claimed via `--self` (anonymous, attributed via `ops.actor` instead). Owners are **machine-local** — they reference `agents`, so ownership never syncs. | "claimer", "assignee" |
|
|
47
47
|
| **anonymous claim** | A claim made via `--self` where the **actor** isn't a registered **worker**. `tasks.owner` stays NULL; the actor is recorded in `ops.actor` for the auto-emitted `task.claim` op. The orchestrator-doing-direct-work pattern. | "self-claim" (in code; "anonymous claim" in prose), "unowned claim" |
|
|
48
48
|
| **release** | Verb: clear `tasks.owner` | "unclaim", "unassign" |
|
|
49
|
-
| **
|
|
50
|
-
| **status** | Persisted enum on `agents` (busy/needs_input/free/...) | "state" (use only "lifecycle state") |
|
|
51
|
-
| **lifecycle state** | A position in the agent state machine | "state" alone, "phase" |
|
|
49
|
+
| **agent state** | Runtime state reported by the **state source**: `busy`, `needs_input`, `needs_permission`, or `unknown`. It is not persisted in mu. | "agent status", "lifecycle state" |
|
|
52
50
|
| **role** | `full-access` or `read-only` capability flag | "permission" (avoid), "tier" |
|
|
53
51
|
| **persistent** | Agent that stays alive across tasks | "long-lived" (only in prose) |
|
|
54
52
|
| **one-shot** | Agent that exists for a single task and then terminates | "ephemeral", "transient" |
|
|
55
53
|
| **workspace** | A VCS-isolated checkout (jj workspace / sl worktree / git worktree / cp). **In mu, "workspace" is always the VCS sense** — never the mux sense. herdr calls its session-level container a "workspace" too; in mu docs and code that is a **mux session**. | "branch" (it has one but isn't one), "checkout" (only for `none` backend), the herdr sense |
|
|
56
54
|
| **ghost** | An `agents` row whose `pane_id` no longer exists in the **mux**. Pruned by **reconcile**, which runs in `mu agent list` and `mu doctor`. | "dead agent" (a dead agent may still have a pane), "stale row" |
|
|
57
55
|
| **reaper** | The part of reconcile that releases a **ghost**'s tasks: `IN_PROGRESS → OPEN`, owner cleared. Makes `mu task wait` exit 6. | "garbage collector", "janitor" |
|
|
58
|
-
| **needs attention** | The condition `mu task wait --stuck-after` detects: an IN_PROGRESS task whose **owner** has
|
|
56
|
+
| **needs attention** | The condition `mu task wait --stuck-after` detects: an IN_PROGRESS task whose **owner** has been in `needs_input` for at least N seconds according to murmur's `since`. `unknown` never counts. The predicate cannot distinguish a worker that finished without closing, one waiting on an answer, or one at an approval prompt, so every surface points at `mu agent read <owner>`. | "stuck" / "stalled" (the `stuck` JSON field and exit-7 `STALL_DETECTED` keep their names for compatibility), "close discipline", "negligent worker" |
|
|
59
57
|
| **workspace orphan** | A directory under `<state-dir>/workspaces/<workstream>/` with no row in `vcs_workspaces`. Blocks subsequent `--workspace` spawns. Surfaced by `mu workspace orphans -w X`, `mu state -w X`, and `mu doctor`'s `ws-dirs` row. | "stray dir", "leftover workspace" |
|
|
60
58
|
| **stranded** | A **workspace orphan** whose parent *workstream* row is also gone. Reported separately because no workstream-scoped verb can reach it — `mu workspace orphans --all` and `mu doctor` are the only surfaces. | "double orphan", "abandoned" |
|
|
61
59
|
| **missing workspace dir** | The INVERSE of a **workspace orphan**: a `vcs_workspaces` row whose `path` is not on disk (usually a hand-run `rm -rf` where `mu workspace free` was wanted). More dangerous than an orphan, because every read surface reports the row as a healthy workspace and the next send fails inside the VCS backend rather than at the row that lied. `mu doctor`'s `ws-rows` row. | "broken workspace", "dangling row" |
|
|
@@ -64,7 +62,7 @@ defined here, fix the doc. If you need a new term, add it here first.
|
|
|
64
62
|
| **stale workspace** | A workspace whose `parent_ref` is N commits behind the project's default branch HEAD (per the workspace's local refs cache). Rendered as a color-coded `behind` column (green ≤2, yellow 3–9, red ≥10) in `mu workspace list` and `mu state`; ≥10 triggers a one-line warn in `mu state`, `mu task claim --for`, and `mu agent send` (or refusal on the two dispatch verbs with `--strict-staleness`). Pure observation — mu never auto-fetches. | "out of date", "drifting" |
|
|
65
63
|
| **refresh** | `mu workspace refresh <agent>` — rebase the agent's workspace onto a fresh base (default = backend's tracked main; `--from <ref>` overrides) WITHOUT touching the agent or pane. Refuses on dirty WC; surfaces conflicts as exit 5 with a resolve-in-place hint. The `none` backend errors (no VCS to rebase). | "recycle", "reset" (overloaded) |
|
|
66
64
|
| **backend** | Implementation of `MuxBackend` or `VcsBackend`. Always qualify which (**mux backend** / **VCS backend**) when both are in scope. | "driver", "provider" |
|
|
67
|
-
| **
|
|
65
|
+
| **state source** | The system that reports **agent state**: herdr's `paneStatus()` on herdr, or murmur on tmux. mu reads local murmur pane options in one tmux call and uses `murmur status --json` only for remote workers. No source yields `unknown` with a reason. | "scraper" |
|
|
68
66
|
| **op** | The atomic unit of change: one row in the `ops` table, written by a trigger inside the same transaction as the mutation it records. Carries `(hlc, machine_id, group_id, actor, intent, entity, key, op, payload)`. A **semantic partial update** — the payload holds only the columns that actually changed, which is what makes per-field merge free. | "event", "delta", "change" (all overloaded) |
|
|
69
67
|
| **ops log** | The `ops` table: the single append-only record of every change, and the substrate **sync**, **undo**, and history are all queries or replays over. Canonical and ACID because it lives in `mu.db` alongside the tables it records. | "event log", "journal", "WAL" (reserved by SQLite) |
|
|
70
68
|
| **intent** | The semantic label on an **op** (`task.close`, `task.reparent`, `agent.spawn`). Set once per public SDK function via **op context**, not per mutation. `mu log` renders prose from it through one formatter. | "verb" (overloaded by CLI verbs), "action" |
|
|
@@ -165,36 +163,25 @@ window.
|
|
|
165
163
|
|
|
166
164
|
---
|
|
167
165
|
|
|
168
|
-
##
|
|
169
|
-
|
|
170
|
-
### Agent
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
`src/glyphs.ts` (`
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
|
177
|
-
|
|
|
178
|
-
| `
|
|
179
|
-
| `
|
|
180
|
-
| `
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
All of them are classic Nerd Font `nf-fa-*` (Font Awesome 4)
|
|
188
|
-
codepoints, single-codepoint and one cell wide, so `cli-table3`
|
|
189
|
-
columns line up. `busy` is deliberately the same glyph murmur's dash
|
|
190
|
-
paints for a `running` pane — they drive the same panes, so one symbol
|
|
191
|
-
means one thing on both surfaces. Non-agent state glyphs (blocked,
|
|
192
|
-
dirty, stale, ok/warn/fail, filter toggles) come from the `GLYPH`
|
|
193
|
-
record in the same file.
|
|
194
|
-
|
|
195
|
-
**Source of truth:** the substrate — the **mux backend**, plus the
|
|
196
|
-
**detector** when that backend cannot classify panes itself. The DB is
|
|
197
|
-
a cache; `mu agent list` reconciles on every call.
|
|
166
|
+
## State, lifecycle, and the verbs that touch them
|
|
167
|
+
|
|
168
|
+
### Agent state
|
|
169
|
+
|
|
170
|
+
Agent state is runtime data and is not persisted. The codepoints live in
|
|
171
|
+
`src/glyphs.ts` (`AGENT_STATE_GLYPH`).
|
|
172
|
+
|
|
173
|
+
| Value | Glyph slot | Meaning |
|
|
174
|
+
| --- | --- | --- |
|
|
175
|
+
| `busy` | nf-fa-play | Actively working |
|
|
176
|
+
| `needs_input` | nf-fa-moon_o | Waiting for input |
|
|
177
|
+
| `needs_permission` | nf-fa-lock | Waiting for a human answer |
|
|
178
|
+
| `unknown` | nf-fa-question_circle | No state source or no usable reading; the reason accompanies the state |
|
|
179
|
+
|
|
180
|
+
The state source is herdr on the herdr backend and murmur on the tmux
|
|
181
|
+
backend. mu maps murmur `working` to `busy`, `blocked` to
|
|
182
|
+
`needs_permission`, and `idle`, `done`, and `crashed` to `needs_input`.
|
|
183
|
+
The retained `agents.status` column is deprecated and always contains
|
|
184
|
+
`spawning`; no runtime read uses it.
|
|
198
185
|
|
|
199
186
|
### Agent lifecycle verbs
|
|
200
187
|
|