@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
|
@@ -1,326 +1,25 @@
|
|
|
1
1
|
# Remote workers
|
|
2
2
|
|
|
3
|
-
Use when an agent
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
326
|
-
|
|
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
|
|
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
|
-
|
|
5
|
+
**A task is work the graph tracks. Checking a thing is a call.**
|
|
9
6
|
|
|
10
|
-
|
|
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
|
|
61
|
-
| a gate
|
|
62
|
-
| a finding,
|
|
63
|
-
|
|
|
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
|
-
##
|
|
14
|
+
## The call
|
|
70
15
|
|
|
71
|
-
|
|
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
|
-
|
|
18
|
+
```text
|
|
19
|
+
VERDICT: <id> CONFIRMED|REFUTED|UNVERIFIED <one line>
|
|
20
|
+
EVIDENCE: <file:line or command + result> (3-6 lines)
|
|
21
|
+
```
|
|
79
22
|
|
|
80
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:**
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
13
|
+
Record a gate in a task note:
|
|
27
14
|
|
|
28
15
|
```text
|
|
29
|
-
GATE: commit=<sha
|
|
30
|
-
RESULT: exit=<code>; duration=<wall
|
|
31
|
-
CONDITIONS: <toolchain, host
|
|
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
|
|
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
|
-
|
|
23
|
+
A new test sits at the lowest level that catches the failure.
|
|
41
24
|
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
|
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
|
|
13
|
-
mu
|
|
14
|
-
|
|
15
|
-
mu task
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
31
|
-
|
|
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 "..."`.
|