---
title: Install, Update & Adopt
topic: install
description: Installing via npm/Homebrew/plugin, keeping current, and adopting scaffold into a new or existing project
category: reference
order: 25
---

## Overview

Scaffold ships as one tool with two install surfaces: the **`scaffold` CLI**
(distributed on npm as `@zigrivers/scaffold` and via Homebrew) and an optional
**Claude Code plugin** that auto-activates the runner and pipeline-reference
skills. The CLI is the core; the plugin only adds interactive guidance on top of
it. The published npm package exposes the single `scaffold` binary
(:cite[package.json:37]) and bundles the compiled CLI plus the pipeline content,
knowledge entries, and skills (:cite[package.json:27]).

This guide is for **users** installing, updating, and bootstrapping projects.
Maintainers releasing Scaffold itself follow a separate flow in
`docs/architecture/operations-runbook.md` :cite[docs/architecture/operations-runbook.md:326]{mode=advisory}.

:::callout{type=note}
**Prerequisite — Node.js 18.17+.** The CLI requires Node.js `>=18.17.0`
(:cite[package.json:34]). The Homebrew formula installs and manages Node as a
dependency, so you don't install Node separately; the npm install uses your
system Node.
:::

## Installing

Pick one of the three surfaces below. The npm and Homebrew tabs install the CLI;
the plugin tab adds the optional Claude Code skills on top.

::::tabs
:::tab{title="npm"}
```bash
npm install -g @zigrivers/scaffold
```
Verify with `scaffold version`. This is the recommended path — it uses your
system Node and updates with `npm update -g`.
:::
:::tab{title="Homebrew"}
```bash
brew tap zigrivers/scaffold
brew trust zigrivers/scaffold   # only if the next command refuses the tap
brew install scaffold
```
The formula installs and manages Node as a dependency, so no separate Node
install is needed. Verify with `scaffold version`.

Newer Homebrew refuses to load a formula from a tap it doesn't trust. If you see
`Refusing to load formula … from untrusted tap zigrivers/scaffold`, run
`brew trust zigrivers/scaffold` once — it's Scaffold's own official tap — then
retry. This is a local Homebrew policy, not a problem with the release.
:::
:::tab{title="Claude Code plugin"}
Inside a Claude Code session:
```text
/plugin marketplace add zigrivers/scaffold
/plugin install scaffold@zigrivers-scaffold
```
This is **optional** and complements the CLI — it auto-activates the Scaffold
Runner and pipeline-reference skills for interactive guidance. Everything the
plugin does is also reachable via `scaffold run <step>`. CLI-only users don't
need it: `scaffold init` installs the skills automatically and later CLI
commands keep them current.
:::
::::

## Installing `mmr` (the review CLI)

`mmr` is a **separate package** — installing `scaffold` does not install it. The
review workflow (`scaffold run review-pr` / `review-code`, and the mandatory
post-PR review) drives `mmr`, so install it alongside:

```bash
npm install -g @zigrivers/mmr    # or: brew install mmr  (same zigrivers/scaffold tap)
mmr doctor                       # which reviewer CLIs are installed + authed, and how to fix each
```

Both surfaces are published on every `mmr-v*` tag, so pick whichever matches how
you installed `scaffold`. Keep it current with `npm update -g @zigrivers/mmr` or
`brew update && brew upgrade mmr`.

`mmr` orchestrates *other* CLIs — it does not bundle any model. `mmr doctor`
tells you which of `codex`, `claude`, `grok`, `agy`, and `opencode` are present
and authenticated, and prints the exact recovery command for each. A channel
whose CLI simply isn't installed is skipped rather than compensated, so a fresh
machine typically needs at least two of them before a review yields a usable
verdict — see [the MMR reference](../mmr/index.md).

## Keeping current

Check what you have and whether a newer release exists with `scaffold version`
(or `scaffold update --check-only`); both query the npm registry for the latest
`@zigrivers/scaffold` (:cite[src/cli/commands/version.ts:93]). `scaffold update`
detects how you installed and prints the right upgrade command rather than
running the install for you — Homebrew installs map to `brew upgrade scaffold`
(:cite[src/cli/commands/update.ts:47]), npm-global installs to
`npm update -g @zigrivers/scaffold` (:cite[src/cli/commands/update.ts:51]), and
anything else falls back to `npx @zigrivers/scaffold@latest`
(:cite[src/cli/commands/update.ts:55]).

The Homebrew command it prints is exactly `brew upgrade scaffold` — it does
**not** include the `brew update` prefix. Homebrew users must prepend it
themselves and run `brew update && brew upgrade scaffold`, or the upgrade can
silently no-op against a stale tap cache (see the danger callout below).

Run the upgrade for your channel:

::::tabs
:::tab{title="npm"}
```bash
npm update -g @zigrivers/scaffold
```
:::
:::tab{title="Homebrew"}
```bash
brew update && brew upgrade scaffold
```
:::
:::tab{title="Claude Code plugin"}
```text
/plugin marketplace update zigrivers-scaffold
```
:::
::::

