@mu-crew/mu 3.13.3 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +73 -35
- package/README.md +71 -57
- package/dist/chunk-4ULY3ZKO.js +4482 -0
- package/dist/chunk-4ULY3ZKO.js.map +1 -0
- package/dist/chunk-7M634JMD.js +375 -0
- package/dist/chunk-7M634JMD.js.map +1 -0
- package/dist/{chunk-3BARPJLY.js → chunk-PZ5GOCWH.js} +16 -2
- package/dist/chunk-PZ5GOCWH.js.map +1 -0
- package/dist/chunk-SS7NQSSZ.js +3660 -0
- package/dist/chunk-SS7NQSSZ.js.map +1 -0
- package/dist/chunk-UCZPJX7K.js +14253 -0
- package/dist/chunk-UCZPJX7K.js.map +1 -0
- package/dist/{cli-CKOMHBXV.js → cli-TV3N47AZ.js} +7317 -4593
- package/dist/cli-TV3N47AZ.js.map +1 -0
- package/dist/cli.js +2 -3
- package/dist/cli.js.map +1 -1
- package/dist/errors-GRONKWFS.js +65 -0
- package/dist/extension/mu-pi.js +1632 -837
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.d.ts +4067 -2561
- package/dist/index.js +614 -297
- package/dist/index.js.map +1 -1
- package/dist/tui-FUBQ326D.js +1848 -0
- package/dist/tui-FUBQ326D.js.map +1 -0
- package/docs/ARCHITECTURE.md +118 -66
- package/docs/VOCABULARY.md +113 -49
- package/docs/guide/README.md +3 -3
- package/docs/guide/backends.md +8 -4
- package/docs/guide/cleanup.md +69 -33
- package/docs/guide/delegate.md +149 -66
- package/docs/guide/dispatch.md +148 -53
- package/docs/guide/getting-started.md +37 -44
- package/docs/guide/other-agent-clis.md +102 -0
- package/docs/guide/recovery.md +31 -50
- package/docs/guide/remote.md +122 -45
- package/docs/guide/sql.md +104 -24
- package/docs/guide/stop-a-worker.md +30 -37
- package/docs/guide/sync.md +11 -3
- package/docs/guide/upgrade.md +93 -43
- package/docs/reference/env.md +24 -32
- package/docs/reference/naming.md +14 -7
- package/docs/reference/surface-contract.md +153 -0
- package/package.json +33 -11
- package/prompts/mu-debug.md +3 -1
- package/prompts/mu-refute.md +2 -1
- package/prompts/mu-research.md +3 -1
- package/prompts/mu-review.md +2 -1
- package/prompts/mu-rules-audit.md +5 -4
- package/prompts/mu-sweep.md +2 -1
- package/prompts/mu-tournament.md +4 -2
- package/prompts/mu-until.md +3 -1
- package/prompts/ultrathink.md +1 -1
- package/skills/mu/SKILL.md +60 -291
- package/skills/mu/recipes/adversarial-review.md +12 -103
- package/skills/mu/recipes/brief.md +14 -61
- package/skills/mu/recipes/course-correct.md +23 -0
- package/skills/mu/recipes/findings.md +17 -111
- package/skills/mu/recipes/models.md +17 -92
- package/skills/mu/recipes/move.md +14 -0
- package/skills/mu/recipes/orchestrator-loop.md +20 -119
- package/skills/mu/recipes/recovery.md +8 -29
- package/skills/mu/recipes/remote-workers.md +17 -318
- package/skills/mu/recipes/tasks-or-calls.md +15 -78
- package/skills/mu/recipes/test-health.md +19 -77
- package/skills/mu/recipes/worker.md +17 -24
- package/dist/chunk-45KQLMEL.js +0 -2908
- package/dist/chunk-45KQLMEL.js.map +0 -1
- package/dist/chunk-G434JKV2.js +0 -641
- package/dist/chunk-G434JKV2.js.map +0 -1
- package/dist/chunk-KUGUFBWH.js +0 -12527
- package/dist/chunk-KUGUFBWH.js.map +0 -1
- package/dist/chunk-QITLNZEM.js +0 -87
- package/dist/chunk-QITLNZEM.js.map +0 -1
- package/dist/chunk-VIEYQMQA.js +0 -393
- package/dist/chunk-VIEYQMQA.js.map +0 -1
- package/dist/chunk-WI6AWCMK.js +0 -19
- package/dist/chunk-WI6AWCMK.js.map +0 -1
- package/dist/cli-CKOMHBXV.js.map +0 -1
- package/dist/devtools-LS4ZEPWM.js +0 -3772
- package/dist/devtools-LS4ZEPWM.js.map +0 -1
- package/dist/tui-LFJ5P4Y2.js +0 -40956
- package/dist/tui-LFJ5P4Y2.js.map +0 -1
- package/dist/tui-sync-worker.js +0 -17
- package/dist/tui-sync-worker.js.map +0 -1
- package/dist/yank-XDOONQSL.js +0 -13
- package/dist/yank-XDOONQSL.js.map +0 -1
- package/docs/ROADMAP.md +0 -123
- package/docs/VISION.md +0 -298
- package/docs/architecture/control-socket.md +0 -142
- package/docs/architecture/dag.md +0 -117
- package/docs/architecture/mux.md +0 -167
- package/docs/architecture/ops-log.md +0 -160
- package/docs/architecture/sdk.md +0 -187
- package/docs/architecture/sync.md +0 -159
- package/docs/architecture/tui.md +0 -165
- package/docs/guide/tui.md +0 -98
- package/docs/history/CHANGELOG-pre-3.md +0 -4866
- package/docs/img/tui-dashboard.png +0 -0
- package/docs/specs/2026-09-28-agent-state-from-murmur.md +0 -333
- package/docs/specs/2026-09-29-task-substates.md +0 -247
- package/docs/specs/2026-10-03-keep-driving-nudge.md +0 -163
- package/docs/specs/2026-10-21-fast-and-slow-gates.md +0 -229
- package/skills/mu/recipes/backlog-triage.md +0 -45
- package/skills/mu/recipes/codemode-driver.md +0 -118
- package/skills/mu/recipes/deep-research.md +0 -69
- package/skills/mu/recipes/drift-audit.md +0 -75
- package/skills/mu/recipes/fan-out.md +0 -42
- package/skills/mu/recipes/hypothesis-panel.md +0 -48
- package/skills/mu/recipes/long-run.md +0 -32
- package/skills/mu/recipes/loop-until-done.md +0 -45
- package/skills/mu/recipes/plan.md +0 -67
- package/skills/mu/recipes/refute.md +0 -55
- package/skills/mu/recipes/review-panel.md +0 -65
- package/skills/mu/recipes/rules-audit.md +0 -89
- package/skills/mu/recipes/tournament.md +0 -44
- package/skills/mu/recipes/ultrathink.md +0 -86
- package/skills/mu/recipes/watcher.md +0 -28
- package/skills/mu/recipes/waves.md +0 -21
- /package/dist/{chunk-3BARPJLY.js.map → errors-GRONKWFS.js.map} +0 -0
package/dist/tui-sync-worker.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { createRequire as __muCreateRequire } from "node:module"; const require = __muCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
ambientSyncPass,
|
|
4
|
-
openDb
|
|
5
|
-
} from "./chunk-45KQLMEL.js";
|
|
6
|
-
import "./chunk-WI6AWCMK.js";
|
|
7
|
-
import "./chunk-3BARPJLY.js";
|
|
8
|
-
|
|
9
|
-
// src/cli/tui/sync-worker.ts
|
|
10
|
-
import { parentPort, workerData } from "worker_threads";
|
|
11
|
-
var port = parentPort;
|
|
12
|
-
if (port === null) throw new Error("tui-sync-worker must run as a worker_thread");
|
|
13
|
-
var db = openDb({ path: workerData.dbPath });
|
|
14
|
-
port.on("message", () => {
|
|
15
|
-
void ambientSyncPass(db, { quiet: true }).catch(() => null).then((result) => port.postMessage(result));
|
|
16
|
-
});
|
|
17
|
-
//# sourceMappingURL=tui-sync-worker.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/tui/sync-worker.ts"],"sourcesContent":["// worker_thread entry for the TUI's ambient sync pass (built to\n// dist/tui-sync-worker.js). ingest and flush are synchronous SQLite and\n// file work (seconds on a first read, hundreds of ms per peer append on\n// a 40 MB segment), so on ink's thread they froze input and repaints.\n// Here they block only this thread. The worker owns its own connection\n// to the same DB file: WAL serves the TUI's reads meanwhile, and the\n// TUI sees the result on its next read.\n//\n// Protocol: the parent posts any message to start one pass, and the\n// worker replies with the pass's result (`null` if it threw) when the\n// pass is over. ambientSyncPass is total, and `quiet` keeps stderr off\n// the alternate screen.\n\nimport { parentPort, workerData } from \"node:worker_threads\";\nimport { openDb } from \"../../db.js\";\nimport { ambientSyncPass } from \"../../sync.js\";\n\nconst port = parentPort;\nif (port === null) throw new Error(\"tui-sync-worker must run as a worker_thread\");\nconst db = openDb({ path: (workerData as { dbPath: string }).dbPath });\nport.on(\"message\", () => {\n void ambientSyncPass(db, { quiet: true })\n .catch(() => null)\n .then((result) => port.postMessage(result));\n});\n"],"mappings":";;;;;;;;;AAaA,SAAS,YAAY,kBAAkB;AAIvC,IAAM,OAAO;AACb,IAAI,SAAS,KAAM,OAAM,IAAI,MAAM,6CAA6C;AAChF,IAAM,KAAK,OAAO,EAAE,MAAO,WAAkC,OAAO,CAAC;AACrE,KAAK,GAAG,WAAW,MAAM;AACvB,OAAK,gBAAgB,IAAI,EAAE,OAAO,KAAK,CAAC,EACrC,MAAM,MAAM,IAAI,EAChB,KAAK,CAAC,WAAW,KAAK,YAAY,MAAM,CAAC;AAC9C,CAAC;","names":[]}
|
package/dist/yank-XDOONQSL.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { createRequire as __muCreateRequire } from "node:module"; const require = __muCreateRequire(import.meta.url);
|
|
2
|
-
import {
|
|
3
|
-
osc52Sequence,
|
|
4
|
-
probeClipboardBackend,
|
|
5
|
-
yank
|
|
6
|
-
} from "./chunk-QITLNZEM.js";
|
|
7
|
-
import "./chunk-3BARPJLY.js";
|
|
8
|
-
export {
|
|
9
|
-
osc52Sequence,
|
|
10
|
-
probeClipboardBackend,
|
|
11
|
-
yank
|
|
12
|
-
};
|
|
13
|
-
//# sourceMappingURL=yank-XDOONQSL.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/docs/ROADMAP.md
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
# Roadmap
|
|
2
|
-
|
|
3
|
-
If a feature is not here, it is not planned. Shipped work is in
|
|
4
|
-
[CHANGELOG.md](../CHANGELOG.md). Pillars are in [VISION.md](VISION.md).
|
|
5
|
-
|
|
6
|
-
## Promotion criteria
|
|
7
|
-
|
|
8
|
-
A roadmap item is built when all three hold:
|
|
9
|
-
|
|
10
|
-
1. **Proven friction.** A real user hit the gap in a real workflow at
|
|
11
|
-
least twice.
|
|
12
|
-
2. **No pillar refactor.** It fits without bending a
|
|
13
|
-
[VISION](VISION.md) pillar.
|
|
14
|
-
3. **Bounded scope.** It fits in <300 LOC, or a smaller subset does.
|
|
15
|
-
|
|
16
|
-
Data-loss footguns ship on the first occurrence. Polish (bug fixes,
|
|
17
|
-
ergonomics, error wording, docs) needs no promotion: ship it through the
|
|
18
|
-
green gate.
|
|
19
|
-
|
|
20
|
-
## Anti-feature pledges
|
|
21
|
-
|
|
22
|
-
mu does not add these unless one earns its way back under the criteria:
|
|
23
|
-
|
|
24
|
-
- **A config file.** Config is CLI flags and env vars.
|
|
25
|
-
- **A daemon, watcher, or background process** beyond tmux and SQLite.
|
|
26
|
-
- **Abstractions with no current consumer** (the cautionary tale: a
|
|
27
|
-
`RunContext` trait with no implementor).
|
|
28
|
-
- **Wrappers around wrappers** (`TextStream`/`TextState`/`StreamResult`).
|
|
29
|
-
- **Codegen, an embedded JS engine, macros, or decorators.** No workflow
|
|
30
|
-
DSL.
|
|
31
|
-
- **Templates or definitions for agent roles.** Spawn flags and the first
|
|
32
|
-
message are the definition.
|
|
33
|
-
- **Render layers beyond `cli-table3` + `picocolors`**, except `ink` in
|
|
34
|
-
`src/cli/tui/`. If `ink` stops paying off, replace it. Never run two
|
|
35
|
-
TUI stacks.
|
|
36
|
-
- **Bundling pi.** It is a peer dependency.
|
|
37
|
-
- **A plugin runtime, web UI, RPC, chat or docs integrations, a memory
|
|
38
|
-
system, or a workflow engine.** A prior internal runtime collected all
|
|
39
|
-
of these. Not inheriting them is the point.
|
|
40
|
-
|
|
41
|
-
## Candidates
|
|
42
|
-
|
|
43
|
-
Each has a design but no proven friction yet. Most come from the prior
|
|
44
|
-
runtime, which hit the gap and fixed it its own way. Parked tasks may
|
|
45
|
-
track them; delete the row when one ships.
|
|
46
|
-
|
|
47
|
-
| Item | Gap today | Shape | Size |
|
|
48
|
-
| --- | --- | --- | --- |
|
|
49
|
-
| **Tag mux sessions with their DB** | `teardown --empty` never removes a `mu-*` session that has no DB row, because another DB may own it. | Set `@mu_db=<abs path>` at session creation. Remove unregistered sessions whose tag matches this DB, and keep foreign or untagged ones. Optional mux method, since herdr may have no equivalent. | ~60 LOC |
|
|
50
|
-
| **Token usage per run** | Orchestrators cannot budget a fan-out. | The extension reports pi's usage for the run, and `wait --json` carries it. Unknown stays unknown, never 0. No dollar estimates. | ~80 LOC |
|
|
51
|
-
| **Global delegate cap** | `MU_DELEGATE_MAX` applies per pi session. Several orchestrators, plus workers running `mu agent spawn -w scratch`, are not capped in total. | Count live `scratch` agents from the DB in the queue check. | ~30 LOC |
|
|
52
|
-
| **Wait for a non-pi CLI's prompt** | `spawn --send` treats a blank or booting screen as calm and can paste before the CLI is ready. | Settle only once the CLI has drawn its input prompt. This needs a screen pattern for each CLI, so it waits for real friction. | ~40 LOC |
|
|
53
|
-
| **Absolute deadline in `wait`** | A delegate re-armed after `/reload` restarts its countdown. | Report `deadline` (epoch ms) alongside `timeoutS`. | ~20 LOC |
|
|
54
|
-
| **Bounded `task tree`** | No depth or node limit. | Cap depth, nodes and edges, and report which cap was hit. | ~30 LOC |
|
|
55
|
-
| **Design-doc review angles** | `review-panel`'s angles are for diffs. | Add rollout and back-compat, alternatives, and integration angles. Synthesize into unanimous findings, tensions, and the strongest objection. | recipe |
|
|
56
|
-
| **Sender framing on sends** | The receiving agent cannot tell a peer's message from its human's. | Prefix text sent by a mu agent with `[mu: from <agent>]`. This touches prompts, so it follows logging the sender. | ~20 LOC |
|
|
57
|
-
| **A third mux backend** | None: tmux and herdr are the two implementations that justify `MuxBackend`. | zellij, wezterm or kitty. A third needs its own friction evidence; the existing interface is not evidence. | — |
|
|
58
|
-
| **Subscription-based wakeups** | `mu log --tail` polls once a second. | SQLite update hooks or `fs.watch` on the WAL. Lower latency for more machinery. | — |
|
|
59
|
-
|
|
60
|
-
## Next breaking release
|
|
61
|
-
|
|
62
|
-
- **Schema v12 drops `agents.status`.** In v11 it stays for
|
|
63
|
-
compatibility and always holds `spawning`.
|
|
64
|
-
- **`mu agent list --json` becomes `{items, count}`.** It emits
|
|
65
|
-
`{workstreamName, agents, orphans}`, the one collection off the
|
|
66
|
-
documented shape (SKILL.md notes the exception). Conforming breaks
|
|
67
|
-
`.agents` readers, `mu_delegate` among them.
|
|
68
|
-
|
|
69
|
-
## Open questions
|
|
70
|
-
|
|
71
|
-
- **Capability tags on operations.** Today the only authorization is
|
|
72
|
-
"the agent ran the verb". Enforce capabilities when an agent does real
|
|
73
|
-
damage.
|
|
74
|
-
- **Per-workstream config.** Resisted by the pledges, but "this
|
|
75
|
-
workstream uses a different pi binary" is a gap env vars solve poorly.
|
|
76
|
-
Revisit when a second user hits it.
|
|
77
|
-
|
|
78
|
-
## Explicitly rejected
|
|
79
|
-
|
|
80
|
-
- **A JS or Lisp DSL** (`mu run`, `mu eval`, `mu repl`) <!-- doc-cli-drift:skip -->. bash, `jq`,
|
|
81
|
-
and `--json` cover it.
|
|
82
|
-
- **A `defineOperation()` registry.** No consumer after the DSL went.
|
|
83
|
-
- **Markdown agent-definition discovery.** Spawn flags and the first
|
|
84
|
-
message are the definition.
|
|
85
|
-
- **mu as only a pi extension or only a library.** Children and humans
|
|
86
|
-
could not drive it from a shell, and processes would fight over the DB.
|
|
87
|
-
- **Two binaries (`mu-agents` + `mu-tasks`).** Agents and tasks need one
|
|
88
|
-
transactional surface.
|
|
89
|
-
- **A `TaskSurface` adapter.** The built-in graph is the point.
|
|
90
|
-
- **Live sync through a daemon or remote backend.** Sync rides on
|
|
91
|
-
ordinary mu calls and mu only reads and writes files. See
|
|
92
|
-
[Rejected sync substrates](#rejected-sync-substrates).
|
|
93
|
-
- **Network-opening verbs (`mu remote check`, `mu sync --push/--pull`)** <!-- doc-cli-drift:skip -->.
|
|
94
|
-
Every network hop is an operator command. Spawn passes it through
|
|
95
|
-
`--command` for the mux to run, or mu prints it as a next step. mu's
|
|
96
|
-
own process stays ssh-free.
|
|
97
|
-
- **An HTTP API over SQLite** or **a hosted mu.**
|
|
98
|
-
- **Personal agent names (`alice`, `bob`).** Use role names
|
|
99
|
-
(`worker-1`, `reviewer-1`).
|
|
100
|
-
- **Pane scraping as a state fallback.** No state source means `unknown`.
|
|
101
|
-
- **Runtime agent state in `mu.db`.** The copy goes stale. The control
|
|
102
|
-
socket, herdr, or murmur owns the current reading.
|
|
103
|
-
- **Reading murmur's `state.db`.** Use its public contract.
|
|
104
|
-
- **murmur as a hard dependency.** pi agents and the task graph do not
|
|
105
|
-
need it.
|
|
106
|
-
|
|
107
|
-
### Rejected sync substrates
|
|
108
|
-
|
|
109
|
-
mu syncs through the SQLite ops log plus append-only JSONL segments.
|
|
110
|
-
These alternatives were rejected:
|
|
111
|
-
|
|
112
|
-
| Substrate | Why not |
|
|
113
|
-
| --------- | ------- |
|
|
114
|
-
| **Litestream** | Daemon, single writer, one-way to object storage, and `restore` overwrites the whole file. It does disaster recovery, not laptop↔devserver merges. |
|
|
115
|
-
| **LiteFS** | FUSE, which on macOS means a macFUSE kernel extension. |
|
|
116
|
-
| **rqlite / dqlite / Marmot** | A consensus cluster and daemons to sync two machines that are rarely both awake. |
|
|
117
|
-
| **cr-sqlite** | Merges rows by primary key. mu's `INTEGER PRIMARY KEY AUTOINCREMENT` ids collide across machines and merge silently. Also WIP upstream, no DDL sync, and a native build matrix. |
|
|
118
|
-
| **RocksDB / LMDB for the op log** | No triggers, so a forgotten capture silently corrupts undo and sync. Single-process access forces a daemon. Loses SQL views, JOINs, and `mu sql`. |
|
|
119
|
-
| **SQLite file per peer** | A torn transfer makes the whole file unreadable instead of one JSONL line. `-wal`/`-shm` sidecars in a synced folder corrupt DBs. Page churn defeats delta transfer. |
|
|
120
|
-
| **`MU_SYNC_PEERS` list** | A config file that must match on every machine. Peers come from segment filenames instead. |
|
|
121
|
-
| **`mu sync --push/--pull <host>` <!-- doc-cli-drift:skip -->** | mu's first ssh egress, with ssh config, auth, and error mapping. mu prints an rsync line instead. |
|
|
122
|
-
|
|
123
|
-
The chosen design adds no dependency beyond `better-sqlite3`.
|
package/docs/VISION.md
DELETED
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
# VISION: A persistent crew of agents
|
|
2
|
-
|
|
3
|
-
Terms are defined in [VOCABULARY.md](VOCABULARY.md).
|
|
4
|
-
|
|
5
|
-
## What mu is
|
|
6
|
-
|
|
7
|
-
mu is a small, durable control plane for a persistent crew of AI agents
|
|
8
|
-
in multiplexer panes. Agents have names and roles, outlive sessions, and
|
|
9
|
-
work on a built-in task graph, each in its own VCS workspace. Humans and
|
|
10
|
-
agents drive them through one CLI. State lives in one SQLite file. Every
|
|
11
|
-
feature is a typed verb over that state or a reconciled view of reality.
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
mu agent spawn worker-1 --tab Backend --workspace
|
|
15
|
-
mu agent spawn reviewer-1 --tab Review --workspace --role read-only
|
|
16
|
-
mu task add --title "Build auth" --impact 80 --effort-days 3
|
|
17
|
-
mu task claim build_auth --for worker-1 --evidence "have implementation plan"
|
|
18
|
-
mu agent send worker-1 "Implement build_auth per the description"
|
|
19
|
-
mu state # canonical state card
|
|
20
|
-
mu log --tail # subscribe to every state change
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Everything else makes those lines recover from failure and scale to
|
|
24
|
-
dozens of agents and hundreds of tasks.
|
|
25
|
-
|
|
26
|
-
## Why it exists
|
|
27
|
-
|
|
28
|
-
Existing tools force a choice:
|
|
29
|
-
|
|
30
|
-
- **Hidden subagents** (pi-subagents, the Claude Code and Codex task
|
|
31
|
-
tools) hand one-shot work to a child you cannot see, steer, or keep
|
|
32
|
-
talking to. Its transcript collapses into a result.
|
|
33
|
-
- **tmux orchestration tools** spawn agents in panes but leave
|
|
34
|
-
coordination to chat transcripts or filesystem conventions.
|
|
35
|
-
- **Task trackers** (GitHub Issues, Linear) model the work but do not
|
|
36
|
-
run the agents.
|
|
37
|
-
- **Large orchestration platforms** hold the coordination state but
|
|
38
|
-
carry breadth that costs more to maintain than it returns. See
|
|
39
|
-
[What a prior runtime taught us](#what-a-prior-runtime-taught-us).
|
|
40
|
-
|
|
41
|
-
mu joins the first three without becoming the fourth.
|
|
42
|
-
|
|
43
|
-
## Design principles
|
|
44
|
-
|
|
45
|
-
### 1. The CLI is the product
|
|
46
|
-
|
|
47
|
-
Everything mu does works from a shell with no pi extension loaded. A
|
|
48
|
-
feature that needs the extension does not ship. The pi extension
|
|
49
|
-
(`mu link pi`) serves the control socket and the `mu_delegate` tool, and
|
|
50
|
-
three rules keep it thin:
|
|
51
|
-
|
|
52
|
-
1. **The DB is canonical.** The extension reads and writes through the
|
|
53
|
-
same modules as the CLI. It keeps no state of its own.
|
|
54
|
-
2. **Every operation works from the CLI.** No extension tool has logic
|
|
55
|
-
the CLI lacks.
|
|
56
|
-
3. **The skill teaches the CLI.** A pi session without the extension
|
|
57
|
-
still gets a working mu from [skills/mu/SKILL.md](../skills/mu/SKILL.md).
|
|
58
|
-
|
|
59
|
-
Delegation is CLI: `mu agent spawn -w scratch`, `mu agent send`, and
|
|
60
|
-
`mu agent wait --json`. `mu_delegate` only adds the callback that puts
|
|
61
|
-
the answer into the parent conversation.
|
|
62
|
-
|
|
63
|
-
### 2. One DB is canonical
|
|
64
|
-
|
|
65
|
-
All state lives in `~/.local/state/mu/mu.db` (SQLite WAL, safe for
|
|
66
|
-
concurrent processes). In-memory state is a cache. The extension and the
|
|
67
|
-
CLI share the DB, so they cannot diverge.
|
|
68
|
-
|
|
69
|
-
### 2b. One log records every change
|
|
70
|
-
|
|
71
|
-
The `ops` table is the only change record. SQLite triggers write it in
|
|
72
|
-
the same transaction as the mutation, so capture cannot be forgotten or
|
|
73
|
-
drift from the data. Sync, undo, rebuild, and history are queries or
|
|
74
|
-
replays over that log.
|
|
75
|
-
|
|
76
|
-
Reads still go to the tables. mu is not event-sourced: the tables are
|
|
77
|
-
the materialized view and triggers keep them in step with the ops.
|
|
78
|
-
`mu doctor` rebuilds into a temp DB and diffs, so that is verified, not
|
|
79
|
-
assumed. A capture bug therefore breaks sync, undo, and rebuild at once,
|
|
80
|
-
which is why the drift check is load-bearing.
|
|
81
|
-
|
|
82
|
-
### 2c. Local-first, transport-agnostic
|
|
83
|
-
|
|
84
|
-
Every machine keeps a complete DB. Machines exchange append-only JSONL
|
|
85
|
-
segments, one per machine with a single writer, so no file is contended
|
|
86
|
-
and any file mover works (Syncthing, rsync, scp, git, a USB stick). mu
|
|
87
|
-
reads and writes files. The user owns transport. mu has no network
|
|
88
|
-
code, no daemon, and no membership config: peers are found from the
|
|
89
|
-
segment files present.
|
|
90
|
-
|
|
91
|
-
### 3. Reality wins reconciliation
|
|
92
|
-
|
|
93
|
-
`mu agent list` queries the mux, prunes ghosts, and surfaces orphans.
|
|
94
|
-
The DB records what mu last observed.
|
|
95
|
-
|
|
96
|
-
### 4. Agents are dumb workers; the task graph is the brain
|
|
97
|
-
|
|
98
|
-
The task DAG is the center of mu, not a sidecar. Tasks require `impact`
|
|
99
|
-
and `effort_days`. Edges are `blocks` relations. `ready`, `blocked`, and
|
|
100
|
-
`goals` are SQL views. The parallel-track detector runs union-find and
|
|
101
|
-
merges diamonds, so two agents never collide on a shared dependency.
|
|
102
|
-
|
|
103
|
-
"What next?" and "can we parallelize?" are deterministic queries. The
|
|
104
|
-
LLM decides what to type to an agent. The graph decides which agent gets
|
|
105
|
-
which task.
|
|
106
|
-
|
|
107
|
-
### 5. One workstream per mux session
|
|
108
|
-
|
|
109
|
-
A workstream is a mux session: a tmux session on tmux, a herdr workspace
|
|
110
|
-
on herdr. Its agents are panes in that session, so
|
|
111
|
-
`tmux a -t mu-<workstream>` shows the whole crew. Workstreams on one
|
|
112
|
-
machine are separate sessions, partitioned in the DB by `workstream_id`.
|
|
113
|
-
The crew survives detach and reattach.
|
|
114
|
-
|
|
115
|
-
The multiplexer is a backend chosen by detection
|
|
116
|
-
(`MU_MUX` → `HERDR_ENV` → `$TMUX` → `PATH`), like the VCS backend.
|
|
117
|
-
Topology, the paste protocol, scrollback capture, pane-id validation,
|
|
118
|
-
and identity fallback live behind `MuxBackend` in `src/mux/`. There are
|
|
119
|
-
two implementations. A third needs its own friction evidence.
|
|
120
|
-
|
|
121
|
-
### 6. Pi-first, with reported agent state
|
|
122
|
-
|
|
123
|
-
mu never infers agent state from pane text. Each state source reports it:
|
|
124
|
-
|
|
125
|
-
| Agent | Send, abort, wait | State |
|
|
126
|
-
| --- | --- | --- |
|
|
127
|
-
| pi (any backend, local or remote over `ssh -L`) | control socket, exact | control socket |
|
|
128
|
-
| other CLI on herdr | mux | herdr |
|
|
129
|
-
| other CLI on tmux | mux (bracketed paste) | murmur |
|
|
130
|
-
|
|
131
|
-
With no source, state is `unknown` with a reason. A pi agent whose
|
|
132
|
-
socket does not answer fails loudly; mu never falls back to pasting.
|
|
133
|
-
murmur is optional for pi agents.
|
|
134
|
-
|
|
135
|
-
`MU_PI_COMMAND="pi-alt --some-flag"` swaps the pi command for every
|
|
136
|
-
spawn. First-class support for other CLIs is not planned. It can earn promotion
|
|
137
|
-
under the [ROADMAP](ROADMAP.md) criteria: spawn accepts any command and
|
|
138
|
-
`agents.cli` is TEXT.
|
|
139
|
-
|
|
140
|
-
### 7. TypeScript on Node
|
|
141
|
-
|
|
142
|
-
mu uses a few well-known npm dependencies (`commander`,
|
|
143
|
-
`better-sqlite3`, `cli-table3`, `picocolors`, `execa`, and `ink` for the
|
|
144
|
-
TUI). There is no native code to maintain and no build matrix.
|
|
145
|
-
|
|
146
|
-
- **Types pay.** The typed error classes map to exit codes in
|
|
147
|
-
`handle()`. The `assertXInWorkstream` family stays type-safe across
|
|
148
|
-
namespaces. `noUncheckedIndexedAccess` has caught real bugs.
|
|
149
|
-
- **`better-sqlite3` fits.** Synchronous calls match a short-lived CLI,
|
|
150
|
-
and `db.transaction()` is the right shape.
|
|
151
|
-
- **Iteration is fast.** Several substantive changes a day land in
|
|
152
|
-
about 99k lines of `src/` and `test/`.
|
|
153
|
-
|
|
154
|
-
The weak spot is cold start: Node takes 30–50 ms to boot, which matters
|
|
155
|
-
only in tight loops. If that changes, Rust is the port target.
|
|
156
|
-
`better-sqlite3` needs prebuilds (darwin-arm64/x64, linux-x64/arm64,
|
|
157
|
-
win32-x64) or a C++ toolchain.
|
|
158
|
-
|
|
159
|
-
### 8. Schema-first: typed verbs over read views, SQL as escape hatch
|
|
160
|
-
|
|
161
|
-
- **Read views**: the `ready`, `blocked`, and `goals` views, and
|
|
162
|
-
`mu state` as the state card.
|
|
163
|
-
- **Typed verbs** that map to resource transitions (`task claim`,
|
|
164
|
-
`task close`, `agent spawn --workspace`, `workstream teardown`).
|
|
165
|
-
- **`--json` on every read verb**, so scripts use `jq`, not table parsing.
|
|
166
|
-
- **`mu sql`** underneath, as the explicit escape hatch.
|
|
167
|
-
|
|
168
|
-
There is no DSL, no plugin system, no workflow engine, and no verb
|
|
169
|
-
registry. The commander wiring in `src/cli.ts` is the verb surface. A new
|
|
170
|
-
verb is one SDK function plus one commander block.
|
|
171
|
-
|
|
172
|
-
### 9. Observed vs claimed
|
|
173
|
-
|
|
174
|
-
A mutating verb records what the caller said it relied on.
|
|
175
|
-
`mu task close design --evidence "npm test exit 0"` lands in the ops log
|
|
176
|
-
with the evidence. mu does not run the tests, but `mu log` can search
|
|
177
|
-
the grounding for every change.
|
|
178
|
-
|
|
179
|
-
### 10. Get out of the model's way
|
|
180
|
-
|
|
181
|
-
mu coordinates agents and does not reason about them. It does not own:
|
|
182
|
-
|
|
183
|
-
- **Model selection or thinking levels.** No tiers, no provider matrix.
|
|
184
|
-
pi already takes `--model` and `--thinking`. Pass them through the
|
|
185
|
-
spawn command.
|
|
186
|
-
- **Prompts.** No system-prompt templates and no role registry. The
|
|
187
|
-
prompt is the spawn command plus the first message.
|
|
188
|
-
- **Tool routing.** The agent CLI owns tool allowlists, MCP servers, and
|
|
189
|
-
extensions.
|
|
190
|
-
- **Output interpretation.** mu does not parse panes for state, facts,
|
|
191
|
-
or tool calls. `--evidence` is recorded as given.
|
|
192
|
-
|
|
193
|
-
The whole vendor surface is one lookup: `--cli <key>` reads
|
|
194
|
-
`$MU_<KEY>_COMMAND`. Per-role models are a convention in your shell rc:
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
export MU_PI_MINI_COMMAND="pi --model haiku:off" # → --cli pi_mini
|
|
198
|
-
export MU_PI_BIG_COMMAND="pi --model opus:high" # → --cli pi_big
|
|
199
|
-
|
|
200
|
-
mu agent spawn worker-1 --cli pi_mini
|
|
201
|
-
mu agent spawn reviewer-1 --cli pi_big
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
The skill's [model tiers](../skills/mu/recipes/models.md) are advice to
|
|
205
|
-
the agent choosing; mu reads none of it.
|
|
206
|
-
|
|
207
|
-
## What it enables
|
|
208
|
-
|
|
209
|
-
- **Visible crews.** Spawn agents once and send them work all day. Each
|
|
210
|
-
sits in a pane you can attach to.
|
|
211
|
-
- **Isolation.** Each agent gets a jj workspace, sl clone, git worktree,
|
|
212
|
-
or `cp -a` copy, detected automatically and freed by `mu agent close`.
|
|
213
|
-
- **Wakeups without a daemon.** `mu log --tail` and event-driven
|
|
214
|
-
`mu agent wait` replace polling.
|
|
215
|
-
- **Crash recovery.** The reaper reopens a dead agent's IN_PROGRESS
|
|
216
|
-
tasks with a note.
|
|
217
|
-
|
|
218
|
-
## What it is not
|
|
219
|
-
|
|
220
|
-
- **Not an orchestrator.** mu provides primitives. The policy (when to
|
|
221
|
-
spawn, what to assign, when to free) is yours: bash, `jq` over
|
|
222
|
-
`--json`, or an LLM following the bundled skill. There is no workflow
|
|
223
|
-
engine and no `mu run script.ts`. <!-- doc-cli-drift:skip -->
|
|
224
|
-
- **Not a chat protocol.** Agents communicate through notes, claims, and
|
|
225
|
-
the ops log.
|
|
226
|
-
- **Not a hidden-subagent runner.** A delegate is an ordinary agent in a
|
|
227
|
-
visible pane: attach, steer, abort, or keep talking to it. It costs one
|
|
228
|
-
pane and one pi process. A hidden subagent is lighter for many tiny
|
|
229
|
-
calls. mu bets that visibility and steering are worth the cost. There
|
|
230
|
-
are no agent types: the brief is plain text. A delegate's answer is
|
|
231
|
-
not recorded in mu; only what the caller writes back (a note, a state
|
|
232
|
-
change) is. The one extension-held list with no pane is the delegate
|
|
233
|
-
queue: bounded, shown in pi's footer, cancellable, and named at
|
|
234
|
-
shutdown when it is dropped.
|
|
235
|
-
- **DB-undoable, not substrate-undoable.** `mu undo <group> --yes`
|
|
236
|
-
restores rows. It does not revive killed panes or freed workspace
|
|
237
|
-
directories. Reconciliation then reports ghosts and orphans.
|
|
238
|
-
|
|
239
|
-
## Key constraints
|
|
240
|
-
|
|
241
|
-
1. **A multiplexer is required** (tmux or herdr). `mu doctor` reports
|
|
242
|
-
the backend. Agent verbs exit 5 when none is reachable.
|
|
243
|
-
2. **The agent never acknowledges a send.** For pi, the control socket
|
|
244
|
-
confirms that pi accepted the message. On the mux path, mu confirms
|
|
245
|
-
only that the text reached the pane and warns when it cannot confirm
|
|
246
|
-
submission. Use `mu agent wait` or `mu log --tail` to see the effect.
|
|
247
|
-
3. **Recursion is opt-in.** `mu_delegate` is hidden in agents mu spawned
|
|
248
|
-
(`MU_MANAGED_AGENT`). Agents have `mu` on PATH, but the skill tells
|
|
249
|
-
them they are not the orchestrator.
|
|
250
|
-
4. **Every invocation is short-lived, except two interactive readers.**
|
|
251
|
-
No daemon, no resident state outside SQLite, no background process.
|
|
252
|
-
The exceptions are `mu log --tail` and the TUI (`mu state --tui`, or
|
|
253
|
-
bare `mu` on a TTY). Both are:
|
|
254
|
-
- owned by a human or parent script and gone when it ends;
|
|
255
|
-
- free of user actions: TUI keys copy the `mu <verb>` command to
|
|
256
|
-
the clipboard and exit, so every change the operator asks for is a
|
|
257
|
-
fresh CLI call. The TUI's slow tick still does the housekeeping
|
|
258
|
-
any `mu` invocation does: ambient sync (ingest peer ops, flush the
|
|
259
|
-
local segment) and reconcile (prune agents whose pane died, which
|
|
260
|
-
reopens their tasks with a `[reaper]` note, and refresh pane
|
|
261
|
-
titles);
|
|
262
|
-
- limited to stdin, stdout, and a poll timer: no sockets or watches.
|
|
263
|
-
The TUI's slow tick runs short-lived probes (mux liveness, VCS
|
|
264
|
-
status) and ambient sync, and its handoffs (lazygit, tuicr, attach,
|
|
265
|
-
clipboard) run one foreground child each; none outlives the TUI;
|
|
266
|
-
- TTY-gated: pipes, CI, `--json`, and `MU_NO_TUI=1` never enter the
|
|
267
|
-
TUI, and plain `mu state` prints the static card.
|
|
268
|
-
|
|
269
|
-
The control socket is not a third exception. The pi process serves it
|
|
270
|
-
and it dies with that process. Any other long-lived process needs its
|
|
271
|
-
own promotion; the [anti-feature pledges](ROADMAP.md#anti-feature-pledges)
|
|
272
|
-
stand.
|
|
273
|
-
|
|
274
|
-
## What a prior runtime taught us
|
|
275
|
-
|
|
276
|
-
A council review of mu's design ancestor, a larger internal multi-agent
|
|
277
|
-
runtime, found it justified only as a durable coordination control
|
|
278
|
-
plane. Its minimal core: sessions, an agent registry, a task graph,
|
|
279
|
-
workspace ownership, an event log, wakeups, human approvals, a typed
|
|
280
|
-
control API, read-only state cards, and orphan recovery. Everything else
|
|
281
|
-
(chat, workflow DSLs, memory, dashboards) had to prove its worth.
|
|
282
|
-
|
|
283
|
-
mu ships nine of the ten. Approvals are missing because 200+ dogfooded
|
|
284
|
-
tasks never needed them. Below the point where coordination is itself
|
|
285
|
-
the work, pi plus manual tmux is more transparent than mu.
|
|
286
|
-
|
|
287
|
-
Two lessons back the orchestrator-pull remote design. The runtime built
|
|
288
|
-
multiplexing, flow control, keepalive and retries above a transport that
|
|
289
|
-
already provided them, then deleted them: don't rebuild what the
|
|
290
|
-
transport gives. A child never dials its parent; the parent pulls.
|
|
291
|
-
Tasks injected as prompts and read back through sentinel markers broke
|
|
292
|
-
on line wrapping and lost notes: state belongs in the DB, not in pane
|
|
293
|
-
text.
|
|
294
|
-
|
|
295
|
-
Known gaps, none promoted yet: `--evidence` grounds but does not verify,
|
|
296
|
-
mutations have no declared idempotency keys, most mutations have no dry
|
|
297
|
-
run (`workstream teardown`, `task delete`, and `undo` do), and the `role`
|
|
298
|
-
field is stored but not enforced.
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
# Control socket
|
|
2
|
-
|
|
3
|
-
mu drives a pi agent through a unix socket served by mu's own pi
|
|
4
|
-
extension inside the agent's interactive pi. The pane stays pi's TUI,
|
|
5
|
-
so a human attached to it shares the same session. There is no
|
|
6
|
-
`pi --mode rpc`, no screen scraping and no daemon: the server lives and
|
|
7
|
-
dies with the pi process. Overview: [ARCHITECTURE.md](../ARCHITECTURE.md).
|
|
8
|
-
|
|
9
|
-
## Path derivation
|
|
10
|
-
|
|
11
|
-
`ctlSocketPath(ws, agent)` (`src/ctl/path.ts`) is
|
|
12
|
-
`<state dir>/sock/<ws>/<agent>.sock`. The state dir is
|
|
13
|
-
`dirname($MU_DB_PATH)` or the default. If the path exceeds 103 bytes
|
|
14
|
-
(the macOS `sun_path` limit), it becomes
|
|
15
|
-
`<state dir>/sock/h/<sha1(ws/agent)[:16]>.sock`.
|
|
16
|
-
|
|
17
|
-
Nothing is stored. Spawn creates the directory (mode 0700), removes any
|
|
18
|
-
stale socket file at the path, and injects the path as `MU_CTL_SOCK`
|
|
19
|
-
into every pane. Every later verb derives the path again.
|
|
20
|
-
|
|
21
|
-
## Protocol v1
|
|
22
|
-
|
|
23
|
-
`src/ctl/protocol.ts` imports nothing from mu, so the extension loads
|
|
24
|
-
it standalone. Framing is JSON lines, one request per connection. Every
|
|
25
|
-
reply carries `v: 1`; the client (`src/ctl/client.ts`) throws
|
|
26
|
-
`CtlVersionError` on anything else.
|
|
27
|
-
|
|
28
|
-
| op | does |
|
|
29
|
-
| --- | --- |
|
|
30
|
-
| `hello` | identity plus `ops` (served ops) and `extVersion` (the mu version the extension was built from) |
|
|
31
|
-
| `status` | `state` (`busy` / `idle`), `since`, `runs`, `pending`, and pi's `sessionFile` when it has one |
|
|
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
|
-
| `wait` | resolves on pi's `agent_settled` after `afterRuns`, with the run's `lastText` and pi's `sessionFile` |
|
|
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 |
|
|
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` |
|
|
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` |
|
|
38
|
-
|
|
39
|
-
`pi.sendUserMessage` dispatches only extension commands, not pi's
|
|
40
|
-
built-in `/new`, `/reload`, `/compact`. Each internal command is an
|
|
41
|
-
extension command, triggered with `expandPromptTemplates: true`, and
|
|
42
|
-
its handler gets the command context that can replace or reload the
|
|
43
|
-
session.
|
|
44
|
-
|
|
45
|
-
These back `mu agent send` (`--fresh`, `--steer`, `--interrupt`, session commands), `mu agent wait`,
|
|
46
|
-
`mu agent abort`, the agent state reading, and `mu_delegate`.
|
|
47
|
-
|
|
48
|
-
## Version skew
|
|
49
|
-
|
|
50
|
-
An op the extension does not serve returns `unknown op: <op>` with its
|
|
51
|
-
`ops` list. `mu agent send --interrupt` then composes `abort`, `wait`
|
|
52
|
-
and `send` itself. Any other op raises `AgentExtensionOutdatedError` (exit 4), whose
|
|
53
|
-
next steps are `/reload` through the mux (an extension that lacks the
|
|
54
|
-
`command` op cannot run it over ctl) or a respawn. `mu doctor`
|
|
55
|
-
probes every pi agent's socket (the `ctl` row) and flags an
|
|
56
|
-
`extVersion` older than the installed mu or a missing op. Its extension
|
|
57
|
-
row reports whether `mu link pi` installed the extension.
|
|
58
|
-
|
|
59
|
-
## Extension lifecycle
|
|
60
|
-
|
|
61
|
-
`extension/mu-pi.ts` is inert unless `MU_CTL_SOCK` is set.
|
|
62
|
-
|
|
63
|
-
- pi re-creates extension runtimes per session. The server, the run
|
|
64
|
-
counters and an in-flight `fresh` therefore live in a process-global
|
|
65
|
-
map (`Symbol.for("mu.pi.ctl")`).
|
|
66
|
-
- Session replacement (`new`, `resume`, `fork`, `reload`) keeps the
|
|
67
|
-
socket and its connections. Quit closes it.
|
|
68
|
-
|
|
69
|
-
**Binding never steals a live socket.**
|
|
70
|
-
|
|
71
|
-
1. If the path already answers, another pi serves it (a nested `pi -p`
|
|
72
|
-
inherited `MU_CTL_SOCK`). The extension leaves it alone and says so
|
|
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.
|
|
77
|
-
2. Otherwise it listens on a private name in the same directory, sets
|
|
78
|
-
mode 0600, and hard-links that name onto the public path. libuv
|
|
79
|
-
unlinks the listened-on name at close, so the public path must never
|
|
80
|
-
be that name. `link()` fails on an existing path, so a racing pi
|
|
81
|
-
keeps its socket.
|
|
82
|
-
3. It records the inode of the public path.
|
|
83
|
-
|
|
84
|
-
On quit it unlinks the public path only if the inode is still its own,
|
|
85
|
-
because another pi may own the path by then. On `session_start`, a
|
|
86
|
-
server whose file was deleted or replaced closes and rebinds. That is
|
|
87
|
-
how `/reload` recovers a lost socket file.
|
|
88
|
-
|
|
89
|
-
## No silent fallback
|
|
90
|
-
|
|
91
|
-
`src/agents/transport.ts` routes sends. `expectsCtl` is true when the
|
|
92
|
-
cli key resolves to pi (`pi` or `pi-meta` as argv0), or when a socket
|
|
93
|
-
file exists at the agent's derived path. The file case covers
|
|
94
|
-
`--cli helper --command "pi-meta ..."`, whose command is not stored.
|
|
95
|
-
|
|
96
|
-
A pi agent whose socket does not answer raises
|
|
97
|
-
`AgentCtlUnreachableError` for send and abort, and reads as `unknown`
|
|
98
|
-
with reason `ctl missing` or `ctl refused` for state. mu never pastes
|
|
99
|
-
into it or asks murmur instead.
|
|
100
|
-
|
|
101
|
-
The mux paste path (bracketed paste, `MU_SEND_DELAY_MS`,
|
|
102
|
-
`MU_SEND_READINESS_MS`) serves only:
|
|
103
|
-
|
|
104
|
-
- non-pi CLIs;
|
|
105
|
-
- adopted panes without ctl;
|
|
106
|
-
- an explicit `--via mux`.
|
|
107
|
-
|
|
108
|
-
A pi agent's `/new`, `/reload` and `/compact [instructions]` go
|
|
109
|
-
through the `command` op. Any other slash command to a pi agent raises
|
|
110
|
-
`AgentSlashCommandUnsupportedError` (exit 2), whose next step is the
|
|
111
|
-
same text with `--via mux`. Text such as `/tmp/x.log ...` is a plain
|
|
112
|
-
prompt, not a slash command. A pi agent therefore never reaches
|
|
113
|
-
`capturePane` or the paste timing in `src/mux/input-timing.ts`.
|
|
114
|
-
|
|
115
|
-
## Remote agents
|
|
116
|
-
|
|
117
|
-
The user's `ssh` command carries `-L <local derived path>:<remote path>`
|
|
118
|
-
and puts `MU_CTL_SOCK=<remote path>` in the remote env.
|
|
119
|
-
`mu agent remote-env` prints both and runs nothing
|
|
120
|
-
(`src/cli/agents-remote.ts`). mu always connects to the local path, so
|
|
121
|
-
local and remote agents share one transport, and state, send, wait and
|
|
122
|
-
abort are exact without murmur.
|
|
123
|
-
|
|
124
|
-
ssh does not create the local directory, which is why spawn makes it
|
|
125
|
-
first. When ssh dies it leaves the local socket file behind. That file
|
|
126
|
-
probes `refused`, and `mu agent close` or the reaper deletes it.
|
|
127
|
-
|
|
128
|
-
## Parent side: `mu_delegate`
|
|
129
|
-
|
|
130
|
-
`extension/delegate.ts` registers the `mu_delegate` and
|
|
131
|
-
`mu_delegate_cancel` tools in the operator's own pi. They are hidden
|
|
132
|
-
when `MU_MANAGED_AGENT` is set (inside a mu-spawned pane) or
|
|
133
|
-
`MU_DELEGATE=0`. The tools shell out to the `mu` CLI (spawn, send,
|
|
134
|
-
`wait --json`, read, abort, close) and only format the CLI's
|
|
135
|
-
`outcome` into a follow-up message. A call runs one
|
|
136
|
-
`mu agent spawn --next-free --send <task> --json` (mu picks the free
|
|
137
|
-
name under its spawn lock and returns the send's `runs`), then one
|
|
138
|
-
`mu agent wait --after-runs <runs>` in the background; with `record`,
|
|
139
|
-
a `mu task show` comes first. `delegateOutcome`
|
|
140
|
-
(`src/agents/delegate.ts`) maps one wait result to `done`, `empty`,
|
|
141
|
-
`error`, `died`, `timeout` or `pending`. The extension imports nothing from pi;
|
|
142
|
-
it types pi's API structurally.
|