@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
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -120,7 +120,7 @@ hub that re-exports them. `src/tasks.ts`, `src/agents.ts`, `src/mux.ts`,
|
|
|
120
120
|
| `src/agents/spawn.ts` | spawn: CLI resolution, pane create or reuse, liveness, readiness, ctl handshake, rollback |
|
|
121
121
|
| `src/agents/spawn-lock.ts` | per-session lock around topology and row insert |
|
|
122
122
|
| `src/agents/transport.ts` | send routing: ctl for pi agents, mux paste otherwise, no fallback; `expectsCtl` |
|
|
123
|
-
| `src/agents/abort.ts` | stop a pi turn through the control socket |
|
|
123
|
+
| `src/agents/abort.ts` | stop a pi turn through the control socket; abort + send (`--interrupt`) |
|
|
124
124
|
| `src/agents/delegate.ts` | `delegateOutcome`: one wait result to `done` / `empty` / `died` / `timeout` / `pending` |
|
|
125
125
|
| `src/agents/wait.ts` | block until task-less agents leave `busy` |
|
|
126
126
|
| `src/agents/adopt.ts` | register an existing pane as an agent |
|
|
@@ -139,7 +139,7 @@ hub that re-exports them. `src/tasks.ts`, `src/agents.ts`, `src/mux.ts`,
|
|
|
139
139
|
| `src/ctl/client.ts` | `ctlRequest`, `ctlProbe`, version and unknown-op errors |
|
|
140
140
|
| `extension/mu-pi.ts` | pi extension, child side: serves `$MU_CTL_SOCK`; built to `dist/extension/mu-pi.js` |
|
|
141
141
|
| `extension/delegate.ts` | pi extension, parent side: `mu_delegate` / `mu_delegate_cancel`, which shell out to `mu` |
|
|
142
|
-
| `extension/nudge.ts` | pi extension: the keep-driving nudge. Arms on a `mu` dispatch, checks `mu state --json` at `agent_before_settle`, injects the SKILL.md rule once per prompt, logs `--kind nudge` |
|
|
142
|
+
| `extension/nudge.ts` | pi extension: the keep-driving nudge. Arms on a `mu` dispatch, checks `mu state --json` at `agent_before_settle`, injects the SKILL.md rule once per prompt, logs `--kind nudge`. Also the close nudge (worker settles owning a task) and the refute nudge (`task claim --for` on a task with no refute decision in `mu task notes --json`; one notice, no continuation) |
|
|
143
143
|
| `src/link.ts` | `mu link pi`: extension shim, skill symlink, `inspectLinks` for doctor |
|
|
144
144
|
|
|
145
145
|
### Tasks, workspaces and workstreams
|
|
@@ -168,7 +168,8 @@ hub that re-exports them. `src/tasks.ts`, `src/agents.ts`, `src/mux.ts`,
|
|
|
168
168
|
| `src/cli.ts` | Commander wiring (`buildProgram`) |
|
|
169
169
|
| `src/cli/*.ts` | one file per verb namespace, thin wrappers over the SDK; `format.ts` renders tables, `handle.ts` maps errors to exit codes and runs ambient sync |
|
|
170
170
|
| `src/cli/tasks/*.ts` | the `mu task` namespace, including `mu me tasks` / `mu me next` |
|
|
171
|
-
| `src/cli/dispatch-hints.ts` | dispatch-time `Next:` hints for pi agents (`--fresh`, `--
|
|
171
|
+
| `src/cli/dispatch-hints.ts` | dispatch-time `Next:` hints for pi agents (`--fresh`, `--interrupt`, abort) |
|
|
172
|
+
| `src/cli/stdin.ts` | `-` as a text argument: reads note / send text from stdin (heredoc prose) |
|
|
172
173
|
| `src/cli/agents-remote.ts` | `mu agent remote-env`: prints the ssh forward and env, runs nothing |
|
|
173
174
|
| `src/cli/tui-launch-focus.ts` | initial-tab focus ladder for bare `mu` and `mu state --tui` |
|
|
174
175
|
| `src/cli/tui/` | the ink TUI; the only place ink and react are imported |
|
|
@@ -28,10 +28,11 @@ reply carries `v: 1`; the client (`src/ctl/client.ts`) throws
|
|
|
28
28
|
| op | does |
|
|
29
29
|
| --- | --- |
|
|
30
30
|
| `hello` | identity plus `ops` (served ops) and `extVersion` (the mu version the extension was built from) |
|
|
31
|
-
| `status` | `state` (`busy` / `idle`
|
|
32
|
-
| `send` | `pi.sendUserMessage`; when busy, `mode` is `steer` or `followUp` (default) |
|
|
31
|
+
| `status` | `state` (`busy` / `idle`), `since`, `runs`, `pending` |
|
|
32
|
+
| `send` | `pi.sendUserMessage`; when busy, `mode` is `steer` or `followUp` (default). Replies with the `status` fields measured before the dispatch, so `runs` is the baseline for a later `wait` |
|
|
33
33
|
| `wait` | resolves on pi's `agent_settled` after `afterRuns`, with the run's `lastText` |
|
|
34
34
|
| `abort` | `ctx.abort()` (pi's Esc) |
|
|
35
|
+
| `interrupt` | busy: `ctx.abort()`, wait for `agent_settled` (up to `timeoutMs`), then `pi.sendUserMessage(text)` as a new run; idle: just the send. Replies `wasBusy`, `pending` (measured before the abort) and the `status` fields measured after the settle and before the send, so `runs` is the `wait` baseline for the new run. `timeout`: nothing sent |
|
|
35
36
|
| `fresh` | new session plus prompt as one operation, through the internal `/mu-fresh` command; replies once the new run starts; refused with `busy` unless `force` |
|
|
36
37
|
| `command` | `name` `new`, `reload` or `compact` (with optional `instructions`), through the internal `/mu-new`, `/mu-reload`, `/mu-compact` commands, which call `ctx.newSession()`, `ctx.reload()`, `ctx.compact()`. `new` replies once the session is replaced, `reload` after the `session_start` it causes, `compact` when compaction starts or with pi's error (`Nothing to compact ...`). Refused with `busy` unless `force` |
|
|
37
38
|
|
|
@@ -41,13 +42,14 @@ extension command, triggered with `expandPromptTemplates: true`, and
|
|
|
41
42
|
its handler gets the command context that can replace or reload the
|
|
42
43
|
session.
|
|
43
44
|
|
|
44
|
-
These back `mu agent send` (`--fresh`, `--steer`, session commands), `mu agent wait`,
|
|
45
|
+
These back `mu agent send` (`--fresh`, `--steer`, `--interrupt`, session commands), `mu agent wait`,
|
|
45
46
|
`mu agent abort`, the agent state reading, and `mu_delegate`.
|
|
46
47
|
|
|
47
48
|
## Version skew
|
|
48
49
|
|
|
49
50
|
An op the extension does not serve returns `unknown op: <op>` with its
|
|
50
|
-
`ops` list. mu
|
|
51
|
+
`ops` list. `mu agent send --interrupt` then composes `abort`, `wait`
|
|
52
|
+
and `send` itself. Any other op raises `AgentExtensionOutdatedError` (exit 4), whose
|
|
51
53
|
next steps are `/reload` through the mux (an extension that lacks the
|
|
52
54
|
`command` op cannot run it over ctl) or a respawn. `mu doctor`
|
|
53
55
|
probes every pi agent's socket (the `ctl` row) and flags an
|
|
@@ -68,7 +70,10 @@ row reports whether `mu link pi` installed the extension.
|
|
|
68
70
|
|
|
69
71
|
1. If the path already answers, another pi serves it (a nested `pi -p`
|
|
70
72
|
inherited `MU_CTL_SOCK`). The extension leaves it alone and says so
|
|
71
|
-
on stderr.
|
|
73
|
+
on stderr. Identity follows the bind: that pi, and one that loses
|
|
74
|
+
the `link()` race, is nested and gets no keep-driving, close or
|
|
75
|
+
refute nudge, though it inherited the agent's `MU_AGENT_NAME`.
|
|
76
|
+
The decision lives in the process-global map, so `/reload` keeps it.
|
|
72
77
|
2. Otherwise it listens on a private name in the same directory, sets
|
|
73
78
|
mode 0600, and hard-links that name onto the public path. libuv
|
|
74
79
|
unlinks the listened-on name at close, so the public path must never
|
package/docs/architecture/mux.md
CHANGED
|
@@ -104,7 +104,10 @@ as a capability, not a name check:
|
|
|
104
104
|
- **tmux.** After `MU_SPAWN_LIVENESS_MS` (default 1500, `0` skips) mu
|
|
105
105
|
verifies the pane survived and scans its tail for provider or auth
|
|
106
106
|
startup errors. mu does not wait for murmur to claim the pane: state
|
|
107
|
-
reads before the first claim report `unknown`.
|
|
107
|
+
reads before the first claim report `unknown`. A pi agent skips the
|
|
108
|
+
fixed wait: mu checks the pane on every handshake tick (a dead pane
|
|
109
|
+
rolls back at once) and scans for startup errors when the handshake
|
|
110
|
+
ends.
|
|
108
111
|
- **herdr.** mu creates a bare pane and calls `startAgentInPane`, which
|
|
109
112
|
subsumes both checks.
|
|
110
113
|
- **pi, either backend.** After the agent starts, mu polls its control
|
package/docs/guide/delegate.md
CHANGED
|
@@ -23,6 +23,7 @@ Delegates called in one turn run in parallel.
|
|
|
23
23
|
| `workspace` | Own VCS checkout, for delegates that edit files. The follow-up names its path. It isolates repository edits only. |
|
|
24
24
|
| `cli` | Key for `$MU_<CLI>_COMMAND` (default `pi`), e.g. a cheaper model. |
|
|
25
25
|
| `keep` | Keep the pane after it finishes, to talk to it again. |
|
|
26
|
+
| `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). |
|
|
26
27
|
|
|
27
28
|
- Watch or steer: run the attach command.
|
|
28
29
|
- Stop: `mu_delegate_cancel`, or `mu agent abort <name> -w scratch`.
|
|
@@ -45,21 +46,42 @@ Delegates called in one turn run in parallel.
|
|
|
45
46
|
|
|
46
47
|
`MU_DELEGATE=0` hides the tool ([env vars](../reference/env.md)).
|
|
47
48
|
|
|
49
|
+
### Record a verdict
|
|
50
|
+
|
|
51
|
+
For a refuter or check, pass `record` so the verdict lands on the task
|
|
52
|
+
it judged. The task must exist (`mu task show`), else the call fails
|
|
53
|
+
and nothing spawns. When the answer arrives, the tool runs
|
|
54
|
+
`mu task note <task> -w <ws> --author <delegate>` once:
|
|
55
|
+
|
|
56
|
+
- Done: `REFUTER <label> (<delegate>, <elapsed>):`, then the last
|
|
57
|
+
`VERDICT:` line and every `EVIDENCE:` line after it. Without a
|
|
58
|
+
VERDICT line, the answer's last 1500 chars after `NO VERDICT LINE:`.
|
|
59
|
+
Capped at 4000 chars.
|
|
60
|
+
- Timeout, died, empty, error, or cancelled:
|
|
61
|
+
`REFUTER <label>: no verdict (<outcome>)`.
|
|
62
|
+
|
|
63
|
+
The follow-up still carries the full answer and ends with
|
|
64
|
+
`Recorded on <ws>/<task> as a note.`, or the reason recording failed.
|
|
65
|
+
|
|
48
66
|
## Delegate without pi
|
|
49
67
|
|
|
50
68
|
From a script or other shell, run what the tool runs:
|
|
51
69
|
|
|
52
70
|
```bash
|
|
53
71
|
mu agent spawn helper-1 -w scratch
|
|
54
|
-
mu agent send helper-1 -w scratch --fresh 'Investigate why foo.spec.ts fails. Report the cause.'
|
|
55
|
-
mu agent wait helper-1 -w scratch --json
|
|
72
|
+
runs=$(mu agent send helper-1 -w scratch --fresh --json 'Investigate why foo.spec.ts fails. Report the cause.' | jq .runs)
|
|
73
|
+
mu agent wait helper-1 -w scratch --after-runs "$runs" --json
|
|
56
74
|
```
|
|
57
75
|
|
|
76
|
+
`--after-runs` waits for the first run past the count the send
|
|
77
|
+
reported, so a run that settles before the wait starts still counts.
|
|
78
|
+
|
|
58
79
|
Use `--fresh`: a plain send to a reused agent carries the previous
|
|
59
80
|
task's context.
|
|
60
81
|
|
|
61
82
|
`mu agent wait` fires when the agent leaves busy (including to
|
|
62
|
-
`needs_input`), never on an already idle agent
|
|
83
|
+
`needs_input`), never on an already idle agent unless it finished a run
|
|
84
|
+
past `--after-runs`. For pi, the `--json`
|
|
63
85
|
row carries:
|
|
64
86
|
|
|
65
87
|
- `outcome`: `done`, `empty`, `error`, `died`, `timeout`, or `pending`.
|
package/docs/guide/dispatch.md
CHANGED
|
@@ -33,7 +33,8 @@ socket. Pick the mode by what the agent is doing:
|
|
|
33
33
|
| Situation | Command |
|
|
34
34
|
| --------- | ------- |
|
|
35
35
|
| New task, any state | `mu agent send worker-1 --fresh '<brief>'` |
|
|
36
|
-
| Busy, and
|
|
36
|
+
| Busy, and the current work is wasted (wrong input, changed rule): act now | `mu agent send worker-1 --interrupt '<text>'` |
|
|
37
|
+
| Busy, advice that can wait for the next tool boundary | `mu agent send worker-1 --steer '<text>'` |
|
|
37
38
|
| Answering a question, or adding to the same task | `mu agent send worker-1 '<text>'` |
|
|
38
39
|
|
|
39
40
|
- `--fresh` starts a new pi session and sends the prompt into it as
|
|
@@ -41,7 +42,14 @@ socket. Pick the mode by what the agent is doing:
|
|
|
41
42
|
`mu agent abort` first, or pass `--force` to drop the running turn.
|
|
42
43
|
- Never send `/new` and then the prompt as two sends to pi. The prompt
|
|
43
44
|
can land during the reset and vanish.
|
|
44
|
-
- A plain send to a busy agent queues as a follow-up
|
|
45
|
+
- A plain send to a busy agent queues as a follow-up: pi sees it after
|
|
46
|
+
the run ends. `--steer` lands between tool calls, after the running
|
|
47
|
+
tool returns; it does not stop a long tool such as a test batch, a
|
|
48
|
+
wait, or a `sleep`.
|
|
49
|
+
- `--interrupt` aborts the run (kills the running tool), waits for pi
|
|
50
|
+
to settle, then sends the text as a new run. Queued messages go back
|
|
51
|
+
to the pane's editor unsent. Exit 5 when pi does not settle within
|
|
52
|
+
`--timeout` (default 30 s); the text is then not sent.
|
|
45
53
|
- `/new`, `/reload` and `/compact [instructions]` run inside pi through
|
|
46
54
|
the socket and report pi's answer (for example `Nothing to compact`).
|
|
47
55
|
They refuse with exit 4 while pi is busy; `--force` overrides. Any
|
|
@@ -77,7 +85,9 @@ git commit -am '...' THEN
|
|
|
77
85
|
mu task close build -w auth --evidence '...'
|
|
78
86
|
```
|
|
79
87
|
|
|
80
|
-
Single-quote prompts
|
|
88
|
+
Single-quote short prompts. Pass prose (apostrophes, `$`, backticks) as `-` with a
|
|
89
|
+
quoted heredoc: `mu agent send worker-1 - <<'EOF'`; see
|
|
90
|
+
[brief](../../skills/mu/recipes/brief.md#quoting). To see only what the worker wrote after the claim, run
|
|
81
91
|
`mu task notes build -w auth --since-claim`.
|
|
82
92
|
|
|
83
93
|
## Give each worker a workspace
|
|
@@ -118,8 +128,11 @@ mu task wait auth/build auth/docs --first --on-stall exit --json
|
|
|
118
128
|
polling instead.
|
|
119
129
|
|
|
120
130
|
Exit 7 has several causes: the worker finished but did not close, it
|
|
121
|
-
asked a question, or it hit a prompt. In each case, run
|
|
122
|
-
`
|
|
131
|
+
asked a question, or it hit a prompt. In each case, run the exit's
|
|
132
|
+
`Next:` first. For a pi owner, it starts with
|
|
133
|
+
`mu agent wait <owner> --after-runs <runs-1> --json`, which prints the
|
|
134
|
+
last answer at once. Then it shows `mu agent read <owner>`, for the
|
|
135
|
+
dialogs and crashes that only the pane shows.
|
|
123
136
|
|
|
124
137
|
Pipeline the work: merge one task, run your tests on the merged tree,
|
|
125
138
|
then dispatch the next task. Waiting for a whole wave hides partial
|
|
@@ -136,6 +149,10 @@ mu task release build -w auth
|
|
|
136
149
|
|
|
137
150
|
- Closed substates other than `done` need `--why`. Every `CLOSED`
|
|
138
151
|
substate satisfies a blocker.
|
|
152
|
+
- Deciding a finding (`accept`, or `close --as rejected|wontfix|duplicate`)
|
|
153
|
+
with a reason under 40 characters and no `VERDICT:` or `REFUTER` note
|
|
154
|
+
prints a warning. The exit code stays the same. A `REJECTED` or `SUPERSEDED`
|
|
155
|
+
note appends the title of each task id it names.
|
|
139
156
|
- `--if-ready` closes only when every blocker is closed. Otherwise it
|
|
140
157
|
lists the open blockers and exits 0.
|
|
141
158
|
- A parked task leaves the ready set, and its dependents keep waiting.
|
|
@@ -126,7 +126,7 @@ The exit code tells you what happened:
|
|
|
126
126
|
| `0` | the task closed | merge the work |
|
|
127
127
|
| `5` | `--timeout` expired (default 600 s) | wait again |
|
|
128
128
|
| `6` | the worker's pane died and the task went back to `OPEN` | spawn and claim again |
|
|
129
|
-
| `7` | the worker sat in `needs_input` for
|
|
129
|
+
| `7` | the worker sat in `needs_input` for `--stuck-after` seconds (120, or 5 for a pi worker read over its control socket) | run its `Next:` (for a pi worker, `mu agent wait worker-1 --after-runs <runs-1> --json -w auth` returns the last answer; otherwise `mu agent read worker-1 -w auth`), then answer it |
|
|
130
130
|
|
|
131
131
|
`--on-stall exit` is the default; it is spelled out above so older mu
|
|
132
132
|
versions behave the same. With `--on-stall warn`, a stalled worker only
|
|
@@ -179,7 +179,7 @@ mu has not freed. That protects work you have not merged.
|
|
|
179
179
|
## Next steps
|
|
180
180
|
|
|
181
181
|
- [Dispatch work to a worker](dispatch.md) covers more than one
|
|
182
|
-
worker and the `--fresh`, `--steer`, and plain send choices.
|
|
182
|
+
worker and the `--fresh`, `--interrupt`, `--steer`, and plain send choices.
|
|
183
183
|
- [Use the TUI dashboard](tui.md): run bare `mu` to see every
|
|
184
184
|
workstream at once.
|
|
185
185
|
- [Clean up](cleanup.md) when the workstream is finished.
|
package/docs/guide/recovery.md
CHANGED
|
@@ -41,22 +41,27 @@ back to pasting.
|
|
|
41
41
|
|
|
42
42
|
| State | Means | Fix |
|
|
43
43
|
| ----- | ----- | --- |
|
|
44
|
-
| `ctl missing` | no socket: the extension is not loaded | run `mu link pi`, then respawn the agent |
|
|
44
|
+
| `ctl missing` | no socket: the extension is not loaded, or a new pi waits at its trust prompt | answer the [trust prompt](#a-new-pi-agent-shows-ctl-missing), or run `mu link pi`, then respawn the agent |
|
|
45
45
|
| `ctl refused` | the socket exists but does not answer | respawn the agent; for a remote agent, check the ssh forward |
|
|
46
|
-
| `extension X older than installed Y` | pi loaded an older mu build |
|
|
46
|
+
| `extension X older than installed Y` or `extension lacks ops` | pi loaded an older mu build | send `/reload`, or respawn |
|
|
47
47
|
|
|
48
48
|
To send `/reload` without attaching:
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
mu agent send worker-1 -w auth '/reload'
|
|
51
|
+
mu agent send worker-1 -w auth '/reload' # extension serves op command
|
|
52
|
+
mu agent send worker-1 -w auth '/reload' --via mux # older: type it into the pane
|
|
52
53
|
```
|
|
53
54
|
|
|
54
|
-
`/reload` keeps the pi session. A `send --fresh` or `abort` against an
|
|
55
|
+
The error names the right form. `/reload` keeps the pi session. A `send --fresh` or `abort` against an
|
|
55
56
|
outdated extension fails with exit 4 and prints the same two fixes.
|
|
56
57
|
|
|
57
|
-
## A new pi agent
|
|
58
|
+
## A new pi agent shows `ctl missing`
|
|
58
59
|
|
|
59
|
-
pi asks whether to trust a project folder on first start.
|
|
60
|
+
pi asks whether to trust a project folder on first start. It asks
|
|
61
|
+
before it loads extensions, so the agent has no control socket yet:
|
|
62
|
+
mu shows `unknown (ctl missing)` and spawn warns after 30 s. A pi
|
|
63
|
+
launched through a wrapper whose name is not `pi` or `pi-meta` shows
|
|
64
|
+
`needs_input` instead. Run
|
|
60
65
|
`/trust` in the pane once, or spawn with
|
|
61
66
|
`--command 'pi --approve'`. `--approve` trusts every directory,
|
|
62
67
|
including workspace forks, so use it only on your own code.
|
package/docs/guide/upgrade.md
CHANGED
|
@@ -25,15 +25,15 @@ For agents other than pi, see [README § Install](../../README.md#install).
|
|
|
25
25
|
## Reload running pi agents
|
|
26
26
|
|
|
27
27
|
A running pi keeps the extension it loaded at start. After an upgrade,
|
|
28
|
-
|
|
29
|
-
shell:
|
|
28
|
+
send `/reload` to each agent, or respawn the agent. From a shell:
|
|
30
29
|
|
|
31
30
|
```bash
|
|
32
|
-
mu agent send worker-1 -w auth '/reload'
|
|
31
|
+
mu agent send worker-1 -w auth '/reload' # extension serves op command
|
|
32
|
+
mu agent send worker-1 -w auth '/reload' --via mux # older extension
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Until then, the `ctl` row of `mu doctor` warns
|
|
36
|
-
`extension X older than installed Y`. Ops the old extension lacks,
|
|
36
|
+
`extension X older than installed Y` or `extension lacks ops`. Ops the old extension lacks,
|
|
37
37
|
such as `send --fresh`, fail with exit 4.
|
|
38
38
|
|
|
39
39
|
## Upgrade from 3.1 or earlier
|
package/docs/reference/env.md
CHANGED
|
@@ -29,7 +29,7 @@ milliseconds; `0` disables a wait unless noted.
|
|
|
29
29
|
| --- | --- | --- |
|
|
30
30
|
| `MU_<CLI>_COMMAND` | Executable for `--cli <cli>`; hyphens become underscores (`--cli pi-meta` reads `MU_PI_META_COMMAND`). May hold arguments. `--command` wins; the spawn line names the env var when it supplied the command. | the cli value |
|
|
31
31
|
| `MU_SPAWN_CTL_MS` | Budget for the control-socket handshake with a new pi agent, polled every 250ms. On timeout spawn still exits 0, reports `ctl: missing` or `ctl: refused`, and warns. `--no-ctl` skips it per spawn. | `30000` |
|
|
32
|
-
| `MU_SPAWN_LIVENESS_MS` | tmux only. Wait this long, then check the pane is alive and its scrollback has no startup error (auth failure, `command not found`). Failure rolls back the row and throws `AgentDiedOnSpawnError` or `AgentSpawnStartupError`. | `1500` |
|
|
32
|
+
| `MU_SPAWN_LIVENESS_MS` | tmux only. Wait this long, then check the pane is alive and its scrollback has no startup error (auth failure, `command not found`). Failure rolls back the row and throws `AgentDiedOnSpawnError` or `AgentSpawnStartupError`. A pi agent skips the wait: the pane is checked on each ctl handshake tick and scanned when it ends. | `1500` |
|
|
33
33
|
| `MU_SPAWN_LOCK_TIMEOUT_MS` | How long a spawn waits for the per-workstream spawn lock. | `15000` |
|
|
34
34
|
|
|
35
35
|
## Send and state (tmux path)
|
|
@@ -68,7 +68,7 @@ pi agent's `--command`. mu never reads them back.
|
|
|
68
68
|
| --- | --- | --- |
|
|
69
69
|
| `MU_DELEGATE` | `0` hides the `mu_delegate` tool. `mu doctor` reports it. | unset: shown |
|
|
70
70
|
| `MU_DELEGATE_MAX` | Most delegates one pi session runs at once. Further calls queue, up to four times this; past that `mu_delegate` refuses. A positive integer. | `16` |
|
|
71
|
-
| `MU_NUDGE` | `0` turns off
|
|
71
|
+
| `MU_NUDGE` | `0` turns off the three nudges: the keep-driving nudge (one reminder when an orchestrator ends a turn with dispatched work still IN_PROGRESS), the close nudge (one reminder when a mu-spawned pi worker ends a turn still owning an IN_PROGRESS task), and the refute nudge (one notice when an orchestrator dispatched a task whose notes hold no `REFUTER`, `VERDICT:` or `REFUTE-EXEMPT:` line). A pi nested in an agent's pane (it found `MU_CTL_SOCK` served by another pi) gets none of them; a pi without UI (`pi -p`, json mode) gets no close or refute nudge. `mu doctor` reports it. | unset: on |
|
|
72
72
|
| `MU_PI_HOME` | Root under which `mu link pi` writes `.pi/` and `.agents/`. | `$HOME` |
|
|
73
73
|
| `PI_CODING_AGENT_DIR` | Read only. pi's agent dir, checked for a linked murmur extension. | `~/.pi/agent` |
|
|
74
74
|
| `MU_EXTENSION_ENTRY` | Test only. Built extension the `mu link pi` shim imports. | `dist/extension/mu-pi.js` |
|
|
@@ -140,3 +140,24 @@ claimed a task for a worker, ended its turn, received one
|
|
|
140
140
|
`[mu-keep-driving]` message with `mu task wait nudgeprobe/slow ...`, and
|
|
141
141
|
`mu log --kind nudge` held one entry. With nothing IN_PROGRESS, no
|
|
142
142
|
nudge fired.
|
|
143
|
+
|
|
144
|
+
## Refute nudge (2026-10-05)
|
|
145
|
+
|
|
146
|
+
A sibling hook in the same file (`registerRefuteNudge`), registered on
|
|
147
|
+
its own: it does not need the keep-driving markers and has its own
|
|
148
|
+
once-per-prompt flag.
|
|
149
|
+
|
|
150
|
+
- **Arm** on `mu task claim <id> --for` (`dispatchedTasks`: the id is
|
|
151
|
+
the first positional that is not an option value; `<ws>/<id>`
|
|
152
|
+
splits). `review_*` tasks never arm: their brief is the fixed
|
|
153
|
+
reviewer template, judging work against an already-refuted brief.
|
|
154
|
+
- **Check** at a completed `agent_before_settle`: `mu task notes <id>
|
|
155
|
+
-w <ws> --json` per armed task. This is a second read beside
|
|
156
|
+
`mu state --json`. A task counts as refuted when a note has a line
|
|
157
|
+
starting `REFUTER `, `VERDICT:` or `REFUTE-EXEMPT:`; prose that only
|
|
158
|
+
mentions the words mid-line does not count.
|
|
159
|
+
- **Notify** once per prompt: one `custom_message`
|
|
160
|
+
(`customType: "mu-refute-brief"`, `display: true`) listing every
|
|
161
|
+
unrefuted `<ws>/<id>`, and `mu log --kind nudge 'refute: ...'`. No
|
|
162
|
+
`continue`: it informs, and the orchestrator decides. `MU_NUDGE=0`
|
|
163
|
+
turns it off.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mu-crew/mu",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.0",
|
|
4
4
|
"description": "A persistent, observable crew of pi agents running in one tmux or herdr session per workstream, coordinated through a built-in task DAG.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
package/skills/mu/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mu
|
|
3
|
-
description:
|
|
3
|
+
description: Fresh-context subagents and crews in tmux/herdr panes. Check before you commit: before acting on a claim, root cause, plan, fix or brief, have a `mu_delegate` call refute it. Also for a fresh delegate's second look at your own work or diff; parallel read-only research, investigation or fan-out over files; background helpers (watchers, soak runs, agents you keep talking to); persistent crews with a task graph, review gates and merges. Outside pi, delegate through the reserved `scratch` workstream.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# mu — Multi-agent orchestration
|
|
@@ -53,9 +53,9 @@ Recipe words, the same in every recipe:
|
|
|
53
53
|
- **wave** — the units dispatched from one main revision; refresh
|
|
54
54
|
workspaces before the next.
|
|
55
55
|
- **finding** — one reported problem, recorded as an `OPEN/triage` task.
|
|
56
|
-
- **verdict** —
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
- **verdict** — a check's answer: `VERDICT: <id> CONFIRMED | REFUTED |
|
|
57
|
+
UNVERIFIED <one line>` plus `EVIDENCE:` lines (or ACCEPT | REJECT for
|
|
58
|
+
a review gate).
|
|
59
59
|
- **stop rule** — the command and condition that end a loop, written on
|
|
60
60
|
the umbrella first ([loop-until-done](recipes/loop-until-done.md)).
|
|
61
61
|
|
|
@@ -65,12 +65,18 @@ Use mu for persistent helpers, parallel work, dependencies, gated review, or
|
|
|
65
65
|
work that must survive context compaction. Stay in one context for tiny edits
|
|
66
66
|
or inspection.
|
|
67
67
|
|
|
68
|
-
###
|
|
68
|
+
### Quick checks and off-the-cuff helpers (`scratch`)
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
Before you act on a claim, root cause, plan, fix or brief, or to get a second
|
|
71
|
+
look at your own work or diff, make a [delegate call](recipes/tasks-or-calls.md#delegate-call)
|
|
72
|
+
that tries to refute it (briefs: see Orchestrator rules; many claims: [refute](recipes/refute.md)).
|
|
73
|
+
|
|
74
|
+
For one-shot work inside pi, call `mu_delegate` (installed by `mu link pi`). Outside pi: spawn
|
|
75
|
+
into the reserved `scratch` workstream (no task DAG, auto-created), `send --fresh --json`, then
|
|
76
|
+
`mu agent wait --after-runs <its runs> --json` (`lastText`); without `--after-runs` a run that
|
|
77
|
+
ends first hangs the wait. Recipes call either form a **delegate call**. A check judging a mu
|
|
78
|
+
task lands its verdict there: `record: { task: "<ws>/<id>" }` on `mu_delegate`, a hand-written
|
|
79
|
+
`REFUTER` note on the spawn path; with no task, skip both.
|
|
74
80
|
|
|
75
81
|
- `mu agent wait <names...> --first` waits for busy → idle instead of a
|
|
76
82
|
`sleep` loop; exit 0 met, 5 timeout, 6 pane died.
|
|
@@ -78,8 +84,10 @@ Recipes call either form a **delegate call**.
|
|
|
78
84
|
- One agent per independent unit; `--workspace` for any helper that may edit,
|
|
79
85
|
build, or test the shared repo.
|
|
80
86
|
|
|
81
|
-
A helper
|
|
82
|
-
|
|
87
|
+
A pi helper showing `unknown (ctl missing)` right after spawn (spawn
|
|
88
|
+
warns after 30 s) likely sits at pi's project trust prompt (through a
|
|
89
|
+
wrapper whose argv0 is not `pi`/`pi-meta` it shows `needs_input`): add
|
|
90
|
+
`--approve` to `MU_<CLI>_COMMAND`. Move off
|
|
83
91
|
`scratch` when work gains dependencies or review gates.
|
|
84
92
|
|
|
85
93
|
## Mental model
|
|
@@ -170,11 +178,18 @@ rules hold even when you skip it:
|
|
|
170
178
|
- **`mu task wait --first --on-stall exit`**; exit 7 means read the
|
|
171
179
|
owner's pane and answer it.
|
|
172
180
|
- **Stop a worker gently**: `mu agent abort`, then `kick`, then `close`.
|
|
181
|
+
To redirect a busy pi now: `send --interrupt` (`--steer` waits for
|
|
182
|
+
the running tool).
|
|
183
|
+
- **Send, don't note, a running worker**: it never sees new notes. The note is the durable copy
|
|
184
|
+
([how to send](recipes/orchestrator-loop.md#sending)).
|
|
185
|
+
- **Refute a brief claiming a cause, fix, threshold or code fact** before dispatch:
|
|
186
|
+
one `record`ed refuter call; rewrite on AMEND. Others get a `REFUTE-EXEMPT: <why>` note.
|
|
173
187
|
- **Checks are calls, not tasks.** Refuters, claim checkers, judges and
|
|
174
188
|
skeptics are [delegate calls](recipes/tasks-or-calls.md#delegate-call)
|
|
175
189
|
(`mu_delegate`, or a `scratch` spawn without it), all issued in one
|
|
176
|
-
turn
|
|
177
|
-
`
|
|
190
|
+
turn. Refuters and claim checkers pass `record` (or hand-write the
|
|
191
|
+
`REFUTER` note) to land the verdict on the task; judges report
|
|
192
|
+
`WINNER:`. `MU_DELEGATE_MAX` (16) run at once; the rest queue.
|
|
178
193
|
- **Findings are tasks.** A reviewer's or auditor's findings become
|
|
179
194
|
`mu task add --triage` tasks blocking the review, decided with
|
|
180
195
|
`mu task accept` or `close --as rejected|duplicate`. A review nobody
|
|
@@ -193,6 +208,8 @@ rules hold even when you skip it:
|
|
|
193
208
|
- **For waits use `task wait`, not `log --tail`.** `mu log --kind <k>`
|
|
194
209
|
entries are your own durable state (a ledger); `--intent` filters what
|
|
195
210
|
mu recorded.
|
|
211
|
+
- **Prose in notes, prompts, `--why` or `--evidence`**: an apostrophe
|
|
212
|
+
ends `'...'`; use a quoted heredoc ([brief](recipes/brief.md#quoting)).
|
|
196
213
|
- **`mu sql`** does not pull synced ops; run any other mu command first.
|
|
197
214
|
- **Never put `MU_DB_PATH` inside `MU_SYNC_DIR`**: it corrupts the DB.
|
|
198
215
|
- Before undo, rebuild, teardown (dry-run without `--yes`), sync setup,
|
|
@@ -209,9 +226,15 @@ export MU_PI_COMMAND="pi --model sonnet:medium"
|
|
|
209
226
|
mu agent spawn a --cli pi_big # uses $MU_PI_BIG_COMMAND
|
|
210
227
|
```
|
|
211
228
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
229
|
+
`pi_mini` scouts and finds, `pi` builds and refactors, `pi_big` designs and
|
|
230
|
+
handles incidents. A reviewer, refuter,
|
|
231
|
+
judge or auditor checks level or up, never down: at least the worker's
|
|
232
|
+
capability, from another family if one exists (provider or model-id prefix in
|
|
233
|
+
`pi --list-models`). Small-model signs: a local runtime (ollama, lmstudio,
|
|
234
|
+
llama.cpp), a size (`4b`, `27b`), mini/haiku/flash/nano/lite, thinking `no`,
|
|
235
|
+
context or max-out far below the worker's. No such peer: same model, fresh
|
|
236
|
+
context, higher thinking unless at max. Probe an unused model first
|
|
237
|
+
(`pi --model <provider/model> -p "say ok"`); `ctl: ok` does not test it.
|
|
215
238
|
|
|
216
239
|
## Reaper and agent state
|
|
217
240
|
|
|
@@ -254,6 +277,7 @@ risky job that needs several of them, start with
|
|
|
254
277
|
| [remote-workers](recipes/remote-workers.md) | an agent runs on another machine |
|
|
255
278
|
| [waves](recipes/waves.md) | more than one worker edits the same repo at once |
|
|
256
279
|
| [long-run](recipes/long-run.md) | a task or proof runs for hours, or must survive flakes |
|
|
280
|
+
| [drift-audit](recipes/drift-audit.md) | hours into a long run, after a batch, compaction or resume, before a stop rule |
|
|
257
281
|
| [watcher](recipes/watcher.md) | a helper polls a PR, CI, or log for change |
|
|
258
282
|
| [findings](recipes/findings.md) | any review, audit, or check reports problems: where they live, how they are triaged |
|
|
259
283
|
| [tasks-or-calls](recipes/tasks-or-calls.md) | a recipe step spawns an agent: DAG task or delegate call |
|
|
@@ -28,9 +28,8 @@ PR or diff from several angles, use [review-panel](review-panel.md).
|
|
|
28
28
|
3. **Dispatch the work** as usual. When `x` closes, `review_x` becomes
|
|
29
29
|
ready.
|
|
30
30
|
4. **Spawn a fresh reviewer.** A new agent, or `--fresh` on an idle one,
|
|
31
|
-
so it has none of the author's reasoning
|
|
32
|
-
|
|
33
|
-
model has different blind spots. Give it the worker's workspace path
|
|
31
|
+
so it has none of the author's reasoning, on a model chosen per
|
|
32
|
+
[Models](../SKILL.md#models-and-thinking-effort). Give it the worker's workspace path
|
|
34
33
|
and commits read-only by instruction; it edits nothing.
|
|
35
34
|
5. **Claim `review_x` for the reviewer**, send the brief (below), wait.
|
|
36
35
|
6. **Act on the verdict:**
|
|
@@ -71,11 +70,20 @@ where it fails the acceptance criteria in `mu task notes <x>`.
|
|
|
71
70
|
UNVERIFIED for it. Unverified is not a pass and not a fail.
|
|
72
71
|
- Do not edit files.
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
73
|
+
Write the verdict note (FILES/COMMANDS/FINDINGS/VERIFIED), then close
|
|
74
|
+
(long reasons: a heredoc variable, brief.md § Quoting):
|
|
75
|
+
ACCEPT: mu task close review_<x> --evidence "<key command>: <result>"
|
|
76
|
+
REJECT: mu task close review_<x> --as rejected \
|
|
77
|
+
--why "<n> gaps: <id> (<why it fails, one clause>), ..."
|
|
77
78
|
```
|
|
78
79
|
|
|
80
|
+
mu adds each named gap's title to the REJECTED note.
|
|
81
|
+
|
|
82
|
+
**Closing a review yourself** (you fixed a finding, or accept without a
|
|
83
|
+
fresh reviewer): write the reviewer's note plus `COMMIT: <sha> fixes
|
|
84
|
+
<finding>`, and name the check in `--evidence`. Not `one finding fixed
|
|
85
|
+
by orchestrator`.
|
|
86
|
+
|
|
79
87
|
## Traps
|
|
80
88
|
|
|
81
89
|
- **A reviewer that sees the author's reasoning agrees with it.** Send
|
|
@@ -32,6 +32,7 @@ not in the brief, or one pointer away, does not exist for it.
|
|
|
32
32
|
6. **Ask for evidence, not reassurance.** The final note names the
|
|
33
33
|
commands run and their exit codes (the task note contract). "Done,
|
|
34
34
|
all good" is not a result.
|
|
35
|
+
7. **A brief that makes claims is refuted before dispatch** ([SKILL.md](../SKILL.md#orchestrator-rules)).
|
|
35
36
|
|
|
36
37
|
## Shape
|
|
37
38
|
|
|
@@ -46,8 +47,35 @@ VERIFY: <exact command>
|
|
|
46
47
|
|
|
47
48
|
⚠️ FINAL ACTION
|
|
48
49
|
git commit -am '<msg>' THEN
|
|
49
|
-
mu task close <id> -w <ws> --evidence
|
|
50
|
+
mu task close <id> -w <ws> --evidence "$v" # command + result; see Quoting
|
|
50
51
|
```
|
|
51
52
|
|
|
53
|
+
## Quoting
|
|
54
|
+
|
|
55
|
+
Single quotes suit short text with no `'`. Prose (an apostrophe ends
|
|
56
|
+
`'...'`; `"..."` expands `$` and backticks) goes through stdin with a
|
|
57
|
+
quoted heredoc, stored verbatim:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
mu task note <id> -w <ws> - <<'EOF'
|
|
61
|
+
it's fine: $HOME and `pwd` stay literal
|
|
62
|
+
EOF
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`mu task add --note -`, `--text -` and `mu agent send <a> -` read stdin
|
|
66
|
+
the same way. `--why` and `--evidence` have no `-` form: capture the
|
|
67
|
+
heredoc in a variable and double-quote it:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
v=$(cat <<'EOF'
|
|
71
|
+
it's fine: $HOME stays literal
|
|
72
|
+
EOF
|
|
73
|
+
)
|
|
74
|
+
mu task close <id> -w <ws> --evidence "$v"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Chain batched adds with `&&`, then `mu task list`, so one
|
|
78
|
+
quoting failure cannot half-apply the batch unseen.
|
|
79
|
+
|
|
52
80
|
Done when a worker with no other context could finish the task from
|
|
53
81
|
the brief and the notes it points at, and could tell when it is done.
|
|
@@ -62,16 +62,24 @@ the `scratch` form through `tools.bash`:
|
|
|
62
62
|
|
|
63
63
|
```js
|
|
64
64
|
// @options: {"timeout_ms": 1800000}
|
|
65
|
+
const ws = "audit";
|
|
65
66
|
const findings = ["f_auth_put", "f_sql_order"]; // finding task ids, at most the cap per script
|
|
66
67
|
const sh = async (c) => (await tools.bash({ command: c })).output;
|
|
68
|
+
const json = (s) => { try { return JSON.parse(s); } catch { return {}; } };
|
|
69
|
+
const el = (ms) => { const t = Math.round(ms / 1000); return t < 60 ? `${t}s` : `${Math.floor(t / 60)}m ${String(t % 60).padStart(2, "0")}s`; };
|
|
67
70
|
const rows = await Promise.all(findings.map(async (id, i) => {
|
|
68
|
-
const a = `refuter-${i + 1}
|
|
71
|
+
const a = `refuter-${i + 1}`, t0 = Date.now();
|
|
69
72
|
await sh(`mu agent spawn ${a} -w scratch`);
|
|
70
|
-
await sh(`mu agent send ${a} -w scratch --fresh '<brief for ${id}
|
|
71
|
-
const w =
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
const { runs } = json(await sh(`mu agent send ${a} -w scratch --fresh --json - <<'MU_EOF'\n<brief for ${id}, ending with the VERDICT block>\nMU_EOF`));
|
|
74
|
+
const w = json(await sh(`mu agent wait ${a} -w scratch --after-runs ${runs} --json --timeout 1200`)).agents?.[0] ?? {};
|
|
75
|
+
const lines = (w.lastText ?? "").trimEnd().split("\n");
|
|
76
|
+
const at = lines.findLastIndex((l) => /^[\s>*_`-]*VERDICT:/.test(l));
|
|
77
|
+
const note = w.outcome !== "done" ? `REFUTER ${i + 1}: no verdict (${w.outcome ?? "no result"})`
|
|
78
|
+
: `REFUTER ${i + 1} (${a}, ${el(Date.now() - t0)}):\n` + (at < 0 ? `NO VERDICT LINE: ${(w.lastText ?? "").slice(-1500)}`
|
|
79
|
+
: [lines[at], ...lines.slice(at + 1).filter((l) => /^[\s>*_`-]*EVIDENCE:/.test(l))].join("\n"));
|
|
80
|
+
await sh(`mu task note ${id} -w ${ws} - <<'MU_EOF'\n${note}\nMU_EOF`);
|
|
81
|
+
if (w.outcome === "done") await sh(`mu agent close ${a} -w scratch`);
|
|
82
|
+
return `${id}\t${note.split("\n")[1] ?? note}`;
|
|
75
83
|
}));
|
|
76
84
|
return rows.join("\n");
|
|
77
85
|
```
|
|
@@ -82,9 +90,11 @@ What the tool did for you, the script now owns:
|
|
|
82
90
|
each script's list at or under it.
|
|
83
91
|
- **Cleanup.** Close each scratch pane; a timed-out one stays, readable
|
|
84
92
|
with `mu agent read <a> -w scratch`.
|
|
85
|
-
- **Recording.** The
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
- **Recording.** The script writes each `REFUTER` note in `record`'s
|
|
94
|
+
shape, and `no verdict (<outcome>)` for a failed wait; it does not
|
|
95
|
+
cap long answers or special-case empty ones as `record` does. Decide
|
|
96
|
+
each finding after it returns ([findings § Triage](findings.md#triage)
|
|
97
|
+
step 3).
|
|
88
98
|
|
|
89
99
|
## Traps
|
|
90
100
|
|
|
@@ -41,12 +41,13 @@ answer rests on is an `OPEN/triage` task, decided like a finding
|
|
|
41
41
|
gets the claim and its sources, not the searcher's reasoning, fetches
|
|
42
42
|
the source itself, and tries to break the claim: is the quote there,
|
|
43
43
|
does it say that, is it current, does another source disagree? It
|
|
44
|
-
ends with
|
|
44
|
+
ends with the VERDICT block
|
|
45
|
+
([tasks-or-calls § Delegate call](tasks-or-calls.md#delegate-call)).
|
|
45
46
|
For contradicted claims, one checker per side. Batch under the cap
|
|
46
|
-
([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)).
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
([orchestrator-loop § Concurrency](orchestrator-loop.md#concurrency)).
|
|
48
|
+
In workstream mode the checker passes `record` on the claim task, and
|
|
49
|
+
the verdict is decided as in [findings § Triage](findings.md#triage)
|
|
50
|
+
step 3.
|
|
50
51
|
5. **Synthesize** once every checker has answered (in workstream mode,
|
|
51
52
|
when no claim task is left undecided): answer the question
|
|
52
53
|
from confirmed claims only, each with its source URL. List
|