@mu-crew/mu 3.13.3 → 4.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 +73 -35
- package/README.md +71 -57
- package/dist/chunk-5HECDBK3.js +4482 -0
- package/dist/chunk-5HECDBK3.js.map +1 -0
- package/dist/chunk-AW2NONYU.js +301 -0
- package/dist/chunk-AW2NONYU.js.map +1 -0
- package/dist/chunk-GQNHIPJN.js +4060 -0
- package/dist/chunk-GQNHIPJN.js.map +1 -0
- package/dist/{chunk-3BARPJLY.js → chunk-PZ5GOCWH.js} +16 -2
- package/dist/chunk-PZ5GOCWH.js.map +1 -0
- package/dist/chunk-S424D5EP.js +13766 -0
- package/dist/chunk-S424D5EP.js.map +1 -0
- package/dist/{cli-CKOMHBXV.js → cli-GB2CAVVW.js} +6776 -4350
- package/dist/cli-GB2CAVVW.js.map +1 -0
- package/dist/cli.js +2 -3
- package/dist/cli.js.map +1 -1
- package/dist/errors-KHOYKD7D.js +65 -0
- package/dist/extension/mu-pi.js +1617 -836
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +4015 -2561
- package/dist/index.js +614 -297
- package/dist/index.js.map +1 -1
- package/dist/tui-ALPHYTA2.js +1773 -0
- package/dist/tui-ALPHYTA2.js.map +1 -0
- package/docs/ARCHITECTURE.md +117 -66
- package/docs/VOCABULARY.md +112 -49
- package/docs/guide/README.md +3 -3
- package/docs/guide/backends.md +8 -4
- package/docs/guide/cleanup.md +61 -33
- package/docs/guide/delegate.md +141 -66
- package/docs/guide/dispatch.md +148 -53
- package/docs/guide/getting-started.md +37 -44
- package/docs/guide/other-agent-clis.md +102 -0
- package/docs/guide/recovery.md +31 -50
- package/docs/guide/remote.md +115 -45
- package/docs/guide/sql.md +104 -24
- package/docs/guide/stop-a-worker.md +30 -37
- package/docs/guide/sync.md +11 -3
- package/docs/guide/upgrade.md +93 -43
- package/docs/reference/env.md +23 -32
- package/docs/reference/naming.md +12 -7
- package/docs/reference/surface-contract.md +153 -0
- package/package.json +33 -11
- package/prompts/mu-debug.md +3 -1
- package/prompts/mu-refute.md +2 -1
- package/prompts/mu-research.md +3 -1
- package/prompts/mu-review.md +2 -1
- package/prompts/mu-rules-audit.md +5 -4
- package/prompts/mu-sweep.md +2 -1
- package/prompts/mu-tournament.md +4 -2
- package/prompts/mu-until.md +3 -1
- package/prompts/ultrathink.md +1 -1
- package/skills/mu/SKILL.md +60 -291
- package/skills/mu/recipes/adversarial-review.md +12 -103
- package/skills/mu/recipes/brief.md +14 -61
- package/skills/mu/recipes/course-correct.md +23 -0
- package/skills/mu/recipes/findings.md +17 -111
- package/skills/mu/recipes/models.md +17 -92
- package/skills/mu/recipes/move.md +14 -0
- package/skills/mu/recipes/orchestrator-loop.md +20 -119
- package/skills/mu/recipes/recovery.md +8 -29
- package/skills/mu/recipes/remote-workers.md +16 -318
- package/skills/mu/recipes/tasks-or-calls.md +15 -78
- package/skills/mu/recipes/test-health.md +19 -77
- package/skills/mu/recipes/worker.md +17 -24
- package/dist/chunk-45KQLMEL.js +0 -2908
- package/dist/chunk-45KQLMEL.js.map +0 -1
- package/dist/chunk-G434JKV2.js +0 -641
- package/dist/chunk-G434JKV2.js.map +0 -1
- package/dist/chunk-KUGUFBWH.js +0 -12527
- package/dist/chunk-KUGUFBWH.js.map +0 -1
- package/dist/chunk-QITLNZEM.js +0 -87
- package/dist/chunk-QITLNZEM.js.map +0 -1
- package/dist/chunk-VIEYQMQA.js +0 -393
- package/dist/chunk-VIEYQMQA.js.map +0 -1
- package/dist/chunk-WI6AWCMK.js +0 -19
- package/dist/chunk-WI6AWCMK.js.map +0 -1
- package/dist/cli-CKOMHBXV.js.map +0 -1
- package/dist/devtools-LS4ZEPWM.js +0 -3772
- package/dist/devtools-LS4ZEPWM.js.map +0 -1
- package/dist/tui-LFJ5P4Y2.js +0 -40956
- package/dist/tui-LFJ5P4Y2.js.map +0 -1
- package/dist/tui-sync-worker.js +0 -17
- package/dist/tui-sync-worker.js.map +0 -1
- package/dist/yank-XDOONQSL.js +0 -13
- package/dist/yank-XDOONQSL.js.map +0 -1
- package/docs/ROADMAP.md +0 -123
- package/docs/VISION.md +0 -298
- package/docs/architecture/control-socket.md +0 -142
- package/docs/architecture/dag.md +0 -117
- package/docs/architecture/mux.md +0 -167
- package/docs/architecture/ops-log.md +0 -160
- package/docs/architecture/sdk.md +0 -187
- package/docs/architecture/sync.md +0 -159
- package/docs/architecture/tui.md +0 -165
- package/docs/guide/tui.md +0 -98
- package/docs/history/CHANGELOG-pre-3.md +0 -4866
- package/docs/img/tui-dashboard.png +0 -0
- package/docs/specs/2026-09-28-agent-state-from-murmur.md +0 -333
- package/docs/specs/2026-09-29-task-substates.md +0 -247
- package/docs/specs/2026-10-03-keep-driving-nudge.md +0 -163
- package/docs/specs/2026-10-21-fast-and-slow-gates.md +0 -229
- package/skills/mu/recipes/backlog-triage.md +0 -45
- package/skills/mu/recipes/codemode-driver.md +0 -118
- package/skills/mu/recipes/deep-research.md +0 -69
- package/skills/mu/recipes/drift-audit.md +0 -75
- package/skills/mu/recipes/fan-out.md +0 -42
- package/skills/mu/recipes/hypothesis-panel.md +0 -48
- package/skills/mu/recipes/long-run.md +0 -32
- package/skills/mu/recipes/loop-until-done.md +0 -45
- package/skills/mu/recipes/plan.md +0 -67
- package/skills/mu/recipes/refute.md +0 -55
- package/skills/mu/recipes/review-panel.md +0 -65
- package/skills/mu/recipes/rules-audit.md +0 -89
- package/skills/mu/recipes/tournament.md +0 -44
- package/skills/mu/recipes/ultrathink.md +0 -86
- package/skills/mu/recipes/watcher.md +0 -28
- package/skills/mu/recipes/waves.md +0 -21
- /package/dist/{chunk-3BARPJLY.js.map → errors-KHOYKD7D.js.map} +0 -0
package/docs/VOCABULARY.md
CHANGED
|
@@ -15,7 +15,7 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
15
15
|
| Term | Meaning | Don't use |
|
|
16
16
|
| --- | --- | --- |
|
|
17
17
|
| **workstream** | The unit of organization: one **mux session** and one DB partition. | "project", "session" (alone), "context" |
|
|
18
|
-
| **scratch workstream** | The reserved workstream `scratch` for helpers outside any task DAG. Auto-created
|
|
18
|
+
| **scratch workstream** | The reserved workstream `scratch` for helpers outside any task DAG. Auto-created by `task add` and `agent spawn`; any other unknown `-w` is exit 3 (only `agent spawn` still creates its workstream) (`mu workstream init <name>` creates it); `mu workstream init scratch` is rejected. Its session keeps a `_mu` window, so it stays open after the last agent closes; `teardown --empty` skips it. | "throwaway ws", "temp workstream" |
|
|
19
19
|
| **multiplexer** / **mux** | The terminal program that owns panes: **tmux** or **herdr**. "mux" in code (`src/mux/`, `MU_MUX`), "multiplexer" in prose; one is active per invocation. | "terminal", "emulator", "backend" (alone) |
|
|
20
20
|
| **mux backend** | An implementation of `MuxBackend` (`src/mux/tmux.ts`, `src/mux/herdr.ts`). Owns everything backend-specific. | "driver", "provider", "adapter" |
|
|
21
21
|
| **mux detection** | Picks the mux backend: `MU_MUX` → `HERDR_ENV=1` → `$TMUX` → binary on `PATH` (tmux wins a tie) → `NoMultiplexerError`. | "auto-detect", "probe" |
|
|
@@ -25,36 +25,43 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
25
25
|
| **window name** | A window's name: the agent's `--tab` value, or the agent name. | "tab name" |
|
|
26
26
|
| **pane** | One shell view inside a **window**. | "terminal", "shell" |
|
|
27
27
|
| **pane id** | The mux's stable pane handle: tmux `%15`, herdr `w1:p1`. Not the volatile tmux pane index, which is never stored. | "pane number", "pane index" |
|
|
28
|
-
| **
|
|
29
|
-
| **substrate** | An external system mu depends on: tmux, herdr, jj, sl, git, SQLite. | "dependency" (an npm dep), "service" |
|
|
28
|
+
| **substrate** | An external system mu depends on: tmux, herdr, git, SQLite. | "dependency" (an npm dep), "service" |
|
|
30
29
|
| **crew** | Informal: the agents in a workstream. Prose only. | |
|
|
31
30
|
|
|
32
31
|
### Agents
|
|
33
32
|
|
|
34
33
|
| Term | Meaning | Don't use |
|
|
35
34
|
| --- | --- | --- |
|
|
36
|
-
| **agent** | A named process in a pane with a row in `agents`. Identity is `$MU_AGENT_NAME
|
|
35
|
+
| **agent** | A named process in a pane with a row in `agents`. Identity is `$MU_AGENT_NAME`; mu never reads or writes pane titles. | "subagent", "worker" (a role) |
|
|
37
36
|
| **worker** | An agent in its role as task claimer. Prefer **agent** when ambiguous. | |
|
|
38
|
-
| **remote worker** |
|
|
37
|
+
| **remote worker** | An agent spawned with `--host <profile>`: its pane is local and is the transport (the profile's `shell` template runs there and forwards the remote pi's control socket), its process is remote, and its host, remote cwd and base are `agents.host/cwd/base`. The pane dying is the agent dying. | "REMOTE: note", "remote-env" | "remote agent record", "host registry" |
|
|
38
|
+
| **command gate** | A remote spawn of a non-pi command (`spawn --host dev --command 'npm test'`): a foreground pane, not a worker. Its `agents.gate_token` marks it and keys its remote completion record; `mu wait` returns the command's own numeric exit (event `exited`, `data.exit`). The pane is retained after the command ends until `agent close`. | "remote job", "gate worker" |
|
|
39
|
+
| **collect** | `mu agent collect <agent>`: run a remote worker's `--fetch` template locally and pin the fetched commit as `refs/mu/collect/<ws>/<agent>`; the commit is recorded as `agents.collected_head`, and `agent close` accepts a remote worktree at its base or that HEAD. mu prints the merge, never runs it. | "pull", "sync" (that is `mu sync`) |
|
|
39
40
|
| **delivery unknown** | A send/fresh/interrupt/command request was written to a live agent's control socket but no reply arrived (`AgentSendIndeterminateError`). pi may have acted; read the pane before resending. | "refused" (the request never went out) |
|
|
40
41
|
| **actor** | Whoever caused a state change (`ops.actor`); need not be a worker. | "caller", "author" (notes only) |
|
|
41
|
-
| **role** |
|
|
42
|
+
| **role** | Advisory label, `full-access` or `read-only`: recorded and shown, not enforced and not a security boundary. A read-only auditor simply gets no worktree. | "permission", "tier", "capability" |
|
|
42
43
|
| **persistent** | An agent that stays alive across tasks. | "long-lived" (prose only) |
|
|
43
44
|
| **one-shot** | An agent that exists for one task. | "ephemeral", "transient" |
|
|
44
|
-
| **nudge** |
|
|
45
|
-
| **delegate** | A scratch agent started for one task; its answer
|
|
46
|
-
| **
|
|
45
|
+
| **nudge** | A pi extension continuation at settle. The keep-driving one is the **settle wait**: every completed settle of an orchestrator runs `mu wait` as its callers and continues the turn with the event, until nothing is owed, a `mu human-needed` stop is open, or the user cancels. The close nudge tells a worker once per prompt to close the task it still owns (never a delegate's own `kind=delegate` task: its call closes it). | "goal", "loop" |
|
|
46
|
+
| **delegate** | A scratch agent started for one check. Its call is a `delegate`-kind task; its answer is that task's report, and the settle wait shows it to pi (a wave's as one **wave summary**). The `mu_delegate` tool does it in one call; the pane stays attachable. With no tmux or herdr the tool runs it as a **delegate process** instead (no pane). | "subagent", "child agent" |
|
|
47
|
+
| **wake** | The one pi message the delegate side sends for a recorded answer when no settle wait will show it (pi idle, `MU_NUDGE=0`): a pointer per answer (`mu task notes <task> -w <ws>`), no answer text, that starts a turn whose settle shows the report. Losing or repeating one loses or repeats nothing. | "echo", "follow-up answer" |
|
|
48
|
+
| **wave summary** | What the settle wait shows for a delegate of a wave: it waits while siblings run (never on refused ones), then ONE entry with counts per verdict, a line per call and the answers, instead of one per call. | "wave echo" |
|
|
49
|
+
| **envelope** | The one JSON document a `--json` invocation prints on stdout: `{ok:true,data,next}`, or on failure `{ok:false,error,message,next,exit}` with the real non-zero exit (`src/output-contract.ts`). A failed verb that already produced evidence (a spawn whose `--send` failed, a `doctor` report) carries it in `data`. `mu log --tail` is always NDJSON (one item per line), never enveloped. | "wrapper", "result object" |
|
|
50
|
+
| **delegate call** | Using a delegate for one check (a refuter, judge, claim checker): one `mu_delegate` call, or `mu agent spawn -w scratch` + `send --fresh` + `wait --json` without the tool. A call is a task (see **task kind**) with a `call_id` and a state (`queued starting running recording done failed refused cancelled`, `mu delegates`). Its verdict is recorded on the task it judged, then the call's own report and close. Admission control (`MU_DELEGATE_MAX` running, a bounded queue) stays; a call past it is **refused**: durable, parked, reissuable, never dropped. `mu next --refute` makes one per closed attempt (call id `refute:<ws>:<task>:<attempt key>`, wave `refute-<ws>`), launched and recorded by the executor itself. | "subtask" |
|
|
51
|
+
| **delegate process** | The mux-free way to run a **delegate call** (`mu delegates run <call-id>`, `src/delegate-process.ts`): one child `pi --mode rpc` with its own ctl socket, log and session, no pane and no agents row (`transport: "process"`, `attach: null`). The call and its task stay the authority. Its **attempt receipt** (`<state dir>/delegate-process/<hash>/receipt.json`, machine-local) marks that a child may have run: a call with one left behind finishes `unknown`, never respawned or resent. | "headless agent", "background agent" |
|
|
47
52
|
| **hidden subagent** | A child agent in other tools (pi-subagents, Claude Code and Codex task tools) with no pane to attach or steer. mu's counterpart is the **delegate**. | "subagent" (alone) |
|
|
48
53
|
| **agent state** | `busy`, `needs_input`, `needs_permission`, or `unknown`, from the **state source**. Not persisted; see [Agent state values](#agent-state-values). | "agent status", "lifecycle state" |
|
|
49
54
|
| **state source** | The **control socket** for pi agents; else herdr's `paneStatus()` or, on tmux, murmur. A silent pi socket gives `unknown` (`ctl missing`, `ctl refused`). | "scraper" |
|
|
50
55
|
| **control socket** / **ctl** | The per-agent unix socket (`$MU_CTL_SOCK`) the mu pi extension serves inside pi. **ctl state** is `ok`, `missing`, or `refused`. | "rpc", "daemon" |
|
|
51
|
-
| **session command** | `/new`, `/reload`, or `/compact [instructions]` sent to a pi agent. mu runs it inside pi through the ctl `command` op, never as a paste. Any other slash command to a pi agent is refused
|
|
56
|
+
| **session command** | `/new`, `/reload`, or `/compact [instructions]` sent to a pi agent. mu runs it inside pi through the ctl `command` op, never as a paste. Any other slash command to a pi agent is refused. | "slash paste" |
|
|
52
57
|
| **outdated extension** | A running pi whose loaded extension is older than mu (exit 4 on a missing op). pi's `/reload` fixes it. | |
|
|
53
|
-
| **lastText** | A pi run's final assistant message, returned verbatim by `wait`. mu
|
|
58
|
+
| **lastText** | A pi run's final assistant message, returned verbatim by `wait`. `mu_delegate` `record` finds its first `VERDICT:` line (also behind one role word such as `REFUTER:`) and writes everything from it, uncapped, as a `verdict` task note, then the call's report; mu applies no close or status change to the judged task from it. A worker's own run is different: a valid **CLOSE block** at its end closes the worker's task. | "result", "output" (alone) |
|
|
54
59
|
| **ghost** | An `agents` row whose `pane_id` no longer exists. Pruned by **reconcile**. | "dead agent", "stale row" |
|
|
55
|
-
| **reaper** | The part of reconcile that releases a ghost's tasks to `OPEN`. Makes `mu
|
|
60
|
+
| **reaper** | The part of reconcile that releases a ghost's tasks to `OPEN`. Makes `mu wait` exit 6 (a `dead` event). | "garbage collector", "janitor" |
|
|
61
|
+
| **wait event** | What ends a `mu wait`: `closed`, `settled`, `input`, `dead`, `stall`, `delegate`, `exited` (a **command gate** ended: `data.exit` is its numeric status, also the process exit), `pane-text` (a non-pi pane's tail matched `--until-text`: no run finished, never `settled`), `heartbeat` (the timeout, `ok:true`, `timedOut`), `interrupted` (SIGINT/SIGTERM). It is `data.firing` of the one JSON result, beside `exit`, `snapshots`, `cursor` and `resume`. | "wait result" (alone), "firing task" |
|
|
62
|
+
| **typed ref** | A `mu wait` argument that names its kind: `task:[<ws>/]<id>`, `agent:[<ws>/]<name>[@<runs>][#<incarnation>]`, `delegate:<call id>`. A bare word is refused. | "bare ref" |
|
|
63
|
+
| **resume** | `data.resume` of a wait result: the one-line handle `mu wait --resume <id>` that continues it. The condition set (refs with the run baseline and pi incarnation last seen, mode, filters, deadline, callers) is stored in `wait_resumes`; null (with `resumeWhy`) when nothing is left to wait for. | "retry command" |
|
|
56
64
|
| **needs attention** | An `IN_PROGRESS` task whose owner has been `needs_input` for `--stuck-after` seconds. Check with `mu agent read <owner>`. | "stuck", "stalled" (kept only in the `stuck` JSON field and exit-7 `STALL_DETECTED`) |
|
|
57
|
-
| **adopt** | Register an existing pane in the workstream's mux session as an agent (`mu agent adopt`). | "import", "absorb" |
|
|
58
65
|
| **reconcile** | Re-derive registry rows from the mux. Runs in `mu agent list` and `mu doctor`. | "sync", "refresh" |
|
|
59
66
|
| **extension** | The pi extension shipped in the mu package. | "plugin" |
|
|
60
67
|
| **skill** | The bundled `SKILL.md` that teaches the LLM. | "system prompt" |
|
|
@@ -68,10 +75,12 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
68
75
|
| **substate** | What the status means, shown as `STATUS/substate`; never null. `OPEN`: `todo`, `parked`, `triage`. `IN_PROGRESS`: `active`. `CLOSED`: `done`, `rejected`, `wontfix`, `duplicate`, `superseded`. | "resolution", "reason" |
|
|
69
76
|
| **park** / **unpark** | `OPEN/todo` ↔ `OPEN/parked` (park needs `--why`). Parked tasks leave **ready**. | "defer", "snooze" |
|
|
70
77
|
| **triage** / **accept** | `OPEN/triage` is a proposed task, usually a review **finding**, not yet accepted as work: out of **ready**, refused by `claim`, but it blocks its dependents. `mu task add --triage` creates one; `mu task accept` moves it to `OPEN/todo`; declining is `close --as rejected` or `--as duplicate`. | "inbox", "pending" |
|
|
78
|
+
| **human-needed** | `mu human-needed <reason>`: the caller records a `human` task, `OPEN/parked`, whose brief is the reason; the loop's only legitimate stop. Scoped to the caller (`human_needs`, machine-local: managed `<ws>/<agent>` or `pi:<session>`, never a note author; a rebuild keeps the task but loses the caller). Same reason is a no-op; a new reason appends a brief. A `human` task resolves only by an explicit `mu task close`: unpark, claim (even `--force`) and a CLOSE block are refused. Never created on an error or a queue refusal. | "blocker", "escalation" |
|
|
71
79
|
| **finding** | One problem a reviewer, checker, or auditor reports. Recorded as an `OPEN/triage` task (the mu way), or as an answer line when a **delegate** reviews something nobody will track. | "issue", "comment" |
|
|
72
80
|
| **task DAG** / **graph** | The directed acyclic graph of tasks. | "task list", "tree" |
|
|
73
81
|
| **edge** | The single edge type: `A blocks B` means A must close before B starts. | "dependency" (prose only) |
|
|
74
82
|
| **subtree** / **scope** | Tasks reachable from a root via blocks-edges. | "subgraph" |
|
|
83
|
+
| **explicit scope** / **injected scope** | The workstream a verb acts on: `-w <name>` or a qualified `<ws>/<name>` ref (explicit), else the `MU_WORKSTREAM` spawn gives a managed worker (injected, only with `MU_MANAGED_AGENT=1`). Nothing else routes a verb: not `MU_SESSION`, not the mux session name, which only appears as a suggestion in the one-line error. | "ambient workstream", "current workstream", "default workstream" |
|
|
75
84
|
| **track** | An independent subtree found by parallel-track detection. | "branch", "lane" |
|
|
76
85
|
| **diamond merge** | Merging two tracks that share a prerequisite into one. | "join" |
|
|
77
86
|
| **ready** | An `OPEN/todo` task with no open blockers (the `ready` view). | "unblocked", "available" |
|
|
@@ -81,7 +90,7 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
81
90
|
| **claim** | Set `tasks.owner` to an agent. Atomic compare-and-set. | "assign" (prose only), "lock" |
|
|
82
91
|
| **owner** | The worker in `tasks.owner`; NULL after an **anonymous claim**. Never syncs. | "claimer", "assignee" |
|
|
83
92
|
| **anonymous claim** | A `--self` claim by an actor that is not a worker. `owner` stays NULL; `ops.actor` records who. | "unowned claim" |
|
|
84
|
-
| **release** | Clear `tasks.owner
|
|
93
|
+
| **release** | Clear `tasks.owner`; an `IN_PROGRESS` task returns to `OPEN` (`--reopen` also reopens a `CLOSED` one). | "unclaim", "unassign" |
|
|
85
94
|
|
|
86
95
|
### Recipe gates
|
|
87
96
|
|
|
@@ -94,36 +103,35 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
94
103
|
| **test upkeep** | Ordinary DAG work to profile, speed up, move down, merge or remove tests while preserving coverage; see [test-health](../skills/mu/recipes/test-health.md). | "coverage reduction" |
|
|
95
104
|
| **test level** | Unit < integration < e2e; use the lowest level that catches the guarded failure. | |
|
|
96
105
|
| **review gate** | A review task blocked by a work task, deciding whether its commits count. | "gate command" |
|
|
106
|
+
| **course check** | A periodic look at whether a long job is still on course ([course-correct](../skills/mu/recipes/course-correct.md)), recorded as a task note starting `COURSE CHECK`. `courseCheckHint` reports one due after 10 CLOSED/done work tasks, or 24 h with at least one, since the last such note; `mu state` and `mu wait` show it in `data.notices`. | "retro" |
|
|
97
107
|
| **merge batch** | Accepted commits combined into one pinned tree for full merge verification, without a crew-wide barrier. | "wave" (when only verification is batched) |
|
|
98
108
|
|
|
99
|
-
###
|
|
109
|
+
### Worktrees and housekeeping
|
|
100
110
|
|
|
101
111
|
| Term | Meaning | Don't use |
|
|
102
112
|
| --- | --- | --- |
|
|
103
|
-
| **
|
|
104
|
-
| **
|
|
105
|
-
| **
|
|
106
|
-
| **
|
|
107
|
-
| **
|
|
108
|
-
| **stranded** | A workspace orphan whose workstream row is gone too. Only `mu workspace orphans --all` and `mu doctor` reach it. | "abandoned" |
|
|
109
|
-
| **missing workspace dir** | A `vcs_workspaces` row whose path is gone. Worse than an orphan: read surfaces still call it healthy. | "dangling row" |
|
|
110
|
-
| **dormant** | An idle workstream with no agents or workspaces: **finished** (all closed, 14 days) or **abandoned** (open tasks, 60 days). | "stale", "dead", "empty" |
|
|
113
|
+
| **worktree** | A git worktree for one agent (`spawn --worktree`): `git worktree add --detach`, the agent's cwd. Closed by the one rule: dirty refuses, merged is removed, unmerged commits keep a branch. Git only. | "workspace", "checkout" |
|
|
114
|
+
| **worktree registry** | The machine-local `worktrees` table (path, agent, workstream, root, base, last collected head). Outlives the agent row; only closing the worktree removes it. | "workspace row" |
|
|
115
|
+
| **backend** | An implementation of `MuxBackend` (tmux, herdr). | "driver", "provider" |
|
|
116
|
+
| **missing worktree dir** | A `worktrees` row whose path is gone. Read surfaces still call it healthy. | "dangling row" |
|
|
117
|
+
| **dormant** | An idle workstream with no agents or worktrees: **finished** (all closed, 14 days) or **abandoned** (open tasks, 60 days). | "stale", "dead", "empty" |
|
|
111
118
|
| **residue** | Bytes in `<state-dir>` that no row references and no code reads. Reported by `mu doctor`, never removed. | "garbage", "junk" |
|
|
112
119
|
| **disk↔DB reconciliation** | `mu doctor`'s report-only `disk` section. Not **reconcile** (rows vs mux) or **drift** (log vs tables). | "gc", "cleanup" |
|
|
113
120
|
| **doctor** | The diagnostic command and its report. | "health check" |
|
|
114
121
|
|
|
115
|
-
### Ops log
|
|
122
|
+
### Ops log and sync
|
|
116
123
|
|
|
117
124
|
| Term | Meaning | Don't use |
|
|
118
125
|
| --- | --- | --- |
|
|
119
126
|
| **op** | One `ops` row, written by a trigger in the mutation's transaction. Holds only changed columns. | "event", "delta", "change" |
|
|
120
|
-
| **ops log** | The `ops` table: the append-only record that sync
|
|
121
|
-
| **log entry** | An op as
|
|
127
|
+
| **ops log** | The `ops` table: the append-only record that sync and history read. | "event log", "journal", "WAL" |
|
|
128
|
+
| **log entry** | An op as `mu log` prints it: one escaped line of at most 400 characters (or one JSON item keyed by the `ops` column names: `key`, `actor`, `entity`, `group_id`, `created_at`, `rendered`), through one formatter (`src/log-render.ts`). Parent-row touch ops are not entries. A cut says `more=N`/`cut=N` and names the read that recovers it by seq (`mu log --seq A..B`, `mu log --after S`), never by filter. An intent this build does not know prints as `op put|del <key> intent=… kind=… patch=…`, never as a verb. | "message", "event" |
|
|
122
129
|
| **kind** | The operator's channel tag on a log entry (`mu log --kind`), stored as the op's `entity`. `workstream`, `task`, `edge`, and `note` are reserved. | "category", "type" |
|
|
123
130
|
| **log ledger** | A convention: a custom `--kind` used as a watcher loop's durable dedupe record. | "state file" |
|
|
124
131
|
| **intent** | The semantic label on an op (`task.close`), set once per SDK function via **op context**. | "verb", "action" |
|
|
125
|
-
| **group** | The ops of one user action (`group_id`),
|
|
126
|
-
| **op context** | The `
|
|
132
|
+
| **group** | The ops of one user action (`group_id`), read as a unit (`mu log --group`). Any unique id prefix works. | "transaction", "batch" |
|
|
133
|
+
| **op context** | The one-row `op_ctx` table that stamps intent, actor, and group onto ops. Written only by `src/op-context.ts`, inside a transaction the wrapper owns, so it holds defaults at rest. | "thread local" |
|
|
134
|
+
| **scoped views** | The `TEMP` views `ready`, `blocked`, `blockers` that `mu db query -w <ws>` (or `mu db --shell -w <ws>`) installs on its own connection, cutting the global views to one workstream (id as a literal; same columns). `main.ready` stays the global one. | "filtered view", "session views" |
|
|
127
135
|
| **apply** | Land one op under the **merge rules** (`src/apply.ts`). Idempotent; mints no op. | "merge", "import", "replay" |
|
|
128
136
|
| **merge rules** | Notes: **grow-only set**. Tasks, workstreams: **per-field LWW**. Edges: **LWW-element-set**. Unknown entities are ignored. | "conflict resolution", "CRDT" |
|
|
129
137
|
| **per-field LWW** | Each field keeps the value from the newest **HLC** that wrote it. | "row LWW" |
|
|
@@ -132,11 +140,20 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
132
140
|
| **tombstone** | An `op='del'` row. There is no tombstone table. | "deletion marker" |
|
|
133
141
|
| **resurrection** | A put newer than a seen tombstone, which legitimately recreates the row. | "undelete", "revive" |
|
|
134
142
|
| **provenance** | Which HLC last wrote a field, derived from the ops log by query, never stored. | "version vector" |
|
|
135
|
-
| **
|
|
136
|
-
| **
|
|
137
|
-
| **
|
|
143
|
+
| **teardown** | Soft: kill a workstream's mux session, delete its machine-local agent rows whose pane is dead (a live pane keeps its row, orphaned; worktrees are never removed), set `torn_down_at`. Tasks, edges and notes stay, hidden. Previewed first, applied with `--if <rev>`. Panes do not come back. Reusing the name (`init --if`) hard-deletes the old rows. | "destroy", "nuke", "purge" |
|
|
144
|
+
| **agent incarnation** | `AgentRow.incarnation`: the registry row's AUTOINCREMENT id (`id` in `--json` agent records, with `pane_id`, `workstream_id`; the SDK keeps camelCase). Never reused, so a name deleted and created again is a new one even on the same pane id. Every destructive agent write compares it (`deleteAgent`'s `expected`, `agent close --if`); not pi's **incarnation**. | "agent id", "pane id" |
|
|
145
|
+
| **incarnation** | A pi process's id on its control socket: minted once per process, kept across `/new` and `/reload`, new after a restart. `send` returns it; `wait --inc` refuses another one. | "session id", "pid" |
|
|
146
|
+
| **msgId / receipt** | The id a ctl `send`, `--fresh` or `--interrupt` carries. `status {msgId}` (`mu agent check`) says whether the extension accepted it: the receipt for a send that got no reply. Never a reason to resend. | "ack", "nonce" |
|
|
138
147
|
| **drift** | The ops log and live tables disagree. Always a bug. | "inconsistency", "corruption" |
|
|
139
148
|
| **shallow / deep check** | Drift checks in `mu doctor` and `mu doctor --deep` (full rebuild). | "fsck" |
|
|
149
|
+
| **scored** | `tasks.scored`: impact/effort were given (`-i`/`-e`, `update`), not defaulted (50 / 1). `ready` order: scored by impact/effort desc, then unscored oldest first. | "prioritised" |
|
|
150
|
+
| **dispatch host** | `tasks.dispatch_host` (synced): the `machine_identity` allowed to dispatch the task; `mu task auto` sets it to this machine; `next` on another machine skips it. Not the remote **host profile** that `--host` selects. | "target machine" |
|
|
151
|
+
| **local-write guard** | A persistent trigger gated on `applying = 0`: claim CAS, close needs evidence, close to `done` refuses open blockers. Ingest and import are never blocked; `mu doctor` warns about the states they accept. | "constraint", "validation" |
|
|
152
|
+
| **task record** | One task as a read prints it: a single escaped TAB-separated line `task id STATE key=value … title` (<= 400 characters), or one JSON item whose keys are the SQL column names (`id` is the `local_id`; `workstream_id` and `owner_id` are the real foreign keys; `owner` appears only while IN_PROGRESS). A cut says `more=N`/`cut=N` and names one way back: the same command with `--all` (`--full` on `owned-by`), uncapped. | "row", "card", "name" (as a key) |
|
|
153
|
+
| **open frontier** | The part of the task DAG `task tree` and the dashboard read (`loadOpenTaskFrontier`): open tasks expand, CLOSED neighbours are leaves counted past a few, depth and node counts are capped, and every cap says how much it left out. Not `loadFullDag`, which is the whole workstream. | "subtree" |
|
|
154
|
+
| **note kind** | `task_notes.kind`: `brief`, `report`, `verdict`, `close` or `note`. Set once at insert; a local change raises, as does a local change to a note's author, content or created_at (append-only). | "note type", "tag" |
|
|
155
|
+
| **torn down** | `workstreams.torn_down_at` set (soft teardown). Views and reads skip it (exit 3 "is torn down"); ingest still sees the row. Teardowns an earlier mu wrote as deletes stay final and are listed from the ops log. | "archived", "deleted" |
|
|
156
|
+
| **revision** | `rev=<n>`: a number a preview prints and `--if <n>` must repeat. `workstreamRevision` hashes the newest op touching the workstream plus its agents (name, pane) and worktrees, so any change in those since the preview makes the destructive verb refuse (exit 4). `taskRevision` (src/revision.ts) is the task-side revision: a hash derived from current state (task row, owner, incoming and outgoing edges, note count; never a counter, so sync apply and cascades move it too), shown as `revision` by `task show`/`list` and as `rev` by a `task delete` preview; `--if <rev>` on `task delete`/`block`/`unblock`/`reparent`/`claim`/`release` refuses a changed task (exit 4, `expected_rev`/`current_rev` in `--json`). `agentRevision` is the agent-side one: a hash of the registry **agent incarnation**, the row's fields, every owned task (any workstream) and the registered worktree rows (an orphan worktree has its own); bare `agent close` previews it and `--if <rev>` applies. Also called **preview revision**. | "etag", "version" |
|
|
140
157
|
| **portable** | Syncable: `workstreams`, `tasks`, `task_edges`, `task_notes`. The rest is **machine-local** (`src/db.ts`). | "shared", "global" |
|
|
141
158
|
| **HLC** | Hybrid logical clock `(wall_ms, counter, machine_id)`; orders every op. Never regresses. | "timestamp", "version" |
|
|
142
159
|
| **machine_id** | Per-state-dir uuid naming this DB's **peer** and **segment**. | "device id", "host id" |
|
|
@@ -144,7 +161,7 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
144
161
|
| **peer** | Another machine, found by its segment; named by `machine_id` prefix. **Stale** after 24h unchanged. | "node", "remote" |
|
|
145
162
|
| **watermark** | `sync_peers.last_applied_seq`: how many lines of a peer's segment file have been applied. A conflict copy has its own, keyed by its file stem. | "offset", "cursor" |
|
|
146
163
|
| **flush** / **ingest** | Write my ops to my segment; apply peers' from their watermarks. Every invocation, when `MU_SYNC_DIR` is set. | "push", "pull" |
|
|
147
|
-
| **
|
|
164
|
+
| **fold** | The pure function from the ops of one key (and its tombstone horizon) to that row's state (`src/fold.ts`). Live apply and rebuild both use it, so live == rebuild for any arrival order. | "merge", "reprojection", "retry queue" |
|
|
148
165
|
| **mixed fleet** | Machines sharing state across different OSes or filesystems. | "cluster" |
|
|
149
166
|
|
|
150
167
|
### CLI and TUI
|
|
@@ -155,18 +172,66 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
155
172
|
| **operation** | A canonical mu verb, each a thin wrapper over a typed SDK function. | "command", "action" |
|
|
156
173
|
| **qualified ref** | `<workstream>/<name>`, used instead of `-w`. | "prefixed name" |
|
|
157
174
|
| **DB** / **registry** | `<state-dir>/mu.db` and its tables. | "store" |
|
|
158
|
-
| **TUI** | The read-only ink dashboard
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
|
167
|
-
|
|
|
168
|
-
| **
|
|
169
|
-
| **
|
|
175
|
+
| **TUI** | The read-only ink dashboard. The 3.x card TUI (cards, popups, toasts, tick, help overlay) is removed; bare `mu` on a TTY opens the dashboard (help when piped or `--json`). | "GUI" |
|
|
176
|
+
|
|
177
|
+
### Terms added in 4.0
|
|
178
|
+
|
|
179
|
+
Terms the [4.0 contract](reference/surface-contract.md) added.
|
|
180
|
+
|
|
181
|
+
<!-- doc-cli-drift:skip-start -->
|
|
182
|
+
|
|
183
|
+
| Term | Meaning | Don't use |
|
|
184
|
+
| --- | --- | --- |
|
|
185
|
+
| **task kind** | `tasks.kind`: `work` (default), `delegate` or `human`. Not a **note kind** (`task_notes.kind`) and not a log **kind** (`mu log --kind`): three columns, three vocabularies. | "task type" |
|
|
186
|
+
| **wave** | `tasks.wave`: a label grouping the delegate calls of one fan-out so one wait returns one verdict tally. Not a **merge batch**. | "batch" |
|
|
187
|
+
| **call_id** | The durable id of one `mu_delegate` call (`delegate_calls.call_id`), session-qualified: `pi:<session>:<n>`. A repeat of the same call is deduplicated by it; a changed request under it is refused. Not a **msgId**. | "request id" |
|
|
188
|
+
| **attempt key** | Names one task-bound spawn attempt with its task: `agent spawn --task <t> [--attempt <k>]` is the key `manual:<k>` (default `manual:<task id>`). The same key replays its saved outcome and never sends a second prompt; a changed request under it conflicts (exit 4); reopened work takes a new key. The executor's authorised attempts are `auto:<n>` (n = the run it charged) with their latest record in `task_auto.last_spawn`: a different namespace. An `auto` attempt is reserved (and its **run** charged) before any effect, and a failed one is never reset: the next attempt is a new key. The record stores the exact prompt: a replay sends those bytes, never a rebuild. An attempt that cannot be reconciled (task closed, agent gone, UNKNOWN the one probe cannot confirm) is ended on the first `mu next` that sees it: `abandoned` (nothing sent) or `needs_human` (it may have landed: never resent, a human need is recorded); an ended attempt is never replayed or counted again. | "nonce" |
|
|
189
|
+
| **remote recovery** | `remote_recovery`: one machine-local row per ORIGINAL registry incarnation (`agents.id`) of a finalized remote worker (host, worktree path and base all recorded), written by an AFTER DELETE trigger on `agents` (and a BEFORE DELETE one on `workstreams` for the cascade; `src/db-recovery.ts`) in the transaction of ANY delete of its row: the reaper (`reap`, also raw SQL), workstream teardown (`teardown`) and a workstream deletion cascade (`workstream-delete`). It keeps the host, path, base, last collected HEAD, the exact aside path (`asideOf(cwd, agents.id)`, never derived from a later id), the profile's exec/repo when it existed, and why. No foreign key (it outlives the agent, its workstream and its host profile), no op, no sync; `mu rebuild` reports it lost. A record of a resource, not a live channel or an agent. `agent close` that itself removed the tree writes none, nor does a failed spawn whose rollback removed it (or found it gone). `agent close <name>` / `agent collect <name>` read it back when no agent holds the name (`--recovery <id>` = the original incarnation, picks one of several; the preview's `kind` is `recovery`, its `recovery_id` is never the registry `id`); a current agent, a shared path (a live agent, or a NEWER record of the same host and path), or a changed profile refuses; a `--recovery <id>` that is gone is never read as the live agent, and only that record is deleted, only once the tree is removed, kept on a branch or gone. | "tombstone", "graveyard" |
|
|
190
|
+
| **dead staging** | A `--worktree` spawn's placeholder row (pane `%pending-<name>`) left for over 60 s by a spawn killed before its pane (SIGKILL, crash): no pane ever ran in its worktree. `mu doctor` lists it (`ws-staging`); the next spawn in the workstream removes the row and its unused worktree. SIGINT/SIGTERM roll the spawn back and leave none. | "orphan", "zombie spawn" |
|
|
191
|
+
| **spawn receipt** | `spawn_receipts`: one machine-local row per (task, attempt key), written BEFORE each effect: `reserved`, `pane` (agent row + pane exist), `claimed`, `sending` (the prompt may be written: never resend), then `sent` or `unknown`; `failed` is definitely unsent and rolled back. It stores the registry id (`agents.id`) and pane with no foreign key, so a replay after the agent was deleted or the name reused says `stale` and never acts on the replacement; the send re-checks that id + pane and the claim just before the write. | "journal row", "ticket" |
|
|
192
|
+
| **delivery unknown** | A prompt that may or may not have landed (written, no reply; a pane that died after the write; a pane paste). Never resent and never reaped: the pane and the claim stay, `mu agent check` asks the extension, and an id the extension no longer remembers (it keeps the last 64) is still unknown, not unsent. | "failed send" |
|
|
193
|
+
| **spawn replay** | Returning the saved `{msgId, incarnation, runs}` for a repeated spawn attempt. A **receipt** (msgId) answers "did pi accept this send"; replay answers "was this attempt already made". | "retry" |
|
|
194
|
+
| **spawner** | `agents.spawner`: who spawned an agent: `<workstream>/<agent>` for a managed caller, else `pi:<PI_SESSION_ID>`. Never guessed from task ownership; null on older rows. | "parent" (alone), "owner" |
|
|
195
|
+
| **wait ref** | One thing a wait watches: a task, an agent (pinned by `@<runs>` and `#<incarnation>`) or a delegate; written as a **typed ref**. | "target" |
|
|
196
|
+
| **first / all** | A wait returns on the **first** event of any owned ref (default) or, with the all-of alias, once every ref has closed. | "any", "race" |
|
|
197
|
+
| **heartbeat** | A wait's own cap (`--timeout`, default and maximum 1500 s): it ends with `timedOut` true and `ok:true`, never an error. | "keepalive" |
|
|
198
|
+
| **embedded exit** | The process exit number repeated inside the JSON (`exit`), so a pipe that hides the status keeps the reason: 0 fired or timed out, 6 dead, 7 stall, 130 interrupted. | "status code" |
|
|
199
|
+
| **wait cursor** | `wait_cursors`: per caller and ref, the last consumed incarnation and runs, so a settled run is never reported twice and a restart is not mistaken for one. Machine-local. | "offset", **watermark** (that is sync) |
|
|
200
|
+
| **completion token** | What a **wait cursor** stores as `(incarnation, runs)` once an event is delivered: an agent's ctl incarnation and settled run count; `closed` + the task's newest note id (a re-close is news); `delegate` + 1. Written only for delivered refs, in the transaction that ends the wait. | "ack" |
|
|
201
|
+
| **owned event** | An event on a ref the callers own: their registered refs and their own delegate calls. The wait observes them while listed refs are waited on (`eventScope: owned`, the default; `refs` sees only the listed ones); another caller's are never seen. | "global event" |
|
|
202
|
+
| **callers** | The SET a wait owns for: the managed `<ws>/<agent>` (spawned workers, human stops) and `pi:<session>` (delegate calls), whichever are present. Owned refs, delegates, human needs and the tally are the union. An empty set owns nothing; never "every caller". | "identity", "user" |
|
|
203
|
+
| **unconsumed baseline** | `wait_registrations.baselines_json`: per registered agent ref, the ctl run count, pi incarnation and registry id a producer saw BEFORE its effect, so a run that settles before any wait starts is still delivered. Not a **cursor** (which is what a wait already delivered). | "watermark" |
|
|
204
|
+
| **stall** | A wait event: an IN_PROGRESS work task whose owner sat needs_input (or behind a dead control socket) for `stuckAfterMs`. The engine detects and reports it (exit 7); `handleStall` owns any action. | "stuck" (the legacy warning) |
|
|
205
|
+
| **action receipt** | `wait_action_receipts`: one machine-local row per stall action a wait took, keyed by task id, owner registry id, pi's ctl incarnation and action (never the wait generation, the revision or the caller). It is the exclusion that keeps a nudge or a release to ONE per incarnation across callers, restarts and generations, and the record of a release. A steer row walks `reserved -> sending -> sent | unknown | refused`: `sending` means the write MAY have happened (a crash there is `unknown`, only ever probed, never resent); a guard that vetoes before the write leaves the row `reserved`, so the budget is not spent. No foreign key: it outlives the task and the agent. A rebuild cannot restore it (reported as lost). Not a **spawn receipt**. | "nudge log" |
|
|
206
|
+
| **guarded release** | The `release` stall action (`releaseStall`): free a stalled task in ONE immediate transaction that rechecks everything: the caller is in the callers set, the task is an IN_PROGRESS `work` task at the revision the stall saw, owned by the agent row the stall named (same id and pane) that a caller spawned, `autoPermitted`, and no caller has an open human stop. A failed guard writes nothing and returns the stall. Never reopens, closes, spawns or kills. | "auto-release", "unstick" |
|
|
207
|
+
| **urgent event** | In an **all** wait: a dead owned ref, an agent blocked on a dialog or an owned delegate report. Ends the wait early and does not count toward "all". | "interrupt" |
|
|
208
|
+
| **arming** | A producer (`spawn --send`, `send`, `send --interrupt`, `claim --for`) registering what it started in `wait_registrations` for the caller (managed `<ws>/<agent>`, else `pi:<session>`), from real state, never from a shell line. Only an effect that landed arms: not `claim --self`, a slash command, an undelivered or UNKNOWN send. A refused registration is a `warnings` entry; the effect stands. Direct SDK calls do not arm. An agent ref is **owed** only while the agent owns open work or a run it was sent is unsettled; when every task it owned is CLOSED and its last run settled it is **done**, so a later `agent close` (or a lost pane) is not a `dead` event. The engine decides this in one place (`src/wait-owed.ts`) and keeps a DONE mark per owned agent. | "subscribe", "auto-wait" |
|
|
209
|
+
| **wait registration** | `wait_registrations`: per caller, the typed refs it still owes a wait (each existed when registered), and whether a wait is `armed` (work owed) or `waiting` (inside one). `generation` counts the waits begun: a wait that ends compares it, so an older one cannot overwrite a newer. Ending a wait removes only the refs it delivered. An optimisation and observable state, never the only test: the engine also reads the tasks and delegates directly. Not a **cursor**. | "subscription" |
|
|
210
|
+
| **agent observation** | `AgentObservation`: one typed read or watch result of an agent. `agentId` is the registry row id (a number); `incarnation` is pi's process string; `settled` is true only for a ctl wait that ended `settled`. | "snapshot" (that is the legacy `AgentStatusSnapshot`) |
|
|
211
|
+
| **settle replay** | `agent_settles`: one row per (agent, incarnation, runs) already applied, so a **CLOSE block** takes effect once per settled run. | "dedupe table" |
|
|
212
|
+
| **CLOSE block** | The last lines of a pi worker's final message: `CLOSE: task=<id> evidence="..."` then `REPORT:` and the text. Counts only at the very end and for the worker's own task; applied as report plus close in one op group. `mu task close` stays. | "completion marker" |
|
|
213
|
+
| **report / verdict** | The pinned notes of a task: **report** is the closer's account (`kind=report`), **verdict** a judge's (`kind=verdict`). With the **brief** they are never truncated in the default notes view. | "result" |
|
|
214
|
+
| **pinned content** | A task's brief, last report and verdicts: exempt from output caps. Ordinary notes are capped and cut with `more=N`. | "important notes" |
|
|
215
|
+
| **more / cut** | `more=N`: N notes left out of a view; `cut=N`: N records dropped by a size cap. Each names the exact command that fetches the rest. | "truncated" |
|
|
216
|
+
| **message table** | `MESSAGES` in `src/messages.ts`: every error and hint line an agent reads, keyed `<domain>.<what>` and parameterised by facts; `say(key, ...facts)` renders one. The wording is free to change; the key, class, exit code and fields are not. | "error strings", "hint text" |
|
|
217
|
+
| **NextPlan** | The `next` of a result: `{mode, commands}`. `seq` is an ordered sequence, never truncated; `alt` is alternatives. Only state-advancing, executable-as-printed moves, computed only by `computeNext` and finalised once per result by `handle()` (JSON `next`, human `next:` line). Replaces the deleted `nextSteps` / `Next:` block. | "suggestion", "nextSteps", "hint block" |
|
|
218
|
+
| **notice** | A one-line fact beside `next`, not a command: `data.notices` on `mu state` and `mu wait`, from `computeNotices` (today only a due **course check**). Absent when there is none. | "warning" (that is `data.warning`), "hint" |
|
|
219
|
+
| **outcome** (of a verb, for `next`) | What the verb that just ran did that a follow-up depends on (`NextOutcome`: sent, send-unknown, gate-spawned, claimed-for, preview, waited). Declared by the verb with `setNextOutcome`; the only per-verb input to `next`. | "hint" |
|
|
220
|
+
| **auto** | A task authorised for the executor (`mu task auto`: a machine-local `task_auto` row, `enabled`, with a cli key, worktree mode and run ceiling, plus this machine as `dispatch_host`; `--off` keeps the counters). Ready is not permission: `next` acts only on `auto` tasks. | "autopilot" |
|
|
221
|
+
| **run** | One charge against a task's `task_auto.max_runs`: taken once, when the executor reserves a new `auto:<n>` attempt, in the same transaction as the reservation. A replay, a receipt check or an UNKNOWN probe never charges; a definitely-unsent failure keeps its charge. (pi's own `runs` in a receipt or wait is a different counter: settled runs of one pi.) | "try", "retry count" |
|
|
222
|
+
| **recovery (executor)** | What `mu next` does for a worker it dispatched. DEAD (pane gone) is reaped through `deleteAgent`'s id + pane compare-and-swap and its task retried as a new attempt; LIVE with an API-errored last run is retried IN PLACE (same pane, reserved msgId, `expectIncarnation`), never reaped or duplicated; a remote worker's tree is never touched; what cannot be acted on is an `attention` move. Each retry is one **run**. | "restart", "respawn" |
|
|
223
|
+
| **worker ceiling** | `mu next --workers <n>`: the most workers WORKING at once (an IN_PROGRESS task or an attempt in flight). An idle worker whose task is CLOSED does not count. Enforced where a pane would be created; never holds back an in-place retry. | "concurrency", "slots" |
|
|
224
|
+
| **hold** | `mu next --hold`: after dispatching, wait (bounded) for the first event on the in-flight workers; a death or an API error is recovered and the wait goes on, anything else is returned. | "watch mode", "daemon" |
|
|
225
|
+
| **brief (executor)** | `buildTaskBrief`: the prompt of one attempt, built from the task's first `brief` note and latest `report` note, stored verbatim with the reservation (a replay never rebuilds it). Never re-quotes a previous prompt. | "template" |
|
|
226
|
+
| **host profile** | A machine-local template (`shell`, `exec`, `fetch`, `repo`, `max_sessions`) for one remote host, filled by mu and run with `/bin/sh -c` (`exec`, `fetch`) or as the local pane's command (`shell`); mu never connects. Selected by `spawn --host`. Not the **dispatch host**. | "remote config" |
|
|
227
|
+
| **host template** | One field of a host profile (`shell`, `exec`, `fetch`) with `{env}`, `{cmd}`, `{local_sock}`, `{remote_sock}`, `{cwd}` placeholders. Each value is one shell-quoted word (inside your own quotes, the value itself); `{name:sh}` adds a second-shell quoting layer; `{env}` is whitelisted `KEY='value'` words; `{{` `}}` are literal braces; anything else in braces is refused. | "ssh command" |
|
|
228
|
+
| **host channel** | One connection slot of a host (an attached pane, `--exec`, `--fetch` or `host check`) counted against `max_sessions`: one `host_channels` row per holder. **Transient** rides one invocation (reclaimed only when its pid is proven gone and its template's process group, recorded before it runs, is gone too); **attached** rides an agent's registry id and pane: `spawn --host` reserves it before the pane opens, binds it to the new id + pane, and `deleteAgent` frees it (reclaimed otherwise only when the pane is proven dead). A refusal is one line naming the holder. | "session" |
|
|
229
|
+
| **collected HEAD** | A remote worktree's HEAD as last fetched home (`agents.collected_head`, set by `mu agent collect`; a **remote recovery** record keeps it after the row is gone). A remote close needs HEAD equal to the base or this. | "synced commit" |
|
|
230
|
+
| **identity trio** | Three unrelated identities: **spawner** (who started an agent), **dispatch host** (which machine may dispatch a task), **revision** (`workstreamRevision`, a preview fence). Do not substitute one for another. | |
|
|
231
|
+
| **dashboard** | The human-only read-only five-tab view (Overview, the default card grid; Tasks, DAG, Agents, Log) over a workstream row and the attention strip (on every view, drills included), opened by bare `mu` on a TTY. Enter drills a row (task notes, agent scrollback, one log op); `y` copies the row's command; only `a` on an agent runs anything (the mux's attach steps, falling back to the scrollback with the reason; from a client of another tmux server it nests on purpose and says `C-b C-b d`). Replaces the removed card TUI. Every view is live on one poll loop (3.x's tiers: a fast SQL tick, 1 s by default and set with `+`/`-`, and a 10 s slow tick for agent state and scrollback); `r` only nudges. Colours are the 3.x palette as named theme roles (`src/cli/tui/theme.ts`; NO_COLOR turns them off). Its read model is `loadDashboard` (`src/dashboard-data.ts`); its Next line is `computeNext` for the caller, "unavailable" (never "no authorised work") only when that fails. | "home screen" |
|
|
232
|
+
| **attention item** | One line of the dashboard's trouble list (`DashboardSnapshot.attention`), read over every live workstream regardless of filters: `dead` (pane gone), `permission`, `stalled` (one tool over 15 min), `input` (the agent's `idle` flag), `human` (an OPEN `kind=human` task, any recorder), `next_unavailable`, `sync` (the latest ingest's warnings, until an ingest comes back clean). Not **needs attention**, which is the `task wait` stall. | "alert", "notification" |
|
|
233
|
+
|
|
234
|
+
<!-- doc-cli-drift:skip-end -->
|
|
170
235
|
|
|
171
236
|
## Topology
|
|
172
237
|
|
|
@@ -184,9 +249,7 @@ agent names, and file paths are in [reference/naming.md](reference/naming.md).
|
|
|
184
249
|
└──────────────────────────────────────────────────────────────┘
|
|
185
250
|
```
|
|
186
251
|
|
|
187
|
-
Actor resolution reads `$MU_AGENT_NAME
|
|
188
|
-
(adopted panes have only a title). On tmux, read `#{pane_title}`, not
|
|
189
|
-
`#W`: they differ when agents share a window.
|
|
252
|
+
Actor resolution reads `$MU_AGENT_NAME` only; pane titles are not identity.
|
|
190
253
|
|
|
191
254
|
## Agent state values
|
|
192
255
|
|
|
@@ -211,7 +274,7 @@ deprecated, always `spawning`, and never read.
|
|
|
211
274
|
| --- | --- | --- |
|
|
212
275
|
| "subagent" | Means a hidden child in other tools; mu has none | "agent", "delegate", or "hidden subagent" when contrasting |
|
|
213
276
|
| "session" | pi, tmux, and herdr each have one | "workstream", "mux session", "tmux session" |
|
|
214
|
-
| "workspace"
|
|
277
|
+
| "workspace" | The retired word for a worktree; in the mux sense only "herdr workspace", about herdr's CLI | "worktree"; "mux session" |
|
|
215
278
|
| "project" | Means a `.pi/` project root | "workstream" |
|
|
216
279
|
| "context" | LLM, project, and fork context | Be specific: "task context" |
|
|
217
280
|
| "tab" | tmux has windows (herdr calls them tabs) | "window"; `--tab` is the flag |
|
|
@@ -221,7 +284,7 @@ deprecated, always `spawning`, and never read.
|
|
|
221
284
|
| "manager", "instance" | Vague | The specific noun |
|
|
222
285
|
| "service", "broker" | Imply a daemon or middleware; mu has none | Be specific |
|
|
223
286
|
| "plugin" | pi has extensions | "extension" |
|
|
224
|
-
| "checkpoint", "snapshot" | mu has no savepoints | "group" (
|
|
287
|
+
| "checkpoint", "snapshot" | mu has no savepoints | "group" (op group), "backup" (whole-DB copy) |
|
|
225
288
|
| "agent type", "agent definition", "agent template" | mu has no class system or templates; spawn flags and the prompt define an agent | "agent role", or describe the spawn |
|
|
226
289
|
| "worker" (general) | Names the task-claimer role | "agent" |
|
|
227
290
|
| "claimer" | | "owner" |
|
package/docs/guide/README.md
CHANGED
|
@@ -15,14 +15,14 @@ How-to guides:
|
|
|
15
15
|
- [Run a worker on another machine](remote.md)
|
|
16
16
|
- [Recover from a broken state](recovery.md)
|
|
17
17
|
- [Sync between machines](sync.md)
|
|
18
|
-
- [Use the TUI dashboard](tui.md)
|
|
19
18
|
- [Query and script mu](sql.md)
|
|
20
19
|
- [Upgrade mu](upgrade.md)
|
|
21
20
|
- [Choose a multiplexer backend](backends.md)
|
|
21
|
+
- [Run mu with other agent CLIs](other-agent-clis.md)
|
|
22
22
|
- [Clean up](cleanup.md)
|
|
23
23
|
|
|
24
|
-
Agent-facing recipes (orchestrator loop, worker
|
|
25
|
-
|
|
24
|
+
Agent-facing recipes (orchestrator loop, worker, recovery, remote
|
|
25
|
+
workers, findings, move) live
|
|
26
26
|
in [skills/mu/recipes/](../../skills/mu/recipes/). The skill's
|
|
27
27
|
[recipe index](../../skills/mu/SKILL.md#recipes) says when to read each.
|
|
28
28
|
|
package/docs/guide/backends.md
CHANGED
|
@@ -20,6 +20,12 @@ mu picks the backend from the first rule that matches:
|
|
|
20
20
|
4. The first binary that runs, tmux before herdr.
|
|
21
21
|
5. Neither: `NoMultiplexerError`, exit 5.
|
|
22
22
|
|
|
23
|
+
## Worktrees are git worktrees
|
|
24
|
+
|
|
25
|
+
`mu agent spawn --worktree` makes a git worktree. Outside a git repo it
|
|
26
|
+
fails with `WorktreeVcsRequiredError` (exit 4). mu has no jj, sl or
|
|
27
|
+
copy backend.
|
|
28
|
+
|
|
23
29
|
## Know what differs
|
|
24
30
|
|
|
25
31
|
| | tmux | herdr |
|
|
@@ -27,10 +33,10 @@ mu picks the backend from the first rule that matches:
|
|
|
27
33
|
| Workstream | session `mu-<ws>` | workspace labelled `mu-<ws>` |
|
|
28
34
|
| Window | window | tab |
|
|
29
35
|
| Pane id | `%15` | `w1:p1` |
|
|
30
|
-
| Attach | `tmux attach -t mu-<ws>` | `herdr workspace focus <id>`, then `herdr` outside a herdr pane |
|
|
36
|
+
| Attach | `tmux attach -t mu-<ws>` (a spawn prints `attach-session -t mu-<ws>:<agent>`, `-L <socket>` on a private socket, `switch-client` inside tmux) | `herdr workspace focus <id>`, then `herdr` outside a herdr pane |
|
|
31
37
|
| pi agent state | control socket | control socket |
|
|
32
38
|
| Other agents' state | murmur | herdr |
|
|
33
|
-
| Send to non-pi agents |
|
|
39
|
+
| Send to non-pi agents | refused (exit 4) | one atomic `agent prompt` |
|
|
34
40
|
| Spawn | one command | bare pane, then `agent start` |
|
|
35
41
|
| Pane borders, layout | set by mu | left to herdr |
|
|
36
42
|
| Test isolation | `MU_TMUX_SOCKET` | `MU_HERDR_SESSION` |
|
|
@@ -40,8 +46,6 @@ Where each agent's state comes from, per backend:
|
|
|
40
46
|
|
|
41
47
|
## Know herdr's limits
|
|
42
48
|
|
|
43
|
-
- `mu agent kick` works on Linux only. It reads the TTY from
|
|
44
|
-
`/proc/<pid>/fd/0`, which macOS does not have.
|
|
45
49
|
- `mu agent read --lines` cannot recover rows that scrolled off a pane
|
|
46
50
|
on the alternate screen.
|
|
47
51
|
- herdr starts the agent binary itself (`herdr agent start --kind
|
package/docs/guide/cleanup.md
CHANGED
|
@@ -3,30 +3,61 @@
|
|
|
3
3
|
## Close one agent
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
mu agent close worker-1 -w auth
|
|
6
|
+
mu agent close worker-1 -w auth # preview: writes nothing, prints rev=<n>
|
|
7
|
+
mu agent close worker-1 -w auth --if <n> # apply that preview
|
|
7
8
|
```
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
`mu agent stop` is the same verb.
|
|
11
|
+
|
|
12
|
+
Close removes the agent's worktree with it. A worktree with uncommitted
|
|
13
|
+
edits makes close refuse with exit 4 before anything is killed: commit
|
|
14
|
+
them, or pass `--discard` to lose them. Clean commits that are not merged
|
|
15
|
+
are kept on a branch `mu/<workstream>/<agent>-<sha>`, named in the output.
|
|
16
|
+
The row, its tasks and its worktree go only once the pane is proven gone:
|
|
17
|
+
a pane that survives the kill, or one mu cannot ask (the probe fails),
|
|
18
|
+
refuses with exit 4. So does a worktree a process has a file open for
|
|
19
|
+
writing in (a survivor of the pane kill), or one no scan can check (no
|
|
20
|
+
/proc, no lsof): stop it and close again, or preview with `--force`. A
|
|
21
|
+
process with only its cwd or a read-only file there (a shell cd'd in, the
|
|
22
|
+
dashboard) does not block: close names it in a warning and goes on. If you
|
|
23
|
+
know the pane is gone, `--force` also closes past a pane mu cannot ask;
|
|
24
|
+
it never overrides a live pane or uncommitted work.
|
|
25
|
+
See [Stop a worker](stop-a-worker.md).
|
|
14
26
|
|
|
15
27
|
## Tear down a workstream
|
|
16
28
|
|
|
17
29
|
```bash
|
|
18
|
-
mu workstream teardown auth
|
|
19
|
-
mu workstream teardown auth --
|
|
30
|
+
mu workstream teardown auth # preview: counts and rev=<n>; writes nothing
|
|
31
|
+
mu workstream teardown auth --if <n> # apply that preview
|
|
20
32
|
```
|
|
21
33
|
|
|
22
|
-
Teardown kills the tmux session first, then deletes the
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
Teardown is soft. It kills the tmux session first, then deletes the
|
|
35
|
+
agent rows and marks the workstream torn down. It refuses (exit 4) while
|
|
36
|
+
a registered pane is still alive outside the session. A pane that comes
|
|
37
|
+
alive after the kill (moved while it ran) keeps its agent row, and the
|
|
38
|
+
output says `KEPT`; `mu agent close <agent> -w auth` removes the row once
|
|
39
|
+
the pane is gone, and refuses (exit 4) while it lives. `mu doctor` lists
|
|
40
|
+
such rows as `orphaned-agents`. Its tasks, edges,
|
|
41
|
+
and notes stay but every view and `-w auth` verb hides them (exit 3,
|
|
42
|
+
"workstream auth is torn down"). Teardown never removes a worktree: each
|
|
43
|
+
stays on disk and registered, and the output names
|
|
44
|
+
`mu agent close <agent> -w auth` for it (dirty refuses; `--discard` is
|
|
45
|
+
lossy). Running it again is a no-op.
|
|
46
|
+
|
|
47
|
+
`--if <n>` refuses (exit 4) when the workstream changed since the
|
|
48
|
+
preview: a new op, agent, or worktree. Preview again and read it.
|
|
49
|
+
|
|
50
|
+
To reuse the name, run `mu workstream init auth`. It previews what it
|
|
51
|
+
will permanently delete (`will permanently delete torn-down auth: N tasks,
|
|
52
|
+
M notes; rev=<n>`); `mu workstream init auth --if <n>` deletes the old
|
|
53
|
+
rows and creates the new workstream. It refuses (exit 4) while the old
|
|
54
|
+
tmux session is alive, and when the mux cannot be asked.
|
|
55
|
+
|
|
56
|
+
To sweep every workstream that has no tasks, agents, or worktrees:
|
|
26
57
|
|
|
27
58
|
```bash
|
|
28
|
-
mu workstream teardown --empty
|
|
29
|
-
mu workstream teardown --empty --
|
|
59
|
+
mu workstream teardown --empty # preview: the list and one rev=<n>
|
|
60
|
+
mu workstream teardown --empty --if <n>
|
|
30
61
|
```
|
|
31
62
|
|
|
32
63
|
The sweep skips `scratch`, whose idle session is kept open on purpose.
|
|
@@ -34,26 +65,24 @@ It never takes a `mu-*` session that has no workstream row in this DB:
|
|
|
34
65
|
it may be a live workstream from another DB. The output names
|
|
35
66
|
such sessions; tear one down by name once you know it is unused.
|
|
36
67
|
|
|
37
|
-
##
|
|
38
|
-
|
|
39
|
-
Teardown writes tombstone ops, so the ops log keeps everything. You do
|
|
40
|
-
not need a backup first.
|
|
68
|
+
## Find a past teardown
|
|
41
69
|
|
|
42
70
|
```bash
|
|
43
71
|
mu workstream list --torn-down
|
|
44
|
-
mu
|
|
72
|
+
mu log --group 7a40e6cc
|
|
45
73
|
```
|
|
46
74
|
|
|
47
|
-
The list shows
|
|
48
|
-
|
|
49
|
-
means the name is in use again
|
|
50
|
-
|
|
75
|
+
The list shows every torn-down workstream (`rows: kept`), newest first,
|
|
76
|
+
and the older teardowns an earlier mu wrote as deletes (`rows: deleted`;
|
|
77
|
+
`← recreated since` means the name is in use again). A `--empty` sweep
|
|
78
|
+
writes one op group per workstream.
|
|
51
79
|
|
|
52
80
|
## Keep mu.db small
|
|
53
81
|
|
|
54
|
-
Teardown keeps
|
|
55
|
-
`mu.db`. `mu doctor` names the largest
|
|
56
|
-
are worth reclaiming.
|
|
82
|
+
Teardown keeps its rows and history, and that is most of
|
|
83
|
+
`mu.db`. `mu doctor` names the largest workstreams that earlier teardowns
|
|
84
|
+
deleted once they are worth reclaiming. A soft-torn-down workstream is
|
|
85
|
+
reclaimed by reusing its name (`init --if`), then tearing down again.
|
|
57
86
|
|
|
58
87
|
```bash
|
|
59
88
|
mu db compact # dry run: redundant note tombstones
|
|
@@ -63,7 +92,7 @@ mu db forget hail-smoke reltest --yes
|
|
|
63
92
|
```
|
|
64
93
|
|
|
65
94
|
`compact` changes nothing you can see. `forget` deletes those
|
|
66
|
-
workstreams' history for good
|
|
95
|
+
workstreams' history for good.
|
|
67
96
|
Both write a backup next to the DB first (`mu.db.pre-forget-<time>`),
|
|
68
97
|
which is the only way back, and run the drift check after. Only this
|
|
69
98
|
machine's DB shrinks; sync segments are untouched.
|
|
@@ -78,21 +107,20 @@ The `housekeeping` section of `mu doctor` lists two kinds:
|
|
|
78
107
|
| abandoned | unclosed tasks, idle 60 days or more | read the open tasks first |
|
|
79
108
|
|
|
80
109
|
It skips your current workstream, `scratch`, and any workstream with a
|
|
81
|
-
live agent or a
|
|
110
|
+
live agent or a worktree. Teardown hides the plan, not the code: no
|
|
82
111
|
commit or checkout is touched.
|
|
83
112
|
|
|
84
113
|
## Free disk space
|
|
85
114
|
|
|
86
115
|
```bash
|
|
87
|
-
mu doctor --disk
|
|
88
|
-
mu
|
|
89
|
-
mu
|
|
116
|
+
mu doctor --disk # bytes per worktree
|
|
117
|
+
mu doctor # the disk section lists directories with no DB row
|
|
118
|
+
mu agent close worker-1 -w auth --discard # preview deleting one worktree
|
|
119
|
+
mu agent close worker-1 -w auth --discard --if <n> # apply it
|
|
90
120
|
```
|
|
91
121
|
|
|
92
122
|
## Keep a copy of the graph
|
|
93
123
|
|
|
94
124
|
```bash
|
|
95
125
|
mu db backup /tmp/mu-backup.db # VACUUM INTO; never overwrites
|
|
96
|
-
mu task list -w auth --json
|
|
97
|
-
mu task notes design -w auth --json
|
|
98
126
|
```
|