@mu-crew/mu 3.13.3 → 4.1.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-4ULY3ZKO.js +4482 -0
- package/dist/chunk-4ULY3ZKO.js.map +1 -0
- package/dist/chunk-7M634JMD.js +375 -0
- package/dist/chunk-7M634JMD.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-SS7NQSSZ.js +3660 -0
- package/dist/chunk-SS7NQSSZ.js.map +1 -0
- package/dist/chunk-UCZPJX7K.js +14253 -0
- package/dist/chunk-UCZPJX7K.js.map +1 -0
- package/dist/{cli-CKOMHBXV.js → cli-TV3N47AZ.js} +7317 -4593
- package/dist/cli-TV3N47AZ.js.map +1 -0
- package/dist/cli.js +2 -3
- package/dist/cli.js.map +1 -1
- package/dist/errors-GRONKWFS.js +65 -0
- package/dist/extension/mu-pi.js +1632 -837
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +4067 -2561
- package/dist/index.js +614 -297
- package/dist/index.js.map +1 -1
- package/dist/tui-FUBQ326D.js +1848 -0
- package/dist/tui-FUBQ326D.js.map +1 -0
- package/docs/ARCHITECTURE.md +118 -66
- package/docs/VOCABULARY.md +113 -49
- package/docs/guide/README.md +3 -3
- package/docs/guide/backends.md +8 -4
- package/docs/guide/cleanup.md +69 -33
- package/docs/guide/delegate.md +149 -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 +122 -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 +24 -32
- package/docs/reference/naming.md +14 -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 +17 -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-GRONKWFS.js.map} +0 -0
|
@@ -8,19 +8,20 @@ You need Node.js, the pi coding agent, tmux 3.0
|
|
|
8
8
|
or later, and a git repository to work in. Run every command from
|
|
9
9
|
inside a tmux session, in the root of that repository.
|
|
10
10
|
|
|
11
|
-
## Install mu and
|
|
11
|
+
## Install mu and the pi package
|
|
12
12
|
|
|
13
|
-
First, install mu and
|
|
13
|
+
First, install mu and install its pi package:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
npm i -g @mu-crew/mu
|
|
17
|
-
|
|
17
|
+
pi install npm:@mu-crew/mu
|
|
18
18
|
mu doctor
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
`
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
`pi install` loads the mu extension, skill, and recipe prompts as one
|
|
22
|
+
package. Once a pi agent is running, the "mu ext" and `ctl` rows of
|
|
23
|
+
`mu doctor` report the live extension; before that, "mu ext" says
|
|
24
|
+
`unknown`. If pi was already running, restart it so it loads the package.
|
|
24
25
|
|
|
25
26
|
## Create a workstream
|
|
26
27
|
|
|
@@ -33,13 +34,11 @@ mu workstream init auth
|
|
|
33
34
|
|
|
34
35
|
```
|
|
35
36
|
Created workstream auth (mux session mu-auth)
|
|
36
|
-
|
|
37
|
-
Attach the session : tmux attach -t mu-auth
|
|
38
|
-
...
|
|
37
|
+
attach: tmux attach -t mu-auth
|
|
39
38
|
```
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
When a verb leaves a move to make (a wait a send owes, the `--if` apply
|
|
41
|
+
of a preview), it ends with a `next:` line you can run as printed.
|
|
43
42
|
|
|
44
43
|
## Plan two tasks
|
|
45
44
|
|
|
@@ -53,11 +52,7 @@ mu task next -w auth
|
|
|
53
52
|
```
|
|
54
53
|
|
|
55
54
|
```
|
|
56
|
-
|
|
57
|
-
│ name │ status │ title │ impact │ effort │ ROI │ owner │
|
|
58
|
-
├────────┼────────┼────────────────────────┼────────┼────────┼──────┼───────┤
|
|
59
|
-
│ design │ OPEN │ Design the auth module │ 80 │ 2 │ 40.0 │ — │
|
|
60
|
-
└────────┴────────┴────────────────────────┴────────┴────────┴──────┴───────┘
|
|
55
|
+
task design OPEN impact=80 effort_days=2 Design the auth module
|
|
61
56
|
```
|
|
62
57
|
|
|
63
58
|
Only `design` is ready. `build` appears when `design` closes.
|
|
@@ -67,12 +62,12 @@ Only `design` is ready. `build` appears when `design` closes.
|
|
|
67
62
|
Spawn a pi agent with its own git worktree:
|
|
68
63
|
|
|
69
64
|
```bash
|
|
70
|
-
mu agent spawn worker-1 -w auth --
|
|
65
|
+
mu agent spawn worker-1 -w auth --worktree
|
|
71
66
|
```
|
|
72
67
|
|
|
73
68
|
```
|
|
74
|
-
Spawned worker-1 (pi) in window worker-1 of mu-auth, pane %15 with
|
|
75
|
-
|
|
69
|
+
Spawned worker-1 (pi) in window worker-1 of mu-auth, pane %15 with its own worktree
|
|
70
|
+
cwd: ~/.local/state/mu-next/worktrees/auth/worker-1
|
|
76
71
|
```
|
|
77
72
|
|
|
78
73
|
The worker runs in a new window of the `mu-auth` session. To watch
|
|
@@ -81,7 +76,7 @@ it, run `tmux attach -t mu-auth`. Detach with `Ctrl+b d`.
|
|
|
81
76
|
## Claim the task for the worker
|
|
82
77
|
|
|
83
78
|
Assign the task before you send any text. The claim is what
|
|
84
|
-
`mu
|
|
79
|
+
`mu wait` watches.
|
|
85
80
|
|
|
86
81
|
```bash
|
|
87
82
|
mu task note design -w auth 'SCOPE: write docs/auth.md with the token design'
|
|
@@ -108,29 +103,26 @@ and closes the task.
|
|
|
108
103
|
## Wait for the task to close
|
|
109
104
|
|
|
110
105
|
```bash
|
|
111
|
-
mu
|
|
106
|
+
mu wait task:design -w auth
|
|
112
107
|
```
|
|
113
108
|
|
|
114
109
|
```
|
|
115
|
-
auth/design
|
|
116
|
-
any-of 1 reached CLOSED in 41094ms
|
|
117
|
-
Next:
|
|
118
|
-
Cherry-pick worker-1's commit onto your branch : git cherry-pick 26278f1...
|
|
119
|
-
Refresh worker-1's workspace onto current main : mu workspace refresh worker-1 -w auth
|
|
110
|
+
{"ok":true,"data":{"firing":{"kind":"closed","ref":"task:auth/design"},...},"next":null}
|
|
120
111
|
```
|
|
121
112
|
|
|
122
113
|
The exit code tells you what happened:
|
|
123
114
|
|
|
124
115
|
| Exit | Meaning | Next move |
|
|
125
116
|
| ---- | ------- | --------- |
|
|
126
|
-
| `0` | the task closed | merge the work |
|
|
127
|
-
| `5` | `--timeout` expired (default 600 s) | wait again |
|
|
117
|
+
| `0` | the task closed (`firing.kind` `closed`), or the heartbeat cap passed (`heartbeat`, `timedOut: true`; default 1500 s) | merge the work, or run `data.resume` to keep waiting |
|
|
128
118
|
| `6` | the worker's pane died and the task went back to `OPEN` | spawn and claim again |
|
|
129
|
-
| `7` | the worker sat in `needs_input` for `--stuck-after` seconds (120, or 5 for a pi worker read over its control socket) |
|
|
119
|
+
| `7` | the worker sat in `needs_input` for `--stuck-after` seconds (120, or 5 for a pi worker read over its control socket) | read it (`mu agent read worker-1 -w auth`), then answer it |
|
|
130
120
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
prints a warning and the wait
|
|
121
|
+
To keep waiting, run `data.resume` as printed (`mu wait --resume <id> -w auth`):
|
|
122
|
+
it replays the stored wait whole, and refuses any other flag. With
|
|
123
|
+
`--on-stall warn`, a stalled worker only prints a warning and the wait
|
|
124
|
+
keeps running. `--on-stall steer|release` act on a worker you spawned;
|
|
125
|
+
see [dispatch](dispatch.md).
|
|
134
126
|
|
|
135
127
|
A pi worker that ends its turn while it still owns an `IN_PROGRESS`
|
|
136
128
|
task gets one reminder to close it or say why not, so exit 7 mostly
|
|
@@ -138,8 +130,8 @@ means it is blocked or asking something.
|
|
|
138
130
|
|
|
139
131
|
## Merge the commit
|
|
140
132
|
|
|
141
|
-
|
|
142
|
-
tests on the result:
|
|
133
|
+
Inspect the worker's commits (`git -C <worktree> log --oneline`),
|
|
134
|
+
cherry-pick what you want, then run your tests on the result:
|
|
143
135
|
|
|
144
136
|
```bash
|
|
145
137
|
git cherry-pick 26278f1
|
|
@@ -149,11 +141,12 @@ Before the next task, rebase the worker's worktree onto the new main.
|
|
|
149
141
|
The worker keeps its pi context:
|
|
150
142
|
|
|
151
143
|
```bash
|
|
152
|
-
mu
|
|
144
|
+
cwd=$(mu agent list -w auth --json | jq -r '.agents[] | select(.name == "worker-1") | .cwd')
|
|
145
|
+
git -C "$cwd" fetch && git -C "$cwd" rebase origin/HEAD
|
|
153
146
|
```
|
|
154
147
|
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
In a repository without a remote, rebase onto local `main`. On a conflict,
|
|
149
|
+
run `git -C "$cwd" rebase --abort` and resolve it by hand.
|
|
157
150
|
|
|
158
151
|
## Check the graph
|
|
159
152
|
|
|
@@ -166,20 +159,20 @@ claim, send, wait, and merge steps.
|
|
|
166
159
|
|
|
167
160
|
## Close the worker
|
|
168
161
|
|
|
169
|
-
When you are done,
|
|
162
|
+
When you are done, close the agent:
|
|
170
163
|
|
|
171
164
|
```bash
|
|
172
|
-
mu
|
|
173
|
-
mu agent close worker-1 -w auth
|
|
165
|
+
mu agent close worker-1 -w auth # preview; prints the --if command
|
|
166
|
+
mu agent close worker-1 -w auth --if <n> # close it
|
|
174
167
|
```
|
|
175
168
|
|
|
176
|
-
|
|
177
|
-
|
|
169
|
+
Close removes the worktree. It refuses while the worktree has uncommitted
|
|
170
|
+
edits, which protects work you have not committed. If the worker made
|
|
171
|
+
commits you have not merged, close keeps them on a branch
|
|
172
|
+
`mu/auth/worker-1-<sha>` and prints its name.
|
|
178
173
|
|
|
179
174
|
## Next steps
|
|
180
175
|
|
|
181
176
|
- [Dispatch work to a worker](dispatch.md) covers more than one
|
|
182
177
|
worker and the `--fresh`, `--interrupt`, `--steer`, and plain send choices.
|
|
183
|
-
- [Use the TUI dashboard](tui.md): run bare `mu` to see every
|
|
184
|
-
workstream at once.
|
|
185
178
|
- [Clean up](cleanup.md) when the workstream is finished.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# How to run mu with other agent CLIs
|
|
2
|
+
|
|
3
|
+
mu is built around pi, but codex, cursor-agent and claude can be its workers
|
|
4
|
+
or its orchestrator. They get less: they have no control socket, so mu
|
|
5
|
+
cannot hand them a prompt on tmux, abort them, or read their final text, and
|
|
6
|
+
nothing replaces `mu_delegate`. Tested with codex 0.164 and cursor-agent
|
|
7
|
+
2026.10.22 on tmux ([report](../eval/harnesses.md)).
|
|
8
|
+
|
|
9
|
+
## Pin the mu the harness runs
|
|
10
|
+
|
|
11
|
+
Check this first. codex and cursor-agent pass mu's env (`MU_*`, `PATH`) on
|
|
12
|
+
to their shell tool, but they run each command through your interactive
|
|
13
|
+
shell rc, and the rc wins. If `~/.zshrc` puts another `mu` first on `PATH`,
|
|
14
|
+
or exports `MU_SYNC_DIR` / `MU_DB_PATH`, the harness uses that `mu` and
|
|
15
|
+
that DB. codex's `shell_environment_policy.set` does not help: it is applied
|
|
16
|
+
before the rc runs. Pin it for each harness:
|
|
17
|
+
|
|
18
|
+
- codex: `codex --disable shell_snapshot` (as `MU_CODEX_COMMAND`, or in a
|
|
19
|
+
wrapper).
|
|
20
|
+
- cursor-agent: `ZDOTDIR=<a dir with an empty .zshrc> cursor-agent`.
|
|
21
|
+
- Or keep the rc file from adding `mu` and `MU_*` at all.
|
|
22
|
+
|
|
23
|
+
A wrapper that sets the env itself (`MU_SYNC_DIR=`, `MU_DB_PATH`,
|
|
24
|
+
`MU_STATE_DIR`, then `exec mu "$@"`) holds its env under any rc. Name it
|
|
25
|
+
something the rc does not shadow (`mun`). The skill and briefs still say
|
|
26
|
+
`mu`, so pin `mu` as well.
|
|
27
|
+
|
|
28
|
+
Then check from inside the harness:
|
|
29
|
+
`command -v mu; mu --version; echo "<$MU_SYNC_DIR>"`.
|
|
30
|
+
|
|
31
|
+
## Run one as a worker
|
|
32
|
+
|
|
33
|
+
On tmux, mu cannot type into a non-pi pane, so `spawn --send` and `agent
|
|
34
|
+
send` exit 4. Put the brief in a task note, start the agent with the prompt
|
|
35
|
+
as its argument, then claim:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
mu task note build -w auth - <<'EOF'
|
|
39
|
+
<brief, ending with: mu task close build -w auth --evidence "...">
|
|
40
|
+
EOF
|
|
41
|
+
export MU_CODEX_COMMAND="codex --disable shell_snapshot --dangerously-bypass-approvals-and-sandbox"
|
|
42
|
+
mu agent spawn worker-1 -w auth --cli codex --worktree \
|
|
43
|
+
--command "$MU_CODEX_COMMAND 'Do task build. Run: mu task notes build -w auth'"
|
|
44
|
+
mu task claim build -w auth --for worker-1
|
|
45
|
+
mu wait task:auth/build
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
On herdr, `--send` and `agent send` work (herdr's `agent prompt`, see
|
|
49
|
+
[dispatch](dispatch.md#non-pi-agents)), but herdr refuses `--command`.
|
|
50
|
+
|
|
51
|
+
- **Dialogs.** A new folder makes codex ask "Trust this folder?", and
|
|
52
|
+
unreviewed hooks ask again. On tmux mu cannot answer them. Pre-trust the
|
|
53
|
+
repo (`-c 'projects."<repo>".trust_level="trusted"'`; worktrees inherit the
|
|
54
|
+
root's trust), or attach and press the key.
|
|
55
|
+
- **State** comes from murmur on tmux, from herdr on herdr. Wire murmur to
|
|
56
|
+
the harness's stop hook (cursor: `.cursor/hooks.json` `stop`, see murmur's
|
|
57
|
+
`docs/setup.md`). Without it the agent is `unknown` throughout. With it,
|
|
58
|
+
you see `needs_input` when a turn ends, but never `busy`.
|
|
59
|
+
- **codex: use its `Stop` hook, not `notify`.** codex runs a hidden turn to
|
|
60
|
+
title each new thread, and `notify` reports that turn as finished about 2 s
|
|
61
|
+
into the worker's first turn. murmur then reads `done`, and `--stuck-after`
|
|
62
|
+
reports the running worker as stalled (3.x does the same). `Stop` fires only
|
|
63
|
+
for real turns. Drop `notify` from `~/.codex/config.toml` and put this in
|
|
64
|
+
`~/.codex/hooks.json`:
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{"hooks": {"Stop": [{"hooks": [{"type": "command",
|
|
68
|
+
"command": "murmur notify --source codex --event-type agent-turn-complete"}]}]}}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Keep `--event-type`: without it murmur reads a `Stop` payload as `blocked`.
|
|
72
|
+
codex asks you to trust a new hook once (`/hooks`), and `--disable hooks`
|
|
73
|
+
turns it off.
|
|
74
|
+
- **Wait on the task, not the agent.** `mu wait task:<ws>/<id>` fires when the
|
|
75
|
+
worker closes it. `mu wait agent:<w>` fires only on busy → not busy, as in
|
|
76
|
+
3.x: an agent already idle, or one that goes from `unknown` to
|
|
77
|
+
`needs_input`, does not count. murmur's notify path never reports `busy`,
|
|
78
|
+
so on tmux that wait runs to its timeout. `--until-text <re>` matches the
|
|
79
|
+
pane's tail instead.
|
|
80
|
+
- **Stalls** mean the owner has read `needs_input` for `--stuck-after` while
|
|
81
|
+
its task is still open. Read the pane (`mu agent read`) before you act.
|
|
82
|
+
- **No abort, no CLOSE block.** Stop it with `mu agent close` (preview, then
|
|
83
|
+
`--if`). The brief must end with the worker's own `mu task close`.
|
|
84
|
+
|
|
85
|
+
## Run one as the orchestrator
|
|
86
|
+
|
|
87
|
+
Install the skill (`npx skills add mu-crew/mu`) and point the harness at it.
|
|
88
|
+
It dispatches pi workers as usual (`spawn --worktree --task --send -`).
|
|
89
|
+
|
|
90
|
+
- **Wait on refs.** A bare `mu wait` owns only what a pi session or a managed
|
|
91
|
+
pane started. From codex or cursor in a plain shell it is a usage error.
|
|
92
|
+
Name what you started: `mu wait task:<ws>/<a> task:<ws>/<b>`.
|
|
93
|
+
- **Delegate through `scratch`**, since there is no `mu_delegate`. Spawn a pi
|
|
94
|
+
agent there (the first spawn creates the workstream; `init` refuses it),
|
|
95
|
+
`send --fresh --json -`, then wait on the exact ref the send prints. See
|
|
96
|
+
[tasks-or-calls](../../skills/mu/recipes/tasks-or-calls.md).
|
|
97
|
+
|
|
98
|
+
## With no multiplexer
|
|
99
|
+
|
|
100
|
+
Task, DAG, `sql`, `log` and `mu wait task:` verbs work. `workstream init`,
|
|
101
|
+
`state`, and the agent verbs exit 5 and name the install. The child-pi
|
|
102
|
+
delegate (`mu delegates run`) needs pi.
|
package/docs/guide/recovery.md
CHANGED
|
@@ -8,33 +8,25 @@ read the same rules in
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
mu doctor # exit 0 healthy (WARN rows too), 5 on drift or a FAIL row
|
|
11
|
-
mu doctor --deep # rebuild the ops log and diff every field
|
|
12
|
-
mu doctor --disk # add per-
|
|
11
|
+
mu doctor --deep # rebuild the ops log and diff every field; PRAGMA quick_check on the DB
|
|
12
|
+
mu doctor --disk # add per-worktree byte usage
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## An agent's pane died
|
|
16
16
|
|
|
17
|
-
Run `mu agent list` or `mu state
|
|
17
|
+
Run `mu agent list` or `mu state -w <ws>`. Each run reconciles the registry
|
|
18
18
|
with the multiplexer:
|
|
19
19
|
|
|
20
20
|
- An agent row whose pane is gone is a ghost. mu deletes the row, and
|
|
21
|
-
its `IN_PROGRESS` task returns to `OPEN`. A `mu
|
|
21
|
+
its `IN_PROGRESS` task returns to `OPEN`. A `mu wait` on that
|
|
22
22
|
task exits 6.
|
|
23
23
|
- A pane in the session that runs an agent CLI but has no row is an
|
|
24
|
-
orphan. mu lists it
|
|
24
|
+
orphan. mu lists it and does not register it. Close the pane with
|
|
25
|
+
tmux or herdr, or ignore it.
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
mu agent adopt %15 -w auth
|
|
30
|
-
mu agent adopt %15 -w auth --name investigator
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
On herdr, pass its pane id instead (`mu agent adopt w1:p2 -w auth`).
|
|
34
|
-
|
|
35
|
-
The pane title becomes the agent name. The pane must be in the
|
|
36
|
-
`mu-<workstream>` session. An adopted pi has no control socket until
|
|
37
|
-
you restart it with the `MU_CTL_SOCK` path that `adopt` prints.
|
|
27
|
+
A `mu agent spawn --task` after a dead worker, with the same attempt
|
|
28
|
+
key but a new request, is refused (`already ran with a different
|
|
29
|
+
request`): pass `--attempt <new key>`.
|
|
38
30
|
|
|
39
31
|
## A pi agent shows `ctl missing` or `ctl refused`
|
|
40
32
|
|
|
@@ -43,19 +35,19 @@ back to pasting.
|
|
|
43
35
|
|
|
44
36
|
| State | Means | Fix |
|
|
45
37
|
| ----- | ----- | --- |
|
|
46
|
-
| `ctl missing` | no socket: the extension is not loaded, or a new pi waits at its trust prompt | answer the [trust prompt](#a-new-pi-agent-shows-ctl-missing), or run `
|
|
38
|
+
| `ctl missing` | no socket: the extension is not loaded, or a new pi waits at its trust prompt | answer the [trust prompt](#a-new-pi-agent-shows-ctl-missing), or run `pi install npm:@mu-crew/mu`, then respawn the agent |
|
|
47
39
|
| `ctl refused` | the socket exists but does not answer | respawn the agent; for a remote agent, check the ssh forward |
|
|
48
40
|
| `extension X older than installed Y` or `extension lacks ops` | pi loaded an older mu build | send `/reload`, or respawn |
|
|
49
41
|
|
|
50
42
|
To send `/reload` without attaching:
|
|
51
43
|
|
|
52
44
|
```bash
|
|
53
|
-
mu agent send worker-1 -w auth '/reload'
|
|
54
|
-
mu agent send worker-1 -w auth '/reload' --via mux # older: type it into the pane
|
|
45
|
+
mu agent send worker-1 -w auth '/reload' # extension serves op command
|
|
55
46
|
```
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
An extension without op command cannot be reloaded by mu: respawn the
|
|
49
|
+
agent. `/reload` keeps the pi session. A `send --fresh` or `abort`
|
|
50
|
+
against an outdated extension fails with exit 4 and prints the fix.
|
|
59
51
|
|
|
60
52
|
## A new pi agent shows `ctl missing`
|
|
61
53
|
|
|
@@ -66,7 +58,7 @@ launched through a wrapper whose name is not `pi` or `pi-meta` shows
|
|
|
66
58
|
`needs_input` instead. Run
|
|
67
59
|
`/trust` in the pane once, or spawn with
|
|
68
60
|
`--command 'pi --approve'`. `--approve` trusts every directory,
|
|
69
|
-
including
|
|
61
|
+
including worktrees, so use it only on your own code.
|
|
70
62
|
|
|
71
63
|
Claude asks the same on an untrusted folder, with "No, exit" as the
|
|
72
64
|
default. Spawn warns and skips `--send`: attach the pane, answer it, then
|
|
@@ -80,22 +72,10 @@ needs restarting.
|
|
|
80
72
|
|
|
81
73
|
## You ran the wrong command
|
|
82
74
|
|
|
83
|
-
Every action is one group of ops.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
mu undo # list recent groups
|
|
88
|
-
mu undo 6380dd3d # preview
|
|
89
|
-
mu undo 6380dd3d --yes # apply
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
- Any unique prefix of a group id works.
|
|
93
|
-
- The undo is its own group, so undoing it again is redo.
|
|
94
|
-
- If later work changed the same fields, undo exits 4 and names the
|
|
95
|
-
conflict. A later write to `updated_at` alone, such as `mu task note`,
|
|
96
|
-
does not count. `--force --yes` overrides and discards the newer work.
|
|
97
|
-
- Undo restores rows only. Killed panes and freed workspace
|
|
98
|
-
directories do not come back.
|
|
75
|
+
Every action is one group of ops. `mu log` shows the group ids, and
|
|
76
|
+
`mu log --group <prefix>` shows what one action wrote. Any unique prefix
|
|
77
|
+
of a group id works. mu has no general undo: fix a wrong change with the
|
|
78
|
+
inverse verb.
|
|
99
79
|
|
|
100
80
|
## `mu doctor` reports drift
|
|
101
81
|
|
|
@@ -106,7 +86,7 @@ a write, the live table holds real work that a rebuild would discard.
|
|
|
106
86
|
```bash
|
|
107
87
|
mu db backup /tmp/mu-drift-evidence.db # 1. keep the evidence
|
|
108
88
|
mu rebuild /tmp/mu-rebuilt.db # 2. replay the log into a new file
|
|
109
|
-
MU_DB_PATH=/tmp/mu-rebuilt.db mu
|
|
89
|
+
MU_DB_PATH=/tmp/mu-rebuilt.db mu db query "SELECT local_id, title FROM tasks" # 3. compare
|
|
110
90
|
```
|
|
111
91
|
|
|
112
92
|
Decide which side is right, then report the drift as a bug with the
|
|
@@ -117,22 +97,23 @@ command.
|
|
|
117
97
|
|
|
118
98
|
| Row | Means |
|
|
119
99
|
| --- | ----- |
|
|
120
|
-
| `ws-rows` | a
|
|
121
|
-
| `ws-
|
|
122
|
-
| `ws-empty` | a workstream directory with no
|
|
100
|
+
| `ws-rows` | a worktree row whose directory is gone; a reused name trips over it. `mu agent close <agent>` forgets it |
|
|
101
|
+
| `ws-staging` | a `--worktree` spawn killed (SIGKILL, crash) before its pane: its placeholder row and maybe a half-made worktree. The next `mu agent spawn` in that workstream removes them |
|
|
102
|
+
| `ws-empty` | a workstream directory with no worktrees |
|
|
123
103
|
| `db-copies` | stray `mu.db*` files that nothing reads, including the `pre-compact` / `pre-forget` backups |
|
|
124
104
|
| `exports` | output left by the removed export verb |
|
|
125
105
|
| `locks` | lock directories older than one hour, from a spawn or flush that died |
|
|
126
106
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
107
|
+
The worktree registry outlives the agent, so a worktree whose agent was
|
|
108
|
+
reaped is still closed by name: `mu agent close <agent>` keeps unmerged
|
|
109
|
+
commits on a branch and refuses dirty work (`--discard` drops it). A
|
|
110
|
+
directory mu never registered has no row: inspect it, then remove it with
|
|
111
|
+
`git worktree remove --force <path>` from the project root, or `rm -rf
|
|
112
|
+
<path>` when it is not a worktree.
|
|
132
113
|
|
|
133
114
|
## Rename a workstream
|
|
134
115
|
|
|
135
|
-
There is no rename verb, and `mu
|
|
116
|
+
There is no rename verb, and `mu db query` refuses to change
|
|
136
117
|
`workstreams.name`. The name is part of the key that every op is filed
|
|
137
118
|
under, so a raw rename leaves the ops log on the old name: `mu doctor`
|
|
138
119
|
reports drift, and sync or `mu rebuild` brings the old name back.
|
|
@@ -142,7 +123,7 @@ Re-create the workstream instead:
|
|
|
142
123
|
mu db backup /tmp/mu-before-rename.db
|
|
143
124
|
mu workstream init auth-refactor
|
|
144
125
|
# re-add the tasks you still need, with -w auth-refactor
|
|
145
|
-
mu workstream teardown auth
|
|
126
|
+
mu workstream teardown auth # preview, then --if <rev>
|
|
146
127
|
```
|
|
147
128
|
|
|
148
129
|
Names start with a lowercase letter, use letters, digits, `_`, or
|
package/docs/guide/remote.md
CHANGED
|
@@ -1,74 +1,151 @@
|
|
|
1
1
|
# How to run a worker on another machine
|
|
2
2
|
|
|
3
|
-
The pane is local and the pi process is remote. mu
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The pane is local and the pi process is remote. mu never connects and
|
|
4
|
+
knows no ssh flags: a host profile holds your own command templates, and
|
|
5
|
+
`mu agent spawn --host` fills them. The full recipe, with collecting and
|
|
6
|
+
the traps, is in
|
|
7
7
|
[skills/mu/recipes/remote-workers.md](../../skills/mu/recipes/remote-workers.md).
|
|
8
8
|
Read it before your first remote spawn.
|
|
9
9
|
|
|
10
10
|
## Prepare the host
|
|
11
11
|
|
|
12
|
-
On the
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
1. On the host, install pi and the mu package:
|
|
13
|
+
`pi install npm:@mu-crew/mu`. The host needs no mu DB: a remote worker
|
|
14
|
+
cannot run `mu task` verbs. It ends with a `CLOSE:` block. `mu wait`
|
|
15
|
+
applies it when it sees the run settle; `mu agent wait` does not. Re-run
|
|
16
|
+
the evidence first, or close the task yourself.
|
|
16
17
|
2. Allow unix-socket forwards in the host's sshd:
|
|
17
18
|
`AllowStreamLocalForwarding yes`.
|
|
18
|
-
3.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
ssh dev 'git -C ~/repo worktree add ~/ws/worker-1'
|
|
23
|
-
```
|
|
19
|
+
3. Have a git repo there for `--worktree` to branch from. One profile serves
|
|
20
|
+
every repo on the host: `--max-sessions` caps the machine, so never add
|
|
21
|
+
the same machine twice.
|
|
24
22
|
|
|
25
23
|
Use one orchestrator DB on your machine. Do not run a second mu on the
|
|
26
|
-
host for the same work: task ownership points into your local
|
|
27
|
-
|
|
24
|
+
host for the same work: task ownership points into your local `agents`
|
|
25
|
+
table.
|
|
28
26
|
|
|
29
|
-
##
|
|
27
|
+
## Add a profile and check it
|
|
30
28
|
|
|
31
29
|
```bash
|
|
32
|
-
|
|
33
|
-
mu
|
|
34
|
-
|
|
30
|
+
mu host init dev --ssh # prints a starter `mu host add`; runs nothing
|
|
31
|
+
mu host add dev --shell '<pane cmd>' --exec '<run cmd>' --fetch '<fetch cmd>' --max-sessions 1
|
|
32
|
+
mu host check dev --root '~/repo' # host answers, repo, pi, mu extension
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
## Spawn the agent
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
the local end of the forward.
|
|
43
|
-
- `MU_REMOTE_ENV` sets the agent's identity inside the remote shell.
|
|
44
|
-
tmux `-e` variables do not cross the ssh hop.
|
|
45
|
-
- `$SHELL -ilc` starts pi in an interactive login shell, so the
|
|
46
|
-
remote `~/.zshrc` or `~/.bashrc` loads PATH and provider keys.
|
|
47
|
-
Without it, ssh's non-interactive shell skips them and pi can die at
|
|
48
|
-
startup.
|
|
49
|
-
- `pi --approve` skips pi's project-trust prompt. It trusts whatever
|
|
50
|
-
directory the pane starts in, so use it only on your own code.
|
|
37
|
+
```bash
|
|
38
|
+
mu agent spawn worker-1 -w auth --host dev --worktree --root '~/repo' --task build --send 'Read: mu task notes build -w auth'
|
|
39
|
+
```
|
|
51
40
|
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
- The pane runs the profile's `--shell` template, filled with the remote
|
|
42
|
+
identity (`MU_MANAGED_AGENT`, `MU_AGENT_NAME`, `MU_WORKSTREAM`,
|
|
43
|
+
`MU_CTL_SOCK`, `MU_REMOTE`, never your DB, state or sync dir, which are unset in the pane), your
|
|
44
|
+
`--command` (default `pi`), the local and remote socket paths and the
|
|
45
|
+
remote cwd. The template starts the remote pi and forwards its control
|
|
46
|
+
socket to the local derived path.
|
|
47
|
+
- `--worktree` makes a detached `git worktree add` in the remote repo
|
|
48
|
+
`--root` names (default: the profile's `--repo`; with neither the spawn
|
|
49
|
+
refuses) through its `--exec`, at
|
|
50
|
+
`~/.local/state/mu-next/remote-worktrees/<ws>/<name>` on the host. Its path,
|
|
51
|
+
base commit and the repo's absolute toplevel are the agent's `cwd`, `base`
|
|
52
|
+
and `repo`; close and recovery use that repo, never the profile's.
|
|
53
|
+
`--cwd` names an existing remote directory instead; without either, the
|
|
54
|
+
agent starts in `--root` (default the profile's repo), else the login
|
|
55
|
+
directory. Without a repo, templates get `.` for `{cwd}`. `--root` is part
|
|
56
|
+
of a `--task` attempt's identity: the same attempt in another repo conflicts.
|
|
57
|
+
- `--task` is the same one journaled attempt as for a local agent: claim
|
|
58
|
+
for the new agent, then the brief, never sent twice.
|
|
59
|
+
- mu reserves the host's channel before its first remote command and
|
|
60
|
+
keeps it while the pane lives (`--max-sessions` counts it). A full host
|
|
61
|
+
refuses the spawn up front and names the holder. A failed spawn removes
|
|
62
|
+
only the worktree it made (still clean, still at its base) and frees
|
|
63
|
+
the slot. If the host's answer was lost after it made the worktree (a
|
|
64
|
+
timeout), spawning the same name again takes that tree over while it is
|
|
65
|
+
clean, at its base and unused; anything else at the path refuses.
|
|
66
|
+
- The pane is the transport: closing it, or its death, ends the agent
|
|
67
|
+
and frees the slot. tmux only; herdr refuses `--host` in one line.
|
|
68
|
+
- A non-pi `--command` (`--host dev --command 'npm test'`, no `--cli pi`) is a
|
|
69
|
+
**command gate**, not a worker: its pane is kept after the command ends, and
|
|
70
|
+
`mu wait agent:auth/gate-1` returns the command's own exit status (the
|
|
71
|
+
`exit` of the result and of the process; 23 stays 23). Never a held
|
|
72
|
+
`ssh dev …`. The remote command writes a token-bound completion record that
|
|
73
|
+
mu reads once the pane has exited; no record, a signal or a lost transport is
|
|
74
|
+
exit 6, never 0. `mu agent close gate-1` frees the pane and removes that
|
|
75
|
+
record. No `--worktree`, no `--task`.
|
|
76
|
+
- If the spawn reports `ctl refused` or `missing`, run
|
|
77
|
+
`mu host check dev --agent worker-1 -w auth`, then check
|
|
78
|
+
`AllowStreamLocalForwarding` on the host.
|
|
54
79
|
|
|
55
80
|
## Drive it like a local agent
|
|
56
81
|
|
|
57
|
-
|
|
58
|
-
|
|
82
|
+
`mu agent send`, `wait`, `abort` and `check` go through the forwarded
|
|
83
|
+
socket and behave as they do locally. `mu state` shows remote workers
|
|
84
|
+
as agent records with `host`, `cwd`, `base` and `collected_head`.
|
|
85
|
+
|
|
86
|
+
## Collect and close
|
|
59
87
|
|
|
60
88
|
```bash
|
|
61
|
-
|
|
62
|
-
mu
|
|
63
|
-
|
|
89
|
+
cd ~/repo # the local repo the commits come home to
|
|
90
|
+
mu agent collect worker-1 -w auth # runs the profile's --fetch, prints the merge
|
|
91
|
+
git merge <sha> # mu prints the exact sha; it never merges
|
|
92
|
+
mu agent close worker-1 -w auth # preview, then --if <rev>
|
|
64
93
|
```
|
|
65
94
|
|
|
66
|
-
|
|
67
|
-
|
|
95
|
+
- `collect` runs the `--fetch` template locally, in the current directory's
|
|
96
|
+
git repo, under one channel. It pins the fetched commit as
|
|
97
|
+
`refs/mu/collect/<ws>/<agent>` (gc keeps it) and records it as the
|
|
98
|
+
agent's `collected_head`. A fetch that fails, or succeeds without leaving a
|
|
99
|
+
commit, records nothing. Collecting the same HEAD again says so.
|
|
100
|
+
- The pane is the transport, so a live worker holds its host's channel. At
|
|
101
|
+
`--max-sessions 1`, `collect` is refused with the holder named; raise the
|
|
102
|
+
cap to collect while the worker runs.
|
|
103
|
+
- `close` kills the pane first (that frees the channel), then removes the
|
|
104
|
+
remote worktree **only if** it is clean and its HEAD is the base or the
|
|
105
|
+
collected HEAD, and no process on the host is inside it. Its `git worktree
|
|
106
|
+
remove` never uses git's `--force`. A process inside it, or a host with
|
|
107
|
+
neither /proc nor lsof to check, refuses naming `close --force`, which
|
|
108
|
+
removes past either with a warning. A newer HEAD refuses with one line:
|
|
109
|
+
`collect` again, or `close --keep-branch` to keep the commits on the remote
|
|
110
|
+
branch `mu/<ws>/<agent>-<sha12>` and remove the worktree. Uncommitted files
|
|
111
|
+
always refuse (`--discard` and `--keep-branch` do not override that).
|
|
112
|
+
- A `--cwd` agent has no remote worktree of its own: close never touches the
|
|
113
|
+
host. When a row is deleted (its pane died and the
|
|
114
|
+
reaper took it, a workstream teardown, a peer's workstream delete, even a raw
|
|
115
|
+
SQL delete) the database keeps a
|
|
116
|
+
machine-local `remote_recovery` record of the host, path and base (`mu sql
|
|
117
|
+
"select * from remote_recovery"`; `mu rebuild` loses it). A failed spawn whose
|
|
118
|
+
own rollback removed the tree (or found it gone) leaves none. With no agent row left,
|
|
119
|
+
`mu agent close <name> -w <ws>` (or `<ws>/<name>`) previews and closes THAT
|
|
120
|
+
worktree under the rule above (no pane, no task; the recorded host profile only), and
|
|
121
|
+
`mu agent collect <name>` fetches from it. Several records of one name need
|
|
122
|
+
`--recovery <id>`; a current agent of the name or path, a newer record of the same path, or a changed `--exec`, refuses (a changed default repo does not).
|
|
123
|
+
|
|
124
|
+
## Host profiles
|
|
125
|
+
|
|
126
|
+
A host profile stores your own command templates, so you stop retyping
|
|
127
|
+
them. mu never connects and knows no ssh flags: it fills the templates and
|
|
128
|
+
runs them with `/bin/sh -c`. `spawn --host` uses them (above); `agent
|
|
129
|
+
collect` runs the `--fetch` template.
|
|
68
130
|
|
|
69
131
|
```bash
|
|
70
|
-
|
|
132
|
+
mu host init dev --ssh # prints a starter `mu host add`; runs nothing
|
|
133
|
+
mu host add dev --shell '<pane cmd>' --exec '<run cmd>' --fetch '<fetch cmd>' --max-sessions 1
|
|
134
|
+
mu host check dev --root '~/repo' # host answers, repo, pi, mu extension
|
|
135
|
+
mu host show dev # templates and the holders of its channels
|
|
71
136
|
```
|
|
72
137
|
|
|
73
|
-
|
|
74
|
-
|
|
138
|
+
- Placeholders: `{env}` (the five `MU_*` identity variables only), `{cmd}`,
|
|
139
|
+
`{local_sock}`, `{remote_sock}`, `{cwd}`. Each value is one quoted word and
|
|
140
|
+
is exactly the text you passed, also inside your own `"..."` or `'...'`.
|
|
141
|
+
A template that hands command text to a second shell (ssh's remote login
|
|
142
|
+
shell) says so per placeholder: `{cmd:sh}`, `{cwd:sh}` quote the value for
|
|
143
|
+
that shell too. Write `{{` and `}}` for literal braces. Anything else in
|
|
144
|
+
braces is refused.
|
|
145
|
+
- A command that times out, or whose caller is killed, takes its whole process
|
|
146
|
+
group with it before its channel is freed, so `--max-sessions` never
|
|
147
|
+
undercounts a live transport.
|
|
148
|
+
- `--max-sessions N` counts every channel mu holds to the host. At the cap mu
|
|
149
|
+
refuses with one line naming the holder.
|
|
150
|
+
- `host check --agent <name> -w <ws>` also probes that agent's forwarded
|
|
151
|
+
control socket.
|