# update

> Move an installed project to a newer BMAD+ version with a plan, backups and a receipt you can restore from: flags, what is preserved, refusals, recovery and every message.

Canonical: https://bmad-plus.rochetta.fr/docs/reference/cli-update/
Language: en
BMAD+ version: 0.23.1
Documentation reviewed: 2026-10-19
Author: Laurent Rochetta
License: MIT

BMAD+ documentation › [Reference](https://bmad-plus.rochetta.fr/docs/reference/) › update

`update` takes a project that already has BMAD+ and brings its files to the version of the package you run. It never works blindly: it first computes a plan from the ownership inventory recorded at install, shows how many files change and which ones it will leave alone because you edited them, asks for confirmation, backs everything up, writes, verifies, and leaves a receipt. If anything fails halfway it rolls back, and a finished update can be undone later with `--restore`.

<a id="synopsis"></a>
## Synopsis

**In your project terminal**

```sh
npx bmad-plus@latest update [-d <path>] [-y] [-l <code>] [--latest] [--expected-version <v>] [--auto]
npx bmad-plus update --restore <receipt-id> [-d <path>] [-y]
```

**Options of update**

| Flag | Argument | What it does |
| --- | --- | --- |
| `-d, --directory <path>` | folder | Project to update (default: current folder). |
| `-y, --yes` | - | Confirm without prompting. Required when there is no terminal. |
| `-l, --lang <code>` | language code | Language of the confirmation texts. Defaults to the language recorded at install. |
| `--latest` | - | Do not use the package you are running: look up the latest compatible release on npm and run exactly that version. Without `--yes` or `--auto` it only reports what it would run. |
| `--expected-version <version>` | exact version | Refuse unless the running package is exactly this version. Used by the updater itself as a safety check. |
| `--auto` | - | Apply only if the project’s update policy allows it, the ownership inventory is complete and nothing is in conflict. Needs `--expected-version`. |
| `--restore <receipt-id>` | receipt id | Put back the files saved by an earlier update. Cannot be combined with `--latest`, `--expected-version` or `--auto`. |

<a id="two-paths"></a>
## Two ways to pick the version

- Plain `update` uses the package you are running. `npx bmad-plus@0.23.0 update` moves the project to 0.23.0. When the installed and running versions are equal, it prints “Nothing to update.” and stops.
- `update --latest` asks npm (`update-check` does the same lookup) for the newest release of your update channel, checks that it is a newer, eligible, Node-compatible version allowed by your policy, then runs `npm exec` on exactly that version in a temporary folder with `update --yes --expected-version <version>`. Without `--yes` (or `--auto`) it stops after naming the target: the report is the approval request.
- After `--latest` the manifest is read again. If it does not show the target version, the command fails and asks you to inspect the project.

<a id="what-changes"></a>
## What it changes and what it keeps

**How update treats each kind of file**

| File | Treatment |
| --- | --- |
| Agents, skills, data, module files that you did not touch | Replaced by the new version after a backup. |
| Managed files you edited (`modified-managed-file`) | Left as they are and listed as a preserved conflict. |
| A file in the way that BMAD+ never recorded (`unowned-file`) | Left as it is, listed as a conflict. |
| Files the new version no longer ships | Removed with a backup when unchanged; kept and listed (`modified-orphaned-file`) when you edited them. Empty folders are cleaned up. |
| `AGENTS.md` and tool files carrying the BMAD+ marker and unchanged | Regenerated. |
| Instruction files you wrote, or edited after install (`local-instructions`, `repository-adopted`) | Left as they are, listed as a conflict. |
| `_bmad/config.yaml`, memory, `_bmad-output/` | Not touched. |
| Legacy installations without a complete ownership inventory | Original pack files are backed up before replacement, with a warning; older instruction files are saved as `<file>.bak`. `--auto` refuses. |

A backup of every file the update changes is stored under `.bmad/updates/<receipt-id>/backups/`, next to `receipt.json`. The receipt records the status of the update: `prepared`, `committed`, `rolled-back`, `recovery-required` or `restored`. Only one install or update can run at a time (`.bmad/update.lock`).

<a id="exit-codes"></a>
## Exit codes

**Exit codes of update**

| Code | Meaning |
| --- | --- |
| 0 | Updated, restored, nothing to update, you declined the prompt, or `--latest` reported the target and waits for `--yes`. |
| 1 | Any error: not installed, refused, conflict with the lock, failed and rolled back, no terminal and no `--yes`. |

<a id="real-output"></a>
## Output

No update run was recorded in the 0.23.0 acceptance runs, so the two transcripts below are composed from the message templates in the code (version numbers and counts are placeholders) and are marked as simulated.

**A plain update with one preserved conflict** (Simulated)

```text
$ npx bmad-plus@<new> update
Installed: v<old> -> Executing package: v<new>
Planned changes: <N> files (<R> no longer shipped, removed with backup); preserved conflicts: 1.
CLAUDE.md: preserved (local-instructions).
? Apply this update from v<old> to v<new>?  Yes
<N> files updated; 1 local conflicts preserved.
Receipt and backups: <project>/.bmad/updates/<receipt-id>/receipt.json
BMAD+ v<new> applied partially. Reload your agent instructions or start a new session.
```

Illustrative transcript, not captured from a real run. Source: tools/cli/commands/update.js lines 120-190

**Latest release, approval requested then given** (Simulated)

```text
$ npx bmad-plus update --latest
Confirm this exact update with --yes.
Target: v<new>
# Nothing was changed; exit code 0.
$ npx bmad-plus update --latest --yes
updated
# The updater that this command starts prints its own lines here (the plan, the receipt and the “applied” line, as in the previous transcript); they are omitted.
Target: v<new>
Reload your agent instructions or start a new session.
```

Illustrative transcript, not captured from a real run. Source: tools/cli/lib/update-dispatch.js lines 110-180 and tools/cli/commands/update.js lines 62-74

<a id="recovery"></a>
## Recovery with --restore

If an update fails after it started writing, it rolls itself back and ends with a line such as `; rolled-back. Recovery: bmad-plus update --restore <id> --directory "<dir>" --yes`. The receipt id is also the folder name under `.bmad/updates/`. `--restore` checks that every saved file still matches its recorded hash, that the current manifest is the one from before or after that update, and that no live update holds the lock; then it puts the old files back and marks the receipt `restored`. Nothing is restored if a file changed since the update: the command refuses and names it.

<a id="errors"></a>
## Errors and what to do

**Messages of update**

| Message | Cause | What to do |
| --- | --- | --- |
| `No BMAD+ installation found in <dir> (missing _bmad/.bmad-plus-install.json).` | You are in the wrong folder, or BMAD+ is not installed. | Run from the project folder, pass `--directory`, or install first. |
| `--restore cannot be combined with --latest or --expected-version.` | Incompatible flags. | Run the restore alone. |
| `Automatic update requires --expected-version.` | `--auto` without a target version. | Add `--expected-version <v>`, or let `--latest --auto` do it. |
| `Executing package version X does not match expected version Y.` | The running package is not the one you named. | Run `npx bmad-plus@Y update ...`. |
| `Downgrade refused: A -> B` | The running package is older than the installed version. | Run a newer package. |
| `Automatic update refused: <reason>` | Policy does not allow it (`approval-required`, `updates-disabled`, `outside-allowed-range`, `prerelease-not-allowed`), or the project is legacy or has conflicts. | Use `update-policy` to inspect it, or approve manually with `update --latest --yes`. |
| `Update refused: <reason>.` | A `--latest` safety check failed: `updates-disabled`, `automatic-updates-not-authorized` (`--auto` while the policy mode is not `auto`), `fresh-metadata-required`, `policy-channel-changed`, `downgrade-not-allowed`, `ownership-preflight-failed`, `incompatible-or-invalid-node-engine`, and similar. | Read the reason, fix its cause, retry. `fresh-metadata-required` usually means npm was unreachable. |
| `Updater finished without the expected manifest version X. Inspect the project before retrying.` | The nested updater ended but the manifest does not show the target. | Run `doctor`; do not retry blindly. |
| `Another update is in progress: <path>.` | The project lock is held. | Wait; if it was interrupted, `doctor` says when it is stale and which file to delete. |
| `File changed after preflight: <file>` | A file changed between the plan and the write. | Retry; the update did not start writing. |
| `...; rolled-back. Recovery: bmad-plus update --restore <id> ...` | A write failed; changes were reverted. | Fix the cause and retry; use the printed command only if files look wrong. |
| `Installation changed since this receipt; recovery refused.` | The manifest is neither the one from before nor after the receipt. | Restore from the most recent receipt only. |
| `Backup is missing or corrupt: <file>` / `File changed since the update: <file>` | A saved file was deleted or edited. | Restore that file from your own history, then retry. |

<a id="examples"></a>
## Examples

<a id="example-cli-update-ask-assistant"></a>
### Let the assistant check and update

Every generated instruction file tells the assistant to check once per session and to follow the project policy. You can ask it explicitly.

**In your AI assistant**

```text
Is there a newer BMAD+ for this project? If an update is allowed by our policy, apply it, then tell me what was preserved.
```

**What you should get** The assistant runs `npx bmad-plus update-check --json`. If `updateAvailable` and `canAutoApply` are both true it runs `update --latest --auto`; if an update exists but cannot be applied automatically it explains the version and the reason, and applies it with `update --latest --yes` only because you asked. It does not change the policy, overwrite customised files or resolve conflicts on its own. Afterwards it rereads the project instructions, and reports the preserved conflicts the command listed.

**By hand, with a prompt and a receipt**

```sh
npx bmad-plus update-check
npx bmad-plus update --latest --yes
# something looks wrong afterwards:
npx bmad-plus update --restore <receipt-id> --yes
```

**See also**

- [update-check](https://bmad-plus.rochetta.fr/docs/reference/cli-update-check/)
- [update-policy](https://bmad-plus.rochetta.fr/docs/reference/cli-update-policy/)
- [doctor](https://bmad-plus.rochetta.fr/docs/reference/cli-doctor/)
- [install](https://bmad-plus.rochetta.fr/docs/reference/cli-install/)
- [The whole lifecycle](https://bmad-plus.rochetta.fr/docs/guides/install-lifecycle/)
- [Troubleshooting](https://bmad-plus.rochetta.fr/docs/faq/troubleshooting/)

[BMAD+ documentation](https://bmad-plus.rochetta.fr/docs/) · [Reference](https://bmad-plus.rochetta.fr/docs/reference/)

[Source on GitHub](https://github.com/lrochetta/BMAD-PLUS)
