# How to recover from a broken state

Start with `mu doctor`. Each row that is not `ok` prints the command
that fixes it. mu reports and never cleans up for you, because an
orphan directory can hold the only copy of uncommitted work. Agents
read the same rules in
[recipes/recovery.md](../../skills/mu/recipes/recovery.md).

```bash
mu doctor           # exit 0 healthy (WARN rows too), 5 on drift or a FAIL row
mu doctor --deep    # rebuild the ops log and diff every field; PRAGMA quick_check on the DB
mu doctor --disk    # add per-worktree byte usage
```

## An agent's pane died

Run `mu agent list` or `mu state -w <ws>`. Each run reconciles the registry
with the multiplexer:

- An agent row whose pane is gone is a ghost. mu deletes the row, and
  its `IN_PROGRESS` task returns to `OPEN`. A `mu wait` on that
  task exits 6.
- A pane in the session that runs an agent CLI but has no row is an
  orphan. mu lists it and does not register it. Close the pane with
  tmux or herdr, or ignore it.

A `mu agent spawn --task` after a dead worker, with the same attempt
key but a new request, is refused (`already ran with a different
request`): pass `--attempt <new key>`.

## A pi agent shows `ctl missing` or `ctl refused`

mu reaches pi agents only through the control socket, and never falls
back to pasting.

| State | Means | Fix |
| ----- | ----- | --- |
| `ctl missing` | no socket: the extension is not loaded, or a new pi waits at its trust prompt | answer the [trust prompt](#a-new-pi-agent-shows-ctl-missing), or run `pi install npm:@mu-crew/mu`, then respawn the agent |
| `ctl refused` | the socket exists but does not answer | respawn the agent; for a remote agent, check the ssh forward |
| `extension X older than installed Y` or `extension lacks ops` | pi loaded an older mu build | send `/reload`, or respawn |

To send `/reload` without attaching:

```bash
mu agent send worker-1 -w auth '/reload'   # extension serves op command
```

An extension without op command cannot be reloaded by mu: respawn the
agent. `/reload` keeps the pi session. A `send --fresh` or `abort`
against an outdated extension fails with exit 4 and prints the fix.

## A new pi agent shows `ctl missing`

pi asks whether to trust a project folder on first start. It asks
before it loads extensions, so the agent has no control socket yet:
mu shows `unknown (ctl missing)` and spawn warns after 30 s. A pi
launched through a wrapper whose name is not `pi` or `pi-meta` shows
`needs_input` instead. Run
`/trust` in the pane once, or spawn with
`--command 'pi --approve'`. `--approve` trusts every directory,
including worktrees, so use it only on your own code.

Claude asks the same on an untrusted folder, with "No, exit" as the
default. Spawn warns and skips `--send`: attach the pane, answer it, then
`mu agent send`.

## You closed your terminal

The tmux session keeps running. Reattach with `tmux attach -t mu-auth`.
Every `mu` command is a short process that reads the DB, so nothing
needs restarting.

## You ran the wrong command

Every action is one group of ops. `mu log` shows the group ids, and
`mu log --group <prefix>` shows what one action wrote. Any unique prefix
of a group id works. mu has no general undo: fix a wrong change with the
inverse verb.

## `mu doctor` reports drift

Drift means the ops log and the live tables disagree. `--deep` names
the table, key, and field. Do not rebuild by reflex: if capture missed
a write, the live table holds real work that a rebuild would discard.

```bash
mu db backup /tmp/mu-drift-evidence.db     # 1. keep the evidence
mu rebuild /tmp/mu-rebuilt.db              # 2. replay the log into a new file
MU_DB_PATH=/tmp/mu-rebuilt.db mu db query "SELECT local_id, title FROM tasks"   # 3. compare
```

Decide which side is right, then report the drift as a bug with the
named field. `mu rebuild` never writes in place. It prints the swap
command.

## The `disk` section of `mu doctor` warns

| Row | Means |
| --- | ----- |
| `ws-rows` | a worktree row whose directory is gone; a reused name trips over it. `mu agent close <agent>` forgets it |
| `ws-staging` | a `--worktree` spawn killed (SIGKILL, crash) before its pane: its placeholder row and maybe a half-made worktree. The next `mu agent spawn` in that workstream removes them |
| `ws-empty` | a workstream directory with no worktrees |
| `db-copies` | stray `mu.db*` files that nothing reads, including the `pre-compact` / `pre-forget` backups |
| `exports` | output left by the removed export verb |
| `locks` | lock directories older than one hour, from a spawn or flush that died |

The worktree registry outlives the agent, so a worktree whose agent was
reaped is still closed by name: `mu agent close <agent>` keeps unmerged
commits on a branch and refuses dirty work (`--discard` drops it). A
directory mu never registered has no row: inspect it, then remove it with
`git worktree remove --force <path>` from the project root, or `rm -rf
<path>` when it is not a worktree.

## Rename a workstream

There is no rename verb, and `mu db query` refuses to change
`workstreams.name`. The name is part of the key that every op is filed
under, so a raw rename leaves the ops log on the old name: `mu doctor`
reports drift, and sync or `mu rebuild` brings the old name back.
Re-create the workstream instead:

```bash
mu db backup /tmp/mu-before-rename.db
mu workstream init auth-refactor
# re-add the tasks you still need, with -w auth-refactor
mu workstream teardown auth      # preview, then --if <rev>
```

Names start with a lowercase letter, use letters, digits, `_`, or
`-`, are at most 32 characters, and do not start with `mu-`.

## Report a bug

Include the exact command, its full output, the `environment` block of
`mu doctor`, and your platform. To reproduce without your real data,
set `MU_DB_PATH=/tmp/mu-debug.db` and `MU_SYNC_DIR=` (empty).
