@martintrojer/mu 0.3.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.
@@ -0,0 +1,349 @@
1
+ # Vocabulary
2
+
3
+ Canonical terms for mu. **Use these exact words in code, docs, error
4
+ messages, and the LLM-facing skill.** When two words could mean the
5
+ same thing, the one in this doc wins.
6
+
7
+ This document is the source of truth. If another doc uses a term not
8
+ defined here, fix the doc. If you need a new term, add it here first.
9
+
10
+ ---
11
+
12
+ ## TL;DR — canonical terms
13
+
14
+ | Use this | For… | Don't use |
15
+ | --------------------- | ------------------------------------------------------------------------ | -------------------------------------------------- |
16
+ | **workstream** | The unit of organization. One workstream = one tmux session = one DB partition | "project", "session" (ambiguous), "context" |
17
+ | **tmux session** | The literal tmux session a workstream lives in | "session" alone (ambiguous) |
18
+ | **window** | A tmux window (tmux's tabs); identified by `window_name` | "tab" (except as the frontmatter field name) |
19
+ | **pane** | A tmux pane (one shell view inside a window); identified by **stable pane id** like `%15` | "terminal", "shell" |
20
+ | **pane title** | The string set on a pane via `select-pane -T`. **Equals the agent's name.** Read by the claim protocol. | "pane name" |
21
+ | **window name** | The tmux window's name. **Equals the agent's `tab:` value** (groups one or more agents). | "tab name" (in code; `tab:` only in frontmatter) |
22
+ | **agent** | A named worker running in a pane; identity = pane title; row in `agents` table | "subagent" (reserved for pi-subagents), "worker" (only the specific role) |
23
+ | **worker** | An **agent** in its role-as-task-claimer. Synonym for the registered side of identity — a row in `agents`, owns tasks via the FK. | (when ambiguous, prefer **agent**) |
24
+ | **actor** | The party that *caused* a state change. May or may not be a registered worker. Recorded in `agent_logs.source` for every event. The orchestrator running mu from a top-level shell is an actor but not a worker. | "caller", "author" (only on notes) |
25
+ | **crew** | *Informal* collective noun for the agents in a workstream | (no API surface; prose only) |
26
+ | **task** | A node in the DAG. Has mandatory `impact` and `effort_days`. Status one of `OPEN`, `IN_PROGRESS`, `CLOSED`, `REJECTED`, `DEFERRED` (see **task status** below). | "issue", "ticket", "item" |
27
+ | **task status** | One of 5 states. **OPEN** = ready to be claimed; **IN_PROGRESS** = claimed and active; **CLOSED** = work completed (the only state that satisfies a `--blocked-by` edge); **REJECTED** = terminal 'won't do' (out of scope, duplicate, wontfix); **DEFERRED** = parked, may revisit. REJECTED and DEFERRED both still BLOCK downstream by design — only CLOSED unblocks. | "state" |
28
+ | **reject** | Verb: stamp a task `REJECTED`. Refuses if open dependents would be stranded; pass `--cascade` to apply to the whole sub-tree. | "wontfix", "close as wontfix" |
29
+ | **defer** | Verb: stamp a task `DEFERRED`. Same stranded-dependent guard as reject. Reopen with `mu task open`. | "park", "snooze", "backlog" |
30
+ | **task DAG** / **graph** | The directed acyclic graph of tasks. Cloned from a prior internal task-graph crate. | "task list", "todo", "tree" (it's a DAG, not a tree) |
31
+ | **edge** | A `blocks` relationship between two tasks. The single edge type. `A blocks B` = A must close before B can start. | "dependency" (use only in prose) |
32
+ | **track** | An independent subtree of the DAG identified by parallel-track detection | "branch", "lane" |
33
+ | **diamond merge** | When two tracks share a prerequisite, parallel-track detection collapses them into one track to prevent two agents from colliding on the shared dependency. | "join", "converge" |
34
+ | **ready** | An OPEN task with no unresolved blockers. Exposed as the `ready` SQL view. | "unblocked", "available" |
35
+ | **goals** | Tasks with no outgoing blocks-edges (graph endpoints). Exposed as the `goals` SQL view. | "leaves", "targets" |
36
+ | **sort key** | Argument to `mu task list / next / ready --sort <key>`. One of `roi` (impact / effort_days, default for `next` / `ready`), `recency` (`updated_at` DESC — "what did I touch most recently"), `age` (`created_at` ASC — "what's gone stale"), `id` (`local_id` ASC, default for `task list`). The two time-based keys also render an `updated`/`created` relative-time column in the table view. | "order by", "sort by" |
37
+ | **subtree** / **scope** | The set of tasks reachable from a root via blocks-edges | "subgraph" (only for technical descriptions) |
38
+ | **note** | An append-only piece of context attached to a task | "comment" (reserved for VCS), "log" (reserved for `agent_logs`) |
39
+ | **log entry** | A row in `agent_logs` (broadcast channel) | "message" (overloaded), "event" (overloaded) |
40
+ | **claim** | Verb: set `tasks.owner` to an agent. Atomic CAS. | "assign" (use only in prose), "lock" |
41
+ | **owner** | The **worker** name in `tasks.owner`. Set by claim. NULL when the task is unowned OR was claimed via `--self` (anonymous, attributed via `agent_logs.source` instead). | "claimer", "assignee" |
42
+ | **anonymous claim** | A claim made via `--self` where the **actor** isn't a registered **worker**. `tasks.owner` stays NULL; the actor is recorded in `agent_logs.source` for the auto-emitted `task claim` event. The orchestrator-doing-direct-work pattern. | "self-claim" (in code; "anonymous claim" in prose), "unowned claim" |
43
+ | **release** | Verb: clear `tasks.owner` | "unclaim", "unassign" |
44
+ | **free** | Verb: mark an agent's `status = 'free'` (idle, available) | "park", "idle" (verb) |
45
+ | **status** | Persisted enum on `agents` (busy/needs_input/free/...) | "state" (use only "lifecycle state") |
46
+ | **lifecycle state** | A position in the agent state machine | "state" alone, "phase" |
47
+ | **role** | `full-access` or `read-only` capability flag | "permission" (avoid), "tier" |
48
+ | **persistent** | Agent that stays alive across tasks | "long-lived" (only in prose) |
49
+ | **one-shot** | Agent that exists for a single task and then terminates | "ephemeral", "transient" |
50
+ | **workspace** | A VCS-isolated checkout (jj workspace / sl worktree / git worktree / cp) | "branch" (it has one but isn't one), "checkout" (only for `none` backend) |
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
+ | **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
+ | **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
+ | **backend** | Implementation of `AgentBackend` or `VcsBackend` | "driver", "provider" |
55
+ | **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
+ | **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" |
57
+ | **prune** | Verb: bulk-drop rows from the snapshots collection per a policy (`mu snapshot prune` with `--keep-last`, `--older-than <D>d`, `--stale-version`, `--all`, or the bare GC-policy form). Sibling of the auto-GC that runs on every capture; the explicit verb is for the dogfood case where the auto-GC's count + age caps need an operator-driven supplement (e.g. "drop every snapshot whose schema_version is now stale"). Surgical single-row removal is `mu snapshot delete <id>`. | "reap", "sweep" (overloaded by workstream-destroy --empty) |
58
+ | **export** | A directory of plain markdown files produced by `mu workstream export` (one `.md` per task + `INDEX.md` + `README.md` + `manifest.json`). Survives `mu workstream destroy` (auto-run pre-destroy to `<state-dir>/exports/<ws>-<ts>/` unless `--no-export`). Idempotent: re-export against the same dir rewrites only changed files; deleted tasks are preserved with a banner. Markdown-only by design — no HTML/PDF, no embedded VCS. The inverse is **import** (markdown only; never `.db`). | "dump", "snapshot" (snapshot is the binary `.db`) |
59
+ | **import** | The inverse of **export**: `mu workstream import <bucket-dir>` walks a v0.3 bucket directory and rebuilds every source-ws subdir as live tasks + edges + notes in the DB. Markdown-only by design (cross-machine `.db` is `mu undo` + snapshots). Per-source-ws transactional; refuses to merge silently into an existing workstream (use `--workstream <name>` for single-source rename, or destroy the existing one first). Owners reset to NULL on import (agents aren't restored); the original owner name survives in the markdown frontmatter. | "rehydrate", "restore" (restore = `mu undo`) |
60
+ | **archive** | An operator-named bucket of preserved task graphs (rows in `archives` + `archived_tasks` + `archived_edges` + `archived_notes` + `archived_events`). Cross-workstream and additive: one archive may accumulate snapshots from many workstreams under the same label. Outlives every source workstream; `archived_tasks.source_workstream` is intentionally TEXT (not an FK) so destroyed-workstream attribution survives. Distinct from a **snapshot** (binary whole-DB backup for `mu undo`) and an **export** (markdown files on disk). | "backup", "vault" |
61
+ | **archived task** | A row in `archived_tasks`: a snapshot of a `tasks` row at archive time. Pins `status`, `impact`, `effort_days`, `owner_name`, and the original `created_at`/`updated_at` for retrospect ordering. The `(archive_id, source_workstream, original_local_id)` composite UNIQUE makes `mu archive add` idempotent at the (archive, workstream) granularity. | "closed task" (status-orthogonal) |
62
+ | **archive label** | The operator-facing TEXT name of an **archive**. Globally unique across the machine (NOT per-workstream — archives outlive workstreams). Shape: `/^[a-z][a-z0-9_-]{0,63}$/` (wider than workstream names because labels often encode workstream + date + purpose, e.g. `auth-2026-q1`). | "archive name" (in code; `label` only) |
63
+ | **qualified ref** | An entity-arg form `<workstream>/<name>` that targets a specific workstream's task / agent / workspace without `-w`. Bare `<name>` still resolves via the standard chain (`-w` / `$MU_SESSION` / current tmux session). Mixing a qualified ref with a non-matching `-w` is rejected (`UsageError`). When a bare name appears AND no workstream resolves AND ≥2 workstreams contain that name, mu raises `NameAmbiguousError` (exit 4) listing every candidate as a qualified-form one-paste fix. | "fully-qualified id" (in prose), "prefixed name" |
64
+ | **doctor** | The diagnostic command + report | "health check", "diagnose" |
65
+ | **CLI** | The `mu` command-line binary | "tool" (overloaded), "binary" (only when relevant) |
66
+ | **extension** | The pi extension shipped in the same package | "plugin" |
67
+ | **skill** | The bundled SKILL.md that teaches the LLM | "system prompt", "instruction" |
68
+ | **DB** / **registry** | `~/.local/state/mu/mu.db` and its tables | "store", "database" (full word OK in prose) |
69
+ | **substrate** | An external system mu depends on (tmux, jj, sl, git, sqlite) | "dependency" (means npm dep), "service" |
70
+ | **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
+ | **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
+ | **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
+ ---
76
+
77
+ ## The topology, with terms labeled
78
+
79
+ ```
80
+ workstream (one mu instance, one DB partition)
81
+ ──────────
82
+ ┌─────────────────────────────────────────────────────────────────┐
83
+ │ tmux session: mu-auth-refactor │
84
+ │ ─────────── │
85
+ │ │
86
+ │ ┌──────────────────────────┐ ┌──────────────────────────────┐ │
87
+ │ │ window: Backend │ │ window: Review │ │
88
+ │ │ ───── │ │ ───── │ │
89
+ │ │ ┌──────────┐ ┌────────┐│ │ ┌────────────────────────┐ │ │
90
+ │ │ │ worker-1 │ │worker-2││ │ │ reviewer-1 │ │ │
91
+ │ │ │ pane │ │ pane ││ │ │ pane │ │ │
92
+ │ │ │ (pi) │ │ (pi) ││ │ │ (pi, role=read-only) │ │ │
93
+ │ │ │ agent │ │ agent ││ │ │ agent │ │ │
94
+ │ │ └──────────┘ └────────┘│ │ └────────────────────────┘ │ │
95
+ │ └──────────────────────────┘ └──────────────────────────────┘ │
96
+ │ │
97
+ │ the crew = { worker-1, worker-2, reviewer-1 } (informal) │
98
+ └─────────────────────────────────────────────────────────────────┘
99
+
100
+ partitioned by session_id in ~/.local/state/mu/mu.db
101
+ ```
102
+
103
+ **Identity convention:** the agent's name == the tmux **pane title**
104
+ (set by `select-pane -T <name>` on spawn). The window name comes from
105
+ the `tab:` frontmatter field and may group multiple agents in one
106
+ window.
107
+
108
+ This is what makes the claim protocol zero-config: an agent runs
109
+ `mu task claim foo` and mu reads `tmux display-message -p '#{pane_title}'`
110
+ to know who's claiming. **Read pane title (`#{pane_title}`), not
111
+ window name (`#W`)** — they are different when several agents share a
112
+ window.
113
+
114
+ ---
115
+
116
+ ## Status, lifecycle, and the verbs that touch them
117
+
118
+ ### Agent status enum (persisted in `agents.status`)
119
+
120
+ | Value | Icon | Meaning |
121
+ | ----------------- | ---- | --------------------------------------------------- |
122
+ | `spawning` | ⏳ | Pane created, agent process booting |
123
+ | `busy` | ⚙️ | Actively working (detector saw busy marker) |
124
+ | `needs_input` | 💤 | Idle prompt visible, waiting for input |
125
+ | `needs_permission`| 🔐 | Permission prompt visible (e.g., "Allow once") |
126
+ | `free` | ✓ | Marked available by user (`mu agent free`) |
127
+ | `managed` | 🤝 | Under external orchestration; mu observes only |
128
+ | `unreachable` | ❓ | Transport down, status uncertain |
129
+ | `terminated` | ✕ | Process gone, awaiting reaping |
130
+
131
+ **Source of truth:** the substrate (tmux + detector). The DB is a
132
+ cache; `mu agent list` reconciles on every call.
133
+
134
+ ### The four "stop talking to this agent" verbs — keep them straight
135
+
136
+ | Verb | Effect |
137
+ | --------------------- | --------------------------------------------------------------------------- |
138
+ | `mu agent free alice` | Sets `alice.status = 'free'`. Agent stays alive. Means "I'm done with you for now; you're available." |
139
+ | `mu release feature_a`| Clears `tasks.owner` for `feature_a`. The agent who claimed it is unaffected. |
140
+ | `mu agent close alice` | Terminates alice's pane and removes from registry. Destructive. |
141
+ | `mu detach alice` | (Future) Tmux-detaches alice's pane without killing the process. Not in v1. |
142
+
143
+ **Don't conflate `free` and `release`.** Free is about the *agent*;
144
+ release is about the *task*.
145
+
146
+ ### Verbs that move tasks through the lifecycle
147
+
148
+ | Verb | Effect |
149
+ | ------------------------------------- | ----------------------------------------------------- |
150
+ | `mu task add <id> ...` | Creates a new OPEN task |
151
+ | `mu task close/open/reject/defer <id>` | Lifecycle transition |
152
+ | `mu task claim <task> [--for <agent>]` | Atomic: sets `owner`, flips status to `IN_PROGRESS` |
153
+ | `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
+ | `mu task note <task> "..."` | Appends to `task_notes`. Never edits prior notes. |
155
+
156
+ ---
157
+
158
+ ## Mode of address — who is "you" in each surface?
159
+
160
+ When the docs/code say "you", it must be unambiguous which actor.
161
+
162
+ | Surface | "you" means |
163
+ | -------------------- | ---------------------------------------------------- |
164
+ | README.md | The human user installing/running mu |
165
+ | VISION.md | The human user |
166
+ | ARCHITECTURE.md | A developer working on mu's source |
167
+ | AGENTS.md (root) | An AI coding agent working on this repo |
168
+ | ROADMAP.md | A developer implementing one of the listed items |
169
+ | **SKILL.md** | **The LLM running inside an agent's pane** |
170
+ | Agent prompt bodies | The LLM running as that specific agent |
171
+ | `mu doctor` output | The human user running the diagnostic |
172
+ | Error messages | The caller (CLI user, script, or pi tool invocation) |
173
+
174
+ Avoid second-person across these surfaces unless the audience is
175
+ unambiguous.
176
+
177
+ ---
178
+
179
+ ## Reserved / avoided terms
180
+
181
+ These words show up in adjacent ecosystems and would confuse mu users.
182
+ Don't use them in mu code or docs:
183
+
184
+ | Avoided word | Why | Use instead |
185
+ | ---------------- | ---------------------------------------------------------------- | ---------------------------------------------------- |
186
+ | "subagent" | Pi-subagents owns this term in our ecosystem | "agent" (mu's unit) or quote `pi-subagents` explicitly |
187
+ | "session" | Pi has its own "session"; tmux has "session"; ambiguous alone | "workstream" (mu's unit) or "tmux session" (literal) |
188
+ | "project" | Means a `.pi/` project root; conflict with mu's organizational unit | "workstream" |
189
+ | "context" | Overloaded (LLM context, project context, fork context) | Be specific: "task context", "forked context", etc. |
190
+ | "tab" | Tmux has windows, not tabs. Pi-subagents and dg use "tab" as a frontmatter field; we keep that field for compatibility but use "window" everywhere else | "window" (in prose); only `tab:` in frontmatter |
191
+ | "thread" | OS threads + chat threads + git threads; bad word | Be specific |
192
+ | "message" | Overloaded (LLM message, log message, send-keys input) | "log entry" (for `agent_logs`), "send" (for input to a pane) |
193
+ | "config" | Already means the global mu config; don't reuse | Specific: "settings", "frontmatter", "options" |
194
+ | "manager" | Vague; everything could be a manager | The specific noun (e.g., "the registry", "the eval engine") |
195
+ | "service" | Implies long-running daemon; mu has none | Be specific |
196
+ | "plugin" | Pi has extensions, not plugins | "extension" |
197
+ | "instance" | Vague; could be agent / workstream / process | The specific thing |
198
+ | "broker" | Implies pub-sub middleware; we don't have one | "log entry" or be specific |
199
+ | "checkpoint" | Implies recoverable savepoints in the work; we have snapshots, which back up the DB | "snapshot" |
200
+ | "agent type" | "Type" implies a class hierarchy; mu has no class system | "agent role" (scout/reviewer/etc.) |
201
+ | "agent definition" / "agent template" / "agent role doc" | mu has no template/definition concept. Spawn flags + the orchestrator's prompt are the only "definition" | Just describe the spawn invocation directly |
202
+ | "worker" | "worker" is the name of one specific built-in agent | "agent" (general); "the worker" only when referring to that specific agent |
203
+ | "claimer" | Awkward; we have "owner" already | "owner" |
204
+
205
+ ---
206
+
207
+ ## Operations reference
208
+
209
+ The complete verb list lives in two places, both authoritative:
210
+
211
+ - **`mu --help`** and **`mu <verb> --help`** — the canonical CLI
212
+ reference. If anything below ever disagrees with `--help`, trust
213
+ `--help`.
214
+ - **[skills/mu/SKILL.md](../skills/mu/SKILL.md) § "CLI — complete
215
+ verb list"** — the LLM-facing one-pager with every verb, its
216
+ arguments, and a one-line description.
217
+
218
+ For worked examples of each verb, see
219
+ [USAGE_GUIDE.md](USAGE_GUIDE.md).
220
+
221
+ This document is a *vocabulary* doc; it doesn't try to be a verb
222
+ reference too.
223
+
224
+ ---
225
+
226
+ ## Naming conventions
227
+
228
+ ### IDs
229
+
230
+ - **Agent name**: lowercase, `[a-z][a-z0-9_-]*`, ≤32 chars. Used as
231
+ tmux window name verbatim. Unique within a workstream.
232
+ - **Task local_id**: same shape and rules. Unique within the DB.
233
+ - **Workstream name**: same shape; tmux session is `mu-<name>`.
234
+ - **Tab name (frontmatter `tab:`)**: human-friendly,
235
+ `[A-Za-z][A-Za-z0-9 _-]*`, ≤32 chars. Used as tmux window name when
236
+ multiple agents share the window.
237
+
238
+ ### Agent names: prefer `<role>-<n>`, not human names
239
+
240
+ Agents are workers with **roles**, not people. Pick names that
241
+ describe the role, with a numeric suffix when there are multiples:
242
+
243
+ Good: `worker-1`, `worker-2`, `reviewer-1`, `scout-1`, `auditor-1`,
244
+ `oracle-1`, `planner-1`
245
+
246
+ Avoid: `alice`, `bob`, `carol`, `revv`, `mallory`, `peon`, ...
247
+
248
+ Why: anthropomorphic (or status-loaded) names confuse the model
249
+ when reading commands ("alice claims design" sounds like a person;
250
+ "worker-1 claims design" is obviously a generic worker taking a
251
+ task). Role-based names also make `mu agent list` and tmux's window
252
+ list legible at a glance — you can see "three workers and a
253
+ reviewer" instead of decoding name salad.
254
+
255
+ The roles align with pi-subagents' role taxonomy:
256
+
257
+ `worker` long-lived implementer; the default
258
+ `reviewer` reads diffs/code; usually `--role read-only`
259
+ `scout` fast recon; one-shot, returns context
260
+ `oracle` second opinion before action
261
+ `auditor` long-lived watcher; `--role read-only`
262
+ `planner` designs implementation plans
263
+
264
+ If you have multiple agents in the same role, suffix with `-1`,
265
+ `-2`, ... (`worker-1`, `worker-2`).
266
+
267
+ This is a convention, not enforcement. mu's regex accepts any
268
+ `[a-z][a-z0-9_-]{0,31}` string. Test fixtures often use `alice`/`bob`
269
+ as placeholder names — that's fine for tests; just don't propagate
270
+ it to user-facing examples or actual workstreams.
271
+
272
+ ### File paths
273
+
274
+ XDG-Base-Directory-Spec compliant. The state directory resolves as:
275
+
276
+ `MU_STATE_DIR` > `$XDG_STATE_HOME/mu` > `~/.local/state/mu`
277
+
278
+ - `<state-dir>/mu.db` — the canonical SQLite database (shared across
279
+ all workstreams; partitioned by `workstream` columns)
280
+ - `<state-dir>/workstreams/<workstream>/` — per-workstream artifact
281
+ directory (created lazily); reserved for tracing logs / forensic
282
+ pane captures.
283
+ - `<state-dir>/workspaces/<workstream>/<agent>/` — per-agent VCS
284
+ workspace (created by `mu agent spawn --workspace` or
285
+ `mu workspace create`). Orphan dirs (no row in `vcs_workspaces`)
286
+ surfaced by `mu workspace orphans -w <workstream>` and
287
+ `mu state -w <workstream>`.
288
+ - `<state-dir>/snapshots/<id>.db` — whole-DB snapshots auto-captured
289
+ before destructive verbs (introduced in schema v4; carried forward).
290
+ Indexed by the `snapshots`
291
+ table; restore via `mu undo` (inspect via `mu snapshot list` /
292
+ `mu snapshot show <id>`). Default colocation: snapshots live
293
+ next to the live DB, so per-test isolation works without env
294
+ gymnastics.
295
+ - mu does NOT consult any agent-template directory. If pi-subagents
296
+ is installed, its `~/.pi/agent/agents/` and `.pi/agents/` paths
297
+ are pi-subagents' concern — not mu's.
298
+
299
+ ### Env vars (mu state location)
300
+
301
+ | Name | Effect | Precedence |
302
+ | ----------------- | ------------------------------------------------------------ | ---------- |
303
+ | `MU_DB_PATH` | Override the SQLite file path directly | wins over all |
304
+ | `MU_STATE_DIR` | Override the state directory | beats `XDG_STATE_HOME` |
305
+ | `XDG_STATE_HOME` | Standard XDG base-directory state path; `mu/` appended | default fallback chain |
306
+ | `MU_SESSION` | Override active workstream name (when not auto-detectable) | n/a |
307
+
308
+ ### Env vars passed to spawned children
309
+
310
+ | Name | Value |
311
+ | ---------------------------- | ---------------------------------------------------- |
312
+ | `MU_SESSION_ID` | Workstream identifier |
313
+ | `MU_AGENT_NAME` | This agent's name |
314
+ | `MU_PARENT_PANE` | Tmux pane ID of the spawning process |
315
+ | `MU_DB_PATH` / `MU_STATE_DIR` | Inherited from parent unless overridden |
316
+ | `XDG_STATE_HOME` | Inherited; mu uses `<XDG_STATE_HOME>/mu` by default |
317
+ | `MU_SEND_DELAY_MS` | Delay between bracketed paste and Enter (default `500`) |
318
+ | `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, the DB row is rolled back and `AgentDiedOnSpawnError` is thrown with the captured scrollback. |
321
+
322
+ These mirror pi-subagents' `PI_SUBAGENT_*` env vars in spirit but live
323
+ in a separate namespace so the two can coexist in one pi session.
324
+
325
+ ---
326
+
327
+ ## Type of "session"
328
+
329
+ Because "session" is overloaded, here are the four senses we encounter
330
+ and the disambiguated terms:
331
+
332
+ | Generic word | mu term used in docs/code | What it actually is |
333
+ | ------------ | ------------------------------------- | ------------------------------------------------ |
334
+ | session | **workstream** | mu's unit of organization |
335
+ | session | **tmux session** | The tmux process group `mu-<workstream>` |
336
+ | session | **pi session** | The thing pi calls a session (its conversation) |
337
+ | session | **agent session** (avoid in code) | Colloquial for "an agent's run/lifetime"; prefer "lifetime" or "the work alice has done" |
338
+
339
+ When writing code, say `workstream_id` not `session_id` in any new
340
+ column or variable name. The existing `agents.session_id` column name
341
+ is grandfathered for SQL-schema-stability reasons but should be
342
+ documented as "workstream id" in column comments.
343
+
344
+ <!-- The alphabetical glossary that used to live here was removed:
345
+ it duplicated the canonical-terms table at the top of this file,
346
+ drifted out of sync, and carried entries for rejected features
347
+ (capability, agent-frontmatter `persistent: false`, the JS DSL,
348
+ the `defineOperation` registry). The table is the single source.
349
+ For deeper background, follow the links the table rows carry. -->
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@martintrojer/mu",
3
+ "version": "0.3.1",
4
+ "description": "A persistent, observable crew of pi agents running in one tmux session per workstream, coordinated through a built-in task DAG.",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "type": "module",
9
+ "license": "MIT",
10
+ "author": "Martin Trojer <martin.trojer@gmail.com>",
11
+ "homepage": "https://github.com/martintrojer/mu",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/martintrojer/mu.git"
15
+ },
16
+ "bugs": {
17
+ "url": "https://github.com/martintrojer/mu/issues"
18
+ },
19
+ "keywords": [
20
+ "tmux",
21
+ "agents",
22
+ "ai",
23
+ "orchestration",
24
+ "task-graph",
25
+ "pi-coding-agent",
26
+ "pi-package"
27
+ ],
28
+ "engines": {
29
+ "node": ">=20 <24"
30
+ },
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ }
38
+ },
39
+ "bin": {
40
+ "mu": "./dist/cli.js"
41
+ },
42
+ "files": [
43
+ "dist",
44
+ "skills",
45
+ "docs",
46
+ "README.md",
47
+ "AGENTS.md"
48
+ ],
49
+ "scripts": {
50
+ "build": "tsup",
51
+ "dev": "tsup --watch",
52
+ "test": "vitest run",
53
+ "test:watch": "vitest",
54
+ "lint": "biome check src test",
55
+ "lint:fix": "biome check --write src test",
56
+ "format": "biome format --write src test",
57
+ "typecheck": "tsc --noEmit",
58
+ "prepare": "npm run build"
59
+ },
60
+ "dependencies": {
61
+ "better-sqlite3": "^11.8.0",
62
+ "cli-table3": "^0.6.5",
63
+ "commander": "^14.0.0",
64
+ "execa": "^9.5.2",
65
+ "picocolors": "^1.1.1",
66
+ "zod": "^3.24.1"
67
+ },
68
+ "devDependencies": {
69
+ "@biomejs/biome": "^1.9.4",
70
+ "@types/better-sqlite3": "^7.6.12",
71
+ "@types/node": "^22.10.7",
72
+ "tsup": "^8.3.5",
73
+ "typescript": "^5.7.3",
74
+ "vitest": "^2.1.8"
75
+ }
76
+ }