# update-check

> Ask npm whether a newer BMAD+ release exists and whether your policy would let it apply, without changing anything: flags, statuses, reasons, the JSON fields, cache and offline behaviour.

Canonical: https://bmad-plus.rochetta.fr/docs/reference/cli-update-check/
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-check

`update-check` tells you where your project stands against the latest published release. It compares three things: the version installed in the project, the version of the package you are running, and the newest release on your update channel. It only reports. Nothing is downloaded, installed or written except a small cache file. Assistants run it once per session because the generated instruction files tell them to.

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

**In your project terminal**

```sh
npx bmad-plus update-check [-d <path>] [--refresh] [--offline] [--json]
```

**Options of update-check**

| Flag | What it does |
| --- | --- |
| `-d, --directory <path>` | Project to check (default: current folder). |
| `--refresh` | Ignore the 24-hour cache and the one-hour retry pause after a failure, and ask npm now. |
| `--offline` | Make no network request; report the local state only (status `unknown`, reason `offline`, or the stale cached target). |
| `--json` | Print one line of JSON instead of two lines of text. |

<a id="reads-writes"></a>
## What it reads and writes

- Reads `_bmad/.bmad-plus-install.json` (installed version), `_bmad/update-policy.json` (mode, channel, range) and, for the readiness verdict, the ownership inventory.
- Contacts npm only when the policy mode is not `off`, you are not `--offline`, and there is no fresh cache. The lookup runs `npm view bmad-plus@<channel> version engines --json` against the official registry `https://registry.npmjs.org/` with a 4 second fetch timeout, no retries and a 6 second cap.
- Writes `.bmad/update-check.json`: the release seen and when (valid 24 hours), or the time of the last failure (it then waits an hour before asking again, unless `--refresh`).
- It is the only BMAD+ command that exists to ask npm (`update --latest` also queries npm, then downloads the target through `npm exec`). To stop the lookups entirely, run `update-policy --mode off`.

<a id="statuses"></a>
## Statuses and reasons

Plain output is two lines. The first is `Installed: <v>; running: <v>; channel <name>: <target>`, with `unknown` for a missing value. The second is `<status>: <reason>`, followed by `(cached result is stale)` when the target comes from an expired cache.

**Statuses**

| Status | Meaning |
| --- | --- |
| `update-available` | The channel carries a newer version than the installed one. The reason says whether it may apply (see below). |
| `current` | Installed version equals the channel version (reason `installed-matches-channel`). |
| `ahead` | Installed version is newer than the channel (reason `installed-ahead-of-channel`). |
| `off` | The policy mode is `off` (reason `updates-disabled`). npm was not contacted. |
| `unknown` | No answer: `offline`, `registry-retry-backoff` (a recent failure), or `registry-unavailable`. |
| `invalid-runtime`, `invalid-installation`, `invalid-policy` | The running version or clock is unusable; there is no valid manifest; the policy file is invalid. Exit code 1. |

When the status is `update-available`, the reason explains what stands between you and the update. `ready-for-authorized-update` means the policy authorises it and the files are unchanged: `canAutoApply` is true. Other reasons: `approval-required` (policy mode is `notify`, so a human must approve), `outside-allowed-range`, `prerelease-not-allowed`, `incompatible-node-version`, `Complete file ownership inventory is required.` (a legacy install), `Local changes or an active update require manual review.`, `ownership-readiness-failed`.

The JSON line carries: `schemaVersion`, `installedVersion`, `runningVersion`, `latestVersion` (only on the `latest` channel), `targetVersion`, `channel`, `status`, `checkedAt`, `source` (`registry`, `cache`, `stale-cache` or `none`), `stale`, `updateAvailable`, `releaseEligible`, `versionEligible`, `canAutoApply`, `engineCompatible`, `engines` and `reason`.

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

**Exit codes of update-check**

| Code | Meaning |
| --- | --- |
| 0 | Any other status, including `unknown` and `off`: not being able to reach npm is not a failure. |
| 1 | The status begins with `invalid-`. |

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

The acceptance runs did not exercise this command, so these transcripts are composed from the code’s output templates (versions are placeholders) and marked as simulated.

**A newer release the policy does not apply by itself** (Simulated)

```text
$ npx bmad-plus update-check
Installed: <old>; running: <old>; channel latest: <new>
update-available: approval-required
```

Illustrative transcript, not captured from a real run. Source: tools/cli/commands/update-check.js lines 32-37; tools/cli/lib/update-check.js lines 209-231

**Offline** (Simulated)

```text
$ npx bmad-plus update-check --offline --json
{"schemaVersion":1,"installedVersion":"<old>","runningVersion":"<old>","latestVersion":null,"targetVersion":null,"channel":"latest","status":"unknown","checkedAt":null,"source":"none","stale":false,"updateAvailable":null,"releaseEligible":false,"versionEligible":false,"canAutoApply":false,"engineCompatible":null,"engines":{},"reason":"offline"}
# Exit code 0. An assistant treats this as “continue the task” and never claims the version is current.
```

Illustrative transcript, not captured from a real run. Source: tools/cli/lib/update-check.js lines 161-163

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

**Messages of update-check**

| Message or reason | Cause | What to do |
| --- | --- | --- |
| `No BMAD+ installation found in <dir> (missing _bmad/.bmad-plus-install.json).` (on the error stream) | Wrong folder or not installed; the status is `invalid-installation`. | Run from the project or pass `--directory`. |
| `unknown: registry-unavailable` | npm could not be reached within the time limit. | Retry later, or `--refresh`. Offline machines can ignore it. |
| `unknown: registry-retry-backoff` | A failure was recorded less than an hour ago. | Use `--refresh` to ask again now. |
| `invalid-policy: unreadable-or-invalid-update-policy` | `_bmad/update-policy.json` is not valid. | Fix or delete the file, or rewrite it with `update-policy`. |
| `update-available: incompatible-node-version` | The new release needs a newer Node.js than you run. | Upgrade Node.js, then check again. |

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

**For a script: act only when an automatic update is allowed**

```sh
npx bmad-plus update-check --json --refresh
```

**See also**

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

[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)
