# Commands (/docs/scruff/cli)



`scruff --help` is the exhaustive list and it prints to **stderr**. This page is
the same surface, grouped by what you are trying to do.

`scruff <verb> --help` prints just that verb's lines and does nothing else, so
asking a question about an unfamiliar verb is safe even when the verb deletes.
A verb also refuses an argument it can't explain: exit 1, with nothing run.

## Lanes [#lanes]

|                              |                                                                                                                                                                                                                                                                                              |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scruff`                     | list every live and parked lane, across all repos                                                                                                                                                                                                                                            |
| `scruff <name>`              | resume one: rebuild its checkout, reopen its agent. `<repo>/<name>` to qualify · `--pick` to choose the session instead of the newest                                                                                                                                                        |
| `scruff focus <name>`        | go to the window a lane is already running in. Falls back to resume without a `focus` hook                                                                                                                                                                                                   |
| `scruff new [name]`          | a lane on **this** repo, path on stdout · `--open [agent]` / `--agent <id>` / `--cmd '<command>'`                                                                                                                                                                                            |
| `… --prompt '<task>'`        | open it on a first turn instead of a blank pane · `--prompt-file <file\|->` for a brief · `--image <file>`                                                                                                                                                                                   |
| `scruff child <repo>`        | a lane on **another** repo, as a child of this pane                                                                                                                                                                                                                                          |
| `scruff spawn <repo> <name>` | a named lane for a spawner with no pane of its own. Opened through `[hooks] open`, so **exit 3** means the lane exists and nothing put a window on it. `<name>` is optional with a `--prompt` and a namer configured, and goes in `--derived-name` when your caller derived it from the task |

**Type what the listing shows.** Every verb that takes a lane name
(`scruff <name>`, `focus`, `drop`, `reship`, `runtime up|enter|down`) resolves
it the same way: exact first, then a **unique prefix** of either part. The listing
budgets its cells to your window, so a long name arrives cut; paste the cut cell
back, ellipsis and all, and it still resolves. A prefix matching more than one
lane refuses, and names them.

## The tree [#the-tree]

|                       |                                                              |
| --------------------- | ------------------------------------------------------------ |
| `scruff park [label]` | set the working tree aside as a `wip:` commit on this branch |
| `scruff unpark`       | put the last parked commit's changes back, uncommitted       |

## The other lanes [#the-other-lanes]

|                      |                                                                                                                                                                                                                                                                                                                            |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scruff overlap`     | what the **other** lanes on this repo have already changed, and where their edits and yours land in the same region of the same file. Measured from the shared object store, uncommitted work included, nothing declared by anyone. Exit **3** same file, **4** same region or a `merge-tree` conflict; it refuses nothing |
| `… --brief`          | the roll call: every lane gets a row, even one that shares nothing, and the prose (the intent, the landing order) is dropped. The lane-start version                                                                                                                                                                       |
| `… --path <file>`    | that file only, and **silent when it is clear**. The shape a hook wants: the rows and the prose are stdout, the summary and the merge-tree heading stderr                                                                                                                                                                  |
| `… --committed-only` | read every lane from its branch alone, skipping the working trees                                                                                                                                                                                                                                                          |
| `… --pair <a> <b>`   | two named lanes against each other, from wherever you stand                                                                                                                                                                                                                                                                |
| `… --json`           | the same report as [one document](/docs/scruff/json#the-overlap-report), the exit code inside it                                                                                                                                                                                                                           |

From the main checkout it is lane against lane instead: every pair that shares a
file. [Working in lanes](/docs/scruff/lanes#notice-the-other-lanes) reads a
report.

## Cleanup [#cleanup]

|                        |                                                                                                            |
| ---------------------- | ---------------------------------------------------------------------------------------------------------- |
| `scruff reap`          | sweep every landed lane nobody is standing in. `--dead-ends` also retires the lanes nothing will ever land |
| `scruff reaped`        | what scruff has reaped, why, and the SHA to get it back                                                    |
| `scruff drop <name>`   | retire a lane whose work will never land (closed PR, archived repo). Recorded, undoable                    |
| `scruff reship [name]` | push a branch that outran its merged PR, and open the follow-up                                            |

## Machines [#machines]

|                           |                                                                                                          |
| ------------------------- | -------------------------------------------------------------------------------------------------------- |
| `scruff --json`           | the listing, machine-readable. Same as `scruff list --json`                                              |
| `scruff watch --json`     | lifecycle events on stdout, one NDJSON object per line                                                   |
| `scruff heartbeat [path]` | hold the occupancy lease on a lane, so `reap` spares it · `--pid N` (`0` for TTL-only) · `--release`     |
| `scruff hook create`      | open a lane from a client's hook: JSON on stdin, path on stdout                                          |
| `scruff hook remove`      | retire one without losing work: JSON on stdin                                                            |
| `scruff hook notify`      | client events into a [trill](/docs/trill) banner for the lane. Exit 0 always, silent no-op without trill |

## Runtimes [#runtimes]

|                                              |                                                                      |
| -------------------------------------------- | -------------------------------------------------------------------- |
| `scruff runtime up <name> --backend <id>`    | stand up a lane's isolation backend. `--backend` is required, always |
| `scruff runtime enter <name> --backend <id>` | drop into it interactively                                           |
| `scruff runtime down <name> --backend <id>`  | tear it down                                                         |
| `scruff runtime eject tart`                  | print the built-in backend as an adapter file to edit                |

## Maintenance [#maintenance]

|                                |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scruff doctor`                | diagnose this machine and the repo you're standing in: the base and how it resolved, git, the forge CLI and whether it is authenticated, occupancy, whether the filesystem can reflink, submodules / LFS / sparse-checkout, every remote and the identity it would give, which rung answered the default-branch question, then the findings: remotes that disagree about who the repo is, a repo with no remote at all, stale registry rows, stray checkouts, orphan branches, lanes whose conversation was left at a path they no longer live at, disk per repo. `--json` for the same as data |
| `scruff doctor --migrate-base` | move the base to `~/.cache/scruff`. Refuses with exit 2 while any lane is occupied, repairs every checkout, takes each lane's conversation with it, leaves the old path a symlink                                                                                                                                                                                                                                                                                                                                                                                                               |
| `scruff skill [<name>]`        | print an [agent skill](/docs/scruff/agents): scruff's own, or `handoff`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `scruff skill install`         | write every skill into every agent client on the machine. `--client claude\|codex\|opencode\|pi` or `--dir <path>` to name one                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `scruff --version`             | print the version                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |

## Exit codes [#exit-codes]

Six, and they are a [frozen contract](/docs/scruff/json#what-is-frozen). Each
one means a different next move:

|       |                                                                                                                          | what to do                                      |
| ----- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------- |
| **0** | success, including "nothing to do"                                                                                       | report what happened                            |
| **1** | usage or precondition error                                                                                              | fix the invocation                              |
| **2** | **refused for safety**: occupied, dirty, or not provably landed                                                          | this is scruff working. Don't force it, ask why |
| **3** | degraded: it completed, but a signal was unavailable. For `overlap`, the quiet finding: the same file, different regions | report the caveat                               |
| **4** | conflict found: `overlap` saw the same region, or `merge-tree` saw a conflict                                            | a finding, not an error. Somebody resolves it   |
| **5** | the registry is locked by another scruff                                                                                 | another scruff is mid-operation. Retry shortly  |

`2` versus `1` is the distinction the whole table exists for: a wrapper script
has to be able to tell "you asked wrong" apart from "I declined to destroy
something".
