@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.
Files changed (119) hide show
  1. package/AGENTS.md +73 -35
  2. package/README.md +71 -57
  3. package/dist/chunk-4ULY3ZKO.js +4482 -0
  4. package/dist/chunk-4ULY3ZKO.js.map +1 -0
  5. package/dist/chunk-7M634JMD.js +375 -0
  6. package/dist/chunk-7M634JMD.js.map +1 -0
  7. package/dist/{chunk-3BARPJLY.js → chunk-PZ5GOCWH.js} +16 -2
  8. package/dist/chunk-PZ5GOCWH.js.map +1 -0
  9. package/dist/chunk-SS7NQSSZ.js +3660 -0
  10. package/dist/chunk-SS7NQSSZ.js.map +1 -0
  11. package/dist/chunk-UCZPJX7K.js +14253 -0
  12. package/dist/chunk-UCZPJX7K.js.map +1 -0
  13. package/dist/{cli-CKOMHBXV.js → cli-TV3N47AZ.js} +7317 -4593
  14. package/dist/cli-TV3N47AZ.js.map +1 -0
  15. package/dist/cli.js +2 -3
  16. package/dist/cli.js.map +1 -1
  17. package/dist/errors-GRONKWFS.js +65 -0
  18. package/dist/extension/mu-pi.js +1632 -837
  19. package/dist/extension/mu-pi.js.map +1 -1
  20. package/dist/index.d.ts +4067 -2561
  21. package/dist/index.js +614 -297
  22. package/dist/index.js.map +1 -1
  23. package/dist/tui-FUBQ326D.js +1848 -0
  24. package/dist/tui-FUBQ326D.js.map +1 -0
  25. package/docs/ARCHITECTURE.md +118 -66
  26. package/docs/VOCABULARY.md +113 -49
  27. package/docs/guide/README.md +3 -3
  28. package/docs/guide/backends.md +8 -4
  29. package/docs/guide/cleanup.md +69 -33
  30. package/docs/guide/delegate.md +149 -66
  31. package/docs/guide/dispatch.md +148 -53
  32. package/docs/guide/getting-started.md +37 -44
  33. package/docs/guide/other-agent-clis.md +102 -0
  34. package/docs/guide/recovery.md +31 -50
  35. package/docs/guide/remote.md +122 -45
  36. package/docs/guide/sql.md +104 -24
  37. package/docs/guide/stop-a-worker.md +30 -37
  38. package/docs/guide/sync.md +11 -3
  39. package/docs/guide/upgrade.md +93 -43
  40. package/docs/reference/env.md +24 -32
  41. package/docs/reference/naming.md +14 -7
  42. package/docs/reference/surface-contract.md +153 -0
  43. package/package.json +33 -11
  44. package/prompts/mu-debug.md +3 -1
  45. package/prompts/mu-refute.md +2 -1
  46. package/prompts/mu-research.md +3 -1
  47. package/prompts/mu-review.md +2 -1
  48. package/prompts/mu-rules-audit.md +5 -4
  49. package/prompts/mu-sweep.md +2 -1
  50. package/prompts/mu-tournament.md +4 -2
  51. package/prompts/mu-until.md +3 -1
  52. package/prompts/ultrathink.md +1 -1
  53. package/skills/mu/SKILL.md +60 -291
  54. package/skills/mu/recipes/adversarial-review.md +12 -103
  55. package/skills/mu/recipes/brief.md +14 -61
  56. package/skills/mu/recipes/course-correct.md +23 -0
  57. package/skills/mu/recipes/findings.md +17 -111
  58. package/skills/mu/recipes/models.md +17 -92
  59. package/skills/mu/recipes/move.md +14 -0
  60. package/skills/mu/recipes/orchestrator-loop.md +20 -119
  61. package/skills/mu/recipes/recovery.md +8 -29
  62. package/skills/mu/recipes/remote-workers.md +17 -318
  63. package/skills/mu/recipes/tasks-or-calls.md +15 -78
  64. package/skills/mu/recipes/test-health.md +19 -77
  65. package/skills/mu/recipes/worker.md +17 -24
  66. package/dist/chunk-45KQLMEL.js +0 -2908
  67. package/dist/chunk-45KQLMEL.js.map +0 -1
  68. package/dist/chunk-G434JKV2.js +0 -641
  69. package/dist/chunk-G434JKV2.js.map +0 -1
  70. package/dist/chunk-KUGUFBWH.js +0 -12527
  71. package/dist/chunk-KUGUFBWH.js.map +0 -1
  72. package/dist/chunk-QITLNZEM.js +0 -87
  73. package/dist/chunk-QITLNZEM.js.map +0 -1
  74. package/dist/chunk-VIEYQMQA.js +0 -393
  75. package/dist/chunk-VIEYQMQA.js.map +0 -1
  76. package/dist/chunk-WI6AWCMK.js +0 -19
  77. package/dist/chunk-WI6AWCMK.js.map +0 -1
  78. package/dist/cli-CKOMHBXV.js.map +0 -1
  79. package/dist/devtools-LS4ZEPWM.js +0 -3772
  80. package/dist/devtools-LS4ZEPWM.js.map +0 -1
  81. package/dist/tui-LFJ5P4Y2.js +0 -40956
  82. package/dist/tui-LFJ5P4Y2.js.map +0 -1
  83. package/dist/tui-sync-worker.js +0 -17
  84. package/dist/tui-sync-worker.js.map +0 -1
  85. package/dist/yank-XDOONQSL.js +0 -13
  86. package/dist/yank-XDOONQSL.js.map +0 -1
  87. package/docs/ROADMAP.md +0 -123
  88. package/docs/VISION.md +0 -298
  89. package/docs/architecture/control-socket.md +0 -142
  90. package/docs/architecture/dag.md +0 -117
  91. package/docs/architecture/mux.md +0 -167
  92. package/docs/architecture/ops-log.md +0 -160
  93. package/docs/architecture/sdk.md +0 -187
  94. package/docs/architecture/sync.md +0 -159
  95. package/docs/architecture/tui.md +0 -165
  96. package/docs/guide/tui.md +0 -98
  97. package/docs/history/CHANGELOG-pre-3.md +0 -4866
  98. package/docs/img/tui-dashboard.png +0 -0
  99. package/docs/specs/2026-09-28-agent-state-from-murmur.md +0 -333
  100. package/docs/specs/2026-09-29-task-substates.md +0 -247
  101. package/docs/specs/2026-10-03-keep-driving-nudge.md +0 -163
  102. package/docs/specs/2026-10-21-fast-and-slow-gates.md +0 -229
  103. package/skills/mu/recipes/backlog-triage.md +0 -45
  104. package/skills/mu/recipes/codemode-driver.md +0 -118
  105. package/skills/mu/recipes/deep-research.md +0 -69
  106. package/skills/mu/recipes/drift-audit.md +0 -75
  107. package/skills/mu/recipes/fan-out.md +0 -42
  108. package/skills/mu/recipes/hypothesis-panel.md +0 -48
  109. package/skills/mu/recipes/long-run.md +0 -32
  110. package/skills/mu/recipes/loop-until-done.md +0 -45
  111. package/skills/mu/recipes/plan.md +0 -67
  112. package/skills/mu/recipes/refute.md +0 -55
  113. package/skills/mu/recipes/review-panel.md +0 -65
  114. package/skills/mu/recipes/rules-audit.md +0 -89
  115. package/skills/mu/recipes/tournament.md +0 -44
  116. package/skills/mu/recipes/ultrathink.md +0 -86
  117. package/skills/mu/recipes/watcher.md +0 -28
  118. package/skills/mu/recipes/waves.md +0 -21
  119. /package/dist/{chunk-3BARPJLY.js.map → errors-GRONKWFS.js.map} +0 -0
