@mu-crew/mu 3.3.0 → 3.5.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/README.md +45 -31
- package/dist/cli.js +812 -429
- package/dist/cli.js.map +1 -1
- package/dist/extension/mu-pi.js +221 -55
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +33 -4
- package/dist/index.js +76 -5
- package/dist/index.js.map +1 -1
- package/docs/VISION.md +5 -1
- package/docs/VOCABULARY.md +4 -1
- package/docs/architecture/dag.md +3 -3
- package/docs/architecture/ops-log.md +26 -7
- package/docs/guide/cleanup.md +19 -0
- package/docs/guide/delegate.md +43 -4
- package/docs/reference/env.md +1 -0
- package/docs/reference/naming.md +18 -0
- package/docs/specs/2026-09-29-task-substates.md +1 -1
- package/package.json +1 -1
- package/prompts/mu-debug.md +8 -0
- package/prompts/mu-sweep.md +8 -0
- package/prompts/mu-until.md +8 -0
- package/prompts/ultrathink.md +2 -1
- package/skills/mu/SKILL.md +70 -31
- package/skills/mu/recipes/adversarial-review.md +27 -19
- package/skills/mu/recipes/{triage.md → backlog-triage.md} +9 -4
- package/skills/mu/recipes/codemode-driver.md +68 -20
- package/skills/mu/recipes/deep-research.md +23 -8
- package/skills/mu/recipes/fan-out.md +15 -11
- package/skills/mu/recipes/findings.md +103 -0
- package/skills/mu/recipes/hypothesis-panel.md +18 -13
- package/skills/mu/recipes/long-run.md +4 -4
- package/skills/mu/recipes/loop-until-done.md +7 -3
- package/skills/mu/recipes/orchestrator-loop.md +44 -27
- package/skills/mu/recipes/plan.md +8 -3
- package/skills/mu/recipes/recovery.md +5 -0
- package/skills/mu/recipes/refute.md +38 -36
- package/skills/mu/recipes/remote-workers.md +7 -2
- package/skills/mu/recipes/review-panel.md +36 -31
- package/skills/mu/recipes/rules-audit.md +30 -17
- package/skills/mu/recipes/tasks-or-calls.md +71 -0
- package/skills/mu/recipes/tournament.md +13 -10
- package/skills/mu/recipes/ultrathink.md +20 -11
- package/skills/mu/recipes/watcher.md +4 -1
- package/skills/mu/recipes/waves.md +6 -5
- package/skills/mu/recipes/worker.md +3 -1
|
@@ -1,54 +1,102 @@
|
|
|
1
1
|
# Codemode driver
|
|
2
2
|
|
|
3
|
-
Use when a pi orchestrator with the `codemode` tool
|
|
4
|
-
many
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Use when a pi orchestrator with the `codemode` tool has one step that
|
|
4
|
+
dispatches many workers, or many [delegate calls](tasks-or-calls.md#delegate-call)
|
|
5
|
+
whose verdicts you want back as one table. A script issues those calls
|
|
6
|
+
in parallel. It stays a driver: the script is the agent's, not mu's,
|
|
7
|
+
and the plan, the state, and the results live in the DB.
|
|
7
8
|
|
|
8
9
|
## The rule
|
|
9
10
|
|
|
10
11
|
**Delete the script mid-run and nothing is lost.** That holds when:
|
|
11
12
|
|
|
12
|
-
- The script calls only `mu` verbs, through `tools.bash
|
|
13
|
-
state with `mu state --json` /
|
|
14
|
-
variables across calls.
|
|
13
|
+
- The script calls only `mu` verbs, through `tools.bash` (or
|
|
14
|
+
`tools.mu_delegate`, below). It reads state with `mu state --json` /
|
|
15
|
+
`mu task notes`, never from its own variables across calls.
|
|
15
16
|
- Every task it dispatches exists in the DAG before the script starts.
|
|
16
17
|
The script adds no tasks the orchestrator has not planned, except the
|
|
17
|
-
ones a recipe step names (the next round, a
|
|
18
|
+
ones a recipe step names (the next round, a finding).
|
|
18
19
|
- `store()` / `load()` hold nothing a re-run needs. The DAG is the
|
|
19
20
|
cursor.
|
|
20
|
-
-
|
|
21
|
-
`mu log -w <ws> --kind driver '
|
|
21
|
+
- Before it runs, log a one-line summary and the task ids it touches:
|
|
22
|
+
`mu log -w <ws> --kind driver 'dispatch wave 2: sweep_a sweep_b'`.
|
|
22
23
|
|
|
23
|
-
##
|
|
24
|
+
## Workers
|
|
24
25
|
|
|
25
26
|
```js
|
|
26
27
|
// @options: {"timeout_ms": 1800000}
|
|
27
28
|
const ws = "audit";
|
|
29
|
+
const workers = ["worker-1", "worker-2", "worker-3", "worker-4"]; // within the ceiling
|
|
28
30
|
const sh = async (c) => {
|
|
29
31
|
const r = await tools.bash({ command: c });
|
|
30
32
|
if (r.exit_code !== 0) throw new Error(`${c}: ${r.output}`);
|
|
31
33
|
return r.output;
|
|
32
34
|
};
|
|
33
|
-
const ready = JSON.parse(await sh(`mu task next -w ${ws} -n 0 --json`)).items;
|
|
34
|
-
await Promise.allSettled(ready.
|
|
35
|
-
|
|
36
|
-
await sh(`mu
|
|
37
|
-
await sh(`mu agent send ${
|
|
35
|
+
const ready = JSON.parse(await sh(`mu task next -w ${ws} -n 0 --json`)).items.slice(0, workers.length);
|
|
36
|
+
await Promise.allSettled(ready.map(async (t, i) => {
|
|
37
|
+
await sh(`mu task claim ${t.name} -w ${ws} --for ${workers[i]} --evidence 'driver dispatch'`);
|
|
38
|
+
await sh(`mu workspace refresh ${workers[i]} -w ${ws}`);
|
|
39
|
+
await sh(`mu agent send ${workers[i]} -w ${ws} --fresh 'Work on ${t.name}. Read: mu task notes ${t.name} -w ${ws}'`);
|
|
38
40
|
}));
|
|
39
|
-
const wait = await tools.bash({ command: `mu task wait -w ${ws} ${ready.
|
|
41
|
+
const wait = await tools.bash({ command: `mu task wait -w ${ws} ${ready.map((t) => t.name).join(" ")} --first --on-stall exit --json` });
|
|
40
42
|
return wait.output;
|
|
41
43
|
```
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
Size the worker list from the ceiling on the umbrella
|
|
46
|
+
([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)),
|
|
47
|
+
one per ready track. Merge and verify outside the script
|
|
48
|
+
([orchestrator-loop § Merging](orchestrator-loop.md#merging)). Check
|
|
49
|
+
field names against `--json` output; the script is a shape, not an API.
|
|
50
|
+
|
|
51
|
+
## Delegate calls
|
|
52
|
+
|
|
53
|
+
`tools.mu_delegate` works from a script, but it returns at once and the
|
|
54
|
+
answers arrive after the script, as follow-up messages: the script
|
|
55
|
+
gains nothing over issuing the calls in one turn. Use it from a script
|
|
56
|
+
only when `codemode.mode` is `only` and the tool is not offered
|
|
57
|
+
directly. Check `Promise.allSettled` results for rejections: past the
|
|
58
|
+
cap, `mu_delegate` refuses.
|
|
59
|
+
|
|
60
|
+
To get the verdicts back as one table instead of one message each, use
|
|
61
|
+
the `scratch` form through `tools.bash`:
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
// @options: {"timeout_ms": 1800000}
|
|
65
|
+
const findings = ["f_auth_put", "f_sql_order"]; // finding task ids, at most the cap per script
|
|
66
|
+
const sh = async (c) => (await tools.bash({ command: c })).output;
|
|
67
|
+
const rows = await Promise.all(findings.map(async (id, i) => {
|
|
68
|
+
const a = `refuter-${i + 1}`;
|
|
69
|
+
await sh(`mu agent spawn ${a} -w scratch`);
|
|
70
|
+
await sh(`mu agent send ${a} -w scratch --fresh '<brief for ${id}: ... end with VERDICT: ...>'`);
|
|
71
|
+
const w = JSON.parse(await sh(`mu agent wait ${a} -w scratch --json --timeout 1200`));
|
|
72
|
+
const text = w.agents?.[0]?.lastText ?? "";
|
|
73
|
+
await sh(`mu agent close ${a} -w scratch`);
|
|
74
|
+
return `${id}\t${(text.match(/VERDICT:.*$/m) ?? ["VERDICT: UNVERIFIED no verdict line"])[0]}`;
|
|
75
|
+
}));
|
|
76
|
+
return rows.join("\n");
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
What the tool did for you, the script now owns:
|
|
80
|
+
|
|
81
|
+
- **The cap.** `MU_DELEGATE_MAX` does not apply to bash spawns: keep
|
|
82
|
+
each script's list at or under it.
|
|
83
|
+
- **Cleanup.** Close each scratch pane; a timed-out one stays, readable
|
|
84
|
+
with `mu agent read <a> -w scratch`.
|
|
85
|
+
- **Recording.** The table is not the record. Record each verdict on its
|
|
86
|
+
finding (`mu task accept`, `close --as rejected --why`), from the
|
|
87
|
+
script or after it returns.
|
|
45
88
|
|
|
46
89
|
## Traps
|
|
47
90
|
|
|
48
91
|
- **One wave per script.** A script that loops forever hides progress
|
|
49
92
|
from you and from the human. Dispatch, wait for the first close,
|
|
50
|
-
return; merge and verify outside the script, then run it again.
|
|
93
|
+
return; merge and verify outside the script, then run it again. A
|
|
94
|
+
tournament runs one round per script.
|
|
51
95
|
- **A script timeout cancels the waits, not the workers.** Workers keep
|
|
52
96
|
running and their tasks stay claimed. Re-read `mu state` and carry on.
|
|
53
97
|
- **Exit codes are data.** `mu task wait` exit 7 means a worker needs
|
|
54
98
|
you; return it to the model instead of retrying.
|
|
99
|
+
|
|
100
|
+
Done when the script returned, `mu state` shows the dispatched tasks
|
|
101
|
+
claimed (workers) or every verdict is recorded on its finding (delegate
|
|
102
|
+
calls), and no scratch pane the script opened is left running.
|
|
@@ -7,13 +7,21 @@ a claim in a draft holds. This is [refute](refute.md) applied to
|
|
|
7
7
|
sources. Workers need a web search tool (pi's `brave_search`, or
|
|
8
8
|
`curl` on docs) or the code they research.
|
|
9
9
|
|
|
10
|
+
**Mode:** delegates by default: the report is the result, and claims
|
|
11
|
+
need no permanent record. Use a workstream for a long run that must
|
|
12
|
+
survive compaction or feeds a tracked decision; then each claim the
|
|
13
|
+
answer rests on is an `OPEN/triage` task, decided like a finding
|
|
14
|
+
([findings](findings.md)).
|
|
15
|
+
|
|
10
16
|
## Steps
|
|
11
17
|
|
|
12
|
-
1. **Write the question and the bar
|
|
18
|
+
1. **Write the question and the bar**, into every searcher's brief
|
|
19
|
+
(delegate mode) or on an umbrella task (workstream mode): the exact
|
|
13
20
|
question, what a good answer contains (a recommendation, a
|
|
14
21
|
comparison table, a yes/no with conditions), and how fresh sources
|
|
15
22
|
must be.
|
|
16
|
-
2. **Split by angle**, one
|
|
23
|
+
2. **Split by angle**, one searcher per angle (delegates; tasks only in
|
|
24
|
+
workstream mode): official docs,
|
|
17
25
|
changelogs and release notes, issue trackers, independent write-ups,
|
|
18
26
|
the code itself. Each searcher reads, fetches, and writes claims to
|
|
19
27
|
its note, one per line:
|
|
@@ -24,16 +32,23 @@ sources. Workers need a web search tool (pi's `brave_search`, or
|
|
|
24
32
|
|
|
25
33
|
A claim without a source and a quote is not a claim. Searchers can
|
|
26
34
|
run on a cheap model.
|
|
27
|
-
3. **Dedupe claims
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
3. **Dedupe claims**: merge the same fact from several sources (keep
|
|
36
|
+
every source), and flag claims that contradict each other. In
|
|
37
|
+
workstream mode, each surviving claim becomes an `OPEN/triage` task
|
|
38
|
+
titled with the claim, its sources and quotes in the note.
|
|
39
|
+
4. **One checker per claim** that the answer depends on, as a
|
|
40
|
+
[delegate call](tasks-or-calls.md#delegate-call) in both modes. The checker
|
|
31
41
|
gets the claim and its sources, not the searcher's reasoning, fetches
|
|
32
42
|
the source itself, and tries to break the claim: is the quote there,
|
|
33
43
|
does it say that, is it current, does another source disagree? It
|
|
34
44
|
ends with `VERDICT: c4 CONFIRMED | REFUTED | UNVERIFIED <evidence>`.
|
|
35
|
-
For contradicted claims, one checker per side.
|
|
36
|
-
|
|
45
|
+
For contradicted claims, one checker per side. Batch under the cap
|
|
46
|
+
([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)). In workstream mode the
|
|
47
|
+
verdict is the claim task's state: `accept` for confirmed,
|
|
48
|
+
`close --as rejected` for refuted, an `UNVERIFIED:` note in triage
|
|
49
|
+
otherwise.
|
|
50
|
+
5. **Synthesize** once every checker has answered (in workstream mode,
|
|
51
|
+
when no claim task is left undecided): answer the question
|
|
37
52
|
from confirmed claims only, each with its source URL. List
|
|
38
53
|
unverified claims separately. Note what the sources disagree on and
|
|
39
54
|
which side the evidence favours.
|
|
@@ -6,7 +6,7 @@ some and calls the job done; one task per unit cannot.
|
|
|
6
6
|
|
|
7
7
|
## Steps
|
|
8
8
|
|
|
9
|
-
1. **Enumerate first
|
|
9
|
+
1. **Enumerate first.** A scout (a [delegate call](tasks-or-calls.md#delegate-call)) lists the units and
|
|
10
10
|
writes them to the umbrella's note, one per line. The list is done
|
|
11
11
|
when it matches a command the scout ran (`rg -l`, a test listing),
|
|
12
12
|
not when it looks complete. Record the command and the count.
|
|
@@ -18,19 +18,23 @@ some and calls the job done; one task per unit cannot.
|
|
|
18
18
|
mu task block sweep -w <ws> --by sweep_auth_ts
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Put the shared brief and acceptance criteria on the
|
|
22
|
-
unit task's note holds only what differs.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
Put the shared [brief](brief.md) and acceptance criteria on the
|
|
22
|
+
umbrella; each unit task's note holds only what differs. A sweep that
|
|
23
|
+
only checks (no commits) makes each unit a delegate call instead
|
|
24
|
+
([tasks-or-calls](tasks-or-calls.md)).
|
|
25
|
+
3. **Cap concurrency** ([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)).
|
|
26
|
+
Spawn at most one agent per ready track. Tell workers to avoid
|
|
27
|
+
repo-wide commands so more can run.
|
|
28
|
+
4. **Pipeline.** Dispatch, wait `--first`, merge
|
|
29
|
+
([orchestrator-loop § Merging](orchestrator-loop.md#merging)), dispatch
|
|
30
|
+
the next unit to the freed worker with `--fresh`. With `codemode`, a
|
|
31
|
+
[driver](codemode-driver.md) can dispatch each batch. Units that touch the same files
|
|
28
32
|
go on one track (see [waves](waves.md)).
|
|
29
33
|
5. **Review per unit** when a wrong unit is costly: add a review task
|
|
30
34
|
per unit ([adversarial-review](adversarial-review.md)).
|
|
31
|
-
6. **Synthesize** when the output is a report, not commits:
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
6. **Synthesize** when the output is a report, not commits: one
|
|
36
|
+
delegate call reads the unit notes (not transcripts) and writes one
|
|
37
|
+
result into the umbrella's note.
|
|
34
38
|
|
|
35
39
|
Done when `mu task close sweep --if-ready` closes the umbrella: every
|
|
36
40
|
unit is closed, and the closed count matches the step 1 count.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Findings
|
|
2
|
+
|
|
3
|
+
Use whenever an agent reviews, audits, checks, or researches something
|
|
4
|
+
and reports problems: every recipe that produces findings follows this
|
|
5
|
+
one. It decides where findings live, and how they become work.
|
|
6
|
+
|
|
7
|
+
## Pick the mode first
|
|
8
|
+
|
|
9
|
+
Ask: **will anyone act on these findings through the DAG?**
|
|
10
|
+
|
|
11
|
+
| Situation | Mode | Findings live in |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| The result is read once and acted on directly: PR comments, doc edits, a go/no-go, a draft fact-check | **Delegate** | the delegate's answer |
|
|
14
|
+
| Findings become work agents fix, or must be tracked to closure | **Workstream** | one `OPEN/triage` task per finding |
|
|
15
|
+
|
|
16
|
+
Delegate mode keeps reviews of other people's PRs and docs out of the
|
|
17
|
+
ops log, which is permanent and syncs to every machine. Workstream mode
|
|
18
|
+
is the mu way for your own work: the graph shows every finding, who
|
|
19
|
+
decided it, and the fix.
|
|
20
|
+
|
|
21
|
+
## Delegate mode
|
|
22
|
+
|
|
23
|
+
1. Run reviewers as [delegate calls](tasks-or-calls.md#delegate-call):
|
|
24
|
+
one per angle or slice, all in one turn so they run in parallel,
|
|
25
|
+
under the cap ([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)).
|
|
26
|
+
2. Each delegate ends its answer with one line per finding:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
FINDING: high src/api/user.ts:88 PUT handler skips the auth check EVIDENCE: curl -X PUT ... returned 200
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
3. You read the answers, merge duplicates, and act: post the comments,
|
|
33
|
+
edit the doc, give the verdict.
|
|
34
|
+
4. **Promote** when the findings turn out to be work: create one
|
|
35
|
+
`OPEN/triage` task per line (below) and continue in workstream mode.
|
|
36
|
+
|
|
37
|
+
Done when every delegate answered and every finding line was acted on
|
|
38
|
+
or dropped with a reason.
|
|
39
|
+
|
|
40
|
+
## Workstream mode
|
|
41
|
+
|
|
42
|
+
### Record
|
|
43
|
+
|
|
44
|
+
The reviewer records each finding as a task in triage, blocking the
|
|
45
|
+
review's umbrella so the umbrella cannot close while findings are
|
|
46
|
+
undecided:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
mu task add -w <ws> --triage \
|
|
50
|
+
-t "high: PUT /user skips the auth check" -i 70 -e 0.5 \
|
|
51
|
+
--note 'FINDING: high src/api/user.ts:88 PUT skips the auth check EVIDENCE: curl -X PUT ... returned 200 without a token'
|
|
52
|
+
mu task block <umbrella> -w <ws> --by <finding-id>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The title starts with the severity. The note is one `FINDING:` line,
|
|
56
|
+
the same shape everywhere: `FINDING: <severity> <file:line> <what>
|
|
57
|
+
EVIDENCE: <command + output>`. `OPEN/triage` keeps the finding out of `mu task next`, and
|
|
58
|
+
`claim` refuses it, so no worker starts on an undecided finding.
|
|
59
|
+
|
|
60
|
+
**More than 5 findings from one reviewer:** the reviewer writes them as
|
|
61
|
+
`FINDING:` lines in its own task note instead. Before that reviewer
|
|
62
|
+
task closes, the orchestrator adds `triage_<umbrella>` blocking the
|
|
63
|
+
umbrella; the triage agent ([Triage](#triage) step 1) merges duplicates
|
|
64
|
+
across reviewers and creates one task per real problem.
|
|
65
|
+
|
|
66
|
+
### Triage
|
|
67
|
+
|
|
68
|
+
1. **Who:** a handful of findings, the orchestrator triages itself. Many,
|
|
69
|
+
or several reviewers on one change: a `triage_<umbrella>` task, run
|
|
70
|
+
by a fresh agent, so the orchestrator reads only its result.
|
|
71
|
+
2. **Refute** each finding before accepting it with a
|
|
72
|
+
[delegate call](tasks-or-calls.md#delegate-call): a fresh agent tries
|
|
73
|
+
to prove it false and ends with
|
|
74
|
+
`VERDICT: <id> CONFIRMED | REFUTED | UNVERIFIED <evidence>`. Skip this
|
|
75
|
+
for low-severity style findings. High severity: three refuters,
|
|
76
|
+
accept only if at least two say CONFIRMED.
|
|
77
|
+
3. **Decide** each one; the decision is the task's state:
|
|
78
|
+
|
|
79
|
+
| Decision | Command |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| real work | `mu task accept <id> --evidence '<what confirmed it>'` |
|
|
82
|
+
| false | `mu task close <id> --as rejected --why '<evidence>'` |
|
|
83
|
+
| same as another | `mu task close <id> --as duplicate --why 'same as <id>'` |
|
|
84
|
+
| valid, not worth it | `mu task close <id> --as wontfix --why '<reason>'` |
|
|
85
|
+
| could not check | stays in triage, with an `UNVERIFIED: <why>` note |
|
|
86
|
+
|
|
87
|
+
4. **Group** accepted findings that touch the same files into one fix
|
|
88
|
+
task when separate workers would collide; close the grouped findings
|
|
89
|
+
`--as superseded --why 'fixed in <fix-task>'`.
|
|
90
|
+
|
|
91
|
+
Done when `mu task list --substate triage -w <ws>` lists only findings
|
|
92
|
+
with an `UNVERIFIED` note, and each of those is reported to the human.
|
|
93
|
+
|
|
94
|
+
### Fix and close
|
|
95
|
+
|
|
96
|
+
Accepted findings are ordinary tasks: dispatch them, review the fix
|
|
97
|
+
([adversarial-review](adversarial-review.md)), merge. The umbrella
|
|
98
|
+
closes with `mu task close <umbrella> --if-ready` once every finding is
|
|
99
|
+
`CLOSED/*`. A plain `close` would succeed with findings still open.
|
|
100
|
+
|
|
101
|
+
The report is a query, not a document: `mu task list -w <ws>
|
|
102
|
+
--substate rejected`, `--substate duplicate`, `--status OPEN`, and the
|
|
103
|
+
notes on each task.
|
|
@@ -9,19 +9,23 @@ form independent theories; separate agents then try to kill them.
|
|
|
9
9
|
|
|
10
10
|
1. **Write the symptom** on the umbrella: what happens, how often, the
|
|
11
11
|
repro command, and what would count as fixed.
|
|
12
|
-
2. **One
|
|
13
|
-
recent commits, data, environment. Each
|
|
14
|
-
so the theories do not anchor on each other.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
2. **One reader per evidence source** (a [delegate call](tasks-or-calls.md#delegate-call)): logs, the
|
|
13
|
+
code path, recent commits, data, environment. Each sees only its
|
|
14
|
+
source, so the theories do not anchor on each other. Record each
|
|
15
|
+
theory as an `OPEN/triage` task blocking the umbrella, decided like
|
|
16
|
+
a finding ([findings § Triage](findings.md#triage)):
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
mu task add -w <ws> --triage -t "h: <cause>" -i 60 -e 0.5 \
|
|
20
|
+
--note 'PREDICTS: <an observation true if this is the cause, false otherwise>'
|
|
19
21
|
```
|
|
20
22
|
|
|
21
|
-
3. **
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
3. **Test each hypothesis.** An experiment that changes code (force the
|
|
24
|
+
race, revert the commit) needs a workspace: `mu task accept` the
|
|
25
|
+
hypothesis and dispatch it as a task. One that only reads (feed the
|
|
26
|
+
data, grep the logs) is a delegate call. A killed hypothesis closes
|
|
27
|
+
`--as rejected --why '<evidence>'`; a survivor gets a
|
|
28
|
+
`SURVIVED: <evidence>` note.
|
|
25
29
|
4. **If one survives**, add a fix task for it, then a review task
|
|
26
30
|
([adversarial-review](adversarial-review.md)). The fix is accepted
|
|
27
31
|
only if the step 1 repro stops reproducing.
|
|
@@ -29,12 +33,13 @@ form independent theories; separate agents then try to kill them.
|
|
|
29
33
|
([loop-until-done](loop-until-done.md)): the new hypothesis tasks get
|
|
30
34
|
the killed hypotheses and their evidence as input.
|
|
31
35
|
|
|
32
|
-
Done when
|
|
36
|
+
Done when the fix's review task is `CLOSED/done` (ACCEPT) and the
|
|
37
|
+
repro from step 1 no longer
|
|
33
38
|
reproduces at the rate step 1 recorded.
|
|
34
39
|
|
|
35
40
|
## Traps
|
|
36
41
|
|
|
37
42
|
- **Two survivors** usually means the experiments were too weak. Design
|
|
38
43
|
one experiment that separates them before you fix either.
|
|
39
|
-
- **Flaky repros need counts
|
|
44
|
+
- **Flaky repros need counts** ([long-run](long-run.md) step 1). "Passed once" proves nothing for a 1 in
|
|
40
45
|
50 failure. Put the run count in step 1.
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
Use when a task or proof runs for hours, crosses context compaction,
|
|
4
4
|
or may hit flakes.
|
|
5
5
|
|
|
6
|
-
1. **
|
|
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
9
|
the bar, not at the first green.
|
|
10
|
-
2. **Split into independent units
|
|
10
|
+
2. **Split into independent units** ([fan-out](fan-out.md)). Shard a long proof into tasks
|
|
11
11
|
that run in parallel, so one flake restarts only its unit. Each unit
|
|
12
12
|
carries its own criterion.
|
|
13
13
|
3. **Keep state in the DB.** Progress lives in task notes, not in the
|
|
14
14
|
orchestrator's context. After a compaction, `mu state` and
|
|
15
15
|
`mu task notes <id>` are the whole picture.
|
|
16
|
-
4. **Accept evidence, not close notes
|
|
17
|
-
|
|
16
|
+
4. **Accept evidence, not close notes**
|
|
17
|
+
([orchestrator-loop § Merging](orchestrator-loop.md#merging)).
|
|
18
18
|
|
|
19
19
|
Done when every unit is `CLOSED/done` and the criterion from step 1
|
|
20
20
|
holds on the merged tree.
|
|
@@ -15,14 +15,18 @@ written down first does neither.
|
|
|
15
15
|
NO-PROGRESS: two rounds in a row reduce the error count by zero
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
2. **Each round is a task
|
|
18
|
+
2. **Each round is a task** that blocks the umbrella and is blocked by
|
|
19
|
+
the previous round:
|
|
19
20
|
`round_1`, `round_2`, .... Add the next round only when the current
|
|
20
|
-
one closes; never pre-create rounds.
|
|
21
|
+
one closes; never pre-create rounds. Dispatch each per
|
|
22
|
+
[orchestrator-loop](orchestrator-loop.md); multi-hour loops follow
|
|
23
|
+
[long-run](long-run.md).
|
|
21
24
|
3. **Each round ends with its measurement** in the note:
|
|
22
25
|
`MEASURE: 14 errors (was 31)`, or `NEW: 0 flaky tests`.
|
|
23
26
|
4. **After each round, check the rule** yourself, from the measurement
|
|
24
27
|
command, not from the worker's note.
|
|
25
|
-
- Rule met: close
|
|
28
|
+
- Rule met: `mu task close <umbrella> --if-ready --evidence '<stop
|
|
29
|
+
command + result>'` (each round blocks the umbrella).
|
|
26
30
|
- No progress: stop the loop and decide. Change the approach, split
|
|
27
31
|
the work, or park the umbrella with
|
|
28
32
|
`mu task park <umbrella> --why '<what is stuck>'` and tell the human.
|
|
@@ -8,42 +8,59 @@ the loop and the reasons behind them.
|
|
|
8
8
|
|
|
9
9
|
1. `mu state -w <ws>` — read agents, IN_PROGRESS, ready tasks,
|
|
10
10
|
parallel tracks.
|
|
11
|
-
2. Spawn at most one agent per independent ready track.
|
|
11
|
+
2. Spawn at most one agent per independent ready track ([waves](waves.md)
|
|
12
|
+
when workers share files).
|
|
12
13
|
3. **Claim before sending — even one-shot reviewers/scouts.**
|
|
13
14
|
`mu task claim <id> -w <ws> --for <agent> --evidence "..."`.
|
|
14
15
|
If no task exists, `mu task add` first (`--note 'REPRO: ...'` when
|
|
15
16
|
the title is not enough). Ownership is durable and waitable; agent
|
|
16
|
-
state is not.
|
|
17
|
-
4.
|
|
18
|
-
session + prompt in one step;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
5. End with a loud final-action block:
|
|
23
|
-
|
|
24
|
-
```text
|
|
25
|
-
⚠️ FINAL ACTION
|
|
26
|
-
git commit -am '...' THEN
|
|
27
|
-
mu task close <id> -w <ws> --evidence '...'
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
6. `mu task wait ... --first --on-stall exit --json`.
|
|
31
|
-
7. Cherry-pick the closed worker's **new** commit(s), verify the MERGE,
|
|
17
|
+
state is not. Review tasks: [adversarial-review](adversarial-review.md).
|
|
18
|
+
4. Run `mu workspace refresh <w>`, then send a [brief](brief.md) with
|
|
19
|
+
`mu agent send <w> --fresh '...'` (new session + prompt in one step;
|
|
20
|
+
refuses while busy). The brief ends with its final-action block.
|
|
21
|
+
5. `mu task wait ... --first --on-stall exit --json`.
|
|
22
|
+
6. Cherry-pick the closed worker's **new** commit(s), verify the MERGE,
|
|
32
23
|
then continue the loop in the same turn. Do not barrier or loop in
|
|
33
24
|
shell.
|
|
34
25
|
Only `CLOSED/done` ships; other closes: read the reason note.
|
|
35
|
-
|
|
26
|
+
7. Repeat from `mu state`.
|
|
27
|
+
|
|
28
|
+
## Concurrency
|
|
29
|
+
|
|
30
|
+
Write the ceiling on the umbrella before the first wave
|
|
31
|
+
(`CONCURRENCY: delegates 12, workers 4`) so a resumed orchestrator
|
|
32
|
+
keeps it.
|
|
33
|
+
|
|
34
|
+
- **[Delegate calls](tasks-or-calls.md#delegate-call)** (read-only): 10 to 20 at once is reasonable.
|
|
35
|
+
Token spend and provider rate limits bind first; start near 8 and
|
|
36
|
+
raise after a clean wave. `mu_delegate` runs at most
|
|
37
|
+
`MU_DELEGATE_MAX` (default 16) and queues up to four times that
|
|
38
|
+
(`queued-N`, started as slots free); past that it refuses.
|
|
39
|
+
- **Answers arrive when you stop**, as pi follow-up messages, never
|
|
40
|
+
mid-turn. pi's `followUpMode: "all"` delivers every waiting answer in
|
|
41
|
+
one turn instead of one turn each; each answer names its delegate and
|
|
42
|
+
ends with its `VERDICT: <id>` line, so a batch still maps back. Record
|
|
43
|
+
every verdict in the batch before acting on any.
|
|
44
|
+
- **Workers with workspaces** build and test: about one per CPU core,
|
|
45
|
+
fewer when each runs the full suite. A remote host has its own
|
|
46
|
+
session cap ([remote-workers](remote-workers.md)).
|
|
47
|
+
- **Stream, do not batch.** Keep the pool full: dispatch the next unit
|
|
48
|
+
when one closes, rather than waiting for a whole wave. With the
|
|
49
|
+
`codemode` tool, a [driver](codemode-driver.md) can dispatch a batch
|
|
50
|
+
of workers in one script.
|
|
36
51
|
|
|
37
52
|
## Waiting
|
|
38
53
|
|
|
39
54
|
Use `--first --on-stall exit`: `--first` populates `.firing`, and
|
|
40
55
|
`--on-stall exit` stops an unattended wait when a worker needs attention.
|
|
41
|
-
Exit 6
|
|
56
|
+
Exit 6: the owner's pane died and the reaper reopened the task; exit 7:
|
|
57
|
+
the owner sat in `needs_input`. Read that
|
|
42
58
|
pane (`mu agent read <owner>`) and answer: the worker may be waiting on
|
|
43
|
-
you.
|
|
59
|
+
you.
|
|
44
60
|
|
|
45
61
|
For an idle worker, read the pane, then answer, retry, or release its
|
|
46
|
-
task. `MU_IDLE_THRESHOLD_MS` defaults to 5m.
|
|
62
|
+
task. `MU_IDLE_THRESHOLD_MS` defaults to 5m. A remote owner: poll once
|
|
63
|
+
per turn ([remote-workers](remote-workers.md#step-5-poll-once-per-turn)).
|
|
47
64
|
|
|
48
65
|
## Merging
|
|
49
66
|
|
|
@@ -51,10 +68,10 @@ task. `MU_IDLE_THRESHOLD_MS` defaults to 5m.
|
|
|
51
68
|
new commits, verify, dispatch the next. An umbrella wait hides progress;
|
|
52
69
|
merging stale branches can restore reverted code.
|
|
53
70
|
- **Verify the merge, not the worker's rerun.** Only the combination
|
|
54
|
-
with moved main is new
|
|
55
|
-
|
|
56
|
-
- **Push only
|
|
57
|
-
`set -e`. Check the gate runs what it claims: an env-gated randomized
|
|
71
|
+
with moved main is new, and it breaks in ways the worker's own run
|
|
72
|
+
cannot show. Remote hosts: [run the merged gate there](remote-workers.md#run-the-merged-gate-on-the-host).
|
|
73
|
+
- **Push only when the gate command passes.** Make `git push` the last
|
|
74
|
+
line under `set -e`. Check the gate command runs what it claims: an env-gated randomized
|
|
58
75
|
test once passed with zero cases.
|
|
59
76
|
- **Accept evidence, not close notes.** Re-run the key measurement from
|
|
60
77
|
a clean checkout; close notes have claimed unpushed commits. A
|
|
@@ -63,8 +80,6 @@ task. `MU_IDLE_THRESHOLD_MS` defaults to 5m.
|
|
|
63
80
|
no is not evidence: a test filtered to zero cases, a script you wrote
|
|
64
81
|
agreeing with itself, a fixture you tuned on. A nonzero diff is a
|
|
65
82
|
failure even when the command exited 0.
|
|
66
|
-
- **Dispatch from current main.** Reset the worker's worktree to main
|
|
67
|
-
before each task.
|
|
68
83
|
|
|
69
84
|
## Sending
|
|
70
85
|
|
|
@@ -85,3 +100,5 @@ task. `MU_IDLE_THRESHOLD_MS` defaults to 5m.
|
|
|
85
100
|
context, waits for idle; exit 5 = still busy; queued follow-ups return
|
|
86
101
|
to the editor unsent). Then `mu agent kick` (pi unresponsive, or
|
|
87
102
|
non-pi; local panes only), then `mu agent close`.
|
|
103
|
+
|
|
104
|
+
Done when every task is closed, or a decision only a human can make blocks all progress (SKILL.md § Orchestrator rules).
|
|
@@ -17,9 +17,12 @@ human asks for a file.
|
|
|
17
17
|
in two or three sentences, and the global constraints copied
|
|
18
18
|
verbatim from the spec. Every other task is blocked by it; close it
|
|
19
19
|
at once. It carries notes, not work.
|
|
20
|
-
4. **Write each task's note** as a [brief](brief.md):
|
|
20
|
+
4. **Write each task's note** as a [brief](brief.md): its Shape, plus
|
|
21
|
+
INTERFACES and STEPS:
|
|
21
22
|
|
|
22
23
|
```text
|
|
24
|
+
GOAL: one sentence
|
|
25
|
+
DONE WHEN: checkable, exhaustive criterion
|
|
23
26
|
FILES: Create/Modify/Test with exact paths (line ranges if known)
|
|
24
27
|
INTERFACES: Consumes: <exact signatures from earlier tasks>
|
|
25
28
|
Produces: <exact names and types later tasks use>
|
|
@@ -35,14 +38,16 @@ human asks for a file.
|
|
|
35
38
|
of order.
|
|
36
39
|
6. **Add edges for dependencies only.** `mu task block A --by B` when A
|
|
37
40
|
consumes what B produces. Plan order is not a dependency: an extra
|
|
38
|
-
edge serialises tracks that could run in parallel.
|
|
41
|
+
edge serialises tracks that could run in parallel. The exception:
|
|
42
|
+
tasks that edit the same files share a track ([waves](waves.md)).
|
|
39
43
|
7. **Self-review before dispatch.** Walk each spec requirement and name
|
|
40
44
|
the task that implements it. Grep the notes for placeholders. Check
|
|
41
45
|
that names in INTERFACES match across tasks. Then read the graph back
|
|
42
46
|
with `mu task tree task_0 -w <ws> --down`, or `mu state -w <ws>` for the tracks.
|
|
43
47
|
|
|
44
48
|
Done when every spec requirement maps to a task, no note holds a
|
|
45
|
-
placeholder, and `mu state` shows the intended parallel tracks.
|
|
49
|
+
placeholder, and `mu state` shows the intended parallel tracks. Then
|
|
50
|
+
dispatch per [orchestrator-loop](orchestrator-loop.md).
|
|
46
51
|
|
|
47
52
|
## Notes
|
|
48
53
|
|
|
@@ -19,8 +19,13 @@ when done in the wrong order.
|
|
|
19
19
|
mu never runs ssh or rsync; `mu sync` prints the line.
|
|
20
20
|
`--repair <peer>` is always safe. Agents, workspaces, and task
|
|
21
21
|
ownership never travel.
|
|
22
|
+
- **`mu db forget <ws...>`** deletes torn-down workstreams' ops for
|
|
23
|
+
good (no undo); `mu db compact` only blanks redundant tombstones. Both
|
|
24
|
+
back up beside the DB first. Forget only what the human named.
|
|
22
25
|
- **`mu doctor --deep` DRIFT** (exit 5) is a capture bug: back up and
|
|
23
26
|
report it. Do not rebuild; the live rows may hold work the log missed.
|
|
24
27
|
- The `doctor` `disk` section is report-only: an orphan dir may hold the
|
|
25
28
|
only copy of uncommitted work, so mu prints cleanup commands and runs
|
|
26
29
|
none. Read before you run them.
|
|
30
|
+
|
|
31
|
+
Done when `mu doctor` reports no DRIFT and every cleanup command you ran was read first.
|