@mu-crew/mu 3.13.3 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +73 -35
- package/README.md +71 -57
- package/dist/chunk-5HECDBK3.js +4482 -0
- package/dist/chunk-5HECDBK3.js.map +1 -0
- package/dist/chunk-AW2NONYU.js +301 -0
- package/dist/chunk-AW2NONYU.js.map +1 -0
- package/dist/chunk-GQNHIPJN.js +4060 -0
- package/dist/chunk-GQNHIPJN.js.map +1 -0
- package/dist/{chunk-3BARPJLY.js → chunk-PZ5GOCWH.js} +16 -2
- package/dist/chunk-PZ5GOCWH.js.map +1 -0
- package/dist/chunk-S424D5EP.js +13766 -0
- package/dist/chunk-S424D5EP.js.map +1 -0
- package/dist/{cli-CKOMHBXV.js → cli-GB2CAVVW.js} +6776 -4350
- package/dist/cli-GB2CAVVW.js.map +1 -0
- package/dist/cli.js +2 -3
- package/dist/cli.js.map +1 -1
- package/dist/errors-KHOYKD7D.js +65 -0
- package/dist/extension/mu-pi.js +1617 -836
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +4015 -2561
- package/dist/index.js +614 -297
- package/dist/index.js.map +1 -1
- package/dist/tui-ALPHYTA2.js +1773 -0
- package/dist/tui-ALPHYTA2.js.map +1 -0
- package/docs/ARCHITECTURE.md +117 -66
- package/docs/VOCABULARY.md +112 -49
- package/docs/guide/README.md +3 -3
- package/docs/guide/backends.md +8 -4
- package/docs/guide/cleanup.md +61 -33
- package/docs/guide/delegate.md +141 -66
- package/docs/guide/dispatch.md +148 -53
- package/docs/guide/getting-started.md +37 -44
- package/docs/guide/other-agent-clis.md +102 -0
- package/docs/guide/recovery.md +31 -50
- package/docs/guide/remote.md +115 -45
- package/docs/guide/sql.md +104 -24
- package/docs/guide/stop-a-worker.md +30 -37
- package/docs/guide/sync.md +11 -3
- package/docs/guide/upgrade.md +93 -43
- package/docs/reference/env.md +23 -32
- package/docs/reference/naming.md +12 -7
- package/docs/reference/surface-contract.md +153 -0
- package/package.json +33 -11
- package/prompts/mu-debug.md +3 -1
- package/prompts/mu-refute.md +2 -1
- package/prompts/mu-research.md +3 -1
- package/prompts/mu-review.md +2 -1
- package/prompts/mu-rules-audit.md +5 -4
- package/prompts/mu-sweep.md +2 -1
- package/prompts/mu-tournament.md +4 -2
- package/prompts/mu-until.md +3 -1
- package/prompts/ultrathink.md +1 -1
- package/skills/mu/SKILL.md +60 -291
- package/skills/mu/recipes/adversarial-review.md +12 -103
- package/skills/mu/recipes/brief.md +14 -61
- package/skills/mu/recipes/course-correct.md +23 -0
- package/skills/mu/recipes/findings.md +17 -111
- package/skills/mu/recipes/models.md +17 -92
- package/skills/mu/recipes/move.md +14 -0
- package/skills/mu/recipes/orchestrator-loop.md +20 -119
- package/skills/mu/recipes/recovery.md +8 -29
- package/skills/mu/recipes/remote-workers.md +16 -318
- package/skills/mu/recipes/tasks-or-calls.md +15 -78
- package/skills/mu/recipes/test-health.md +19 -77
- package/skills/mu/recipes/worker.md +17 -24
- package/dist/chunk-45KQLMEL.js +0 -2908
- package/dist/chunk-45KQLMEL.js.map +0 -1
- package/dist/chunk-G434JKV2.js +0 -641
- package/dist/chunk-G434JKV2.js.map +0 -1
- package/dist/chunk-KUGUFBWH.js +0 -12527
- package/dist/chunk-KUGUFBWH.js.map +0 -1
- package/dist/chunk-QITLNZEM.js +0 -87
- package/dist/chunk-QITLNZEM.js.map +0 -1
- package/dist/chunk-VIEYQMQA.js +0 -393
- package/dist/chunk-VIEYQMQA.js.map +0 -1
- package/dist/chunk-WI6AWCMK.js +0 -19
- package/dist/chunk-WI6AWCMK.js.map +0 -1
- package/dist/cli-CKOMHBXV.js.map +0 -1
- package/dist/devtools-LS4ZEPWM.js +0 -3772
- package/dist/devtools-LS4ZEPWM.js.map +0 -1
- package/dist/tui-LFJ5P4Y2.js +0 -40956
- package/dist/tui-LFJ5P4Y2.js.map +0 -1
- package/dist/tui-sync-worker.js +0 -17
- package/dist/tui-sync-worker.js.map +0 -1
- package/dist/yank-XDOONQSL.js +0 -13
- package/dist/yank-XDOONQSL.js.map +0 -1
- package/docs/ROADMAP.md +0 -123
- package/docs/VISION.md +0 -298
- package/docs/architecture/control-socket.md +0 -142
- package/docs/architecture/dag.md +0 -117
- package/docs/architecture/mux.md +0 -167
- package/docs/architecture/ops-log.md +0 -160
- package/docs/architecture/sdk.md +0 -187
- package/docs/architecture/sync.md +0 -159
- package/docs/architecture/tui.md +0 -165
- package/docs/guide/tui.md +0 -98
- package/docs/history/CHANGELOG-pre-3.md +0 -4866
- package/docs/img/tui-dashboard.png +0 -0
- package/docs/specs/2026-09-28-agent-state-from-murmur.md +0 -333
- package/docs/specs/2026-09-29-task-substates.md +0 -247
- package/docs/specs/2026-10-03-keep-driving-nudge.md +0 -163
- package/docs/specs/2026-10-21-fast-and-slow-gates.md +0 -229
- package/skills/mu/recipes/backlog-triage.md +0 -45
- package/skills/mu/recipes/codemode-driver.md +0 -118
- package/skills/mu/recipes/deep-research.md +0 -69
- package/skills/mu/recipes/drift-audit.md +0 -75
- package/skills/mu/recipes/fan-out.md +0 -42
- package/skills/mu/recipes/hypothesis-panel.md +0 -48
- package/skills/mu/recipes/long-run.md +0 -32
- package/skills/mu/recipes/loop-until-done.md +0 -45
- package/skills/mu/recipes/plan.md +0 -67
- package/skills/mu/recipes/refute.md +0 -55
- package/skills/mu/recipes/review-panel.md +0 -65
- package/skills/mu/recipes/rules-audit.md +0 -89
- package/skills/mu/recipes/tournament.md +0 -44
- package/skills/mu/recipes/ultrathink.md +0 -86
- package/skills/mu/recipes/watcher.md +0 -28
- package/skills/mu/recipes/waves.md +0 -21
- /package/dist/{chunk-3BARPJLY.js.map → errors-KHOYKD7D.js.map} +0 -0
package/docs/guide/delegate.md
CHANGED
|
@@ -2,16 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Delegate from pi
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
in every pi session. Ask pi in plain words:
|
|
5
|
+
The mu pi package (`pi install npm:@mu-crew/mu`) installs the
|
|
6
|
+
`mu_delegate` and `mu_delegate_cancel` tools in every pi session. Ask pi in plain words:
|
|
7
7
|
|
|
8
8
|
- "Delegate a review of src/x.ts to a helper."
|
|
9
9
|
- "Have three helpers investigate A, B, and C."
|
|
10
10
|
|
|
11
|
-
pi calls `mu_delegate`. It
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
pi calls `mu_delegate`. It registers the call as a task (`kind=delegate`,
|
|
12
|
+
see [Every call is a task](#every-call-is-a-task)), spawns a pi agent in
|
|
13
|
+
the reserved `scratch` workstream and returns at once with the task, the
|
|
14
|
+
delegate's name and attach command. The answer arrives later, with
|
|
15
|
+
pi's next settle; do not poll. Delegates called in one turn run in
|
|
16
|
+
parallel.
|
|
15
17
|
|
|
16
18
|
| Option | Meaning |
|
|
17
19
|
| ------ | ------- |
|
|
@@ -19,46 +21,107 @@ Delegates called in one turn run in parallel.
|
|
|
19
21
|
| `label` | Names the delegate: `review` gives `delegate-review`. |
|
|
20
22
|
| `brief` | Ad hoc persona or ground rules, sent first. Not enforced. |
|
|
21
23
|
| `cwd` | Start directory. Default: the caller's. Must exist. |
|
|
22
|
-
| `timeout` | Seconds to wait for the answer (default 3600). After it, the answer does not come back;
|
|
23
|
-
| `workspace` | Own
|
|
24
|
+
| `timeout` | Seconds to wait for the answer (default 3600). After it, the answer does not come back to pi; it still lands on the delegate task, whose report names a wait command. |
|
|
25
|
+
| `workspace` | Own git worktree, for delegates that edit files. The tool result names its path. It isolates repository edits only. |
|
|
24
26
|
| `cli` | Key for `$MU_<CLI>_COMMAND` (default `pi`). Only keys set in pi's environment exist. |
|
|
25
27
|
| `model` | pi `--model` value, appended to the cli's command (`sonnet`, `<provider>/<model>:high`, copied from `pi --list-models`). Varies models across a panel. tmux only: herdr refuses a command override. |
|
|
26
28
|
| `keep` | Keep the pane after it finishes, to talk to it again. |
|
|
27
29
|
| `record` | `{ task, workstream? }` (or `task: "<ws>/<task>"`): write the answer's verdict onto that task as a note. See [Record a verdict](#record-a-verdict). |
|
|
28
|
-
|
|
30
|
+
| `wave` | A label for one fan-out; `mu delegates tally` counts its verdicts per judged task. |
|
|
31
|
+
| `workstream` | Holds the delegate task and runs the delegate (default `scratch`). |
|
|
32
|
+
|
|
33
|
+
- No tmux or herdr: the same tool runs the delegate as a child pi
|
|
34
|
+
(`mu delegates run <call-id>`), with no pane and no attach command.
|
|
35
|
+
Its report names the session file and, when it fails, the log tail.
|
|
36
|
+
`keep` is dropped. Cancel stops the child. `/reload` lets it finish
|
|
37
|
+
onto its task; quitting pi cancels it.
|
|
29
38
|
- Watch or steer: run the attach command.
|
|
30
|
-
- Stop: `mu_delegate_cancel
|
|
39
|
+
- Stop: `mu_delegate_cancel` (a delegate name, a `queued-N` handle or a
|
|
40
|
+
call id), or `mu agent abort <name> -w scratch`. A cancel is recorded:
|
|
41
|
+
the task closes `wontfix` with a report.
|
|
31
42
|
- The pane closes after a clean finish; died or timed-out panes stay
|
|
32
43
|
as evidence.
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
- The answer reaches the model through the settle wait, never as a
|
|
45
|
+
copy in a pi message. When a delegate finishes, its answer is
|
|
46
|
+
recorded (verdict, report, close); the keep-driving settle wait then
|
|
47
|
+
returns it as a `delegate` event, and the continuation shows that
|
|
48
|
+
call's report (capped at 4000 characters, with the
|
|
49
|
+
`mu task notes <task> -w <ws>` pointer to the rest). A recorded check
|
|
50
|
+
with a verdict shows only its header: the verdict is on its task.
|
|
51
|
+
- A delegate of a `wave` is shown with the rest of the wave: the settle
|
|
52
|
+
keeps waiting while siblings run, then shows ONE summary (counts per
|
|
53
|
+
verdict, a line per call, the answers). A refused call is listed for
|
|
54
|
+
reissue and never waited on. Any other event (a worker closing, a
|
|
55
|
+
dialog) ends that early and is shown after the summary so far.
|
|
56
|
+
- When no settle wait will show an answer (pi is idle, `MU_NUDGE=0`, the
|
|
57
|
+
wait failed), the extension sends one **wake**: a pointer per answer,
|
|
58
|
+
no answer text, that starts a turn. A wake lost from pi's queue (the
|
|
59
|
+
dequeue key, alt+up) is sent once more; lost twice, or dropped by
|
|
60
|
+
Escape, it leaves one line per answer and starts nothing. The report
|
|
61
|
+
stays recorded either way, so the next settle shows it. Escape ends
|
|
62
|
+
only the wait running now: a later answer still wakes an idle pi.
|
|
63
|
+
- `MU_DELEGATE_TRACE=1` logs every wake send and pi lifecycle
|
|
64
|
+
event to `~/.cache/mu/delegate-trace.log`, for finding a lost answer.
|
|
41
65
|
- Each delegate costs a pane and a pi process. A session runs at most
|
|
42
66
|
`MU_DELEGATE_MAX` at once (default 16). Further calls are queued, up
|
|
43
|
-
to four times the cap:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
67
|
+
to four times the cap: each starts when a slot frees, and `mu_delegate_cancel queued-N`
|
|
68
|
+
drops one. Past the queue a call is **refused**, not lost: its task
|
|
69
|
+
and brief exist, its state is `refused`, and it does not start on its
|
|
70
|
+
own. Reissue it with `mu_delegate_reissue { call_id }` in its pi
|
|
71
|
+
session once a slot frees: same call, same task, never a second
|
|
72
|
+
verdict. Only that live runtime can start or drain a call, so
|
|
73
|
+
`mu delegates reissue` refuses and names the tool. A refused call is not in murmur's pending
|
|
74
|
+
count. A queued call has no pane yet, so quitting pi or `/reload`
|
|
75
|
+
parks it as `refused` (reissue it); pi warns which ones.
|
|
47
76
|
- A delegate that stops on an API error (overloaded, connection, auth)
|
|
48
77
|
keeps its pane. The answer names the error and leaves the choice to
|
|
49
|
-
the model: re-issue, or record the check as unverified.
|
|
50
|
-
counts it as `1 failed` until the pane is closed.
|
|
78
|
+
the model: re-issue, or record the check as unverified.
|
|
51
79
|
- Every answer without a final text (API error, empty, timeout, died,
|
|
52
|
-
`mu_delegate_cancel`)
|
|
53
|
-
it wrote anything,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
- Answers arrive as follow-up messages when pi would otherwise stop,
|
|
57
|
-
never mid-turn. To get several at once, set pi's `followUpMode` to
|
|
58
|
-
`"all"`.
|
|
80
|
+
`mu_delegate_cancel`) records the delegate's pi session file and,
|
|
81
|
+
when it wrote anything, its last message so far, in the report.
|
|
82
|
+
Quitting pi or `/reload` lists each running delegate's session file.
|
|
83
|
+
A call whose pane is gone fails when the next runtime re-adopts it.
|
|
59
84
|
|
|
60
85
|
`MU_DELEGATE=0` hides the tool ([env vars](../reference/env.md)).
|
|
61
86
|
|
|
87
|
+
### Every call is a task
|
|
88
|
+
|
|
89
|
+
Each `mu_delegate` call creates, in one transaction, a task of
|
|
90
|
+
`kind=delegate` in `scratch` (or the `workstream` you name) with the
|
|
91
|
+
prompt as its brief, plus a call row keyed by a session-qualified
|
|
92
|
+
`call_id` (`pi:<session>:<n>`). The tool result names both:
|
|
93
|
+
`{ task, state, call_id }`. A repeat of the same call id with the same
|
|
94
|
+
request is a no-op; a changed request under it is refused (exit 4).
|
|
95
|
+
|
|
96
|
+
| State | Meaning |
|
|
97
|
+
| ----- | ------- |
|
|
98
|
+
| `queued` | waits for a slot (the task is parked, so it never reaches `mu task next`) |
|
|
99
|
+
| `starting`, `running` | the pane is coming up, then working |
|
|
100
|
+
| `recording` | the answer is being written |
|
|
101
|
+
| `done` | verdict, report and close are all on record |
|
|
102
|
+
| `failed` | no answer, or the record failed: the task is closed `rejected`, the answer kept as its report, the pane kept |
|
|
103
|
+
| `refused` | past the queue; parked; reissue it |
|
|
104
|
+
| `cancelled` | closed `wontfix` with a report |
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
mu delegates list --caller pi:<session> # every call and its state
|
|
108
|
+
mu delegates list --all --wave review-1 # one wave
|
|
109
|
+
mu delegates tally -w scratch --wave review-1 # CONFIRMED/REFUTED/UNVERIFIED per judged task
|
|
110
|
+
mu task notes <task> -w scratch # its brief, and its report: the full answer
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The answer is the delegate task's `report`, whole; the settle shows it
|
|
114
|
+
from there, so a lost wake (Escape, compaction, `/reload`) loses
|
|
115
|
+
nothing: the next runtime of the same pi session (after `/reload`, or
|
|
116
|
+
`pi -c` after quitting) re-adopts its `running` pane calls and records
|
|
117
|
+
the answer, a delegate that finished meanwhile included. `tally`
|
|
118
|
+
counts one result per call: a done answer by the label of its first
|
|
119
|
+
`VERDICT:` line (none: UNVERIFIED), a failed or cancelled call as
|
|
120
|
+
UNVERIFIED, queued, running and refused ones as pending. So a plain
|
|
121
|
+
research call (an answer with no `VERDICT:` line) tallies UNVERIFIED
|
|
122
|
+
and closes `answered with no VERDICT line`: the answer arrived, it
|
|
123
|
+
just carries no label.
|
|
124
|
+
|
|
62
125
|
### Record a verdict
|
|
63
126
|
|
|
64
127
|
For a refuter or check, pass `record` so the verdict lands on the task
|
|
@@ -66,61 +129,70 @@ it judged. The task must exist (`mu task show`), else the call fails
|
|
|
66
129
|
and nothing spawns. When the answer arrives, the tool runs
|
|
67
130
|
`mu task note <task> -w <ws> --author <delegate>` once:
|
|
68
131
|
|
|
69
|
-
- Done: `REFUTER <label> (<delegate>, <elapsed>):`, then the
|
|
70
|
-
`VERDICT:`
|
|
71
|
-
|
|
72
|
-
|
|
132
|
+
- Done: `REFUTER <label> (<delegate>, <elapsed>):`, then the first
|
|
133
|
+
verdict line (`VERDICT:` at the start of a line, behind at most one
|
|
134
|
+
role word such as `REFUTER:`) and everything after it, a multi-line
|
|
135
|
+
`EVIDENCE:` body included, uncapped. Later `VERDICT:` lines are
|
|
136
|
+
evidence text, kept verbatim. Without a verdict line, the whole answer after
|
|
137
|
+
`NO VERDICT LINE:`.
|
|
73
138
|
- Timeout, died, empty, error, or cancelled:
|
|
74
139
|
`REFUTER <label>: no verdict (<outcome>)`.
|
|
75
140
|
|
|
76
|
-
The
|
|
77
|
-
|
|
141
|
+
The note, the delegate task's report and its close are written together,
|
|
142
|
+
in that order, in one op group (`mu delegates finish`); the delegate
|
|
143
|
+
task is closed before its pane. If the record fails the call is
|
|
144
|
+
`failed`, never `done`, and the answer is kept as the report.
|
|
145
|
+
|
|
146
|
+
The settle then shows the verdict and where the report is. A call whose
|
|
147
|
+
record failed is shown with its whole report and the reason, so you can
|
|
148
|
+
record it yourself.
|
|
78
149
|
|
|
79
150
|
## Delegate without pi
|
|
80
151
|
|
|
81
|
-
From a script or
|
|
152
|
+
From a script or another shell, spawn a helper bound to a task and wait
|
|
153
|
+
for the run it starts:
|
|
82
154
|
|
|
83
155
|
```bash
|
|
84
|
-
mu
|
|
85
|
-
|
|
86
|
-
mu
|
|
156
|
+
mu task add check_foo -w scratch -t 'Why does foo.spec.ts fail?' --note 'Investigate why foo.spec.ts fails. Report the cause.'
|
|
157
|
+
mu agent spawn helper-1 -w scratch --task check_foo --send 'Do task check_foo. Read: mu task notes check_foo -w scratch'
|
|
158
|
+
mu wait agent:scratch/helper-1
|
|
87
159
|
```
|
|
88
160
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
161
|
+
The send's `next` names the exact ref (`agent:scratch/helper-1@<runs>#<inc>`),
|
|
162
|
+
so a run that settles before the wait starts still counts, and a
|
|
163
|
+
restarted pi is refused rather than read. The result's
|
|
164
|
+
`data.snapshots[].lastText` is the answer (its tail if long; the whole
|
|
165
|
+
text is in `sessionFile`), and `data.firing.kind` says how the run ended:
|
|
166
|
+
`settled`, `input` (it stopped to ask), `dead` (exit 6) or `heartbeat`.
|
|
167
|
+
Non-pi agents have no `lastText`; read the pane with
|
|
168
|
+
`mu agent read helper-1 -w scratch -n 80`.
|
|
94
169
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
past `--after-runs`. For pi, the `--json`
|
|
98
|
-
row carries:
|
|
170
|
+
Use a fresh agent or `send --fresh`: a plain send to a reused agent
|
|
171
|
+
carries the previous task's context.
|
|
99
172
|
|
|
100
|
-
|
|
101
|
-
`pending`. `error` means the run stopped on an API error after pi's
|
|
102
|
-
own retries; `lastError` holds the message and the pane is kept.
|
|
103
|
-
`blocked` means pi is waiting on an extension dialog (`blocked` holds
|
|
104
|
-
its kind and title); the run is not finished.
|
|
105
|
-
- `lastText`: the final message, capped at 64 KiB.
|
|
106
|
-
- `sessionFile`: the agent's pi session file, holding the full
|
|
107
|
-
transcript (absent for an ephemeral pi or an older extension).
|
|
173
|
+
### With no multiplexer
|
|
108
174
|
|
|
109
|
-
|
|
110
|
-
`
|
|
175
|
+
`mu delegates run <call-id>` runs one registered call in a child
|
|
176
|
+
`pi --mode rpc` in the foreground: no tmux, no herdr, no pane. Register
|
|
177
|
+
the call first (`mu delegates register <call-id> --caller <id> --text -`),
|
|
178
|
+
then run it; it sends once, waits, records the verdict, report and close
|
|
179
|
+
on the call's task, and prints the child's log and session paths.
|
|
180
|
+
SIGINT cancels. `mu_delegate` does this by itself when no tmux or
|
|
181
|
+
herdr is installed (see above).
|
|
111
182
|
|
|
112
183
|
## Keep a helper
|
|
113
184
|
|
|
114
185
|
Pass `keep: true`, or spawn a named agent in `scratch`. It is created
|
|
115
186
|
on first spawn, needs no tasks, and cannot be `init`ed. Its `mu-scratch`
|
|
116
187
|
session stays open after the last agent closes; remove it with
|
|
117
|
-
`mu workstream teardown scratch
|
|
188
|
+
`mu workstream teardown scratch` (preview), then `--if <rev>`.
|
|
118
189
|
|
|
119
190
|
```bash
|
|
120
191
|
mu agent spawn helper -w scratch
|
|
121
192
|
mu agent send helper -w scratch 'Watch CI on PR 1234 and tell me when it is green'
|
|
122
193
|
mu agent read helper -w scratch -n 50
|
|
123
|
-
mu agent close helper -w scratch
|
|
194
|
+
mu agent close helper -w scratch # preview; prints rev=<n>
|
|
195
|
+
mu agent close helper -w scratch --if <n> # close it
|
|
124
196
|
```
|
|
125
197
|
|
|
126
198
|
A watcher's chat context does not survive compaction. Log each tick
|
|
@@ -146,7 +218,7 @@ pane.
|
|
|
146
218
|
| Steer mid-run | no | `mu agent send`; stop with `mu agent abort` |
|
|
147
219
|
| Keep talking after it answers | no | yes, with `keep: true` |
|
|
148
220
|
| Transcript | collapses into a result | a normal pi session log |
|
|
149
|
-
| If the work grows | re-brief a new agent | same task DAG and
|
|
221
|
+
| If the work grows | re-brief a new agent | same task DAG and worktrees |
|
|
150
222
|
| Cost | light | one pane and one pi process |
|
|
151
223
|
|
|
152
224
|
For many tiny calls, a hidden subagent is lighter. mu bets that seeing
|
|
@@ -155,13 +227,16 @@ and steering agent work is worth a pane.
|
|
|
155
227
|
## When to stop delegating
|
|
156
228
|
|
|
157
229
|
Use delegates when you only need the answer: reviewing someone's PR or
|
|
158
|
-
a doc, a fact-check, a go/no-go.
|
|
159
|
-
|
|
230
|
+
a doc, a fact-check, a go/no-go. Findings stay in the answers and
|
|
231
|
+
never enter your workstream's task graph. Each call's prompt and
|
|
232
|
+
answer are a `scratch` task, which is in the ops log and syncs like any
|
|
233
|
+
task; `mu workstream teardown scratch` hides them and `mu db forget
|
|
234
|
+
scratch` deletes them.
|
|
160
235
|
|
|
161
236
|
Move to a workstream when the findings become work agents will fix, or
|
|
162
237
|
the job has dependencies or several stages: see
|
|
163
238
|
[Getting started](getting-started.md) and
|
|
164
|
-
[How to dispatch work](dispatch.md). There, `mu
|
|
239
|
+
[How to dispatch work](dispatch.md). There, `mu wait` keys on the
|
|
165
240
|
task and has `--on-stall`. The agent-facing rules for both are in
|
|
166
241
|
[recipes/findings.md](../../skills/mu/recipes/findings.md) and
|
|
167
242
|
[recipes/tasks-or-calls.md](../../skills/mu/recipes/tasks-or-calls.md).
|
package/docs/guide/dispatch.md
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This guide assumes you finished [Getting started](getting-started.md).
|
|
4
4
|
The agent-facing loop and its traps are in
|
|
5
|
-
[recipes/orchestrator-loop.md](../../skills/mu/recipes/orchestrator-loop.md).
|
|
6
|
-
one repo, see [waves](../../skills/mu/recipes/waves.md); for runs that
|
|
7
|
-
last hours, see [long runs](../../skills/mu/recipes/long-run.md).
|
|
5
|
+
[recipes/orchestrator-loop.md](../../skills/mu/recipes/orchestrator-loop.md).
|
|
8
6
|
|
|
9
7
|
## Claim before you send
|
|
10
8
|
|
|
@@ -15,14 +13,14 @@ one-shot reviewer:
|
|
|
15
13
|
mu task claim build -w auth --for worker-1
|
|
16
14
|
```
|
|
17
15
|
|
|
18
|
-
`mu
|
|
16
|
+
`mu wait` watches tasks, and the reaper returns a claimed task to
|
|
19
17
|
`OPEN` when its pane dies. An unclaimed task gets neither. If no task
|
|
20
18
|
exists, create one with `mu task add --note '<brief>'`.
|
|
21
19
|
|
|
22
20
|
- `--for` takes a worker name or a qualified `<workstream>/<name>`.
|
|
23
21
|
The worker stays in its own workstream. Only the ownership crosses.
|
|
24
|
-
- Inside a worker's pane, bare `mu task claim <id>`
|
|
25
|
-
|
|
22
|
+
- Inside a worker's pane, bare `mu task claim <id>` claims for
|
|
23
|
+
`$MU_AGENT_NAME`, which spawn injects.
|
|
26
24
|
- To do the task yourself, use `mu task claim <id> --self`.
|
|
27
25
|
|
|
28
26
|
## Pick the send mode
|
|
@@ -53,23 +51,73 @@ socket. Pick the mode by what the agent is doing:
|
|
|
53
51
|
- `/new`, `/reload` and `/compact [instructions]` run inside pi through
|
|
54
52
|
the socket and report pi's answer (for example `Nothing to compact`).
|
|
55
53
|
They refuse with exit 4 while pi is busy; `--force` overrides. Any
|
|
56
|
-
other slash command exits 2
|
|
54
|
+
other slash command exits 2.
|
|
57
55
|
- If the socket does not answer, the send fails with exit 1 and
|
|
58
|
-
pastes nothing.
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
pastes nothing.
|
|
57
|
+
- A send's `--json` carries `msgId`, `incarnation` and `delivery`
|
|
58
|
+
(`delivered`, or `unknown` in the error JSON of a send that got no
|
|
59
|
+
reply). Its `next` is ONE line, the exact wait: `mu wait 'agent:<ws>/<a>@<n>#<inc>'`.
|
|
60
|
+
The `#<inc>` pin refuses (exit 4) when the agent restarted: its run is gone, so
|
|
61
|
+
re-send the brief. `--wait` enters that wait at once: one JSON document, the wait's, with the
|
|
62
|
+
send's receipt as `data.sent`. A delivered send (also `spawn --send`, `spawn --task`,
|
|
63
|
+
`send --interrupt`, `task claim --for`) is registered for the caller, so a bare `mu wait`
|
|
64
|
+
finds it with no ref; `mu task claim <id> --for <w> --and-wait` dispatches and waits.
|
|
65
|
+
- A send written to the socket but never answered is checked, not
|
|
66
|
+
repeated: mu asks once for the `msgId` and either reports success
|
|
67
|
+
(`receipt: confirmed-after-timeout`) or exits 1 with `next` the receipt
|
|
68
|
+
check `mu agent check <a> <msgId> -w <ws> --json` (only while the agent the
|
|
69
|
+
send went to is still registered). That verb prints `accepted runs=<n>
|
|
70
|
+
at=<iso>` (0), `not-accepted` (3) or `unreachable` (1). Only `accepted`
|
|
71
|
+
is an answer: **`not-accepted` is not "unsent"**. The extension keeps
|
|
72
|
+
its last 64 ids, so an old send reads `not-accepted` after eviction,
|
|
73
|
+
and a send that is still in flight can too. Look at the pane
|
|
74
|
+
(`mu agent read`) before any resend.
|
|
75
|
+
|
|
76
|
+
After `mu task claim <id> --for <w>`, `next` is the send that hands the task over (`--fresh` for a pi worker).
|
|
61
77
|
`mu agent spawn --send <text>` spawns and sends the first prompt in one
|
|
62
|
-
call; `--next-free` takes the next free name when `<name>` is taken
|
|
78
|
+
call; with `--task <id>` it is one journaled attempt (below); `--next-free` takes the next free name when `<name>` is taken
|
|
63
79
|
(`worker-1` → `worker-2`; the stem is cut to keep the name within 32
|
|
64
80
|
chars, and it gives up with exit 4 when no free name is near).
|
|
65
81
|
|
|
82
|
+
### Spawn for a task
|
|
83
|
+
|
|
84
|
+
`mu agent spawn <name> --task <id> --send <text>` spawns, **claims the task
|
|
85
|
+
for the new agent**, sends the text and pins it as the task's `brief` (kept
|
|
86
|
+
when the task has one), as one attempt. Without `--send` it sends the
|
|
87
|
+
task's own `brief` note (with the CLOSE footer, as `mu task auto` does), or
|
|
88
|
+
with no brief one line from its title that points at `mu task notes`. A journal (`spawn_receipts`) is
|
|
89
|
+
written before each step, so the same command never sends a second prompt.
|
|
90
|
+
|
|
91
|
+
- Same command again = replay: it returns the saved delivery
|
|
92
|
+
(`task.replay: true`, same `msgId`). `--attempt <key>` names the attempt
|
|
93
|
+
(default: the task id); a changed text or name under one key exits 4, and
|
|
94
|
+
reopened work needs a new key.
|
|
95
|
+
- Fails **before** the prompt could be written (no ctl, Claude's trust
|
|
96
|
+
dialog, a claim that lost the task, the extension refused): its own pane,
|
|
97
|
+
claim and worktree are rolled back, the key is reusable.
|
|
98
|
+
- Delivery **unknown** (written, no reply; the pane died after the write):
|
|
99
|
+
exit 1, the pane and the claim stay, `task.state` is `unknown`, and a
|
|
100
|
+
replay asks the extension once. Never reaped, never resent. Check it
|
|
101
|
+
with `mu agent check`, read the pane, then decide.
|
|
102
|
+
- A replay after the agent was deleted, or its name reused, reports the
|
|
103
|
+
historical delivery with `task.stale` (`deleted` | `replaced`); the
|
|
104
|
+
replacement is never claimed or sent to.
|
|
105
|
+
- The prompt goes only to the agent the spawn created (also plain
|
|
106
|
+
`spawn --send`): a replaced name, a closed task, or a task someone else
|
|
107
|
+
owns now refuses it (exit 4) with nothing sent.
|
|
108
|
+
- Another mu process running the same attempt exits 4 (`SpawnAttemptBusyError`);
|
|
109
|
+
retry and the replay returns its outcome.
|
|
110
|
+
|
|
66
111
|
### Non-pi agents
|
|
67
112
|
|
|
68
|
-
Agents other than pi have no control socket,
|
|
69
|
-
|
|
70
|
-
then the prompt. If mu prints
|
|
71
|
-
agent has not seen the text.
|
|
72
|
-
tmux
|
|
113
|
+
Agents other than pi have no control socket. On herdr, mu sends the
|
|
114
|
+
text with herdr's atomic `agent prompt`. To start a new session, send
|
|
115
|
+
`/new` (codex: `/clear`), then the prompt. If mu prints
|
|
116
|
+
`warning: ... was NOT submitted`, the agent has not seen the text.
|
|
117
|
+
Read the pane before you wait. On tmux, a send to a non-pi agent exits
|
|
118
|
+
4 (`AgentSendUnsupportedError`): spawn it on herdr (`MU_MUX=herdr`), start
|
|
119
|
+
it with the prompt as an argument, or use pi
|
|
120
|
+
([other agent CLIs](other-agent-clis.md)).
|
|
73
121
|
|
|
74
122
|
## Write the brief
|
|
75
123
|
|
|
@@ -94,55 +142,66 @@ quoted heredoc: `mu agent send worker-1 - <<'EOF'`; see
|
|
|
94
142
|
[brief](../../skills/mu/recipes/brief.md#quoting). To see only what the worker wrote after the claim, run
|
|
95
143
|
`mu task notes build -w auth --since-claim`.
|
|
96
144
|
|
|
97
|
-
## Give each worker a
|
|
145
|
+
## Give each worker a worktree
|
|
98
146
|
|
|
99
|
-
`mu agent spawn --
|
|
100
|
-
|
|
147
|
+
`mu agent spawn --worktree` creates a git worktree for the agent and starts
|
|
148
|
+
its pane there: the worker's cwd is its worktree. Outside a git repo it
|
|
149
|
+
fails with exit 4. `--from <ref>` picks the starting commit and `--root <repo>`
|
|
150
|
+
the repo; both default to the HEAD of the checkout you run in (a linked one included). You cherry-pick from it.
|
|
101
151
|
|
|
102
|
-
Refresh the
|
|
103
|
-
context:
|
|
152
|
+
Refresh the worktree between tasks. The rebase keeps the agent's pi
|
|
153
|
+
context. Before a `--fresh` send:
|
|
104
154
|
|
|
105
155
|
```bash
|
|
106
|
-
mu
|
|
156
|
+
cwd=$(mu agent list -w auth --json | jq -r '.agents[] | select(.name == "worker-1") | .cwd')
|
|
157
|
+
git -C "$cwd" fetch && git -C "$cwd" rebase origin/HEAD
|
|
107
158
|
```
|
|
108
159
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
run refresh again so mu records the new base. To throw the workspace away
|
|
114
|
-
instead, run `mu workspace free worker-1 -w auth`.
|
|
115
|
-
|
|
116
|
-
Claim and send warn when the worker's workspace is 10 or more commits
|
|
117
|
-
behind main. `--strict-staleness` makes that a refusal (exit 4).
|
|
160
|
+
Use `origin/HEAD` as the base, or local main when you merged locally. On a
|
|
161
|
+
conflict, run `git -C "$cwd" rebase --abort` and tell the human. To throw
|
|
162
|
+
the worktree away instead, preview `mu agent close worker-1 -w auth --discard`
|
|
163
|
+
and apply it with `--if <n>`.
|
|
118
164
|
|
|
119
165
|
## Wait for the first task to close
|
|
120
166
|
|
|
121
167
|
Wait on every in-flight task and handle the first one that closes:
|
|
122
168
|
|
|
123
169
|
```bash
|
|
124
|
-
mu
|
|
170
|
+
mu wait task:auth/build task:auth/docs
|
|
125
171
|
```
|
|
126
172
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
`
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
173
|
+
`mu wait` prints ONE JSON document, with no `--json` flag. Refs are typed
|
|
174
|
+
(`task:`, `agent:`, `delegate:`); with none, it waits on what you started.
|
|
175
|
+
|
|
176
|
+
- `data.firing` is the event: `closed`, `settled`, `input`, `dead`, `stall`,
|
|
177
|
+
`delegate`, or `heartbeat` on a timeout (`ok:true`, `timedOut`, exit 0).
|
|
178
|
+
- `data.snapshots` are the refs' real states; `data.resume` is the command
|
|
179
|
+
that keeps waiting, with every flag you gave. Run it as printed: it takes
|
|
180
|
+
no other flag (only a matching `-w`). When two watched owners die in one
|
|
181
|
+
wait, only the first fires; follow `resume` to hear the second. A fresh
|
|
182
|
+
`mu wait` with the same refs starts a new anchor and reports the earlier
|
|
183
|
+
death as history.
|
|
184
|
+
- `data.cursor` is what this result consumed per ref (`incarnation`, `runs`);
|
|
185
|
+
the next wait starts after it, so the same event is never reported twice.
|
|
186
|
+
`cursorCut` counts entries dropped to fit the 4 KB result.
|
|
187
|
+
- `close:{applied:false, reason:"no CLOSE block…"}` on a settled worker
|
|
188
|
+
is not a failure: the worker sent no CLOSE block, often because it
|
|
189
|
+
closed its own task. Read the snapshot's task status.
|
|
190
|
+
- `next` is the stored resume while something is still owed, else null.
|
|
191
|
+
- Exit codes: `0` event or timeout, `6` the owner's pane died, `7` the owner
|
|
192
|
+
sat in `needs_input` for `--stuck-after` seconds (default 120, or 5 for a pi
|
|
193
|
+
worker read over its control socket), `130`/`143` SIGINT/SIGTERM (the
|
|
194
|
+
snapshot and `resume` are still printed). `--on-stall warn` flags the stall
|
|
195
|
+
on the snapshot and keeps waiting; `steer` sends the stalled pi worker you
|
|
196
|
+
spawned one fixed reminder and keeps waiting; `release` frees its task and
|
|
197
|
+
ends the wait. `data.action` (and a stderr line) says `sent`, `released`,
|
|
198
|
+
`refused` or `unknown`; both refuse a worker you did not spawn or a task not
|
|
199
|
+
permitted with `mu task auto`. `mu task wait` is the same wait over task
|
|
200
|
+
refs.
|
|
201
|
+
- `--all` waits for every ref; `--until-text <re>` waits for a run's final
|
|
202
|
+
text; `--wave <name>` waits on your delegate wave in any workstream
|
|
203
|
+
(`-w` does not narrow it) and `data.tally` says `6/12 CONFIRMED, ...`;
|
|
204
|
+
a name none of your calls carry is `no such wave` (exit 3).
|
|
146
205
|
|
|
147
206
|
## Close and park tasks
|
|
148
207
|
|
|
@@ -153,8 +212,11 @@ mu task park polish -w auth --why "after the release"
|
|
|
153
212
|
mu task release build -w auth
|
|
154
213
|
```
|
|
155
214
|
|
|
156
|
-
-
|
|
157
|
-
|
|
215
|
+
- `close` needs `--evidence "<command + result>"` for `done`; the other
|
|
216
|
+
substates need `--why`, which is their evidence. `done` also refuses
|
|
217
|
+
while a blocker is open (exit 4, `mu task tree <id>` lists them); the
|
|
218
|
+
other substates may close over open blockers. Every `CLOSED` substate
|
|
219
|
+
satisfies a blocker.
|
|
158
220
|
- Deciding a finding (`accept`, or `close --as rejected|wontfix|duplicate`)
|
|
159
221
|
with a reason under 40 characters and no `VERDICT:` or `REFUTER` note
|
|
160
222
|
prints a warning. The exit code stays the same. A `REJECTED` or `SUPERSEDED`
|
|
@@ -162,7 +224,40 @@ mu task release build -w auth
|
|
|
162
224
|
- `--if-ready` closes only when every blocker is closed. Otherwise it
|
|
163
225
|
lists the open blockers and exits 0.
|
|
164
226
|
- A parked task leaves the ready set, and its dependents keep waiting.
|
|
227
|
+
- `mu human-needed <reason>` records a parked `human` task for a decision only a
|
|
228
|
+
person can make. It never becomes ready and resolves only by `mu task close`
|
|
229
|
+
(unpark, claim and a CLOSE block are refused).
|
|
165
230
|
- `release` clears the owner and returns `IN_PROGRESS` to `OPEN`.
|
|
166
231
|
|
|
232
|
+
## Authorise tasks for the executor
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
mu task auto build --cli pi --max 2 -w auth
|
|
236
|
+
mu task auto --blockers-of umbrella --cli pi -w auth
|
|
237
|
+
mu task auto build --off -w auth
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Ready is not permission: the executor acts only on an `auto` task, and only on
|
|
241
|
+
the machine that authorised it. `--off` keeps the run counter.
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
mu next --dry -w auth # the plan; no pane, socket or write
|
|
245
|
+
mu next --hold -w auth # dispatch, then wait; recover deaths and API errors
|
|
246
|
+
mu next --workers 2 -w auth # never more than 2 working; a CLOSED task's idle pane is free
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`mu next` also recovers. A worker whose pane died is reaped and its task retried as a new
|
|
250
|
+
attempt; a live worker whose run ended in an API error is sent its brief again in place (never
|
|
251
|
+
reaped, never duplicated). Each retry costs one run of the ceiling; a remote worker's tree is never
|
|
252
|
+
touched. At the ceiling, or for anything it will not guess, it reports an `attention` move.
|
|
253
|
+
|
|
254
|
+
`mu next --refute [--refute-cli <key>]` also launches ONE checker per task a worker closed as `done`
|
|
255
|
+
(a delegate call in `scratch`, wave `refute-<ws>`, briefed from the task's pinned brief and its
|
|
256
|
+
report). Its `VERDICT:` is recorded on the task before the call closes; the checker never accepts,
|
|
257
|
+
reopens or closes the work, and a wontfix/rejected close gets none. It needs a caller identity
|
|
258
|
+
(`PI_SESSION_ID` or a managed agent) and a cli that speaks ctl (default: the task's own). A repeat
|
|
259
|
+
`mu next --refute` reads a running checker and records its answer (or its death or timeout as
|
|
260
|
+
UNVERIFIED); `--dry` lists the owed checks. `mu delegates tally --wave refute-<ws>` counts them.
|
|
261
|
+
|
|
167
262
|
To wait on something outside the repo, such as an upstream release,
|
|
168
263
|
block on a placeholder task and close it when the thing lands.
|