@@ -1,326 +1,25 @@
1
1
  # Remote workers
2
2
 
3
- Use when an agent's process runs on another machine (a devserver, a
4
- bigger box) while its pane stays local. mu has no remote backend, ssh
5
- code, or host registry. This is a recipe plus the traps that cost time.
3
+ Use when an agent runs on another machine. A **host profile** holds your command templates; mu never connects.
6
4
 
7
- **If you read one thing:** on a session-capped host, an open attach pane
8
- holds the only ssh channel and silently breaks `git fetch`,
9
- `murmur collect`, and every other ssh. Attach to look, then
10
- `mu agent close`.
11
-
12
- ## The model
13
-
14
- - **The pane is local, the process is remote.** The pane's foreground
15
- process is ssh. `send`, `read`, and the reaper work unchanged. The pi
16
- control socket rides the same ssh as a `-L` forward, so pi state,
17
- `wait`, and `abort` are exact.
18
- - **One orchestrator DB.** Never run a second mu on the host.
19
- `tasks.owner_id` is an FK into the machine-local `agents` table, so a
20
- remote mu cannot claim tasks in your DAG.
21
- - **mu does not know the remote workspace**: no `mu workspace` verbs,
22
- staleness warning, or auto-free. You own it.
23
- - **Everything is orchestrator-pull.** The host usually has no route
24
- back to your laptop. Push setup out, fetch commits back.
25
-
26
- ## The recipe
27
-
28
- ```bash
29
- # 1. WORKSPACE: you create it; --workspace is local-only
30
- ssh dev 'git -C ~/repo worktree add ~/ws/worker-1'
31
-
32
- # 2. RECORD: location and per-worker baseline, in one note
33
- mu task note t1 -w big "REMOTE: dev:~/ws/worker-1
34
- REMOTE_BASE: worker-1:$(ssh dev 'cd ~/ws/worker-1 && git rev-parse HEAD')"
35
-
36
- # 3. SPAWN: env goes INSIDE the command (tmux -e stops at the hop).
37
- # remote-env prints the socket forward and the identity env; it runs nothing.
38
- # $SHELL -ilc: ssh's non-interactive shell skips ~/.zshrc (PATH, provider env).
39
- eval "$(mu agent remote-env worker-1 -w big --shell)" # MU_SSH_ARGS, MU_REMOTE_ENV
40
- mu agent spawn worker-1 -w big --command \
41
- "ssh $MU_SSH_ARGS dev -t 'cd ~/ws/worker-1 && $MU_REMOTE_ENV \$SHELL -ilc \"pi --approve\"'"
42
-
43
- # 4. CLAIM + SEND: as for a local agent
44
- mu task claim t1 -w big --for worker-1 --evidence 'remote on dev'
45
- mu agent send worker-1 -w big --fresh '...'
46
-
47
- # 5. WAIT: pi: mu agent wait worker-1 -w big --after-runs <send's runs> --json,
48
- # then the claim's Next: once, after the worker reports done.
49
- # non-pi: the same, once per reported-done turn
50
-
51
- # 6. COLLECT: fetch straight from the remote worktree
52
- git fetch "ssh://dev/~/ws/worker-1" HEAD && git cherry-pick FETCH_HEAD
53
- ```
54
-
55
- Done when the worker's commits are cherry-picked locally, the merged
56
- tree passes the merged-tree gates (host and local checks below), and the pane is
57
- closed.
58
-
59
- ### Step 2: the note is load-bearing
60
-
61
- Keep the exact forms `REMOTE: <host>:<path>` and
62
- `REMOTE_BASE: <agent>:<sha>`. `mu task claim --for` builds the
63
- poll-and-close command from them, and `mu state` lists `REMOTE:` lines.
64
- For a crew, poll every path in one bounded mule job:
65
-
66
- ```bash
67
- mule run --max-secs 30 'for d in ~/ws/*/; do printf "%s %s\\n" \
68
- "$(basename $d)" "$(cd $d && git rev-parse HEAD 2>/dev/null || echo unreadable)"; done'
69
- mule wait <job>; mule tail <job>
70
- ```
71
-
72
- Accept only 40 hex characters. `unreadable` or an empty field means
73
- retry next turn, not progress.
74
-
75
- ### Step 3: the control-socket forward
76
-
77
- Spawn reports `ctl: ok` when all of these hold (`mu doctor` has a ctl
78
- row per agent):
79
-
80
- - The host has the mu extension: run `mu link pi` there.
81
- - The ssh is direct. `$MU_SSH_ARGS` sets `ControlMaster=no
82
- ControlPath=none`; a multiplexed ssh never binds the forward and spawn
83
- reports `ctl: missing`.
84
- - sshd allows the forward. A refused forward kills the pane at spawn
85
- (`ExitOnForwardFailure=yes`). Check `AllowStreamLocalForwarding`.
86
-
87
- A dead ssh leaves the socket file, which probes `refused`, never a
88
- stale `ok`. Non-pi agents get state from murmur, lagging 30 s ± 10 s
89
- plus a 10 s cache.
90
-
91
- ### Step 5: poll once per turn
92
-
93
- The claim's `Next:` mule poll closes the task as done on any change of
94
- the remote HEAD. Run it once, only after the worker reports done (its
95
- close or final answer). For a pi worker, first block on
96
- `mu agent wait <name> --after-runs <runs> --json`, with `runs` from
97
- `mu agent send --json`. It settles exactly over the forwarded socket,
98
- and it returns at once for a run that settled before the wait started.
99
- Pass `<runs>` unchanged. On exit 5 (timeout), or on a wait that returns
100
- while the worker asks a question, do not poll: read the pane
101
- (`mu agent read <name> -n 20`) and answer.
102
-
103
- - Never `sleep` in a tool call. Aborting the loop can leave remote work
104
- and a capped channel running.
105
- - Set a deadline before dispatch. At expiry, read the pane, then release
106
- or re-dispatch.
107
- - On a capped host, run `Next:` through mule. A refused bare ssh returns
108
- an empty sha that looks like progress.
109
-
110
- ### Step 6: fetch from the worktree
111
-
112
- - No shared remote or bare repo is needed. It exits 128 on failure, so
113
- `&&` chaining is safe.
114
- - Quote the URL. Unquoted, your local shell expands `~` to your laptop's
115
- home.
116
- - Bucket work by file cluster, not by machine.
117
-
118
- ### Run the merged gate on the host
119
-
120
- Reuse only equivalent [gate records](test-health.md#gate-contract).
121
- Cherry-pick a merge batch locally, push its pinned head to the host, and run
122
- full slow there with warm dependencies, plus fast if slow excludes it:
123
-
124
- ```bash
125
- git cherry-pick <sha>
126
- git push -q "ssh://dev/~/hacking/<repo>.git" HEAD:refs/heads/gate-tmp
127
- mule run --cwd ~/hacking/<gate-checkout> --wait \
128
- 'git fetch -q origin gate-tmp && git checkout -q --detach FETCH_HEAD && npm run check'
129
- ```
130
-
131
- `<gate-checkout>` is a scratch checkout or worktree used only for
132
- gates, never one holding work. Push to a temporary ref, never `main`;
133
- delete it afterwards (`git push origin :gate-tmp`). Push to `main` only
134
- after required gates pass. Replace `npm run check` with the repo's canonical
135
- merged-tree command(s), preserving full scope and recording host conditions.
136
- Keep the gate checkout pinned while other remote workers continue in theirs;
137
- use private artifacts ([build cache](orchestrator-loop.md#build-cache)).
138
-
139
- `--wait` exits with the suite's code. A bare ssh would hold the capped
140
- channel for minutes. Retain local platform-sensitive checks (macOS `ps`
141
- returns argv, Linux `ps -e` appends the environment, and a real bug lived
142
- there), and the repo-required final local gate before the push that matters.
143
- A remote pass does not substitute for non-equivalent local conditions.
144
-
145
- ## Traps
146
-
147
- ### A non-pi spawn on an auth prompt looks healthy
148
-
149
- With the channel busy, the attach ssh stopped at `Enter a passcode:`.
150
- Spawn succeeded, the agent showed `needs_input`, and the prompt went
151
- into the passcode field. This applies to non-pi CLIs and to
152
- `--via mux`, which paste into the pane. Confirm such an agent got the
153
- work (`mu agent read <name> -n 20`) before trusting it. Send nothing
154
- sensitive to an unconfirmed pane.
155
-
156
- A pi agent does not paste. Spawn reports `ctl: ok` only when pi
157
- answers on the socket; otherwise it warns `ctl: missing` or
158
- `ctl: refused`, and `mu agent send` fails instead of typing into the
159
- pane.
160
-
161
- ### Use the host's real CLI command
162
-
163
- If your local `$MU_PI_COMMAND` is a wrapper such as `pi-meta
164
- --pi-meta-no-solo --approve`, plain `pi` on the host gives a live pane
165
- with **no models configured**. Check with `ssh dev 'command -v pi-meta'`.
166
-
167
- ### Tell the worker that mu is absent
168
-
169
- mu is usually not on the host, so the in-pane loop cannot run. Say so
170
- in the prompt and have the worker print its sha. You claim, note, and
171
- close. Otherwise `mu task wait` hangs.
172
-
173
- ### A dropped connection reaps the task, not the commit
174
-
175
- The reaper reverts the task to OPEN, but the commit is still on the
176
- host. Fetch from the `REMOTE:` path before re-dispatching.
177
-
178
- ### A dead non-pi remote agent vanishes
179
-
180
- murmur records `crashed` only when a pane outlives its process. Remotely
181
- tmux reaps the session with the agent, so SIGKILL gives zero rows, not
182
- `crashed`. (A dead pi agent probes `refused`.) Trust the `[reaper]`
183
- note and `ssh <host> 'tmux ls'`.
184
-
185
- ### Stopping and cleaning up
186
-
187
- - `mu agent abort <name>` stops a pi turn through the forwarded socket.
188
- - `mu agent kick` signals the local ssh client, not the remote agent.
189
- For an unresponsive agent, `mu agent close` and respawn.
190
- - mu does not remove remote worktrees:
191
- `ssh dev 'git -C ~/repo worktree remove ~/ws/worker-1'`.
192
-
193
- ## murmur
194
-
195
- pi agents need no murmur. [murmur](https://github.com/mu-crew/murmur)
196
- reports state for non-pi agents on tmux, and adds status pills,
197
- attachment hints, and `murmur peer list`. Without it, non-pi agents
198
- report `unknown`; everything else works.
199
-
200
- | Question | Ask |
201
- | --- | --- |
202
- | What happens next, who owns it, is it done | mu: the DAG, `claim`, `task wait` |
203
- | What is a pi agent doing | mu: the control socket |
204
- | What is a non-pi agent doing; is anything blocked on me | murmur |
205
- | Which host can I reach | murmur: `peer list` |
206
-
207
- **`$MU_REMOTE_ENV` goes inside the ssh command.** Without it the agent
208
- reports `driver=human` and shows in your own status bar.
209
-
210
- **murmur sees the remote pane** and links it to your local pane by the
211
- agent name in the local argv (`attached here %N`; focus instead of a
212
- second connection). The detached shape carries the name only in the
213
- session name, so name it `mu-<agent>`. An env prefix does not help:
214
- macOS `ps` reports argv, not env.
215
-
216
- ### Picking a host
217
-
218
- ```bash
219
- murmur peer list --json | jq -r '.[] | select(.error) | .name'
220
- ```
221
-
222
- - `ssh` is last-known reachability. `error` is the current attempt.
223
- - It exits 0 either way. Branch on `.error`, not on presence.
224
- - `murmur collect` prints one line per unreachable host, now.
225
-
226
- Attach with the peer's jump command instead of hardcoding ssh. It may
227
- use a transport that takes no ssh session:
228
-
229
- ```bash
230
- murmur peer set <name> --jump-command '<command with {pane}>'
231
- JUMP=$(murmur peer list --json | jq -r '.[]|select(.name=="dev").jump_command')
232
- mu agent spawn worker-1 -w big --command "${JUMP//\{pane\}/mu-worker-1}"
233
- ```
234
-
235
- ## When the host limits concurrent sessions
236
-
237
- Most sshd allow 10 sessions per connection (`MaxSessions`). A hardened
238
- host may set `MaxSessions 1`. Then the ssh holding your agent takes the
239
- only channel, and every other ssh, including `git fetch`, fails with a
240
- misleading `Permission denied (keyboard-interactive)`.
241
-
242
- Diagnose in this order. The first check is local and instant:
243
-
244
- ```bash
245
- ssh-add -l # "Error connecting to agent" => dead ssh agent, NOT the cap
246
- ssh <host> true # fails while `mu agent read` works => the cap
247
- ```
248
-
249
- A dead `SSH_AUTH_SOCK` gives the same error via an invisible 2FA prompt;
250
- one session lost an hour treating it as the cap. To find what holds the
251
- channel:
252
- `ps -o pid=,command= -ax | grep "[s]sh <host>"`.
253
-
254
- `ControlMaster no` does not help (it governs master creation only).
255
- There is no client fix.
256
-
257
- ### Run commands through mule
258
-
259
- [mule](https://github.com/mu-crew/mule) dispatches detached jobs on its
260
- own ssh ControlPath. On a `MaxSessions 1` host, eight bare `rev-parse`
261
- polls returned one sha and seven empty results; mule ran all eight.
262
-
263
- - Use mule for long work and for any command whose refusal could look
264
- like success. Keep worktree setup and `murmur collect` bare: they fail
265
- loudly.
266
- - A mule job is entirely remote. It cannot fetch from, push to, or rsync
267
- with your laptop.
268
- - For an interactive agent under mule's lifecycle, use `mule run --tui`
269
- (plain `mule run` has no live TUI). It prints the attach command.
270
- Closing that pane does not stop the job.
271
-
272
- | mule exit | Meaning | Do |
273
- | --- | --- | --- |
274
- | 3 | No ssh master; opening one may need a hardware-key touch | Hand back: ask the operator to run the printed command. Never retry, run `ssh -MNf`, or fall back to `ssh <host> <cmd>` |
275
- | 4, 6 | Not yet | Poll again |
276
- | 5 | No result will ever arrive | Stop polling |
277
-
278
- None of these means the work failed. Full table: `mule --help`.
279
-
280
- ### Run the agent in detached remote tmux
281
-
282
- Decouple the agent from the connection to release the channel:
283
-
284
- ```bash
285
- eval "$(mu agent remote-env worker-1 -w big --shell)"
286
- # Agent runs detached on the host; this ssh returns at once
287
- ssh dev "tmux new-session -d -s mu-worker-1 -c ~/ws/worker-1 \
288
- '$MU_REMOTE_ENV \$SHELL -ilc \"pi --approve\"'"
289
-
290
- # Attach a local pane (with the socket forward); claim and send as usual
291
- mu agent spawn worker-1 -w big --command "ssh $MU_SSH_ARGS dev -t 'tmux attach -t mu-worker-1'"
292
-
293
- # COLLECT: detach first to free the channel, then fetch
294
- mu agent close worker-1 -w big
295
- git fetch "ssh://dev/~/ws/worker-1" HEAD && git cherry-pick FETCH_HEAD
296
-
297
- # Reattach later with the same spawn command; LLM context is intact
298
- ```
299
-
300
- - An attached pane blocks other ssh exactly like a direct one. Close it
301
- before fetching, or use mule.
302
- - `mu agent close` detaches. It does not stop the agent. To stop it:
303
- `ssh dev 'tmux kill-session -t mu-worker-1'`. `ssh dev 'tmux ls'` is
304
- the only inventory of these sessions.
305
- - A dropped connection no longer reaps the agent. Each attach
306
- re-creates the socket forward.
307
- - Keep the session name `mu-<agent>`: mu records neither, so it is the
308
- only link. On an uncapped host this shape buys nothing.
309
-
310
- ### Use ET for your own shell
311
-
312
- Eternal Terminal moves off ssh to `etserver`, so `MaxSessions` never
313
- counts it, even with a nested `tmux attach`. It makes a good jump
314
- command but cannot serve `git fetch`.
5
+ The pane is the transport and forwards the remote pi's control socket: `send`, `wait`, `abort` work as locally; a dead pane is a dead agent. The host has no mu DB: you close the task, from the worker's `CLOSE:` block.
315
6
 
316
7
  ```bash
317
- et dev # or your site's wrapper, such as `x2ssh -et dev`
8
+ mu host init dev --ssh # a starter to edit into `mu host add`
9
+ mu host check dev
10
+ mu agent spawn worker-1 -w <ws> --host dev --worktree --root <remote repo> --task <id> --send - <<'EOF'
11
+ <brief>
12
+ EOF
13
+ mu agent wait worker-1 -w <ws> --after-runs <n> --json # n = the spawn's printed "runs" (0 fresh); lastText: its CLOSE block
14
+ mu agent collect worker-1 -w <ws> # run in the local repo
15
+ mu task close <id> -w <ws> --evidence "<the block's evidence>"
16
+ mu agent close worker-1 -w <ws> --if <rev>
318
17
  ```
319
18
 
320
- An aborted `et` or `x2ssh` leaves local processes behind. Find them
321
- with `ps -o pid=,command= -ax | grep "[x]2ssh"` and kill only those of
322
- the aborted invocation (match its host or tty), not every x2ssh, before
323
- retrying.
19
+ End the brief with: commit, then `CLOSE: task=<id> evidence="<command + result>"`. Cherry-pick the collected commits and re-run the evidence before you close.
324
20
 
325
- On a capped host: ET for you, mule for tooling, detached tmux for mu
326
- agents. None of them competes for the slot.
21
+ - **One profile per machine** (the cap is per profile); `--root` picks the repo.
22
+ - **`--max-sessions 1`**: the live pane holds the only channel; `collect` and `ssh dev` refuse. Raise the cap to collect mid-run.
23
+ - **Long remote gates are panes** (`--command 'npm test'`), not a held ssh.
24
+ - `close` refuses a dirty or uncollected tree: collect again.
25
+ - A host command's exit 3 is a hand-back (hardware key): never retry or ssh yourself.
@@ -1,89 +1,26 @@
1
1
  # Tasks or calls
2
2
 
3
- Use when a recipe step spawns an agent: decide whether that agent's job
4
- is a **task** in the DAG or a **call** to a delegate. Getting it wrong
5
- one way loses track of work; the other way, one PR review creates
6
- hundreds of tasks and a workstream nobody wanted.
3
+ Use when a step spawns an agent: is its job a **task** in the DAG or a **delegate call**?
7
4
 
8
- ## Delegate call
5
+ **A task is work the graph tracks. Checking a thing is a call.**
9
6
 
10
- A **delegate call** is one `mu_delegate` tool call in pi, or outside pi
11
- a `scratch` spawn + `send --fresh` + `wait --after-runs` (below).
12
-
13
- - **It starts empty.** The brief carries everything: the finding or
14
- claim, file paths, the criteria, and the answer to end with. See
15
- [brief](brief.md). A tournament judge ends with `WINNER: ...`
16
- ([tournament](tournament.md)). A refuter or claim checker passes
17
- `record: { task: "<ws>/<id>" }` and ends with:
18
-
19
- ```text
20
- VERDICT: <id> CONFIRMED|REFUTED|UNVERIFIED <one line>
21
- EVIDENCE: <file:line or command + result> (3-6 lines)
22
- ```
23
-
24
- - **Fan out in one turn.** Issue every call for a step together; in pi
25
- the answers arrive later as follow-up messages. Calling one, waiting,
26
- then the next runs them in series.
27
- - **Its `scratch` pane** stays attachable while it runs; `mu_delegate`
28
- closes it after a clean finish and keeps it on a crash, timeout, or
29
- API error (or always, with `keep: true`).
30
- - **An API error is yours to decide.** Re-issue the call, or record the
31
- check as `UNVERIFIED` on its task, then close the kept pane
32
- (`mu_delegate_cancel`, or `mu agent close`).
33
-
34
- Without the tool, write the note `record` would, before deciding:
35
-
36
- ```bash
37
- mu agent spawn refuter-1 -w scratch
38
- runs=$(mu agent send refuter-1 -w scratch --fresh - --json <<'EOF' | jq .runs
39
- <brief, ending with the VERDICT block>
40
- EOF
41
- )
42
- mu agent wait refuter-1 -w scratch --after-runs "$runs" --json # answer in lastText
43
- mu task note <id> -w <ws> - <<'EOF'
44
- REFUTER 1 (refuter-1, 4m 05s):
45
- <the VERDICT line and EVIDENCE lines, verbatim>
46
- EOF
47
- mu agent close refuter-1 -w scratch
48
- ```
49
-
50
- A wait that times out or dies leaves `REFUTER 1: no verdict (<outcome>)`.
51
- `--after-runs` counts a run that finished before the wait started; the
52
- quoted heredocs keep the evidence verbatim ([brief § Quoting](brief.md#quoting)).
53
-
54
- ## The rule
55
-
56
- **A task is a thing the graph tracks. Checking a thing is a call.**
57
-
58
- | Make it a task | Make it a delegate call |
7
+ | Task | Delegate call |
59
8
  | --- | --- |
60
- | a unit of work that produces commits | refuting a finding |
61
- | a gate that decides whether work counts (`review_x`) | checking a claim against its source |
62
- | a finding, claim, or hypothesis that survives into the workstream | judging a pair in a tournament |
63
- | the umbrella, and each round of a loop | a skeptic or dedupe pass |
64
- | anything that needs its own workspace | a reader or scout whose output feeds one step |
65
-
66
- A call adds no node: its note and your decision land on the task it
67
- judged ([findings § Triage](findings.md#triage)).
9
+ | a unit that produces commits | refuting a finding, checking a claim |
10
+ | a gate deciding whether work counts (`review_x`) | judging a pair, a skeptic or dedupe pass |
11
+ | a finding, or the umbrella | a scout or reader feeding one step |
12
+ | anything needing its own worktree | |
68
13
 
69
- ## Examples
14
+ ## The call
70
15
 
71
- - 30 findings to refute: 30 delegate calls, 0 new tasks; each finding
72
- gets a `REFUTER` note, then your decision.
73
- - A tournament over 16 names: 15 judge calls; each round's `WINNER:`
74
- lines go on the umbrella.
75
- - A hypothesis test that reverts commits or forces a race needs a
76
- workspace: that one is a task.
16
+ In pi: `mu_delegate`, with `record: {task: "<ws>/<id>"}` when it judges a task, `wave` for a fan-out. It starts empty: the brief carries the claim, paths, criteria and an answer ending:
77
17
 
78
- ## Counting
18
+ ```text
19
+ VERDICT: <id> CONFIRMED|REFUTED|UNVERIFIED <one line>
20
+ EVIDENCE: <file:line or command + result> (3-6 lines)
21
+ ```
79
22
 
80
- Before a wave, count what it will add: units + gates + expected
81
- findings. If the count is more than a few hundred for one change, the
82
- steps that only check things are probably tasks by mistake.
23
+ - **Issue every call of a step in one turn**; one at a time runs in series. Past `MU_DELEGATE_MAX` (16) they queue, then are refused and reissuable.
83
24
 
84
- Cap and queue: [orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency).
25
+ Outside pi, use `scratch`: `mu agent spawn r1 -w scratch`; `mu agent send r1 -w scratch --fresh --json -` (keep `runs`, `incarnation`); `mu wait 'agent:r1@<runs>#<incarnation>' -w scratch`, whose snapshot `lastText` is the answer. Write it on the task as `REFUTER <n> (<agent>): <verdict lines>`, or `REFUTER <n>: no verdict (<outcome>)`. Then `mu agent close r1 -w scratch --if <rev>`.
85
26
 
86
- Done when every agent a recipe step spawns is either a task in the DAG
87
- or a delegate call whose answer landed where its step says: a
88
- `REFUTER` note on the task it judged, a `WINNER` line in the umbrella's
89
- note, or a unit list in the umbrella's note.
@@ -1,92 +1,34 @@
1
1
  # Test health
2
2
 
3
- Read when defining gates, choosing worker/reviewer verification, adding tests,
4
- or doing upkeep at a milestone, a budget crossing, or the user's request.
5
- Testing stays encouraged; upkeep protects coverage and the iteration loop.
3
+ Use when you define gates, verify a merge, add tests, or a merged slow gate exceeds its budget.
6
4
 
7
5
  ## Gate contract
8
6
 
9
- Use the repo's `## Gates` in AGENTS.md or README: fast and slow commands,
10
- slow-gate budget (default 5 min), and a targeted slow-test command. Plan notes
11
- point there. Until a split is approved, keep the existing repo gate intact;
12
- recipe guidance does not waive project checks. Fast means iteration checks,
13
- not a universal seconds promise: measure cold and warm costs.
7
+ Read the repo's `## Gates` (AGENTS.md or README): fast, slow and targeted commands, the slow budget. Never waive a repo check.
14
8
 
15
- - **Worker:** run the fast gate while iterating; before closing, run slow
16
- tests for the changed area once, then fast on the final commit. Record
17
- both, or why a scope is inapplicable/unavailable. Changes invalidate records.
18
- - **Reviewer:** inspect the diff and reuse equivalent worker records. Run
19
- uncovered tests for the diff and reproduce claimed failures, rather than
20
- repeating the full suite or building the parent for every new test.
21
- - **Orchestrator:** verify one pinned merged tree per batch with the full
22
- slow gate, plus fast if slow does not include it. All required integration,
23
- auth, release and packaging checks still pass before push. Bisect a failed
24
- batch; record the corrected tree's pass. See [merging](orchestrator-loop.md#merging).
9
+ - **Worker:** fast while iterating; before close, slow tests for the changed area, then fast on the final commit. Record both, or why one is inapplicable.
10
+ - **Reviewer:** reuse equivalent worker records; run only what they leave uncovered.
11
+ - **Orchestrator:** one pinned merged tree per batch gets the full slow gate, plus fast if slow omits it, before push.
25
12
 
26
- Gate records are task-note text, not a mu command or stored result cache:
13
+ Record a gate in a task note:
27
14
 
28
15
  ```text
29
- GATE: commit=<sha> tree=<hash>; command=<exact command + filters>; scope=<full/area>
30
- RESULT: exit=<code>; duration=<wall time>; counts=<tests/assertions>; skips=<none or reasons>
31
- CONDITIONS: <toolchain, host/platform, privileges, relevant env/features, cache state>
16
+ GATE: commit=<sha>; command=<exact command + filters>; scope=<full|area>
17
+ RESULT: exit=<code>; duration=<wall>; counts=<tests>; skips=<none|reasons>
18
+ CONDITIONS: <toolchain, host, env, cache state>
32
19
  ```
33
20
 
34
- Reuse requires the same tree, command/scope and equivalent execution
35
- conditions. Record uncommitted inputs too; a dirty tree hash alone is not
36
- an identity. A targeted pass, zero selected cases, or a skipped privileged
37
- check is not a full pass. Clear/reject inherited selectors for full runs;
38
- report skips explicitly and resolve required missing checks before push.
21
+ Reuse needs the same tree, command, scope and conditions. A targeted pass, zero selected cases or a skipped required check is not a full pass.
39
22
 
40
- ## Adding or changing tests
23
+ A new test sits at the lowest level that catches the failure.
41
24
 
42
- Use the lowest level that catches the failure, covering behaviour not
43
- already guarded. A new slow case states what only it can see in a comment
44
- or commit message. For a bug with a cheap, obvious local target, the worker
45
- shows red on the base and green on the fix; feature work and integration-heavy
46
- paths need no mandatory red-green ceremony. Use direct executable evidence
47
- when stronger, recording the reason.
25
+ ## Upkeep
48
26
 
49
- Poll readiness/completion with a bound and useful failure output. Retain
50
- necessary temporal sampling, negative-observation windows and deliberately
51
- sleeping process fixtures; explain their timing contract.
27
+ At a milestone or budget crossing, without stopping independent work:
52
28
 
53
- Reviewer findings identify risky untested/broken behaviour, a wrong test
54
- level, duplication of a named test, avoidable readiness padding, or measured
55
- gate slowdown—not every conceivable edge case without a test.
56
-
57
- ## Upkeep loop
58
-
59
- Queue ordinary upkeep work at each phase/milestone end or when a merged slow
60
- gate exceeds budget. Prioritise it before new features; continue independent
61
- work. A budget is a scheduling trigger, not an indefinite crew-wide stop.
62
-
63
- 1. **Profile.** Time each gate step and test, including setup/teardown.
64
- List up to 20 slowest tests per level; inspect waits and repeated builds,
65
- cold caches and profiles. BEFORE records wall time, counts, skips and
66
- conditions. Use inspected execution logs, not commands merely mentioning
67
- a gate or compound-command durations attributed entirely to tests.
68
- 2. **Classify.** Parallel [delegate calls](tasks-or-calls.md#delegate-call),
69
- one per area, give slow/overlapping tests an evidenced verdict:
70
- KEEP; SPEED-UP (poll or share setup with isolation); MOVE-DOWN;
71
- MERGE into a named test; DELETE as covered by a named test.
72
- 3. **Refute.** Send every MERGE/DELETE verdict to a refuter: which failure
73
- would no longer be caught? A refuted or unresolved verdict becomes KEEP.
74
- 4. **Do.** Dispatch surviving changes as normal test-only tasks. Review
75
- coverage preservation, isolation and correctness of the harness changes.
76
- Preserve auth lanes, privilege checks and release scans; measure safe
77
- [build reuse](orchestrator-loop.md#build-cache) separately.
78
- 5. **Measure.** Run the merged gates and record AFTER under comparable
79
- conditions, including coverage/count changes. If neither faster nor
80
- smaller, say so and why; smaller alone does not prove preserved coverage.
81
-
82
- 6. **Report.** Before teardown, commit a dated report to the repo
83
- (`docs/test-health/<YYYY-MM-DD>.md`): conditions, BEFORE/AFTER, each
84
- finding with its evidence, every refuted or rejected verdict with the
85
- reason, and the remaining bottleneck. Task notes die with the
86
- workstream; the next pass reads the latest report first and still
87
- re-measures. Add a file per pass; never edit an old one.
88
-
89
- Done when AFTER records the outcome, the report is committed, and the slow
90
- gate is within budget or the report names the remaining bottleneck and
91
- prioritised follow-up. Keep unmet required checks distinct from a
92
- time-budget overrun.
29
+ 1. Profile each gate step and the 20 slowest tests (BEFORE: time, counts, skips).
30
+ 2. One delegate call per area: KEEP, SPEED-UP, MOVE-DOWN, MERGE or DELETE.
31
+ 3. A refuter checks each MERGE/DELETE: which failure goes uncaught? Unresolved means KEEP.
32
+ 4. Dispatch survivors as test-only tasks with review.
33
+ 5. Re-measure (AFTER); smaller alone proves no coverage.
34
+ 6. Commit `docs/test-health/<date>.md`: BEFORE/AFTER, verdicts, the remaining bottleneck.
@@ -1,31 +1,24 @@
1
- # Worker loop
1
+ # Worker
2
2
 
3
- Use when you are the worker: a task was claimed for you, or you were
4
- told to claim one.
5
-
6
- `$MU_AGENT_NAME` (injected at spawn) resolves identity; adopted panes
7
- fall back to the pane title. In a worker pane, bare `mu task claim <id>`
8
- works. In the unregistered orchestrator pane it errors; use `--self`,
9
- `--for <worker>`, or `mu agent adopt <pane>`.
3
+ Use when you are the worker: a task was claimed for you, or you were told to claim one. `$MU_AGENT_NAME` and `$MU_WORKSTREAM` identify you; your cwd is your worktree.
10
4
 
11
5
  ```bash
12
- mu me
13
- mu me next
14
- mu task show <id>; mu task notes <id>
15
- mu task claim <id> --evidence "starting; read notes"
16
- mu task note <id> "FILES: ...\nCOMMANDS: ... (exit codes)\nDECISION: ...\nVERIFIED: ..."
17
- mu task close <id> --evidence "tests pass: ..." # LAST action
6
+ mu task show <id>; mu task notes <id> # the brief, report and verdicts come first
7
+ mu task claim <id> --evidence "starting" # skip when already yours
8
+ # work; commit before you close: the orchestrator cherry-picks commits, not your tree
9
+ mu task note <id> - <<'EOF'
10
+ FILES: ...
11
+ COMMANDS: ... (exit codes)
12
+ VERIFIED: ...
13
+ EOF
14
+ mu task close <id> --evidence "tests pass: <command> exit 0" # LAST action
18
15
  ```
19
16
 
20
- Follow [test-health](test-health.md) for fast iteration checks, targeted slow
21
- checks before close, gate records, and cheap bug red-green. Include the gate
22
- records in your final note; adding tests uses its test-level and timing rules.
17
+ Skipping `close` hangs the orchestrator's wait.
23
18
 
24
- The note follows the task note contract in SKILL.md. Keep each tool
25
- call to minutes (short batches, waits with a timeout): steering reaches
26
- you only between tool calls. Commit before you close: the orchestrator cherry-picks your commits, not your tree. A
27
- review or audit task records each problem per
28
- [findings § Record](findings.md#record).
19
+ - **Remote host (no mu DB):** `mu task close` cannot work there. Commit, then end your final message with `CLOSE: task=<id> evidence="<command + result>"`; the orchestrator closes from it.
29
20
 
30
- Done when your changes are committed in the workspace, the task note holds FILES, COMMANDS (with exit codes), VERIFIED and applicable gate records, and `mu task close` succeeded as your last action. Skipping close makes the orchestrator's
31
- wait hang. Won't do it: `close --as wontfix --why "..."`.
21
+ - Follow the brief's VERIFY and [test-health](test-health.md): fast while iterating, slow for your area before close; put the gate records in your note.
22
+ - Keep each tool call to minutes; a steer reaches you only between calls.
23
+ - A review or audit records each problem as a finding ([findings](findings.md)).
24
+ - Won't do it: `mu task close <id> --as wontfix --why "..."`.