@martintrojer/mu 0.3.1 → 0.3.2
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 +747 -119
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +505 -72
- package/dist/index.js +601 -97
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +4 -4
- package/docs/ROADMAP.md +8 -6
- package/docs/USAGE_GUIDE.md +73 -9
- package/docs/VOCABULARY.md +6 -3
- package/package.json +1 -1
- package/skills/mu/SKILL.md +42 -15
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -245,7 +245,7 @@ returning. Three steps, in order:
|
|
|
245
245
|
that has no matching `agents` row but whose pane title looks like
|
|
246
246
|
an agent name, add it to the orphans list. **Do not auto-adopt** —
|
|
247
247
|
`mu agent list` shows orphans under a separate "(orphans)" section and
|
|
248
|
-
the user runs `mu adopt %15 [--name X]` to formally claim them.
|
|
248
|
+
the user runs `mu agent adopt %15 [--name X]` to formally claim them.
|
|
249
249
|
|
|
250
250
|
Full algorithm lives in `src/reconcile.ts` (the canonical
|
|
251
251
|
implementation).
|
|
@@ -282,7 +282,7 @@ Each module is concrete and consumed today.
|
|
|
282
282
|
| `src/detect.ts` | Pi-only status detector (`busy` / `needs_input` / `idle` / `done`) |
|
|
283
283
|
| `src/reconcile.ts` | Ghost prune + status detect + orphan surface; "reality wins" |
|
|
284
284
|
| `src/agents.ts` | Hub: CRUD + send / read / list / close / free + liveness + reaper. Re-exports `src/agents/*` (spawn, adopt, errors); pane-title composition (`composeAgentTitle`) lives here. |
|
|
285
|
-
| `src/agents/*.ts` | Cohesive cluster of agent-lifecycle internals: `spawn.ts` (spawnAgent + resolveCliCommand / awaitSpawnLiveness / pane create-or-reuse / prestage / rollback), `adopt.ts` (register an existing tmux pane as a managed agent), `errors.ts` (typed agent error classes — `AgentNotFoundError`, `AgentDiedOnSpawnError`, …). |
|
|
285
|
+
| `src/agents/*.ts` | Cohesive cluster of agent-lifecycle internals: `spawn.ts` (spawnAgent + resolveCliCommand / awaitSpawnLiveness / pane create-or-reuse / prestage / rollback), `adopt.ts` (register an existing tmux pane as a managed agent), `kick.ts` (signal the foreground pgid of an agent pane's TTY — escape hatch for wedged tool subprocesses), `errors.ts` (typed agent error classes — `AgentNotFoundError`, `AgentDiedOnSpawnError`, …). |
|
|
286
286
|
| `src/tasks.ts` | Hub: every read/write verb on the DAG (edit / edges / queries) + cycle check + auto-event emission. Re-exports `src/tasks/*` (status, claim, lifecycle, wait, errors). |
|
|
287
287
|
| `src/tasks/*.ts` | Cohesive cluster of task-graph internals: `status.ts` (TaskStatus enum + helpers — single source of truth), `claim.ts` (claim/release + `resolveActorIdentity`, atomic CAS), `lifecycle.ts` (setTaskStatus / closeTask / openTask / rejectTask / deferTask + cascade), `wait.ts` (waitForTasks: block until tasks reach a target status), `errors.ts` (typed task error classes — `TaskAlreadyOwnedError`, `CycleError`, …). |
|
|
288
288
|
| `src/tracks.ts` | Parallel-tracks union-find with diamond merge |
|
|
@@ -291,7 +291,7 @@ Each module is concrete and consumed today.
|
|
|
291
291
|
| `src/importing.ts` | Inverse of `src/exporting.ts`: parses a v0.3 bucket directory and rebuilds every source-ws as live tasks + edges + notes. Markdown-only (never reads .db); per-source-ws transactional; refuses silent merges into existing workstreams |
|
|
292
292
|
| `src/archives.ts` | Cross-workstream **archives** — feature complete (SDK + 6 CLI verbs: `mu archive create / list / show / add / remove / delete`, plus `search` and `export` via the unified bucket renderer): `createArchive` / `listArchives` / `getArchive` / `deleteArchive` / `addToArchive` (idempotent at `(archive, source_workstream)`) / `removeFromArchive` / `listArchivedTasks`. Backed by the v6 `archives` + `archived_tasks` + `archived_edges` + `archived_notes` + `archived_events` tables; archives outlive workstreams (TEXT `source_workstream` columns, no FK). |
|
|
293
293
|
| `src/logs.ts` | `agent_logs` SDK: appendLog / listLogs / latestSeq / emitEvent |
|
|
294
|
-
| `src/vcs.ts` | `VcsBackend` interface + jj / sl / git / none impls; detection precedence; `commitsBehind(workspacePath, ref)` for staleness signal (no auto-fetch; pure observation) |
|
|
294
|
+
| `src/vcs.ts` | `VcsBackend` interface + jj / sl / git / none impls; detection precedence; `commitsBehind(workspacePath, ref)` for staleness signal (no auto-fetch; pure observation); `isClean(workspacePath)` cheap working-copy probe used by `closeAgent`'s clean-workspace auto-free path |
|
|
295
295
|
| `src/workspace.ts` | Per-agent VCS workspaces (registry layer on top of vcs.ts); CRUD + cascade; orphan-dir detection (`listWorkspaceOrphans`); staleness decoration (`decorateWithStaleness` populates `commitsBehindMain` per row) |
|
|
296
296
|
| `src/snapshots.ts` | Whole-DB snapshots (`VACUUM INTO`); auto-captured before destructive verbs; SDK for `mu undo`. The `snapshots` table is schema v4 (carried forward unchanged through v5/v6/v7). |
|
|
297
297
|
| `src/output.ts` | NextStep type + `printNextSteps` + `errorNextSteps` plumbing for self-documenting output |
|
|
@@ -328,7 +328,7 @@ each are deliberately small.
|
|
|
328
328
|
|
|
329
329
|
| Seam | Add a new impl by... |
|
|
330
330
|
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
331
|
-
| `VcsBackend` | Implementing `detect / createWorkspace / freeWorkspace / commitsBehind` (~80–150 LOC; jj/sl/git/none are working examples) |
|
|
331
|
+
| `VcsBackend` | Implementing `detect / createWorkspace / freeWorkspace / isClean / commitsBehind / rebaseTo / commitsSinceBase` (~80–150 LOC; jj/sl/git/none are working examples) |
|
|
332
332
|
| Per-CLI `Detector` | Adding patterns to `detectPiStatus` (vanilla pi `to interrupt)`; pi-meta + every TUI wrapper covered by Braille spinner glyph fallback `[\u2800-\u28FF]`) |
|
|
333
333
|
| New typed verb | Add an SDK function in the relevant `src/*.ts`; add a `cmd<Verb>` to the matching `src/cli/<namespace>.ts` (or create a new namespace if the verb doesn't fit existing ones); wire one commander block in `src/cli.ts`'s `buildProgram()` (use `handle()` for the exit-code map; route through `printNextSteps` for self-documenting output) |
|
|
334
334
|
| New schema migration| Bump `CURRENT_SCHEMA_VERSION` in `src/db.ts`; mirror the new shape in `CURRENT_SCHEMA`. Two of the three post-v5 bumps were script-free: v5 → v6 was purely additive (the existing CREATE-TABLE-IF-NOT-EXISTS pass picked up the new `archive_*` tables), and v6 → v7 was a destructive-but-idempotent in-place migration (a `DROP TABLE IF EXISTS approvals` block in `applySchema`). Reach for a one-shot migration script only when the change can't be expressed that way (the v4 → v5 surrogate-PK substrate switch was the canonical example; restore from git history if you need to see the shape). The loud-fail hook in `openDb` rejects pre-current DBs with `SchemaTooOldError` (exit code 4) and a migration instruction. |
|
package/docs/ROADMAP.md
CHANGED
|
@@ -115,12 +115,14 @@ if it lands, three rules stay non-negotiable:
|
|
|
115
115
|
If those three rules hold, mu stays driveable from a shell forever
|
|
116
116
|
and the extension stays thin.
|
|
117
117
|
|
|
118
|
-
### `mu adopt <pane-id> [--name <agent>]` — SHIPPED in v0.2 (`e20af89`)
|
|
119
|
-
|
|
120
|
-
Reconciliation surfaces orphan panes; `mu adopt` formally
|
|
121
|
-
one of them as a managed agent. Promotion was triggered
|
|
122
|
-
multi-agent dogfood pattern (orchestrator runs in a pane
|
|
123
|
-
the `mu-<ws>` session and wants to be claimable as a
|
|
118
|
+
### `mu agent adopt <pane-id> [--name <agent>]` — SHIPPED in v0.2 (`e20af89`)
|
|
119
|
+
|
|
120
|
+
Reconciliation surfaces orphan panes; `mu agent adopt` formally
|
|
121
|
+
registers one of them as a managed agent. Promotion was triggered
|
|
122
|
+
by the multi-agent dogfood pattern (orchestrator runs in a pane
|
|
123
|
+
outside the `mu-<ws>` session and wants to be claimable as a
|
|
124
|
+
worker). Originally shipped at the top level as `mu adopt`; moved
|
|
125
|
+
under `mu agent` to match every other agent-lifecycle verb.
|
|
124
126
|
|
|
125
127
|
### Heterogeneous CLI status detection (claude, codex, ...)
|
|
126
128
|
|
package/docs/USAGE_GUIDE.md
CHANGED
|
@@ -561,9 +561,9 @@ mu agent list -w auth-refactor # surfaces orphans at the bottom
|
|
|
561
561
|
# Orphan panes (1)
|
|
562
562
|
# %15 title=worker-2 cli=pi
|
|
563
563
|
|
|
564
|
-
mu adopt %15 -w auth-refactor # adopt by pane id
|
|
565
|
-
mu adopt worker-2 -w auth-refactor # adopt by pane title (same effect)
|
|
566
|
-
mu adopt %15 --name investigator -w auth-refactor # adopt and rename the pane
|
|
564
|
+
mu agent adopt %15 -w auth-refactor # adopt by pane id
|
|
565
|
+
mu agent adopt worker-2 -w auth-refactor # adopt by pane title (same effect)
|
|
566
|
+
mu agent adopt %15 --name investigator -w auth-refactor # adopt and rename the pane
|
|
567
567
|
```
|
|
568
568
|
|
|
569
569
|
The pane title becomes the agent name (`mu`'s claim protocol
|
|
@@ -737,7 +737,7 @@ If the orchestrator tries `mu task claim some-task` directly:
|
|
|
737
737
|
conflict: claimer 'pi-mu' (pane %6441) is not a registered mu agent.
|
|
738
738
|
Working directly? Pass --self to attribute via log instead.
|
|
739
739
|
Dispatching to a worker? Pass --for <worker> to assign.
|
|
740
|
-
Want full registration? Run: mu adopt %6441
|
|
740
|
+
Want full registration? Run: mu agent adopt %6441
|
|
741
741
|
```
|
|
742
742
|
|
|
743
743
|
Three actionable next steps. Pick one based on intent:
|
|
@@ -754,7 +754,7 @@ mu task claim some-task --for worker-1
|
|
|
754
754
|
# -> tasks.owner = 'worker-1'
|
|
755
755
|
|
|
756
756
|
# Orchestrator wants to BE a registered worker (rare):
|
|
757
|
-
mu adopt %6441 -w <ws>
|
|
757
|
+
mu agent adopt %6441 -w <ws> # only if pane is in mu-<ws> session
|
|
758
758
|
mu task claim some-task # now works as a normal worker claim
|
|
759
759
|
```
|
|
760
760
|
|
|
@@ -790,7 +790,31 @@ mu task note design "DECISION: JWT, 24h expiry, refresh via cookie"
|
|
|
790
790
|
mu task note design "FILES: src/auth.rs:45-120"
|
|
791
791
|
```
|
|
792
792
|
|
|
793
|
-
Read them via the
|
|
793
|
+
Read them via the typed verb:
|
|
794
|
+
|
|
795
|
+
```bash
|
|
796
|
+
mu task notes design # all notes, oldest first
|
|
797
|
+
mu task notes design --tail 3 # only the last 3 (alias --last)
|
|
798
|
+
mu task notes design --since 2026-01-01 # only notes after an ISO 8601 cutoff
|
|
799
|
+
mu task notes design --since-claim # only notes since the most recent
|
|
800
|
+
# 'task claim' event for this task
|
|
801
|
+
# (auto-resolved from agent_logs)
|
|
802
|
+
mu task notes design --tail 5 --json # collection envelope {items, count}
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
Filters compose: `--tail` slices the last N of whatever survived
|
|
806
|
+
the timestamp filter. `--since` and `--since-claim` are mutually
|
|
807
|
+
exclusive (both define a cutoff) — pick one. With no filters the
|
|
808
|
+
output is unchanged from prior versions (every note, oldest-first).
|
|
809
|
+
|
|
810
|
+
`--since-claim` is the orchestrator-friendly form: dispatch flows
|
|
811
|
+
often drop a multi-screen SPEC note BEFORE claiming, then the
|
|
812
|
+
worker appends progress notes AFTER the claim. `--since-claim`
|
|
813
|
+
slices off the SPEC so you see only the worker's reports. If no
|
|
814
|
+
claim event exists for the task, it degrades to no filter (so the
|
|
815
|
+
verb stays useful on un-claimed tasks).
|
|
816
|
+
|
|
817
|
+
Or, for ad-hoc shape, the SQL escape hatch:
|
|
794
818
|
|
|
795
819
|
```bash
|
|
796
820
|
mu sql "SELECT author, content, created_at FROM task_notes WHERE task_id='design' ORDER BY id"
|
|
@@ -934,6 +958,10 @@ while (( ${#in_flight[@]} > 0 )); do
|
|
|
934
958
|
# overrides. Refuses on dirty WC; conflicts exit 5 with a `cd`
|
|
935
959
|
# hint to resolve in-place.
|
|
936
960
|
mu workspace refresh "$worker" -w "$ws"
|
|
961
|
+
# Alt: `mu workspace recreate "$worker" -w "$ws"` does free + create
|
|
962
|
+
# atomically — same shortcut, but throws away the worker's local
|
|
963
|
+
# changes (the lossy escape: requires --force on a dirty WC).
|
|
964
|
+
# Use when you don't care about replaying the worker's commits.
|
|
937
965
|
|
|
938
966
|
# 4. Drop $closed from in_flight, dispatch the next task, repeat.
|
|
939
967
|
in_flight=( "${in_flight[@]/$closed}" )
|
|
@@ -1078,7 +1106,32 @@ Reconciliation runs on every `mu agent list` / `mu`. Three steps:
|
|
|
1078
1106
|
3. **Surface orphan panes** — panes in the workstream's tmux session
|
|
1079
1107
|
whose `pane.command` looks like an agent CLI (pi) but
|
|
1080
1108
|
that aren't in the registry. **Not** auto-adopted; mu shows them
|
|
1081
|
-
under "Orphan panes" and tells you `mu adopt <pane-id>` to register
|
|
1109
|
+
under "Orphan panes" and tells you `mu agent adopt <pane-id>` to register
|
|
1110
|
+
|
|
1111
|
+
### A worker is wedged on an unbounded tool subprocess
|
|
1112
|
+
|
|
1113
|
+
A worker ran `find / -maxdepth 6 ...` (30-60 minutes on a populated
|
|
1114
|
+
home directory) or a busy-wait loop. `mu agent send` queues steering
|
|
1115
|
+
messages until the tool returns; `tmux send-keys C-c` against the
|
|
1116
|
+
pane doesn't propagate (the wrapping pi/claude/codex CLI catches it
|
|
1117
|
+
as TUI input). The escape hatch:
|
|
1118
|
+
|
|
1119
|
+
```bash
|
|
1120
|
+
mu agent kick worker-1 # SIGINT (graceful, default)
|
|
1121
|
+
mu agent kick worker-1 --signal SIGTERM # polite escalation
|
|
1122
|
+
mu agent kick worker-1 --signal SIGKILL # hammer
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
`mu agent kick` looks up the pane's TTY via `tmux display-message
|
|
1126
|
+
-p '#{pane_tty}'`, asks `ps -t <tty>` for the foreground process
|
|
1127
|
+
group (the row whose `stat` field contains `+`), and signals the
|
|
1128
|
+
whole pgrp directly. Refuses with `NoForegroundProcessError` when
|
|
1129
|
+
the foreground IS the wrapping CLI itself — use `mu agent close`
|
|
1130
|
+
to close the agent.
|
|
1131
|
+
|
|
1132
|
+
Prevention: don't prompt workers to run filesystem-wide `find`,
|
|
1133
|
+
broad `grep -r /`, or unbounded busy-wait loops. Pass paths
|
|
1134
|
+
explicitly or scope to `$WORKSPACE`.
|
|
1082
1135
|
|
|
1083
1136
|
### You closed your terminal session
|
|
1084
1137
|
|
|
@@ -1219,6 +1272,19 @@ mu agent close reviewer-1
|
|
|
1219
1272
|
`mu agent close` is idempotent: `killPane` swallows "pane already gone"
|
|
1220
1273
|
errors; `deleteAgent` returns false (not throws) on a missing row.
|
|
1221
1274
|
|
|
1275
|
+
If the agent has a workspace, behaviour depends on its state:
|
|
1276
|
+
|
|
1277
|
+
- **Clean** (no uncommitted changes AND no commits since fork) — the
|
|
1278
|
+
workspace is silently auto-freed alongside the close, so a
|
|
1279
|
+
`--workspace` spawn that did no real work doesn't make you type
|
|
1280
|
+
`--discard-workspace` just to clean up.
|
|
1281
|
+
- **Dirty** (uncommitted changes OR commits since fork) — close refuses
|
|
1282
|
+
with `WorkspacePreservedError` (exit 4). Two resolutions: (a) `mu
|
|
1283
|
+
workspace free <agent>` first (optionally with `--commit` to capture
|
|
1284
|
+
pending changes), then `mu agent close <agent>`; or (b) `mu agent
|
|
1285
|
+
close <agent> --discard-workspace` to free both in one shot (lossy:
|
|
1286
|
+
any work in the workspace is gone).
|
|
1287
|
+
|
|
1222
1288
|
### Tear down the whole workstream
|
|
1223
1289
|
|
|
1224
1290
|
`mu workstream destroy` is the symmetric counterpart of `mu workstream init`: it kills the
|
|
@@ -1413,8 +1479,6 @@ Key properties:
|
|
|
1413
1479
|
- **Forward edge refs are deferred.** `blocked_by` / `blocks`
|
|
1414
1480
|
arrays are validated against the bucket's id-set up front, then
|
|
1415
1481
|
inserted after every task in the source-ws is created.
|
|
1416
|
-
- **Pre-0.3 layouts refuse.** Buckets without a `bucketVersion: 2`
|
|
1417
|
-
manifest throw `ImportLegacyLayoutError` with a re-export hint.
|
|
1418
1482
|
- **Partial import.** Multi-source buckets accept either a
|
|
1419
1483
|
per-source-ws subdir path (auto-detected via
|
|
1420
1484
|
`README.md` + `INDEX.md` + `tasks/` + a parent
|
package/docs/VOCABULARY.md
CHANGED
|
@@ -51,6 +51,7 @@ defined here, fix the doc. If you need a new term, add it here first.
|
|
|
51
51
|
| **workspace orphan** | A directory under `<state-dir>/workspaces/<workstream>/` with no row in `vcs_workspaces`. Blocks subsequent `--workspace` spawns. Surfaced by `mu workspace orphans -w X` and `mu state -w X`. | "stray dir", "leftover workspace" |
|
|
52
52
|
| **stale workspace** | A workspace whose `parent_ref` is N commits behind the project's default branch HEAD (per the workspace's local refs cache). Rendered as a color-coded `behind` column (green ≤2, yellow 3–9, red ≥10) in `mu workspace list` and `mu state`; ≥10 triggers a one-line warn in `mu state`. Pure observation — mu never auto-fetches. | "out of date", "drifting" |
|
|
53
53
|
| **refresh** | `mu workspace refresh <agent>` — rebase the agent's workspace onto a fresh base (default = backend's tracked main; `--from <ref>` overrides) WITHOUT touching the agent or pane. Refuses on dirty WC; surfaces conflicts as exit 5 with a resolve-in-place hint. The `none` backend errors (no VCS to rebase). | "recycle", "reset" (overloaded) |
|
|
54
|
+
| **recreate** | `mu workspace recreate <agent>` — free + create the agent's workspace in one shot. The between-wave "prep this worker for the next dispatch" verb. Reuses the previous backend unless `--backend` overrides; bases on current main unless `--from <ref>` overrides. Refuses on dirty WC the same way `free` does; `--force` discards the dirty edits (lossy). Sibling of **refresh**: refresh PRESERVES the worker's commits (rebases them onto fresh main); recreate THROWS THEM AWAY. | "recycle", "reset" (overloaded), "free+create" (only in commit messages) |
|
|
54
55
|
| **backend** | Implementation of `AgentBackend` or `VcsBackend` | "driver", "provider" |
|
|
55
56
|
| **detector** | Per-CLI pattern matcher for busy/permission/ready. Today mu has one (`detectPiStatus` in `src/detect.ts`); covers vanilla pi + any TUI wrapper that uses Braille spinner glyphs. Other CLIs spawned via `--cli <other>` may misclassify; trust scrollback over the emoji. | "matcher", "parser" |
|
|
56
57
|
| **snapshot** | A whole-DB backup (`<state-dir>/snapshots/<id>.db`) auto-captured before each destructive verb (workstream destroy, agent close, task close/reject/defer/release/delete, workspace free). Indexed by the `snapshots` table; restore via `mu undo`. | "checkpoint", "backup" |
|
|
@@ -69,7 +70,7 @@ defined here, fix the doc. If you need a new term, add it here first.
|
|
|
69
70
|
| **substrate** | An external system mu depends on (tmux, jj, sl, git, sqlite) | "dependency" (means npm dep), "service" |
|
|
70
71
|
| **operation** | A canonical mu verb (e.g. `mu task add`). Each verb is a thin CLI wrapper over a typed function in `src/*.ts` — the SDK and the CLI share one surface. | "command" (overloaded), "action" |
|
|
71
72
|
| **reconcile** | Verb: re-derive registry rows from substrate reality (tmux). Always runs in `mu agent list` and `mu doctor`. | "sync", "refresh" |
|
|
72
|
-
| **adopt** | Verb: register an existing tmux pane as a managed **agent**. The inverse of `mu agent list`'s 'orphan' state. Pane must be in the workstream's tmux session. | "import", "absorb" |
|
|
73
|
+
| **adopt** | Verb (`mu agent adopt`): register an existing tmux pane as a managed **agent**. The inverse of `mu agent list`'s 'orphan' state. Pane must be in the workstream's tmux session. | "import", "absorb" |
|
|
73
74
|
| **pi-subagents** | A different package by Nico Bailon for in-pi focused delegation. Mu and pi-subagents are complementary, not competing. | conflating with mu |
|
|
74
75
|
|
|
75
76
|
---
|
|
@@ -138,6 +139,7 @@ cache; `mu agent list` reconciles on every call.
|
|
|
138
139
|
| `mu agent free alice` | Sets `alice.status = 'free'`. Agent stays alive. Means "I'm done with you for now; you're available." |
|
|
139
140
|
| `mu release feature_a`| Clears `tasks.owner` for `feature_a`. The agent who claimed it is unaffected. |
|
|
140
141
|
| `mu agent close alice` | Terminates alice's pane and removes from registry. Destructive. |
|
|
142
|
+
| `mu agent kick alice` | Signals (default SIGINT) the foreground process group of alice's pane TTY. For wedged tool subprocesses (`find /`, busy-wait); the wrapping CLI itself is untouched. Refuses when the foreground IS the wrapping CLI. |
|
|
141
143
|
| `mu detach alice` | (Future) Tmux-detaches alice's pane without killing the process. Not in v1. |
|
|
142
144
|
|
|
143
145
|
**Don't conflate `free` and `release`.** Free is about the *agent*;
|
|
@@ -152,6 +154,7 @@ release is about the *task*.
|
|
|
152
154
|
| `mu task claim <task> [--for <agent>]` | Atomic: sets `owner`, flips status to `IN_PROGRESS` |
|
|
153
155
|
| `mu release <task>` | Clears `owner`. Auto-flips `IN_PROGRESS` → `OPEN` (so the task re-enters the ready set); other statuses preserved. `--reopen` forces `OPEN` from `CLOSED`/`REJECTED`/`DEFERRED` |
|
|
154
156
|
| `mu task note <task> "..."` | Appends to `task_notes`. Never edits prior notes. |
|
|
157
|
+
| `mu task notes <task> [--tail N \| --since <iso> \| --since-claim]` | List notes (oldest first). `--tail N` (alias `--last N`) prints last N; `--since <iso>` filters by `created_at`; `--since-claim` auto-resolves to the most recent `task claim` event timestamp. `--since` and `--since-claim` are mutually exclusive. |
|
|
155
158
|
|
|
156
159
|
---
|
|
157
160
|
|
|
@@ -316,8 +319,8 @@ XDG-Base-Directory-Spec compliant. The state directory resolves as:
|
|
|
316
319
|
| `XDG_STATE_HOME` | Inherited; mu uses `<XDG_STATE_HOME>/mu` by default |
|
|
317
320
|
| `MU_SEND_DELAY_MS` | Delay between bracketed paste and Enter (default `500`) |
|
|
318
321
|
| `MU_TMUX_SOCKET` | Override tmux socket (`-L <name>`); default uses `$TMUX` |
|
|
319
|
-
| `MU_<UPPER_CLI>_COMMAND` | Override the executable launched for `--cli <cli>` (e.g. `MU_PI_COMMAND=pi-alt` makes `--cli pi` exec `pi-alt`). Accepts multi-word strings (`MU_PI_COMMAND="pi-alt --some-flag"`); tmux exec's via a shell. Reconcile also treats the resolved binary as agent-worthy when surfacing orphan panes. |
|
|
320
|
-
| `MU_SPAWN_LIVENESS_MS` | After spawn, wait this many ms then verify the pane is still alive. Default 1500. Set to 0 to disable (useful in CI). On detected death
|
|
322
|
+
| `MU_<UPPER_CLI>_COMMAND` | Override the executable launched for `--cli <cli>` (e.g. `MU_PI_COMMAND=pi-alt` makes `--cli pi` exec `pi-alt`; hyphens in the cli key become underscores in the env var name, so `--cli pi-meta` reads `MU_PI_META_COMMAND`). Accepts multi-word strings (`MU_PI_COMMAND="pi-alt --some-flag"`); tmux exec's via a shell. Reconcile also treats the resolved binary as agent-worthy when surfacing orphan panes. When this env var supplies the override (and `--command` did not), the spawn-success line surfaces the env-var name (`Spawned worker-1 (pi-meta via $MU_PI_META_COMMAND)`) so stale aliases are visible without `mu agent show`. |
|
|
323
|
+
| `MU_SPAWN_LIVENESS_MS` | After spawn, wait this many ms then verify the pane is still alive AND scan the tail of its scrollback for known startup-error patterns (provider auth failures — `No API key found for X`, `401 Unauthorized`, … — plus shell-level `command not found` / `No such file or directory` when the spawned binary vanished post-pre-flight). Default 1500. Set to 0 to disable (useful in CI). On detected death the DB row is rolled back and `AgentDiedOnSpawnError` is thrown with the captured scrollback; on a startup-error match (pane alive but parked at an error prompt) the row is rolled back and `AgentSpawnStartupError` is thrown with the matched line + remediation hints. The complementary pre-flight check (PATH lookup of `--cli`'s resolved binary BEFORE any side effect) is not env-tunable; on miss it throws `AgentSpawnCliNotFoundError` with no orphan workspace / pane / row. |
|
|
321
324
|
|
|
322
325
|
These mirror pi-subagents' `PI_SUBAGENT_*` env vars in spirit but live
|
|
323
326
|
in a separate namespace so the two can coexist in one pi session.
|
package/package.json
CHANGED
package/skills/mu/SKILL.md
CHANGED
|
@@ -86,8 +86,13 @@ track. Don't spawn more agents than there are tracks.
|
|
|
86
86
|
For two agents editing the same project, use `--workspace` on spawn.
|
|
87
87
|
Each gets an isolated working copy under
|
|
88
88
|
`<state-dir>/workspaces/<workstream>/<agent>/`. Auto-detects
|
|
89
|
-
jj/sl/git; `cp -a` for non-VCS. Workspaces are
|
|
90
|
-
close an agent
|
|
89
|
+
jj/sl/git; `cp -a` for non-VCS. Workspaces are auto-freed when
|
|
90
|
+
you close an agent **iff the workspace is clean** (no uncommitted
|
|
91
|
+
changes AND no commits since fork); a non-clean workspace blocks
|
|
92
|
+
`mu agent close` with `WorkspacePreservedError` and forces an
|
|
93
|
+
explicit `mu workspace free <agent>` (or
|
|
94
|
+
`mu agent close <agent> --discard-workspace` for the lossy override).
|
|
95
|
+
Between
|
|
91
96
|
waves, `mu workspace refresh <agent>` rebases the dir onto fresh
|
|
92
97
|
main without killing the agent's LLM context; `mu workspace commits
|
|
93
98
|
<agent>` lists since-fork commits for cherry-picking.
|
|
@@ -222,6 +227,16 @@ running a wave.
|
|
|
222
227
|
un-closing CLOSED/REJECTED/DEFERRED). Tunable via
|
|
223
228
|
`MU_IDLE_THRESHOLD_MS` (default 5 min).
|
|
224
229
|
|
|
230
|
+
- **Wedged on an unbounded tool subprocess (`find /`, busy-wait
|
|
231
|
+
loop)** — `mu agent send` queues until the tool returns;
|
|
232
|
+
`tmux send-keys C-c` doesn't propagate (the wrapping CLI eats
|
|
233
|
+
it as TUI input). Use `mu agent kick <name>` to SIGINT the
|
|
234
|
+
foreground process group of the pane's TTY directly from
|
|
235
|
+
outside. Default `--signal SIGINT` is graceful; escalate to
|
|
236
|
+
`--signal SIGTERM` then `--signal SIGKILL` if the tool
|
|
237
|
+
ignores it. Refuses when the foreground IS the wrapping CLI
|
|
238
|
+
itself — use `mu agent close` for that.
|
|
239
|
+
|
|
225
240
|
## Parallelisation decision table
|
|
226
241
|
|
|
227
242
|
| Situation | Action |
|
|
@@ -259,10 +274,13 @@ running a wave.
|
|
|
259
274
|
`--archive <label>` to preserve graph atomically), `export`,
|
|
260
275
|
`import`.
|
|
261
276
|
- **Agents**: `spawn` (`--workspace`, `--role read-only`,
|
|
262
|
-
`--command`), `send`, `read`, `show`, `list`, `close`, `free
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
277
|
+
`--command`), `send`, `read`, `show`, `list`, `close`, `free`,
|
|
278
|
+
`kick` (signal a wedged foreground tool subprocess from outside
|
|
279
|
+
the pane). **`mu agent adopt <pane-id|title>`** registers an
|
|
280
|
+
orphan pane as a managed agent.
|
|
281
|
+
- **Tasks**: `add`, `list`, `next`, `show`, `tree`, `notes`
|
|
282
|
+
(`--tail N` / `--since <iso>` / `--since-claim` to slice the
|
|
283
|
+
timeline; default = every note, oldest first), `note`,
|
|
266
284
|
`claim` (`--for | --self`), `release` (`--reopen` to un-close),
|
|
267
285
|
`close` (`--if-ready` = no-op unless every blocker terminal),
|
|
268
286
|
`open`, `reject`, `defer`, `block`, `unblock`, `update`,
|
|
@@ -270,9 +288,11 @@ running a wave.
|
|
|
270
288
|
Edge direction: `block <blocked> --by <blocker>`.
|
|
271
289
|
- **Self (in-pane)**: `mu me`, `mu me tasks`, `mu me next`.
|
|
272
290
|
- **Workspace**: `create`, `list` (`behind` column), `refresh`
|
|
273
|
-
(rebase onto fresh base, agent stays alive), `
|
|
274
|
-
|
|
275
|
-
|
|
291
|
+
(rebase onto fresh base, agent stays alive), `recreate` (free +
|
|
292
|
+
create in one shot for between-wave prep; `--force` to discard
|
|
293
|
+
dirty edits), `commits` (since-fork `<sha> <subject>`; `--json`
|
|
294
|
+
for piping), `free`, `path` (`cd $(mu workspace path X)`),
|
|
295
|
+
`orphans`.
|
|
276
296
|
- **Activity log**: `mu log "text"` (write), `mu log -n N` (read),
|
|
277
297
|
`mu log --tail` (subscribe). Don't pipe `--tail` for waits — use
|
|
278
298
|
`mu task wait`.
|
|
@@ -361,10 +381,12 @@ IDs auto-derive from titles via slugify.
|
|
|
361
381
|
# Wait for any-of N to close, cherry-pick that one, return.
|
|
362
382
|
res=$(mu task wait t1 t2 t3 -w ws --any --first --json \
|
|
363
383
|
--timeout 600 --on-stall exit)
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
384
|
+
worker=$(jq -r .firing.owner <<<"$res")
|
|
385
|
+
# Workers run in fresh single-purpose workspaces, so HEAD is the
|
|
386
|
+
# task's commit. Don't filter on subject — workers don't prefix
|
|
387
|
+
# subjects with the task-id, and any such filter silently returns
|
|
388
|
+
# empty (then `git cherry-pick` fails with "empty commit set").
|
|
389
|
+
sha=$(mu workspace commits $worker -w ws --json | jq -r '.items[0].sha')
|
|
368
390
|
git cherry-pick $sha && cargo test --lib
|
|
369
391
|
# Next turn: same wait on the smaller set.
|
|
370
392
|
```
|
|
@@ -439,11 +461,11 @@ Verbs auto-resolve via `$TMUX_PANE` — `mu me`, `mu me next`,
|
|
|
439
461
|
(set at spawn) IS the agent identity.
|
|
440
462
|
|
|
441
463
|
- **Worker**: pane was created by `mu agent spawn` (or promoted via
|
|
442
|
-
`mu adopt`). Bare `mu task claim <id>` works.
|
|
464
|
+
`mu agent adopt`). Bare `mu task claim <id>` works.
|
|
443
465
|
- **Orchestrator**: a top-level pi session NOT in `agents`. Bare
|
|
444
466
|
`mu task claim` errors with `ClaimerNotRegisteredError` whose
|
|
445
467
|
`errorNextSteps()` lists three options: `--self` (work directly,
|
|
446
|
-
owner=NULL), `--for <worker>` (dispatch), or `mu adopt <pane>`.
|
|
468
|
+
owner=NULL), `--for <worker>` (dispatch), or `mu agent adopt <pane>`.
|
|
447
469
|
|
|
448
470
|
Working loop:
|
|
449
471
|
|
|
@@ -504,6 +526,11 @@ orchestrator's `mu task wait` hang.
|
|
|
504
526
|
- **Don't use the `mu_` task-id prefix.** Reserved.
|
|
505
527
|
- **Don't message agents directly.** Coordinate via task notes and
|
|
506
528
|
the activity log.
|
|
529
|
+
- **Don't prompt workers to run filesystem-wide `find`, broad
|
|
530
|
+
`grep -r /`, or unbounded busy-wait loops.** Pass paths
|
|
531
|
+
explicitly or scope to `$WORKSPACE`. If a worker wedges on one,
|
|
532
|
+
use `mu agent kick <name>` to SIGINT the foreground tool
|
|
533
|
+
from outside the pane.
|
|
507
534
|
|
|
508
535
|
## What mu is NOT
|
|
509
536
|
|