@mu-crew/mu 3.6.2 → 3.8.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/dist/cli.js +12652 -12264
- package/dist/cli.js.map +1 -1
- package/dist/extension/mu-pi.js +302 -48
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +59 -13
- package/dist/index.js +1376 -1205
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +4 -3
- package/docs/architecture/control-socket.md +10 -5
- package/docs/architecture/mux.md +4 -1
- package/docs/guide/delegate.md +25 -3
- package/docs/guide/dispatch.md +22 -5
- package/docs/guide/getting-started.md +2 -2
- package/docs/guide/recovery.md +11 -6
- package/docs/guide/upgrade.md +4 -4
- package/docs/reference/env.md +2 -2
- package/docs/specs/2026-10-03-keep-driving-nudge.md +21 -0
- package/package.json +1 -1
- package/skills/mu/SKILL.md +40 -16
- package/skills/mu/recipes/adversarial-review.md +14 -6
- package/skills/mu/recipes/brief.md +29 -1
- package/skills/mu/recipes/codemode-driver.md +19 -9
- package/skills/mu/recipes/deep-research.md +6 -5
- package/skills/mu/recipes/drift-audit.md +72 -0
- package/skills/mu/recipes/findings.md +24 -15
- package/skills/mu/recipes/hypothesis-panel.md +5 -3
- package/skills/mu/recipes/long-run.md +13 -3
- package/skills/mu/recipes/loop-until-done.md +4 -3
- package/skills/mu/recipes/orchestrator-loop.md +29 -16
- package/skills/mu/recipes/plan.md +10 -6
- package/skills/mu/recipes/refute.md +3 -2
- package/skills/mu/recipes/remote-workers.md +23 -6
- package/skills/mu/recipes/review-panel.md +2 -2
- package/skills/mu/recipes/rules-audit.md +10 -5
- package/skills/mu/recipes/tasks-or-calls.md +40 -23
- package/skills/mu/recipes/tournament.md +4 -3
- package/skills/mu/recipes/ultrathink.md +2 -2
- package/skills/mu/recipes/worker.md +3 -2
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Drift audit
|
|
2
|
+
|
|
3
|
+
Use during a long run to catch a crew drifting from what you decided:
|
|
4
|
+
an instruction that never reached its worker, a batch run on stale
|
|
5
|
+
inputs, work continuing on a closed task. One read-only
|
|
6
|
+
[delegate call](tasks-or-calls.md#delegate-call); it edits nothing.
|
|
7
|
+
|
|
8
|
+
## When
|
|
9
|
+
|
|
10
|
+
- every few hours of a long run;
|
|
11
|
+
- after each batch report of a chained task (sweep, campaign, soak);
|
|
12
|
+
- after a context compaction or a resume;
|
|
13
|
+
- before you declare a stop rule met.
|
|
14
|
+
|
|
15
|
+
## Run
|
|
16
|
+
|
|
17
|
+
Issue one delegate call with `record: { task: "<ws>/<umbrella>" }` and
|
|
18
|
+
this brief, with `<ws>` filled in:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
Read-only drift audit of mu workstream <ws>. Change nothing. Sources:
|
|
22
|
+
mu state -w <ws>; mu task list -w <ws> --json; mu task notes <id> -w <ws>;
|
|
23
|
+
mu sql (ops, tasks, task_notes, agents); git log in the repo and in each
|
|
24
|
+
owner's workspace. Never judge by a capped mu log -n window: the claim
|
|
25
|
+
or close you compare against is often older than it.
|
|
26
|
+
1. Unsent notes: notes on IN_PROGRESS tasks, by someone other than the
|
|
27
|
+
owner, after the owner's last task.claim or agent.send op:
|
|
28
|
+
mu sql "select t.local_id task, a.name owner, n.created_at, substr(n.content,1,80) note from tasks t join workstreams w on w.id=t.workstream_id join agents a on a.id=t.owner_id join task_notes n on n.task_id=t.id where w.name='<ws>' and t.status='IN_PROGRESS' and coalesce(n.author,'')<>a.name and n.created_at > max(coalesce((select max(o.created_at) from ops o where o.intent='task.claim' and o.key='<ws>/'||t.local_id),''), coalesce((select max(o.created_at) from ops o where o.intent='agent.send' and o.key='<ws>' and o.payload like 'agent send '||a.name||' (%'),'')) order by n.created_at"
|
|
29
|
+
Quote each task's last claim (seq, time). For each instruction it
|
|
30
|
+
lists: did the owner act on it (later commits, notes, pane)? Also read
|
|
31
|
+
mu sql "select seq, created_at, payload from ops where intent='agent.send' and key='<ws>'"
|
|
32
|
+
and flag mode=plain or mode=steer with state=busy since=<t> long
|
|
33
|
+
before the send: it queued behind a long turn and may not have landed.
|
|
34
|
+
2. Stale pins: for each build/binary sha or oracle commit named in an
|
|
35
|
+
IN_PROGRESS note, and each merged fix its task's findings depend on:
|
|
36
|
+
git merge-base --is-ancestor <fix> <pinned>. Exit 1 = pin is stale.
|
|
37
|
+
3. Closed-task notes: notes added after the task's last task.close op.
|
|
38
|
+
Report each of the top 5 by count as its own finding with its count,
|
|
39
|
+
even when the notes look routine. A late note that reports the
|
|
40
|
+
closed bug again usually ran on a build without the closing fix:
|
|
41
|
+
check its sha with git merge-base --is-ancestor <fix> <sha>.
|
|
42
|
+
mu sql "select t.local_id name, count(*) late from tasks t join workstreams w on w.id=t.workstream_id join task_notes n on n.task_id=t.id where w.name='<ws>' and t.status='CLOSED' and n.created_at > (select max(o.created_at) from ops o where o.intent='task.close' and o.key='<ws>/'||t.local_id) group by t.local_id order by late desc"
|
|
43
|
+
4. Thin decisions: an ACCEPT/REJECTED/CLOSE/SUPERSEDED note under 40
|
|
44
|
+
chars; a refuter tally with no REFUTER or VERDICT note; a review the
|
|
45
|
+
orchestrator closed with no FILES/COMMANDS note and no commit.
|
|
46
|
+
5. Silent tasks: IN_PROGRESS with no note or commit for longer than
|
|
47
|
+
the cadence its notes state (default 2h).
|
|
48
|
+
6. Missing work: a task or finding a note or log line says will be
|
|
49
|
+
filed that does not exist.
|
|
50
|
+
7. Unrefuted briefs: IN_PROGRESS tasks with no note line starting
|
|
51
|
+
REFUTER , VERDICT: or REFUTE-EXEMPT:.
|
|
52
|
+
End with exactly this, one EVIDENCE line per finding (none when clean):
|
|
53
|
+
VERDICT: <ws> DRIFT-AUDIT CLEAN | FINDINGS <n>
|
|
54
|
+
EVIDENCE: FINDING <high|med|low> <file:line|task> <what> (check <1-7>)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`record` keeps only the VERDICT line and the `EVIDENCE:` lines after
|
|
58
|
+
it, so each finding must be an `EVIDENCE: FINDING` line. The note
|
|
59
|
+
lands headed `REFUTER`, which the refute nudge and decision warnings
|
|
60
|
+
read as a recorded verdict; on an umbrella that is harmless.
|
|
61
|
+
|
|
62
|
+
## Act
|
|
63
|
+
|
|
64
|
+
Each finding becomes one of:
|
|
65
|
+
|
|
66
|
+
- an `OPEN/triage` task blocking the umbrella ([findings § Record](findings.md#record));
|
|
67
|
+
- a send to the worker it names, per
|
|
68
|
+
[orchestrator-loop § Sending](orchestrator-loop.md#sending)
|
|
69
|
+
(`--interrupt` when its current work is wasted, as with a stale pin).
|
|
70
|
+
|
|
71
|
+
Done when the verdict is recorded on the umbrella and every finding
|
|
72
|
+
is a task or a delivered send.
|
|
@@ -69,24 +69,33 @@ across reviewers and creates one task per real problem.
|
|
|
69
69
|
or several reviewers on one change: a `triage_<umbrella>` task, run
|
|
70
70
|
by a fresh agent, so the orchestrator reads only its result.
|
|
71
71
|
2. **Refute** each finding before accepting it with a
|
|
72
|
-
[delegate call](tasks-or-calls.md#delegate-call)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
72
|
+
[delegate call](tasks-or-calls.md#delegate-call) that passes
|
|
73
|
+
`record: { task: "<ws>/<id>" }`: a fresh agent tries to prove it
|
|
74
|
+
false, and its VERDICT block lands on the finding as a
|
|
75
|
+
`REFUTER <label> (<delegate>, <elapsed>):` note (VERDICT line, 3-6
|
|
76
|
+
EVIDENCE lines), or `REFUTER <label>: no verdict (<outcome>)` when
|
|
77
|
+
it times out or dies. Without `mu_delegate`, write that note yourself
|
|
78
|
+
before deciding
|
|
79
|
+
([tasks-or-calls § Delegate call](tasks-or-calls.md#delegate-call)).
|
|
80
|
+
Skip this for low-severity style findings. High severity: three
|
|
81
|
+
refuters, accept only if at least two say CONFIRMED.
|
|
82
|
+
3. **Decide** each one; the decision is the task's state. The reason
|
|
83
|
+
names the deciding evidence, not a tally or a judgement. mu warns
|
|
84
|
+
when a reason is under 40 chars and no note holds a `VERDICT:` line
|
|
85
|
+
or `REFUTER` note. Prose reasons go through a heredoc variable
|
|
86
|
+
([brief § Quoting](brief.md#quoting)).
|
|
87
|
+
|
|
88
|
+
| Decision | Command | Bad reason |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| real work | `mu task accept <id> --evidence "2/3 CONFIRMED: refuters 1 and 3 show the checklist:3 vs :33 cycle"` | `valid`, `orchestrator: valid`, `2/3 CONFIRMED` |
|
|
91
|
+
| false | `mu task close <id> --as rejected --why "<the guard or command that disproves it>"` | `refuter REFUTED` |
|
|
92
|
+
| same as another | `mu task close <id> --as duplicate --why "same as <id>"` | |
|
|
93
|
+
| valid, not worth it | `mu task close <id> --as wontfix --why "<cost vs impact>"` | `not worth it` |
|
|
94
|
+
| could not check | stays in triage, with an `UNVERIFIED: <why>` note | |
|
|
86
95
|
|
|
87
96
|
4. **Group** accepted findings that touch the same files into one fix
|
|
88
97
|
task when separate workers would collide; close the grouped findings
|
|
89
|
-
`--as superseded --why
|
|
98
|
+
`--as superseded --why "fixed in <fix-task>"`.
|
|
90
99
|
|
|
91
100
|
Done when `mu task list --substate triage -w <ws>` lists only findings
|
|
92
101
|
with an `UNVERIFIED` note, and each of those is reported to the human.
|
|
@@ -23,9 +23,11 @@ form independent theories; separate agents then try to kill them.
|
|
|
23
23
|
3. **Test each hypothesis.** An experiment that changes code (force the
|
|
24
24
|
race, revert the commit) needs a workspace: `mu task accept` the
|
|
25
25
|
hypothesis and dispatch it as a task. One that only reads (feed the
|
|
26
|
-
data, grep the logs) is a delegate call
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
data, grep the logs) is a delegate call with `record` on the
|
|
27
|
+
hypothesis ([tasks-or-calls § Delegate call](tasks-or-calls.md#delegate-call)).
|
|
28
|
+
A killed hypothesis closes `--as rejected --why "<the observation
|
|
29
|
+
that contradicts PREDICTS>"`; a survivor gets a `SURVIVED: <evidence>`
|
|
30
|
+
note. Prose reasons: [brief § Quoting](brief.md#quoting).
|
|
29
31
|
4. **If one survives**, add a fix task for it, then a review task
|
|
30
32
|
([adversarial-review](adversarial-review.md)). The fix is accepted
|
|
31
33
|
only if the step 1 repro stops reproducing.
|
|
@@ -6,15 +6,25 @@ or may hit flakes.
|
|
|
6
6
|
1. **Define done first.** Before dispatch, write the completion criterion
|
|
7
7
|
into the task note: the checks, how many runs must agree, the
|
|
8
8
|
allowed variance. A worker that finds the bar in the note stops at
|
|
9
|
-
the bar, not at the first green.
|
|
9
|
+
the bar, not at the first green. For chained batches (sweeps,
|
|
10
|
+
campaigns, soaks) it also names the **inputs** each batch runs on
|
|
11
|
+
(build sha, oracle commit, config) and when to refresh them
|
|
12
|
+
("rebuild from main before each batch"); each batch report states
|
|
13
|
+
the inputs it used, and the stop rule counts only batches on
|
|
14
|
+
current inputs.
|
|
10
15
|
2. **Split into independent units** ([fan-out](fan-out.md)). Shard a long proof into tasks
|
|
11
16
|
that run in parallel, so one flake restarts only its unit. Each unit
|
|
12
17
|
carries its own criterion.
|
|
13
18
|
3. **Keep state in the DB.** Progress lives in task notes, not in the
|
|
14
19
|
orchestrator's context. After a compaction, `mu state` and
|
|
15
20
|
`mu task notes <id>` are the whole picture.
|
|
16
|
-
4. **
|
|
17
|
-
|
|
21
|
+
4. **Bound each tool call** to minutes: batches of ≤10 minutes,
|
|
22
|
+
`mu task wait --timeout` re-issued, no open-ended `sleep` loops.
|
|
23
|
+
A `--steer` lands only when the running tool returns.
|
|
24
|
+
5. **Accept evidence, not close notes**
|
|
25
|
+
([orchestrator-loop § Merging](orchestrator-loop.md#merging)), and
|
|
26
|
+
run a [drift-audit](drift-audit.md) after each batch report and
|
|
27
|
+
every few hours.
|
|
18
28
|
|
|
19
29
|
Done when every unit is `CLOSED/done` and the criterion from step 1
|
|
20
30
|
holds on the merged tree.
|
|
@@ -25,11 +25,12 @@ written down first does neither.
|
|
|
25
25
|
`MEASURE: 14 errors (was 31)`, or `NEW: 0 flaky tests`.
|
|
26
26
|
4. **After each round, check the rule** yourself, from the measurement
|
|
27
27
|
command, not from the worker's note.
|
|
28
|
-
- Rule met: `mu task close <umbrella> --if-ready --evidence
|
|
29
|
-
command + result>
|
|
28
|
+
- Rule met: `mu task close <umbrella> --if-ready --evidence "<stop
|
|
29
|
+
command + result>"` (each round blocks the umbrella).
|
|
30
30
|
- No progress: stop the loop and decide. Change the approach, split
|
|
31
31
|
the work, or park the umbrella with
|
|
32
|
-
`mu task park <umbrella> --why
|
|
32
|
+
`mu task park <umbrella> --why "<what is stuck>"` and tell the human.
|
|
33
|
+
Prose reasons: [brief § Quoting](brief.md#quoting).
|
|
33
34
|
- Otherwise: add the next round and dispatch it.
|
|
34
35
|
|
|
35
36
|
Done when the stop rule holds on the merged tree, run by you.
|
|
@@ -39,8 +39,8 @@ keeps it.
|
|
|
39
39
|
- **Answers arrive when you stop**, as pi follow-up messages, never
|
|
40
40
|
mid-turn. pi's `followUpMode: "all"` delivers every waiting answer in
|
|
41
41
|
one turn instead of one turn each; each answer names its delegate and
|
|
42
|
-
ends with its `VERDICT: <id>`
|
|
43
|
-
every verdict in the batch before
|
|
42
|
+
ends with its `VERDICT: <id>` block, so a batch still maps back. Read
|
|
43
|
+
every verdict in the batch before deciding any.
|
|
44
44
|
- **Workers with workspaces** build and test: about one per CPU core,
|
|
45
45
|
fewer when each runs the full suite. A remote host has its own
|
|
46
46
|
session cap ([remote-workers](remote-workers.md)).
|
|
@@ -54,12 +54,16 @@ keeps it.
|
|
|
54
54
|
Use `--first --on-stall exit`: `--first` populates `.firing`, and
|
|
55
55
|
`--on-stall exit` stops an unattended wait when a worker needs attention.
|
|
56
56
|
Exit 6: the owner's pane died and the reaper reopened the task; exit 7:
|
|
57
|
-
the owner sat in `needs_input`.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
the owner sat in `needs_input`. Run the exit's `Next:` and answer: the
|
|
58
|
+
worker may be waiting on you. For a pi owner it leads with
|
|
59
|
+
`mu agent wait <owner> --after-runs <runs-1> --json`, which returns the
|
|
60
|
+
last answer at once. The pane read follows because dialogs and crashes
|
|
61
|
+
show only in the pane.
|
|
62
|
+
|
|
63
|
+
For an idle worker, read its last answer (the same `--after-runs`
|
|
64
|
+
wait for pi, else the pane), then answer, retry, or release its task.
|
|
65
|
+
`MU_IDLE_THRESHOLD_MS` defaults to 5m. A remote owner: for pi,
|
|
66
|
+
`mu agent wait --after-runs` first, then poll once; otherwise poll once
|
|
63
67
|
per turn ([remote-workers](remote-workers.md#step-5-poll-once-per-turn)).
|
|
64
68
|
|
|
65
69
|
## Merging
|
|
@@ -75,7 +79,8 @@ per turn ([remote-workers](remote-workers.md#step-5-poll-once-per-turn)).
|
|
|
75
79
|
test once passed with zero cases.
|
|
76
80
|
- **Accept evidence, not close notes.** Re-run the key measurement from
|
|
77
81
|
a clean checkout; close notes have claimed unpushed commits. A
|
|
78
|
-
worker's "done" counts only once the diff shows the change.
|
|
82
|
+
worker's "done" counts only once the diff shows the change. Your own
|
|
83
|
+
accept and close notes name the check run and the commit.
|
|
79
84
|
- **Ask whether the check could have failed.** A gate that cannot say
|
|
80
85
|
no is not evidence: a test filtered to zero cases, a script you wrote
|
|
81
86
|
agreeing with itself, a fixture you tuned on. A nonzero diff is a
|
|
@@ -83,16 +88,24 @@ per turn ([remote-workers](remote-workers.md#step-5-poll-once-per-turn)).
|
|
|
83
88
|
|
|
84
89
|
## Sending
|
|
85
90
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
A running worker sees what you send, never a new task note: deliver
|
|
92
|
+
an instruction for it with a send (or the next `--fresh` brief), and
|
|
93
|
+
keep the note as the durable copy. pi:
|
|
94
|
+
|
|
95
|
+
| `mu agent send` | busy pi acts | Use for |
|
|
96
|
+
| --- | --- | --- |
|
|
97
|
+
| plain | after the run ends | answers, same-task additions |
|
|
98
|
+
| `--steer` | after the current tool call | advice that can wait for the tool boundary |
|
|
99
|
+
| `--interrupt` | now: kills the running tool | a correction that wastes the current work (stale input, wrong target, changed stop rule) |
|
|
100
|
+
| `--fresh` | refused (`--force` drops the run) | unrelated work: new session + prompt |
|
|
101
|
+
|
|
89
102
|
- claude-code/codex: send `/new` (codex: `/clear`), then the prompt; a
|
|
90
|
-
send it cannot confirm prints a `warning:` on stderr.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
containing shell expansions, or use a quoted heredoc.
|
|
103
|
+
send it cannot confirm prints a `warning:` on stderr.
|
|
104
|
+
- Use `mu agent send`, not raw mux input. Quote prompts per
|
|
105
|
+
[brief](brief.md#quoting).
|
|
94
106
|
- Cross-workstream wait and claim use qualified refs; only task
|
|
95
107
|
ownership crosses.
|
|
108
|
+
- A long run drifts unseen: audit it per [drift-audit](drift-audit.md).
|
|
96
109
|
|
|
97
110
|
## Stopping a worker
|
|
98
111
|
|
|
@@ -40,14 +40,18 @@ human asks for a file.
|
|
|
40
40
|
consumes what B produces. Plan order is not a dependency: an extra
|
|
41
41
|
edge serialises tracks that could run in parallel. The exception:
|
|
42
42
|
tasks that edit the same files share a track ([waves](waves.md)).
|
|
43
|
-
7. **Self-review before dispatch.**
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
7. **Self-review before dispatch.** Map each spec requirement to its
|
|
44
|
+
task, grep the notes for placeholders, match INTERFACES names across
|
|
45
|
+
tasks, and read the graph back (`mu task tree task_0 -w <ws> --down`).
|
|
46
|
+
Then refute each brief that makes claims ([call](tasks-or-calls.md#delegate-call),
|
|
47
|
+
all in one turn): "What in this brief is false about the code,
|
|
48
|
+
ambiguous, or would make a correct worker fail review? Cite
|
|
49
|
+
file:line." Rewrite each AMEND. Five of six briefs refuted in one run had
|
|
50
|
+
such a defect, e.g. a fallback test old extensions made unpassable.
|
|
47
51
|
|
|
48
52
|
Done when every spec requirement maps to a task, no note holds a
|
|
49
|
-
placeholder,
|
|
50
|
-
dispatch per [orchestrator-loop](orchestrator-loop.md).
|
|
53
|
+
placeholder, every claim-making brief has a verdict, and `mu state`
|
|
54
|
+
shows the intended parallel tracks. Then dispatch per [orchestrator-loop](orchestrator-loop.md).
|
|
51
55
|
|
|
52
56
|
## Notes
|
|
53
57
|
|
|
@@ -27,8 +27,9 @@ fact-check nobody will track, use delegate mode from
|
|
|
27
27
|
[delegate call](tasks-or-calls.md#delegate-call), not a task. The
|
|
28
28
|
refuter gets the finding and the code, not the finder's reasoning,
|
|
29
29
|
and tries to prove it false: run it, find the guard, read the caller.
|
|
30
|
-
|
|
31
|
-
three-refuter rules, as in
|
|
30
|
+
Pass `record` so its verdict lands on the finding, and apply the
|
|
31
|
+
skip and three-refuter rules, as in
|
|
32
|
+
[findings § Triage](findings.md#triage).
|
|
32
33
|
Many findings: issue the calls in batches under the cap ([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)); to
|
|
33
34
|
get the verdicts back as one table, see
|
|
34
35
|
[codemode-driver § Delegate calls](codemode-driver.md#delegate-calls).
|
|
@@ -44,7 +44,8 @@ mu agent spawn worker-1 -w big --command \
|
|
|
44
44
|
mu task claim t1 -w big --for worker-1 --evidence 'remote on dev'
|
|
45
45
|
mu agent send worker-1 -w big --fresh '...'
|
|
46
46
|
|
|
47
|
-
# 5. WAIT:
|
|
47
|
+
# 5. WAIT: pi: mu agent wait worker-1 -w big --after-runs <send's runs> --json,
|
|
48
|
+
# then the claim's Next: once. non-pi: run the claim's Next: once per turn
|
|
48
49
|
|
|
49
50
|
# 6. COLLECT: fetch straight from the remote worktree
|
|
50
51
|
git fetch "ssh://dev/~/ws/worker-1" HEAD && git cherry-pick FETCH_HEAD
|
|
@@ -72,13 +73,13 @@ retry next turn, not progress.
|
|
|
72
73
|
|
|
73
74
|
### Step 3: the control-socket forward
|
|
74
75
|
|
|
75
|
-
Spawn reports `ctl ok` when all of these hold (`mu doctor` has a ctl
|
|
76
|
+
Spawn reports `ctl: ok` when all of these hold (`mu doctor` has a ctl
|
|
76
77
|
row per agent):
|
|
77
78
|
|
|
78
79
|
- The host has the mu extension: run `mu link pi` there.
|
|
79
80
|
- The ssh is direct. `$MU_SSH_ARGS` sets `ControlMaster=no
|
|
80
81
|
ControlPath=none`; a multiplexed ssh never binds the forward and spawn
|
|
81
|
-
reports `ctl missing`.
|
|
82
|
+
reports `ctl: missing`.
|
|
82
83
|
- sshd allows the forward. A refused forward kills the pane at spawn
|
|
83
84
|
(`ExitOnForwardFailure=yes`). Check `AllowStreamLocalForwarding`.
|
|
84
85
|
|
|
@@ -88,6 +89,16 @@ plus a 10 s cache.
|
|
|
88
89
|
|
|
89
90
|
### Step 5: poll once per turn
|
|
90
91
|
|
|
92
|
+
The claim's `Next:` mule poll is mandatory. It proves the commit is on
|
|
93
|
+
the host and closes the task. For a pi worker, first block on
|
|
94
|
+
`mu agent wait <name> --after-runs <runs> --json`, with `runs` from
|
|
95
|
+
`mu agent send --json`. It settles exactly over the forwarded socket.
|
|
96
|
+
Without `--after-runs`, a worker that is already idle blocks until
|
|
97
|
+
`--timeout`. If the worker may already be done, pass `<runs-1>`: the
|
|
98
|
+
wait then returns the last answer at once. Then run `Next:` once instead
|
|
99
|
+
of on every turn. On exit 5 (timeout), or on a wait that returns while
|
|
100
|
+
the worker asks a question, run `Next:` anyway.
|
|
101
|
+
|
|
91
102
|
- Never `sleep` in a tool call. Aborting the loop can leave remote work
|
|
92
103
|
and a capped channel running.
|
|
93
104
|
- Set a deadline before dispatch. At expiry, read the pane, then release
|
|
@@ -123,14 +134,20 @@ the final gate before the push that matters.
|
|
|
123
134
|
|
|
124
135
|
## Traps
|
|
125
136
|
|
|
126
|
-
### A spawn on an auth prompt looks healthy
|
|
137
|
+
### A non-pi spawn on an auth prompt looks healthy
|
|
127
138
|
|
|
128
139
|
With the channel busy, the attach ssh stopped at `Enter a passcode:`.
|
|
129
140
|
Spawn succeeded, the agent showed `needs_input`, and the prompt went
|
|
130
|
-
into the passcode field.
|
|
131
|
-
|
|
141
|
+
into the passcode field. This applies to non-pi CLIs and to
|
|
142
|
+
`--via mux`, which paste into the pane. Confirm such an agent got the
|
|
143
|
+
work (`mu agent read <name> -n 20`) before trusting it. Send nothing
|
|
132
144
|
sensitive to an unconfirmed pane.
|
|
133
145
|
|
|
146
|
+
A pi agent does not paste. Spawn reports `ctl: ok` only when pi
|
|
147
|
+
answers on the socket; otherwise it warns `ctl: missing` or
|
|
148
|
+
`ctl: refused`, and `mu agent send` fails instead of typing into the
|
|
149
|
+
pane.
|
|
150
|
+
|
|
134
151
|
### Use the host's real CLI command
|
|
135
152
|
|
|
136
153
|
If your local `$MU_PI_COMMAND` is a wrapper such as `pi-meta
|
|
@@ -56,7 +56,7 @@ triage and the umbrella closes with `--if-ready` (workstream mode).
|
|
|
56
56
|
|
|
57
57
|
- **Reviewers padding the list.** A panel that always finds ten things
|
|
58
58
|
is guessing.
|
|
59
|
-
- **
|
|
60
|
-
|
|
59
|
+
- **Vary models across angles** ([Models](../SKILL.md#models-and-thinking-effort)); one model's blind spot
|
|
60
|
+
repeated five times is still one blind spot.
|
|
61
61
|
- **The panel is not the gate command.** Merge verification still runs on the
|
|
62
62
|
merged tree ([orchestrator-loop](orchestrator-loop.md#merging)).
|
|
@@ -37,7 +37,10 @@ rules are findings: [findings](findings.md) says where they live.
|
|
|
37
37
|
line and the rule, and drops false positives (the rule does not
|
|
38
38
|
apply here, the code already complies, the rule has a stated
|
|
39
39
|
exception). In workstream mode, a dropped flag is
|
|
40
|
-
`close --as rejected --why
|
|
40
|
+
`close --as rejected --why "<why the rule does not bite here>"`; a
|
|
41
|
+
confirmed one is accepted with `--evidence` naming the flagged line
|
|
42
|
+
([findings § Triage](findings.md#triage) step 3; quoting:
|
|
43
|
+
[brief § Quoting](brief.md#quoting)).
|
|
41
44
|
5. **Report or fix** confirmed violations, as in review-panel step 5.
|
|
42
45
|
|
|
43
46
|
Done when every rule from step 1 has a checker result, and every flag
|
|
@@ -62,10 +65,12 @@ is decided.
|
|
|
62
65
|
corrections from different occasions; a one-off is not a rule.
|
|
63
66
|
3. **One `OPEN/triage` task per candidate rule**, the rule as the
|
|
64
67
|
title and its cluster of corrections in the note.
|
|
65
|
-
4. **Refute each candidate** with a
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
4. **Refute each candidate** with a
|
|
69
|
+
[delegate call](tasks-or-calls.md#delegate-call) that passes
|
|
70
|
+
`record`: would it have prevented the real mistakes in its cluster?
|
|
71
|
+
Does it contradict an existing rule? Is it already enforced by a
|
|
72
|
+
linter or test (then it needs no prose)? Dropped candidates close
|
|
73
|
+
`--as rejected --why` naming the deciding answer.
|
|
69
74
|
5. **Propose, don't commit.** The candidates left in triage are the
|
|
70
75
|
proposal: write them as a diff to the rule file in the umbrella's
|
|
71
76
|
note, worded per [brief](brief.md) (positive, specific, with the
|
|
@@ -7,30 +7,49 @@ hundreds of tasks and a workstream nobody wanted.
|
|
|
7
7
|
|
|
8
8
|
## Delegate call
|
|
9
9
|
|
|
10
|
-
A **delegate call** is one `mu_delegate` tool call in pi.
|
|
11
|
-
tool (another harness, a script):
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
mu agent spawn refuter-1 -w scratch
|
|
15
|
-
mu agent send refuter-1 -w scratch --fresh '<brief>'
|
|
16
|
-
mu agent wait refuter-1 -w scratch --json # answer in lastText
|
|
17
|
-
```
|
|
10
|
+
A **delegate call** is one `mu_delegate` tool call in pi.
|
|
18
11
|
|
|
19
12
|
- **It starts empty.** The brief carries everything: the finding or
|
|
20
|
-
claim, file paths, the criteria, and the answer
|
|
21
|
-
|
|
13
|
+
claim, file paths, the criteria, and the answer to end with. See
|
|
14
|
+
[brief](brief.md). A tournament judge ends with `WINNER: ...`
|
|
15
|
+
([tournament](tournament.md)). A refuter or claim checker passes
|
|
16
|
+
`record: { task: "<ws>/<id>" }` and ends with:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
VERDICT: <id> CONFIRMED|REFUTED|UNVERIFIED <one line>
|
|
20
|
+
EVIDENCE: <file:line or command + result> (3-6 lines)
|
|
21
|
+
```
|
|
22
|
+
|
|
22
23
|
- **Fan out in one turn.** Issue every call for a step together; in pi
|
|
23
24
|
the answers arrive later as follow-up messages. Calling one, waiting,
|
|
24
25
|
then the next runs them in series.
|
|
25
|
-
- **
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
form needs `mu agent close <name> -w scratch`. You record its verdict
|
|
29
|
-
on the task it judged.
|
|
26
|
+
- **Its `scratch` pane** stays attachable while it runs; `mu_delegate`
|
|
27
|
+
closes it after a clean finish and keeps it on a crash, timeout, or
|
|
28
|
+
API error (or always, with `keep: true`).
|
|
30
29
|
- **An API error is yours to decide.** Re-issue the call, or record the
|
|
31
30
|
check as `UNVERIFIED` on its task, then close the kept pane
|
|
32
31
|
(`mu_delegate_cancel`, or `mu agent close`).
|
|
33
32
|
|
|
33
|
+
Without the tool, write the note `record` would, before deciding:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
mu agent spawn refuter-1 -w scratch
|
|
37
|
+
runs=$(mu agent send refuter-1 -w scratch --fresh - --json <<'EOF' | jq .runs
|
|
38
|
+
<brief, ending with the VERDICT block>
|
|
39
|
+
EOF
|
|
40
|
+
)
|
|
41
|
+
mu agent wait refuter-1 -w scratch --after-runs "$runs" --json # answer in lastText
|
|
42
|
+
mu task note <id> -w <ws> - <<'EOF'
|
|
43
|
+
REFUTER 1 (refuter-1, 4m 05s):
|
|
44
|
+
<the VERDICT line and EVIDENCE lines, verbatim>
|
|
45
|
+
EOF
|
|
46
|
+
mu agent close refuter-1 -w scratch
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
A wait that times out or dies leaves `REFUTER 1: no verdict (<outcome>)`.
|
|
50
|
+
`--after-runs` counts a run that finished before the wait started; the
|
|
51
|
+
quoted heredocs keep the evidence verbatim ([brief § Quoting](brief.md#quoting)).
|
|
52
|
+
|
|
34
53
|
## The rule
|
|
35
54
|
|
|
36
55
|
**A task is a thing the graph tracks. Checking a thing is a call.**
|
|
@@ -43,17 +62,15 @@ mu agent wait refuter-1 -w scratch --json # answer in lastText
|
|
|
43
62
|
| the umbrella, and each round of a loop | a skeptic or dedupe pass |
|
|
44
63
|
| anything that needs its own workspace | a reader or scout whose output feeds one step |
|
|
45
64
|
|
|
46
|
-
A call
|
|
47
|
-
|
|
48
|
-
(`mu task accept`, `close --as rejected --why '<evidence>'`). The graph
|
|
49
|
-
keeps the decision and its evidence without a node per check.
|
|
65
|
+
A call adds no node: its note and your decision land on the task it
|
|
66
|
+
judged ([findings § Triage](findings.md#triage)).
|
|
50
67
|
|
|
51
68
|
## Examples
|
|
52
69
|
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
- A tournament over 16 names: 15 judge
|
|
56
|
-
|
|
70
|
+
- 30 findings to refute: 30 delegate calls, 0 new tasks; each finding
|
|
71
|
+
gets a `REFUTER` note, then your decision.
|
|
72
|
+
- A tournament over 16 names: 15 judge calls; each round's `WINNER:`
|
|
73
|
+
lines go on the umbrella.
|
|
57
74
|
- A hypothesis test that reverts commits or forces a race needs a
|
|
58
75
|
workspace: that one is a task.
|
|
59
76
|
|
|
@@ -20,8 +20,9 @@ reliable than scoring one.
|
|
|
20
20
|
each, so no judge holds the whole field
|
|
21
21
|
([tasks-or-calls](tasks-or-calls.md)). The judge sees the two
|
|
22
22
|
candidates and the rubric and ends with `WINNER: <a|b> <reason>`.
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
A judge decides a pair, not a task: no `record`. Record each round
|
|
24
|
+
(pair, winner, reason) in the umbrella's note; winners meet in the
|
|
25
|
+
next round. A round wider than the cap runs in batches
|
|
25
26
|
([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)).
|
|
26
27
|
5. **Confirm the winner** with a final check against the rubric, then
|
|
27
28
|
merge it. Free the losing workspaces.
|
|
@@ -35,6 +36,6 @@ final check passed.
|
|
|
35
36
|
calls, judge the pair twice with the order swapped; a split decision
|
|
36
37
|
goes to a third judge.
|
|
37
38
|
- **Same model, same taste.** Vary the attempt models, and judge with a
|
|
38
|
-
model that made no attempt.
|
|
39
|
+
model that made no attempt ([Models](../SKILL.md#models-and-thinking-effort)).
|
|
39
40
|
- **Ranking many items** (tickets by severity): bucket them in parallel,
|
|
40
41
|
then run pairwise comparisons only within and across bucket edges.
|
|
@@ -43,8 +43,8 @@ and check, skip it.
|
|
|
43
43
|
[brief](brief.md) ([plan](plan.md) for a spec-driven build). Rounds
|
|
44
44
|
of a loop are the one exception: add each when the last closes.
|
|
45
45
|
5. **Review every unit that ships.** Each commit-producing task gets a
|
|
46
|
-
review task ([adversarial-review](adversarial-review.md))
|
|
47
|
-
|
|
46
|
+
review task ([adversarial-review](adversarial-review.md)) on a
|
|
47
|
+
[comparable model](../SKILL.md#models-and-thinking-effort). Every finding is a triage task,
|
|
48
48
|
refuted before it is accepted ([findings](findings.md)).
|
|
49
49
|
6. **Run the loop** ([orchestrator-loop](orchestrator-loop.md)): pipeline
|
|
50
50
|
merges, verify each merge, keep workers busy
|
|
@@ -17,8 +17,9 @@ mu task note <id> "FILES: ...\nDECISION: ...\nVERIFIED: ..."
|
|
|
17
17
|
mu task close <id> --evidence "tests pass: ..." # LAST action
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The note follows the task note contract in SKILL.md.
|
|
21
|
-
|
|
20
|
+
The note follows the task note contract in SKILL.md. Keep each tool
|
|
21
|
+
call to minutes (short batches, waits with a timeout): steering reaches
|
|
22
|
+
you only between tool calls. Commit before you close: the orchestrator cherry-picks your commits, not your tree. A
|
|
22
23
|
review or audit task records each problem per
|
|
23
24
|
[findings § Record](findings.md#record).
|
|
24
25
|
|