# Install (/docs/scruff/install)



scruff is a single Go binary with no runtime, no daemon, no port and nothing to
sign in to. Pick whichever of these you already have.

```sh
brew install hausfold/tap/scruff                          # from our tap
nix run github:hausfold/scruff                            # try it, install nothing
nix profile install github:hausfold/scruff                # keep it
go install github.com/hausfold/scruff/cmd/scruff@latest   # or, with Go 1.26+
```

The Homebrew entry lives in [hausfold/tap](https://github.com/hausfold/homebrew-tap)
and it compiles rather than unpacking a binary, so the first install downloads a
Go toolchain and takes a minute. Same version, same behaviour; the one other
difference is timing. `brew upgrade` follows the releases a few minutes behind,
because the tap builds and tests each new scruff formula before taking it. A
formula that stops building never lands: the tap keeps the previous release and
nothing announces it, so a `brew upgrade` that stays a version behind the
[releases](https://github.com/hausfold/scruff/releases) is that check holding,
not your Homebrew.

Then, from inside any git repo:

```sh
scruff --version
scruff            # an empty list is a working install
```

One more line is worth typing once, because nothing else will do it for you:

```sh
scruff skill install   # teach the agents on this machine that scruff exists
```

Without it an agent reaches for `git worktree add` and `git stash`, which is the
one footgun scruff exists to close. [For coding agents](/docs/scruff/agents) is
what the skills contain.

On a [haus](/docs/haus&#x29; machine every line above is already done, &#x2A;*⌘⏎**
included; [the AI room](/docs/haus/rooms/ai) owns that half.

## What it needs [#what-it-needs]

**`git`, and that is the hard requirement.** Two more are optional and both make
scruff sharper rather than possible:

|                                |                                                                                                                                                                                     |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`gh`](https://cli.github.com) | proves a branch **landed**, across squash, rebase and cherry-pick merges. Without it scruff falls back to the offline signals: ancestry, patch equivalence, and an empty merge tree |
| `lsof`                         | proves nobody is **standing in** a checkout. Without it, a lane says `occupied: null`, which means *undetermined* and never *free*                                                  |

Missing either one &#x2A;*degrades toward keep, never toward delete.** The command
still runs, exits **3** instead of 0, and says in `warnings` which signal it
could not get. scruff would rather leave you a branch to tidy up than take one it
could not prove was finished.

<Callout type="info" title="A container or a CI runner has no lsof to ask">
  Anywhere the process holding a checkout is not visible as a cwd, say so
  yourself with a **lease**: `scruff heartbeat` marks the checkout in use for as
  long as the calling process lives. See
  [occupancy](/docs/scruff/landing#who-is-standing-here).
</Callout>

## As a flake input [#as-a-flake-input]

```nix
inputs.scruff.url = "github:hausfold/scruff";
```

The flake exposes `packages.<system>.default` (the CLI) and
`packages.<system>.scruff-skill`, which is the
[agent surface](/docs/scruff/agents) on its own, so a machine can install the
skills with no Go toolchain and no binary. An overlay ships both under
`pkgs.scruff` and `pkgs.scruff-skill`.

## From source [#from-source]

```sh
git clone https://github.com/hausfold/scruff && cd scruff
make check      # gofmt, go vet, the unit tests and the bats acceptance suite
make build      # ./scruff
```

`nix develop` gives you a shell with Go, bats and `gh` already in it.
[`AGENTS.md`](https://github.com/hausfold/scruff/blob/main/AGENTS.md) in the repo
is the rest: what the invariants mean for a change, which contracts are frozen,
and why `make check` deliberately does not cover the SDKs.