:::callout{type=danger}
**Homebrew: run `brew update` *before* `brew upgrade`.** `brew outdated` and
`brew upgrade` both read from the local tap cache. Without a preceding
`brew update`, the cache stays stale and a freshly-published release reports
"already installed" / nothing-outdated even though a newer formula is live on
GitHub. Always upgrade with `brew update && brew upgrade scaffold`
:cite[docs/architecture/operations-runbook.md:326]{mode=advisory}.
:::

After upgrading the CLI, run `scaffold status` inside any existing project. The
state manager auto-migrates old step keys, drops retired steps, and normalizes
artifact paths — no manual editing of `.scaffold/state.json` is needed.

## Starting fresh vs. adopting

Both `scaffold init` and `scaffold adopt` operate on the current project
directory. Use **`init`** to set up a project from scratch and **`adopt`** to
bootstrap pipeline state from documentation you already have.

```mermaid
flowchart TD
  A[New or existing project] --> B{Directory already has<br/>code or docs?}
  B -->|No, brand new| C["scaffold init<br/>wizard + config + skills"]
  B -->|Yes| D["scaffold adopt<br/>renders a plan, then --apply"]
  C --> E[Run the pipeline]
  D --> E
```

### `scaffold init`

`scaffold init` initializes Scaffold for the current project
(:cite[src/cli/commands/init.ts:152]): it runs a wizard, writes `.scaffold/`
config and state, and installs the skills. The wizard detects whether the
directory is brand new or already has code and suggests a methodology preset
(`mvp`, `deep`, or `custom`) accordingly. To re-initialize a project that
already has a `.scaffold/` directory, pass `--force` — it backs up the existing
state before reinitializing (:cite[src/cli/commands/init.ts:157]).

### `scaffold adopt`

`scaffold adopt` adopts an existing project into Scaffold
(:cite[src/cli/commands/adopt.ts:168]). It classifies the project as
`greenfield`, `brownfield`, or `v1-migration`
(:cite[src/project/adopt.ts:72]), discovers which pipeline outputs (PRD,
tech-stack, coding-standards, etc.) you already have on disk, and marks the
corresponding steps complete so you don't re-run work you've already done.

**It writes nothing by default.** Since v3.48.0, `adopt` renders an Adoption
Plan and stops. To execute it, pass `--apply` together with the plan you
approved:

```bash
scaffold adopt                                # render the plan, write nothing
scaffold adopt --write                        # also write docs/adoption-plan.md
scaffold adopt --format json                  # machine-readable plan, includes plan_key
scaffold adopt --apply --plan-key <sha256>    # execute the approved plan
```

`--dry-run` is deprecated and does nothing: plan mode is already the default
(:cite[src/cli/commands/adopt.ts:117]).

**`adopt` initializes for you.** It writes the `.scaffold/` config and state
itself and selects the `brownfield` methodology. Do not run `scaffold init`
first on an existing codebase: `init` would select `deep`, and `adopt` would
then have to replace it.

## Troubleshooting

:::callout{type=tip}
**`scaffold: command not found` after npm install.** Your global npm `bin`
directory isn't on `PATH`. Find it with `echo "$(npm prefix -g)/bin"` (the
binaries live in the `bin` subdirectory of `npm prefix -g`) and add that
directory to your shell `PATH`, or reinstall with a prefix that's already on
`PATH`.
:::

- **Homebrew says "already installed" after a release.** You skipped
  `brew update`. Run `brew update && brew upgrade scaffold` (see the danger
  callout above).
- **Wrong version reported.** Run `scaffold version` to see the installed
  version, Node version, platform, and the latest registry version side by
  side. If two installs collide (e.g. both npm-global and Homebrew), remove one.
- **Node too old.** The CLI needs Node 18.17+ (:cite[package.json:34]). Upgrade
  Node, or use the Homebrew install, which installs and manages Node as a
  dependency.
- **`scaffold update` only prints a command.** That's intentional — it never
  runs installs for you. Copy the printed upgrade command for your channel and
  run it yourself. `--check-only` reports the same information and exits — it
  still names the upgrade command when one is available; the difference is that
  it emits a check-shaped JSON payload under `--format json`. `--skip-build` is
  accepted but currently has no effect: `scaffold update` never installs or
  rebuilds anything, so there is no build to skip.
- **Existing project behaves oddly after upgrade.** Run `scaffold status` to
  trigger automatic state migration before anything else.

## See also

- [Pipeline reference](../pipeline/index.md){mode=advisory} — what the steps are
  and the order they run in.
- [CLI reference](../cli/index.md){mode=advisory} — every `scaffold` subcommand.
- [Multi-agent workflow](../multi-agent/index.md){mode=advisory} — running the
  pipeline across parallel worktrees.
