@mu-crew/mu 3.2.0 → 3.2.1
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 +203 -599
- package/README.md +76 -327
- package/dist/cli.js.map +1 -1
- package/dist/extension/mu-pi.js +178 -45
- package/dist/extension/mu-pi.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +175 -1072
- package/docs/ROADMAP.md +88 -169
- package/docs/VISION.md +205 -415
- package/docs/VOCABULARY.md +202 -466
- package/docs/architecture/control-socket.md +119 -0
- package/docs/architecture/dag.md +113 -0
- package/docs/architecture/mux.md +163 -0
- package/docs/architecture/ops-log.md +140 -0
- package/docs/architecture/sdk.md +185 -0
- package/docs/architecture/sync.md +129 -0
- package/docs/architecture/tui.md +146 -0
- package/docs/guide/README.md +25 -0
- package/docs/guide/backends.md +61 -0
- package/docs/guide/cleanup.md +74 -0
- package/docs/guide/delegate.md +87 -0
- package/docs/guide/dispatch.md +137 -0
- package/docs/guide/getting-started.md +177 -0
- package/docs/guide/recovery.md +133 -0
- package/docs/guide/remote.md +74 -0
- package/docs/guide/sql.md +76 -0
- package/docs/guide/stop-a-worker.md +64 -0
- package/docs/guide/sync.md +78 -0
- package/docs/guide/tui.md +98 -0
- package/docs/guide/upgrade.md +76 -0
- package/docs/history/CHANGELOG-pre-3.md +4866 -0
- package/docs/reference/env.md +87 -0
- package/docs/reference/naming.md +82 -0
- package/docs/specs/2026-09-28-agent-state-from-murmur.md +1 -1
- package/docs/specs/2026-09-29-task-substates.md +1 -1
- package/package.json +1 -1
- package/skills/mu/REMOTE_WORKERS.md +179 -504
- package/skills/mu/SKILL.md +116 -185
- package/docs/HANDOVER.md +0 -486
- package/docs/USAGE_GUIDE.md +0 -2738
package/AGENTS.md
CHANGED
|
@@ -1,623 +1,227 @@
|
|
|
1
1
|
# Repo guide for AI coding agents
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
multiplexer panes (tmux or herdr) coordinated through a built-in
|
|
6
|
-
task DAG.
|
|
7
|
-
|
|
8
|
-
Read the linked docs before you write code. Follow the conventions
|
|
9
|
-
below.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Read these first (in this order)
|
|
14
|
-
|
|
15
|
-
1. **[docs/USAGE_GUIDE.md](docs/USAGE_GUIDE.md)** — what mu does
|
|
16
|
-
from a user's perspective. ~10 minutes.
|
|
17
|
-
2. **[CHANGELOG.md](CHANGELOG.md)** — the upcoming version's entry.
|
|
18
|
-
Single source of truth for the verb list, schema, env vars.
|
|
19
|
-
3. **[docs/VISION.md](docs/VISION.md)** — the design principles you
|
|
20
|
-
must not violate.
|
|
21
|
-
4. **[docs/ROADMAP.md](docs/ROADMAP.md)** — what's next, with
|
|
22
|
-
promotion criteria. **Read the "Anti-feature pledges" section
|
|
23
|
-
before adding any new dep, abstraction, or surface.**
|
|
24
|
-
5. **[docs/VOCABULARY.md](docs/VOCABULARY.md)** — canonical terms.
|
|
25
|
-
**Source of truth for every word** in code, docs, and error
|
|
26
|
-
messages. If you use a term not defined there, fix the docs first.
|
|
27
|
-
6. **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** — module layout,
|
|
28
|
-
reconciliation algorithm, TUI architecture, key seams.
|
|
29
|
-
|
|
30
|
-
Design rationale for rejected and unbuilt features lives in
|
|
31
|
-
[docs/ROADMAP.md](docs/ROADMAP.md) per item, alongside its promotion
|
|
32
|
-
criteria.
|
|
33
|
-
|
|
34
|
-
> **If you are an orchestrator** — a coding agent driving a crew of
|
|
35
|
-
> pi worker agents on this repo via `mu` — read
|
|
36
|
-
> **[docs/HANDOVER.md](docs/HANDOVER.md)** instead of the order
|
|
37
|
-
> above: onboarding steps, the 8-phase dispatch loop,
|
|
38
|
-
> conflict-resolution playbook, known gotchas, end-of-session
|
|
39
|
-
> checklist. AGENTS.md is for workers and humans editing the repo
|
|
40
|
-
> directly.
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
## Repo layout
|
|
3
|
+
This repo builds **mu**: a CLI that runs AI agents in tmux or herdr
|
|
4
|
+
panes, coordinated through a task DAG.
|
|
45
5
|
|
|
46
|
-
|
|
47
|
-
mu/
|
|
48
|
-
├── README.md # human-user entry point
|
|
49
|
-
├── AGENTS.md # this file
|
|
50
|
-
├── CHANGELOG.md # release notes
|
|
51
|
-
├── docs/ # everything else
|
|
52
|
-
│ ├── USAGE_GUIDE.md # user-facing tour (§ 5b is the TUI reference)
|
|
53
|
-
│ ├── HANDOVER.md # orchestrator goto reset doc (8-phase loop + gotchas)
|
|
54
|
-
│ ├── ROADMAP.md # what's next; promotion criteria; anti-feature pledges
|
|
55
|
-
│ ├── VISION.md # design pillars
|
|
56
|
-
│ ├── VOCABULARY.md # canonical terms (single source of truth)
|
|
57
|
-
│ └── ARCHITECTURE.md # module layout, TUI architecture, key seams
|
|
58
|
-
├── extension/ # the mu pi extension (built to dist/extension/mu-pi.js)
|
|
59
|
-
│ ├── mu-pi.ts # serves $MU_CTL_SOCK inside a spawned pi (control socket server)
|
|
60
|
-
│ └── delegate.ts # parent-side mu_delegate / mu_delegate_cancel tools (shell out to mu)
|
|
61
|
-
├── src/ # all source (root files: SDK + shared infra; one
|
|
62
|
-
│ # level of subdirs OK for cohesive clusters — see
|
|
63
|
-
│ # `src/cli/`, `src/agents/`, `src/tasks/`, `src/mux/`, `src/ctl/`)
|
|
64
|
-
│ ├── db.ts # SQLite schema + openDb (single CREATE-IF-NOT-EXISTS block; v11)
|
|
65
|
-
│ │ # also owns SYNCED_ENTITIES / PORTABLE_TABLES / MACHINE_LOCAL_TABLES
|
|
66
|
-
│ ├── mux.ts # multiplexer backend hub (re-exports src/mux/*)
|
|
67
|
-
│ ├── mux/ # cohesive cluster: one file per multiplexer
|
|
68
|
-
│ │ ├── index.ts # re-export hub consumed by src/mux.ts
|
|
69
|
-
│ │ ├── types.ts # MuxBackend interface + MuxError / PaneNotFoundError / NoMultiplexerError
|
|
70
|
-
│ │ ├── detect.ts # MU_MUX → HERDR_ENV → $TMUX → availability ladder; activeMux()
|
|
71
|
-
│ │ ├── tmux.ts # tmux impl: wrapper, 6-step send protocol, pane validation
|
|
72
|
-
│ │ └── herdr.ts # herdr impl: JSON socket API, atomic send, native pane status
|
|
73
|
-
│ ├── tmux.ts # back-compat re-export of the tmux backend (new code imports mux.js)
|
|
74
|
-
│ ├── detect.ts # pi status detector + Braille-spinner fallback; used only when
|
|
75
|
-
│ │ # the backend has no paneStatus() of its own (i.e. tmux)
|
|
76
|
-
│ ├── reconcile.ts # ghost prune + status detect + orphan surface
|
|
77
|
-
│ ├── agents.ts # CRUD + send/read/list/close + liveness + reaper hub (re-exports src/agents/*)
|
|
78
|
-
│ ├── agents/ # cohesive cluster of agent-lifecycle internals
|
|
79
|
-
│ │ ├── spawn.ts # spawnAgent + resolveCliCommand / awaitSpawnLiveness / pane create-or-reuse / prestage / rollback
|
|
80
|
-
│ │ ├── spawn-lock.ts # cross-process advisory lock around a spawn's topology critical section
|
|
81
|
-
│ │ ├── kick.ts # reaper events + cleanup of dead agent rows
|
|
82
|
-
│ │ ├── adopt.ts # adoptAgent: register an existing pane as a managed agent
|
|
83
|
-
│ │ ├── wait.ts # waitForAgents: block on task-less agents finishing (busy → any other state)
|
|
84
|
-
│ │ ├── transport.ts # send routing: ctl for pi agents, mux paste otherwise, no fallback; expectsCtl
|
|
85
|
-
│ │ ├── abort.ts # abortAgent: stop a pi turn through the control socket
|
|
86
|
-
│ │ ├── delegate.ts # delegateOutcome: one wait result → done / empty / died / timeout / pending
|
|
87
|
-
│ │ └── errors.ts # typed agent error classes (AgentNotFoundError, AgentDiedOnSpawnError, …)
|
|
88
|
-
│ ├── tasks.ts # task SDK hub (re-exports src/tasks/*)
|
|
89
|
-
│ ├── tasks/ # cohesive cluster of task-graph internals
|
|
90
|
-
│ │ ├── status.ts # TaskStatus enum + helpers
|
|
91
|
-
│ │ ├── core.ts # core SDK funcs reused across cluster files
|
|
92
|
-
│ │ ├── id.ts # tryResolveTaskId / qualified-id helpers
|
|
93
|
-
│ │ ├── queries.ts # listTasks / nextTasks / owned-by
|
|
94
|
-
│ │ ├── edit.ts # addTask / setTaskTitle / etc (no edges)
|
|
95
|
-
│ │ ├── edges.ts # block / unblock / reparent / delete + dedupe
|
|
96
|
-
│ │ ├── claim.ts # claim / release + resolveActorIdentity (atomic CAS)
|
|
97
|
-
│ │ ├── lifecycle.ts # setTaskStatus / closeTask / openTask + cascade
|
|
98
|
-
│ │ ├── wait.ts # waitForTasks: block until tasks reach a target status
|
|
99
|
-
│ │ ├── sort.ts # sortTasks (roi / recency / age / id)
|
|
100
|
-
│ │ └── errors.ts # typed task error classes (TaskAlreadyOwnedError, CycleError, …)
|
|
101
|
-
│ ├── tracks.ts # parallel-tracks union-find with diamond merge
|
|
102
|
-
│ ├── workstream.ts # ensureWorkstream / list / summarize / destroy
|
|
103
|
-
│ ├── hlc.ts # hybrid logical clock: the monotonic ordering key on every op
|
|
104
|
-
│ ├── capture.ts # SQLite triggers recording every portable mutation as an op, in-transaction
|
|
105
|
-
│ ├── op-context.ts # withOpContext (intent/actor/group) + withCaptureSuppressed echo guard
|
|
106
|
-
│ ├── apply.ts # the apply path: per-field LWW merge + tombstones + deferred reprojection
|
|
107
|
-
│ ├── undo.ts # inverse ops for one group (granular undo; supersede refusal)
|
|
108
|
-
│ ├── rebuild.ts # replay the whole ops log into a NEW DB file (disaster recovery)
|
|
109
|
-
│ ├── drift.ts # ops-log-vs-live-tables drift check (cheap default tier + --deep rebuild-diff)
|
|
110
|
-
│ ├── segments.ts # JSONL segment transport: flush own ops / ingest peers from a watermark
|
|
111
|
-
│ ├── sync.ts # peer status + the ambient flush/ingest hook + --from reader + --repair
|
|
112
|
-
│ ├── fleet-hazards.ts # mixed-fleet doctor checks (DB inside MU_SYNC_DIR, network mount, case collisions)
|
|
113
|
-
│ ├── file-lock.ts # generic cross-process advisory lock via atomic fs.mkdir
|
|
114
|
-
│ ├── ctl/ # control socket client: path.ts (ctlSocketPath), protocol.ts (v1, CTL_OPS), client.ts (ctlRequest / ctlProbe)
|
|
115
|
-
│ ├── link.ts # mu link pi: extension shim + skill symlink + inspectLinks for doctor
|
|
116
|
-
│ ├── logs.ts # typed READER over `ops` + appendLog / emitEvent (the one write path triggers can't cover)
|
|
117
|
-
│ ├── log-render.ts # the ONE op → prose formatter (renderOp); shared by CLI + TUI
|
|
118
|
-
│ ├── vcs.ts # VcsBackend hub (re-exports src/vcs/*: jj/sl/git/none impls)
|
|
119
|
-
│ ├── workspace.ts # per-agent VCS workspaces hub (re-exports src/workspace/*)
|
|
120
|
-
│ ├── glyphs.ts # THE glyph vocabulary: agent status + state glyphs + card digits
|
|
121
|
-
│ ├── shell-quote.ts # POSIX single-quote helper for copy-pasteable Next: hints
|
|
122
|
-
│ ├── dag.ts # full-DAG forest builder (loadFullDag for `mu task tree` + DAG popup)
|
|
123
|
-
│ ├── state.ts # SDK seam for `mu state` (fast SQL tier + slow subprocess tier + merge)
|
|
124
|
-
│ ├── staleness.ts # WORKSPACE_STALE_THRESHOLD + isStaleWorkspace
|
|
125
|
-
│ ├── project-root.ts # detectProjectRoot for the TUI launch cwd ladder
|
|
126
|
-
│ ├── doctor-summary.ts # TUI-friendly slice of `mu doctor` checks + remediation helpers
|
|
127
|
-
│ ├── output.ts # NextStep type + printNextSteps / errorNextSteps
|
|
128
|
-
│ ├── cli.ts # commander wiring (buildProgram); re-exports format/handle for back-compat
|
|
129
|
-
│ ├── cli/ # one file per verb-namespace; thin wrappers over the SDK
|
|
130
|
-
│ │ ├── workstream.ts # workstream init / list / destroy
|
|
131
|
-
│ │ ├── agents.ts # agent spawn / send / read / list / show / close / kick / wait / adopt
|
|
132
|
-
│ │ ├── agents-remote.ts # agent remote-env (prints ssh forward + env; runs nothing)
|
|
133
|
-
│ │ ├── dispatch-hints.ts # dispatch-time Next: hints for pi agents (--fresh / --steer / abort)
|
|
134
|
-
│ │ ├── link.ts # mu link pi (filesystem only; runs outside handle())
|
|
135
|
-
│ │ ├── tasks.ts # `mu task` hub (re-exports wireTaskCommands / cmdMyNext / cmdMyTasks / unescapeNoteText)
|
|
136
|
-
│ │ ├── tasks/ # sub-cluster of the `mu task` namespace
|
|
137
|
-
│ │ │ ├── queries.ts # list / next / owned-by + cmdMyTasks / cmdMyNext (back `mu me tasks` / `mu me next`)
|
|
138
|
-
│ │ │ ├── lifecycle.ts # close / open + cascade preview
|
|
139
|
-
│ │ │ ├── edit.ts # add / show / notes / note / update + helpers
|
|
140
|
-
│ │ │ ├── edges.ts # block / unblock / reparent / delete
|
|
141
|
-
│ │ │ ├── claim.ts # claim / release / wait
|
|
142
|
-
│ │ │ ├── tree.ts # tree rendering
|
|
143
|
-
│ │ │ └── wire.ts # Commander glue
|
|
144
|
-
│ │ ├── workspace.ts # workspace list / free / path / orphans / refresh / commits
|
|
145
|
-
│ │ ├── log.ts # log read / write / tail
|
|
146
|
-
│ │ ├── undo.ts # mu undo [group] (list / preview / --yes apply)
|
|
147
|
-
│ │ ├── sync.ts # mu sync (peer status; --from / --repair)
|
|
148
|
-
│ │ ├── rebuild.ts # mu rebuild <file>
|
|
149
|
-
│ │ ├── state.ts # `mu state` (canonical state card); --tui dispatches to src/cli/tui/
|
|
150
|
-
│ │ ├── staleness.ts # shared workspace-staleness CLI helpers + warn formatter
|
|
151
|
-
│ │ ├── tui-launch-focus.ts # initial-tab focus ladder for bare `mu` and `mu state --tui`
|
|
152
|
-
│ │ ├── tui/ # interactive ink-based TUI cluster; ONLY place ink/react are imported
|
|
153
|
-
│ │ │ ├── index.ts # runTui entrypoint; alt-screen + mouse-mode lifecycle
|
|
154
|
-
│ │ │ ├── escapes.ts # pure ANSI escape constants (ALT_SCREEN_*, mouse-mode bytes) — no ink imports
|
|
155
|
-
│ │ │ ├── app.tsx # <App> root (popup state machine + global keymap + footer + tick + tabs)
|
|
156
|
-
│ │ │ ├── state.ts # poll-loop hook (useDashboardSnapshot; fast/slow tick split)
|
|
157
|
-
│ │ │ ├── keys.ts # pure dispatchGlobalKey + dispatchPopupKey + shouldSwallowGlobalKey
|
|
158
|
-
│ │ │ ├── keymap-spec.ts # canonical keymap source-of-truth (drives help overlay + dispatch)
|
|
159
|
-
│ │ │ ├── yank.ts # clipboard probe + write (pbcopy/wl-copy/xclip/xsel/clip.exe + OSC-52)
|
|
160
|
-
│ │ │ ├── mouse.ts # vendored SGR mouse layer (parser + double-click + useMouse hook)
|
|
161
|
-
│ │ │ ├── layout.ts # responsive multi-column dashboard + per-card row budgets
|
|
162
|
-
│ │ │ ├── columns.ts # column-aligned row layout with protect/clip clipping
|
|
163
|
-
│ │ │ ├── wrap-ansi.ts # ANSI-aware visual-width line wrapper + SGR close-on-end
|
|
164
|
-
│ │ │ ├── format-helpers.ts # shared TUI formatters (relTime, sinceClaim, ROI, etc.)
|
|
165
|
-
│ │ │ ├── titled-box.tsx # rounded border with section header inset into top border + bottomLabel
|
|
166
|
-
│ │ │ ├── popup-shell.tsx # popup outer chrome (cyan TitledBox)
|
|
167
|
-
│ │ │ ├── list-row.tsx # centralised non-selected row primitive (width pin + gutter + truncate)
|
|
168
|
-
│ │ │ ├── padded-rows.tsx # per-card body padder
|
|
169
|
-
│ │ │ ├── help.tsx # ?/F1 keymap overlay (scrollable on short panes)
|
|
170
|
-
│ │ │ ├── status-bar.tsx # bottom status bar (mode + active ws + tick + footer flash)
|
|
171
|
-
│ │ │ ├── tab-strip.tsx # multi-workstream tab switcher (N≥2)
|
|
172
|
-
│ │ │ ├── tab-strip-layout.ts # pure window-around-active layout helper for the tab strip
|
|
173
|
-
│ │ │ ├── tuicr.ts # `t` shortcut: alt-screen handoff to tuicr -r <sha>
|
|
174
|
-
│ │ │ ├── use-popup-filter.tsx # shared '/' substring filter hook + applyFilter + FilterPrompt
|
|
175
|
-
│ │ │ ├── use-status-filter.tsx # task-status toggles for task-list popups (o/i/c)
|
|
176
|
-
│ │ │ ├── use-notes-drill.ts # shared notes-drill memo (5 task popups consume it)
|
|
177
|
-
│ │ │ ├── use-popup-action-queue.ts # consume mouse PopupAction queue once per render
|
|
178
|
-
│ │ │ ├── use-terminal-size.ts # shared reactive terminal-size hook (ink doesn't re-render on resize)
|
|
179
|
-
│ │ │ ├── agent-display.ts # shared agent-row display helpers for cards/popups
|
|
180
|
-
│ │ │ ├── lazygit.ts # `l` in the Commits popup: alt-screen handoff to lazygit
|
|
181
|
-
│ │ │ ├── tmux-attach.ts # `a` in the Agents popup: alt-screen handoff to the agent's mux pane
|
|
182
|
-
│ │ │ ├── cards/{agents,tracks,ready,log,workspaces,inprogress,blocked,recent,commits,doctor}.tsx + _placeholder.tsx
|
|
183
|
-
│ │ │ └── popups/{agents,tracks,ready,log,workspaces,inprogress,blocked,recent,commits,doctor,dag,all-tasks}.tsx
|
|
184
|
-
│ │ │ # plus drill.tsx (DrillScrollView), task-detail.tsx (TaskDetailDrill),
|
|
185
|
-
│ │ │ # cursor-row.tsx, scroll.ts (applyCursor/applyScroll), viewport.ts,
|
|
186
|
-
│ │ │ # show-loader.ts (shared subprocess-preserving loader)
|
|
187
|
-
│ │ ├── db.ts # db backup (VACUUM INTO)
|
|
188
|
-
│ │ ├── sql.ts # sql escape hatch
|
|
189
|
-
│ │ ├── doctor.ts # doctor diagnostic
|
|
190
|
-
│ │ ├── format.ts # pure rendering helpers (table renderers, status colourers, truncate/relTime)
|
|
191
|
-
│ │ └── handle.ts # typed-error → exit-code map + handle() wrapper
|
|
192
|
-
│ └── index.ts # SDK entrypoint (re-exports)
|
|
193
|
-
├── test/ # ~200 *.test.ts files / ~2900 tests (`npm run test`); many use real tmux/git/jj/sl
|
|
194
|
-
├── skills/mu/SKILL.md # what the LLM running inside an agent pane sees
|
|
195
|
-
├── package.json # bin: { mu: ./dist/cli.js }, type: module
|
|
196
|
-
├── tsconfig.json # strict + noUncheckedIndexedAccess + verbatimModuleSyntax
|
|
197
|
-
├── tsup.config.ts # bundles src/ → dist/ (cli + index entries)
|
|
198
|
-
├── biome.json # lint + format
|
|
199
|
-
└── vitest.config.ts # tests
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
---
|
|
6
|
+
## Read these first
|
|
203
7
|
|
|
204
|
-
|
|
8
|
+
1. [docs/guide/README.md](docs/guide/README.md) — what mu does for a user.
|
|
9
|
+
2. [CHANGELOG.md](CHANGELOG.md) — the upcoming version's entry is the
|
|
10
|
+
source of truth for verbs, schema, and env vars.
|
|
11
|
+
3. [docs/VISION.md](docs/VISION.md) — design pillars you must not violate.
|
|
12
|
+
4. [docs/ROADMAP.md](docs/ROADMAP.md) — what's next and the promotion
|
|
13
|
+
criteria. Read [Anti-feature pledges](docs/ROADMAP.md#anti-feature-pledges)
|
|
14
|
+
before you add a dependency, an abstraction, or a surface.
|
|
15
|
+
5. [docs/VOCABULARY.md](docs/VOCABULARY.md) — canonical terms for code,
|
|
16
|
+
docs, and error messages. [docs/reference/](docs/reference/) holds env vars and naming.
|
|
17
|
+
6. [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) — the module map (what
|
|
18
|
+
lives where in `src/`), plus deep dives under [docs/architecture/](docs/architecture/).
|
|
205
19
|
|
|
206
|
-
|
|
20
|
+
## Build, test, lint
|
|
207
21
|
|
|
208
22
|
```bash
|
|
209
23
|
npm install
|
|
210
24
|
npm run build # tsup → dist/
|
|
211
|
-
npm run typecheck
|
|
212
|
-
npm run lint
|
|
213
|
-
npm run test:fast #
|
|
214
|
-
npm run test # full
|
|
215
|
-
npm run test:
|
|
216
|
-
npm run test:watch:fast # fast-tier watch mode
|
|
25
|
+
npm run typecheck
|
|
26
|
+
npm run lint
|
|
27
|
+
npm run test:fast # unit tier; safe to run concurrently
|
|
28
|
+
npm run test # full suite, including integration
|
|
29
|
+
npm run test:stress # pre-release stability gate
|
|
217
30
|
```
|
|
218
31
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
(
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
cluster needs:
|
|
285
|
-
(1) a clear theme (every file does the same kind of thing),
|
|
286
|
-
(2) imports go from cluster-files → root-files (no upward imports),
|
|
287
|
-
(3) ARCHITECTURE.md's module table has a row covering it.
|
|
288
|
-
|
|
289
|
-
### Tests
|
|
290
|
-
|
|
291
|
-
- Unit tests: real SQLite (in-temp-dir), mocked tmux executor via
|
|
292
|
-
`setTmuxExecutor()`. Fast, deterministic. For anything touching the
|
|
293
|
-
multiplexer, use `installMux()` from `test/_mux.ts` rather than the
|
|
294
|
-
raw setters — it installs the backend AND its executor together and
|
|
295
|
-
hands back one `restore()`, which removes the ordering hazard of
|
|
296
|
-
stubbing one backend while asserting against another.
|
|
297
|
-
- TUI popup/card behaviour tests should follow `test/README.md`:
|
|
298
|
-
prefer the `test/_ink-render.ts` CaptureStream seam over
|
|
299
|
-
`readFileSync` source-greps except for narrow structural guards.
|
|
300
|
-
- Fast tier: `npm run test:fast` runs `test/**/*.test.ts` while
|
|
301
|
-
excluding `*.integration.test.ts` and `*.smoke.test.ts`. Keep this
|
|
302
|
-
tier pure/in-process: mocked tmux/VCS, real SQLite only in per-test
|
|
303
|
-
temp DBs, no real tmux/git/jj/sl subprocess fixtures, no
|
|
304
|
-
filesystem-heavy export/import/snapshot paths, and no fixed sleeps
|
|
305
|
-
above 50ms.
|
|
306
|
-
- Integration tests: full-only tests use the `.integration.test.ts`
|
|
307
|
-
suffix (e.g. `tmux.integration.test.ts`). They may touch real tmux
|
|
308
|
-
or herdr servers, git/jj/sl fixture repos, subprocess-backed smoke
|
|
309
|
-
paths, filesystem-heavy export/import/snapshot flows, or
|
|
310
|
-
intentionally slower in-process CLI flows. Real-tmux tests are
|
|
311
|
-
skipped when `$TMUX` is unset; real-herdr tests skip unless a
|
|
312
|
-
running, protocol-compatible server is present. These tests typically opt out of the spawn
|
|
313
|
-
liveness check via `process.env.MU_SPAWN_LIVENESS_MS = "0"` in
|
|
314
|
-
`beforeEach`, since the sh subprocesses they spawn are intentionally
|
|
315
|
-
long-lived.
|
|
316
|
-
- Each test gets its own temp DB and (for integration) a unique
|
|
317
|
-
tmux session like `mu-test-<pid>-<ts>-<rand>` to avoid colliding
|
|
318
|
-
with the user's panes or with parallel test runs.
|
|
319
|
-
- **herdr isolation is a guard, not a socket.** tmux gets a private
|
|
320
|
-
server via `MU_TMUX_SOCKET`, so a stray test is contained
|
|
321
|
-
structurally. herdr has no equivalent: its only isolation is a named
|
|
322
|
-
session (`MU_HERDR_SESSION`), so `test/_mux.ts` enforces it at
|
|
323
|
-
runtime — `assertHerdrIsolated()` refuses to run when the var is
|
|
324
|
-
unset or names `default`, and the fatal verbs (`server stop`,
|
|
325
|
-
`server restart`, `server kill`) are refused even inside a correct
|
|
326
|
-
session, because a stopped server is shared-fate. **Never stop the
|
|
327
|
-
herdr server or kill its main process from a test.** That destroys
|
|
328
|
-
the user's real panes and their unsaved work, with no undo. Clean up
|
|
329
|
-
per-entity (close what you created), never by nuking the server.
|
|
330
|
-
- Dogfood reality: multiple pi worker agents often run `npm run test`
|
|
331
|
-
concurrently on the same machine from different workspaces. Treat
|
|
332
|
-
flakes that pass in isolation but fail under load as concurrency
|
|
333
|
-
bugs first (shared `/tmp` cleanup, tmux socket/session collisions,
|
|
334
|
-
leaked subprocesses, VCS background file activity). Use
|
|
335
|
-
`npm run test:stress` for the pre-release/stability gate; it runs
|
|
336
|
-
the suite repeatedly with a per-run timeout and can simulate
|
|
337
|
-
parallel full-suite runs via
|
|
338
|
-
`MU_TEST_STRESS_MODE=parallel MU_TEST_STRESS_PARALLEL=2`.
|
|
339
|
-
- The acceptance test in `test/acceptance.integration.test.ts` is the
|
|
340
|
-
"everything works" gate. Keep it passing.
|
|
341
|
-
- **DB baseline**: `openDb()` refuses to open the user's REAL
|
|
342
|
-
default DB (`<HOME or XDG_STATE_HOME>/mu/mu.db`) when
|
|
343
|
-
`process.env.VITEST` is set or `NODE_ENV === "test"`. Tests
|
|
344
|
-
MUST use a per-test temp DB — either via MU_DB_PATH (which
|
|
345
|
-
`test/_runCli.ts` sets automatically) or an explicit `{ path }`
|
|
346
|
-
argument to `openDb`. A regression that forgets either one
|
|
347
|
-
fails loudly at the offending openDb() call site instead of
|
|
348
|
-
silently writing to the dev box's live state. Production never
|
|
349
|
-
sets VITEST, so the guard is a no-op outside the test runner.
|
|
350
|
-
- **Env baseline**: `test/_setup.ts` (vitest `setupFiles`) clears
|
|
351
|
-
every `MU_*` env var inherited from the parent shell at the start
|
|
352
|
-
of each fork, so SDK-level overrides (`MU_PI_COMMAND`,
|
|
353
|
-
`MU_IDLE_THRESHOLD_MS`, `MU_SEND_DELAY_MS`, …) can't silently
|
|
354
|
-
change behaviour underneath tests. Allowlist: `MU_TMUX_SOCKET`
|
|
355
|
-
(set by `_global-teardown.ts` at MODULE LOAD time — BEFORE vitest
|
|
356
|
-
spawns the worker pool — for Layer-3 isolation; see round-3
|
|
357
|
-
Part A in the file's header comment for why module-load not
|
|
358
|
-
setup()). Tests that need a specific value opt IN per-test via
|
|
359
|
-
`process.env.X = "..."` or `withEnv()` from `test/_env.ts`.
|
|
360
|
-
- **Default-socket sweep philosophy**: `_global-teardown.ts` runs
|
|
361
|
-
an ALLOWLIST sweep of `mu-*` sessions on the user's default tmux
|
|
362
|
-
socket at suite setup AND teardown. The allowlist is DB-rooted:
|
|
363
|
-
(1) `mu-<name>` for every workstream in the user's REAL DB
|
|
364
|
-
(read-only via better-sqlite3, bypassing the `openDb()` test
|
|
365
|
-
guard) and (2) `mu-$MU_SESSION` if the orchestrator runs the suite
|
|
366
|
-
inside a tmux pane. Anything else is, by elimination, test residue
|
|
367
|
-
and is killed. No session is grandfathered by being present at
|
|
368
|
-
module load — that defeats the self-healing intent. Cost: an ad-hoc
|
|
369
|
-
`tmux new-session -t mu-foo` with no DB row gets killed; run
|
|
370
|
-
`mu workstream init foo` first. Tests can hardcode any workstream
|
|
371
|
-
name — if they accidentally bypass the private socket, the sweep
|
|
372
|
-
catches them.
|
|
373
|
-
|
|
374
|
-
### When you change behaviour, update VOCABULARY first
|
|
375
|
-
|
|
376
|
-
Vocabulary is canonical. If you introduce a new concept, name, or
|
|
377
|
-
verb, **add it to docs/VOCABULARY.md before the code lands**. If you
|
|
378
|
-
rename something, update VOCABULARY.md in the same commit.
|
|
379
|
-
|
|
380
|
-
### Deferred features — don't smuggle them in
|
|
381
|
-
|
|
382
|
-
[docs/ROADMAP.md](docs/ROADMAP.md) lists what's next, by version,
|
|
383
|
-
with **promotion criteria**:
|
|
384
|
-
|
|
385
|
-
> 1. A real user hits the missing feature in real workflows ≥2
|
|
386
|
-
> times.
|
|
387
|
-
> 2. The current substrate makes the addition straightforward (no
|
|
388
|
-
> major pillar refactor).
|
|
389
|
-
> 3. The addition fits in <300 LOC or has a clear smaller subset.
|
|
390
|
-
|
|
391
|
-
If you find yourself adding something not on the roadmap and not
|
|
392
|
-
meeting these criteria, **stop**. Add an entry to
|
|
393
|
-
[docs/ROADMAP.md](docs/ROADMAP.md) (or open an issue) and move on.
|
|
394
|
-
|
|
395
|
-
The "anti-feature pledges" in ROADMAP.md are firm:
|
|
396
|
-
|
|
397
|
-
- No config file
|
|
398
|
-
- No daemon / background process beyond what the multiplexer +
|
|
399
|
-
SQLite give us
|
|
400
|
-
- No anticipatory abstractions (no traits with zero implementors)
|
|
401
|
-
- No wrappers around wrappers
|
|
402
|
-
- No codegen / embedded JS engine / workflow DSL
|
|
403
|
-
- No template/discovery system for agent roles (spawn flags + first
|
|
404
|
-
message ARE the definition)
|
|
405
|
-
- No render layer beyond `cli-table3` + `picocolors`, EXCEPT `ink`
|
|
406
|
-
confined to `src/cli/tui/`. NO second TUI stack alongside `ink`
|
|
407
|
-
(no `blessed` / `terminal-kit` etc.); if `ink` ever stops paying
|
|
408
|
-
off, REPLACE it, don't stack stacks.
|
|
409
|
-
- No plugin runtime, web UI, RPC, chat/docs integrations, memory
|
|
410
|
-
system, workflow engine
|
|
411
|
-
- Don't bundle pi (it's a peer dep)
|
|
412
|
-
|
|
413
|
-
### When in doubt: be small
|
|
414
|
-
|
|
415
|
-
Ship the smallest thing that works, then layer on as real friction
|
|
416
|
-
proves itself.
|
|
417
|
-
|
|
418
|
-
---
|
|
32
|
+
`tsc` is TypeScript 7 (fast typecheck). The `typescript` package is
|
|
33
|
+
aliased to 6.x on purpose: `tsup --dts` needs the programmatic API that
|
|
34
|
+
TS 7.0 lacks. Revisit at TS 7.1.
|
|
35
|
+
|
|
36
|
+
## Code style
|
|
37
|
+
|
|
38
|
+
- Strict TypeScript with `noUncheckedIndexedAccess`, ESM only. Use
|
|
39
|
+
`unknown` instead of `any`, and early returns instead of `!`.
|
|
40
|
+
- Throw typed error classes (`AgentNotFoundError`, `CycleError`,
|
|
41
|
+
`MuxError` and its `TmuxError` / `HerdrError` subclasses, …) so
|
|
42
|
+
`handle()` maps each to an exit code.
|
|
43
|
+
- Auto-fix sort and format with `npx biome check --write src test`.
|
|
44
|
+
Never add `--unsafe`: it rewrites `delete process.env.X` into
|
|
45
|
+
`process.env.X = undefined`, which sets the string `"undefined"`.
|
|
46
|
+
Delete env vars as `const key = "FOO"; delete process.env[key];`.
|
|
47
|
+
- Files cap at 1500 LOC. Refactor at 800.
|
|
48
|
+
- Layout is flat at the `src/` root. One level of subdirectory is
|
|
49
|
+
allowed for a cohesive cluster: one theme, imports only from the
|
|
50
|
+
cluster to root files, and a row in the ARCHITECTURE module map.
|
|
51
|
+
|
|
52
|
+
## Tests
|
|
53
|
+
|
|
54
|
+
- Unit tests use real SQLite in a temp dir and a mocked multiplexer.
|
|
55
|
+
Install mocks with `installMux()` from `test/_mux.ts`: it sets the
|
|
56
|
+
backend and its executor together and returns one `restore()`.
|
|
57
|
+
- TUI tests render through `test/_ink-render.ts` (see `test/README.md`).
|
|
58
|
+
- The fast tier (`*.test.ts`) stays in-process: mocked tmux and VCS,
|
|
59
|
+
per-test temp DBs, no real tmux/git/jj/sl, no sleeps over 50ms.
|
|
60
|
+
- Name full-only tests `*.integration.test.ts`. They may use real
|
|
61
|
+
tmux, herdr, VCS fixtures, or subprocesses. Real-tmux tests skip
|
|
62
|
+
without `$TMUX`. Set `process.env.MU_SPAWN_LIVENESS_MS = "0"` in
|
|
63
|
+
`beforeEach` when the spawned process is meant to live long.
|
|
64
|
+
- Integration tests use unique session names
|
|
65
|
+
(`mu-test-<pid>-<ts>-<rand>`), poll (50ms × 10) instead of sleeping,
|
|
66
|
+
and wrap `afterEach` cleanup in `try {} catch {}`. Unit tests call
|
|
67
|
+
`setSleepForTests(async () => {})`.
|
|
68
|
+
- **Never stop the herdr server or kill its process from a test.** It
|
|
69
|
+
destroys the user's real panes. herdr isolation is only a named
|
|
70
|
+
session (`MU_HERDR_SESSION`, enforced by `assertHerdrIsolated()`), so
|
|
71
|
+
close only what you created.
|
|
72
|
+
- `openDb()` refuses the real DB under vitest. Use `MU_DB_PATH` or
|
|
73
|
+
`{ path }`.
|
|
74
|
+
- `test/_setup.ts` clears inherited `MU_*` vars except
|
|
75
|
+
`MU_TMUX_SOCKET`. Opt in per test with `withEnv()` from `test/_env.ts`.
|
|
76
|
+
- `test/_global-teardown.ts` kills every `mu-*` tmux session on the
|
|
77
|
+
default socket that has no workstream in your real DB.
|
|
78
|
+
- Workers run `npm run test` concurrently. A test that fails
|
|
79
|
+
under load but passes alone is a test-infra concurrency bug (shared
|
|
80
|
+
`/tmp`, sockets, leaked subprocesses). One that also fails alone is a
|
|
81
|
+
real bug.
|
|
82
|
+
- `test/acceptance.integration.test.ts` is the end-to-end gate. Keep it
|
|
83
|
+
green.
|
|
84
|
+
|
|
85
|
+
## Change rules
|
|
86
|
+
|
|
87
|
+
- **VOCABULARY first.** Add or rename a term in
|
|
88
|
+
[docs/VOCABULARY.md](docs/VOCABULARY.md) before or with the code.
|
|
89
|
+
- **Roadmap gate.** Build only what is on the roadmap or meets all
|
|
90
|
+
three promotion criteria: a real user hit the gap ≥2 times, the
|
|
91
|
+
current design makes it straightforward, and it fits in <300 LOC.
|
|
92
|
+
Otherwise add a ROADMAP entry and move on.
|
|
93
|
+
- **Commits:** one logical change each, scope prefix when useful
|
|
94
|
+
(`schema: …`). The body says what changed and why, cites the VISION
|
|
95
|
+
pillar or ROADMAP item, and states that the green gate passed. Add a
|
|
96
|
+
[CHANGELOG.md](CHANGELOG.md) entry under the upcoming version.
|
|
419
97
|
|
|
420
98
|
## Common tasks
|
|
421
99
|
|
|
422
|
-
###
|
|
423
|
-
|
|
424
|
-
1.
|
|
425
|
-
`
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
1.
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
`
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
sequence in `sendToPane` (naive `tmux send-keys "<text>"` is broken —
|
|
510
|
-
`/`, `?`, `f` get eaten by the agent's TUI), while herdr's
|
|
511
|
-
`agent prompt` is one atomic call. Do not port the tmux workaround
|
|
512
|
-
to herdr.
|
|
513
|
-
|
|
514
|
-
### "Fix a flaky integration test"
|
|
515
|
-
|
|
516
|
-
Integration tests against real tmux can be slow because tmux/sh
|
|
517
|
-
processes need time to settle. Use:
|
|
518
|
-
|
|
519
|
-
- Unique session names (`mu-test-<pid>-<ts>-<random>`) so parallel
|
|
520
|
-
runs never collide.
|
|
521
|
-
- Polling loops (50ms × 10 attempts) when waiting for state to
|
|
522
|
-
propagate, not fixed sleeps.
|
|
523
|
-
- `try { ... } catch {}` cleanup in `afterEach` for tmux session
|
|
524
|
-
kills and DB closes — a failure mid-test should never block the
|
|
525
|
-
next.
|
|
526
|
-
- `setSleepForTests(async () => {})` in unit tests so the real
|
|
527
|
-
`MU_SEND_DELAY_MS` doesn't slow them.
|
|
528
|
-
- `process.env.MU_SPAWN_LIVENESS_MS = "0"` in integration-test
|
|
529
|
-
`beforeEach` to skip the 1500ms post-spawn check (the unit-test
|
|
530
|
-
suite covers it).
|
|
531
|
-
|
|
532
|
-
---
|
|
100
|
+
### Add a CLI verb
|
|
101
|
+
|
|
102
|
+
1. Write the SDK function (`src/agents.ts`, `src/tasks.ts`, …) with a
|
|
103
|
+
typed result (`{ changed, previousStatus, … }`). Test with mocks.
|
|
104
|
+
2. Wire it in `src/cli.ts` with commander inside `handle(...)`. For
|
|
105
|
+
`--workstream`, read `this.optsWithGlobals()`; the top-level option
|
|
106
|
+
otherwise swallows it.
|
|
107
|
+
3. Document it in the matching `docs/guide/` how-to, VOCABULARY if
|
|
108
|
+
it adds a term, and CHANGELOG. Remove any `mu sql` workaround it
|
|
109
|
+
replaces. Touch `skills/mu/SKILL.md` only for a gotcha `--help`
|
|
110
|
+
cannot state.
|
|
111
|
+
4. Smoke-test against real tmux, and on herdr with `MU_MUX=herdr` plus
|
|
112
|
+
a private `MU_HERDR_SESSION` if it touches agents:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
MU_SYNC_DIR= MU_DB_PATH=/tmp/mu-smoke.db node dist/cli.js <verb> ...
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Blank `MU_SYNC_DIR` too. Otherwise the first flush writes the
|
|
119
|
+
throwaway DB's `machine_id` into your real sync folder, and `mu sync`
|
|
120
|
+
lists that phantom peer forever.
|
|
121
|
+
|
|
122
|
+
### Update the schema
|
|
123
|
+
|
|
124
|
+
The schema is v11 (`CURRENT_SCHEMA_VERSION` in `src/db.ts`), applied by
|
|
125
|
+
`applySchema(db)` as idempotent CREATE-IF-NOT-EXISTS. `openDb` refuses
|
|
126
|
+
older DBs (`SchemaTooOldError`) and newer ones (`SchemaTooNewError`),
|
|
127
|
+
both exit 4. There is no migration ladder.
|
|
128
|
+
|
|
129
|
+
1. Bump `CURRENT_SCHEMA_VERSION` and mirror the shape in
|
|
130
|
+
`CURRENT_SCHEMA`. Prefer additive or idempotent-drop changes. Write
|
|
131
|
+
a one-shot migration script only when neither works.
|
|
132
|
+
2. Classify every new table in `PORTABLE_TABLES` or
|
|
133
|
+
`MACHINE_LOCAL_TABLES`. `test/entities.test.ts` fails otherwise.
|
|
134
|
+
3. Update `test/db.test.ts` and CHANGELOG `### Changed`.
|
|
135
|
+
|
|
136
|
+
### Add a multiplexer operation
|
|
137
|
+
|
|
138
|
+
Call sites use `await activeMux()` and never name a backend.
|
|
139
|
+
|
|
140
|
+
1. Add the method to `MuxBackend` (`src/mux/types.ts`) with a comment
|
|
141
|
+
saying what it means.
|
|
142
|
+
2. Implement it in `src/mux/tmux.ts` and `src/mux/herdr.ts`. A backend
|
|
143
|
+
with no equivalent no-ops instead of throwing.
|
|
144
|
+
3. If only one backend can do it, make it optional and branch on the
|
|
145
|
+
method's presence, not on `mux.name`.
|
|
146
|
+
4. Let `NoMultiplexerError` propagate (exit 5) for load-bearing calls
|
|
147
|
+
(spawn, send, kill). Wrap best-effort calls in try/catch, like
|
|
148
|
+
`resolveWorkerIdentity` in `src/tasks/claim.ts`.
|
|
149
|
+
|
|
150
|
+
Run tmux only through `tmux(args)` and herdr only through
|
|
151
|
+
`herdr(args)`. pi agents are driven through the control socket, not
|
|
152
|
+
the multiplexer. For non-pi agents and `--via mux`, tmux needs the
|
|
153
|
+
bracketed-paste sequence in `sendToPane`, while herdr's `agent prompt`
|
|
154
|
+
is one atomic call. Keep the tmux workaround out of herdr.
|
|
155
|
+
|
|
156
|
+
## Known traps
|
|
157
|
+
|
|
158
|
+
- **Silent `node dist/cli.js --help`** with "Detected unsettled
|
|
159
|
+
top-level await" is an import cycle: a file in `src/cli/tui/`
|
|
160
|
+
imported `../../../cli.js`. Import from the real source module
|
|
161
|
+
instead (`rg 'from "\.\./\.\./\.\./cli\.js"' src/cli/tui/`).
|
|
162
|
+
- **ANSI in ink `<Text>`** breaks wrap math. Pre-wrap by visual width
|
|
163
|
+
with `src/cli/tui/wrap-ansi.ts` and pad lines to the box width.
|
|
164
|
+
- **A key or click lands in the wrong popup**: a stale mouse event was
|
|
165
|
+
replayed. Consume it once, as `src/cli/tui/use-popup-action-queue.ts`
|
|
166
|
+
does.
|
|
167
|
+
- **A hint for one popup** goes in its `hint` prop, not the global
|
|
168
|
+
`POPUP_DRILL_HINTS`.
|
|
169
|
+
|
|
170
|
+
## Orchestrating on this repo
|
|
171
|
+
|
|
172
|
+
Follow the loop in [skills/mu/SKILL.md](skills/mu/SKILL.md). Repo specifics:
|
|
173
|
+
|
|
174
|
+
- Each workspace runs `npm install` into its own `node_modules`. Never
|
|
175
|
+
symlink main's.
|
|
176
|
+
- `mu task wait` may list commits already on main when a worker forked
|
|
177
|
+
from an old HEAD. Check `git log` in the workspace and cherry-pick
|
|
178
|
+
only the new shas.
|
|
179
|
+
- CHANGELOG.md conflicts are routine: keep both halves in order.
|
|
180
|
+
Resolve source conflicts by hand, never with `--ours` or `--theirs`.
|
|
181
|
+
- Fix a worker's bug in a separate commit after the cherry-pick. Do
|
|
182
|
+
not amend it.
|
|
183
|
+
- Gate the merged tree with the full gate below plus
|
|
184
|
+
`node dist/cli.js --help`.
|
|
185
|
+
- The installed `mu` may be older than the branch build. Confirm a
|
|
186
|
+
worker received its brief (`mu agent read <w> -n 3`).
|
|
533
187
|
|
|
534
188
|
## Skill files are context, not documentation
|
|
535
189
|
|
|
536
|
-
`skills/mu/SKILL.md`
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
-
|
|
555
|
-
|
|
556
|
-
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
a DO/DON'T section was the orchestrator loop written twice — 675 words removed
|
|
566
|
-
with nothing lost. And a warning about wedging a host existed in the file while
|
|
567
|
-
the agent that wedged the host never saw it, because it sat 350 lines from the
|
|
568
|
-
section it applied to. **A skill that sprawls stops being read**, which makes
|
|
569
|
-
sprawl a correctness problem, not a tidiness one.
|
|
570
|
-
|
|
571
|
-
---
|
|
572
|
-
|
|
573
|
-
## What NOT to do
|
|
574
|
-
|
|
575
|
-
- **Don't pad the skill files.** They are context, not docs, and
|
|
576
|
-
`--help` is the verb list. See § Skill files are context, not
|
|
577
|
-
documentation.
|
|
578
|
-
- **Don't add a config file.** mu is CLI flags + env vars.
|
|
579
|
-
- **Don't add a daemon, watcher, or background process.** Every
|
|
580
|
-
invocation is short-lived.
|
|
581
|
-
- **Don't add abstractions for hypothetical future flexibility.**
|
|
582
|
-
Two real impls today, or use a concrete type. (Cautionary tale: a
|
|
583
|
-
prior internal runtime's `RunContext` trait with zero implementors.)
|
|
584
|
-
- **Don't grow stream wrappers around stream wrappers.**
|
|
585
|
-
(`TextStream` / `TextState` / `StreamResult`.)
|
|
586
|
-
- **Don't generate JS strings as a "typed protocol."**
|
|
587
|
-
- **Don't put state-snapshot/handle layering on top of SQLite.**
|
|
588
|
-
SQLite is the canonical state. Read it directly; don't introduce
|
|
589
|
-
a `MuStateHandle` facade.
|
|
590
|
-
- **Don't add a template/discovery system for agent roles** until
|
|
591
|
-
pattern promotion criteria are met.
|
|
592
|
-
- **Don't bundle pi.** It's a peer dep, optional.
|
|
593
|
-
- **Don't write to files outside `~/.local/state/mu/` or the
|
|
594
|
-
project repo** without documenting why.
|
|
595
|
-
- **Don't promote a roadmap item to "shipped"** unless its
|
|
596
|
-
promotion criteria in [docs/ROADMAP.md](docs/ROADMAP.md) are met.
|
|
597
|
-
|
|
598
|
-
---
|
|
190
|
+
`skills/mu/SKILL.md` loads into every orchestrator's context, and
|
|
191
|
+
`skills/mu/REMOTE_WORKERS.md` on demand. Every word competes with the
|
|
192
|
+
user's work. Read the `writing-for-agents` skill before you edit
|
|
193
|
+
either one.
|
|
194
|
+
|
|
195
|
+
- Leave verb lists, flags, and option tables to `--help`. The skill
|
|
196
|
+
carries only what `--help` cannot: the gotcha, the reason, the trap.
|
|
197
|
+
- Say each thing once, next to where it applies.
|
|
198
|
+
- SKILL.md holds the trigger and the rule. Detail that only some
|
|
199
|
+
branches need goes in REMOTE_WORKERS.md.
|
|
200
|
+
- Delete sentences the model obeys by default. State the target
|
|
201
|
+
behaviour.
|
|
202
|
+
|
|
203
|
+
A commit that grows SKILL.md must say why. "The new verb needed
|
|
204
|
+
documenting" is not a reason.
|
|
205
|
+
|
|
206
|
+
## What not to do
|
|
207
|
+
|
|
208
|
+
- No config file. mu is CLI flags plus env vars.
|
|
209
|
+
- No daemon, watcher, or background process. Every invocation is
|
|
210
|
+
short-lived.
|
|
211
|
+
- No abstraction without two real implementations today.
|
|
212
|
+
- No wrappers around wrappers, no JS-string codegen, no facade over
|
|
213
|
+
SQLite (it is the canonical state; read it directly).
|
|
214
|
+
- No template or discovery system for agent roles.
|
|
215
|
+
- No render layer beyond `cli-table3` + `picocolors`, except `ink`
|
|
216
|
+
inside `src/cli/tui/`. Never a second TUI stack.
|
|
217
|
+
- Don't bundle pi. It is an optional peer dependency.
|
|
218
|
+
- Write files only under `~/.local/state/mu/` or the repo.
|
|
599
219
|
|
|
600
220
|
## When you're done
|
|
601
221
|
|
|
602
|
-
Before opening a PR or marking a task complete:
|
|
603
|
-
|
|
604
222
|
```bash
|
|
605
223
|
npm run typecheck && npm run lint && npm run test:fast && npm run test && npm run build
|
|
606
224
|
```
|
|
607
225
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
Checklist for any non-trivial change:
|
|
612
|
-
|
|
613
|
-
- [ ] If you added a typed verb, the corresponding `mu sql`
|
|
614
|
-
workaround row was removed from `docs/USAGE_GUIDE.md`.
|
|
615
|
-
- [ ] If you added vocabulary, `docs/VOCABULARY.md` has the new
|
|
616
|
-
entry.
|
|
617
|
-
- [ ] If you changed an architectural seam,
|
|
618
|
-
`docs/ARCHITECTURE.md` is updated.
|
|
619
|
-
- [ ] [CHANGELOG.md](CHANGELOG.md) has an entry under the upcoming
|
|
620
|
-
version.
|
|
621
|
-
|
|
622
|
-
That's it. Be small, be typed, follow the conventions, ship clean
|
|
623
|
-
green builds.
|
|
226
|
+
Then check that VOCABULARY, ARCHITECTURE, and CHANGELOG reflect the
|
|
227
|
+
change.
|