`mandu upgrade`
Self-updater for both the npm-installed `@mandujs/*` packages and the standalone compile-binary builds. SHA-256 verified, atomic swap, `--rollback` capable.
On this page
mandu upgrade
Self-updater for both the npm-installed @mandujs/* packages and the
standalone compile-binary builds. Auto-detects which mode to use based
on how the CLI was launched.
mandu upgrade # package mode: bun update @mandujs/*
mandu upgrade --check # show installed vs latest (no install)
mandu upgrade # binary mode: self-update (when invoked as compile-binary)
mandu upgrade --dry-run # download + verify; skip the swap
mandu upgrade --rollback # restore the previously-replaced binary
mandu upgrade --channel=canary # use pre-release tags
Package mode vs binary mode
The CLI auto-detects which mode to use:
| Invocation | Mode | Action |
|---|---|---|
bun run mandu / bunx @mandujs/cli |
Package | bun update @mandujs/* |
./mandu.exe / ./mandu-bun-linux-x64 |
Binary | Download + verify + swap |
Package mode
# Upgrade every @mandujs/* package pinned in package.json
mandu upgrade
# Check without installing
mandu upgrade --check
The list of packages is derived from your package.json
dependencies — only packages starting with @mandujs/ are touched.
Nothing else in your lockfile changes.
Binary mode
# Download the latest release matching your platform
mandu upgrade
# Use the canary channel (pre-release tags)
mandu upgrade --channel=canary
# Preview (download + verify, skip the swap)
mandu upgrade --dry-run
# Restore the previous binary after a regression
mandu upgrade --rollback
Binary integrity
Every GitHub Release ships a SHA256SUMS.txt sidecar generated by the
release-binaries.yml workflow. mandu upgrade:
- Fetches the release metadata and sidecar.
- Downloads the platform-appropriate binary (
mandu-bun-linux-x64,mandu-bun-darwin-arm64,mandu.exe, etc.). - Computes the SHA-256 of the downloaded file.
- Compares against the entry in
SHA256SUMS.txt. - Refuses to swap if the hashes diverge — exits with code 1.
Phase 11.A SLSA Build L2 provenance is attached to every artifact
via actions/attest-build-provenance. For the strongest check:
# Before invoking `mandu upgrade`, verify the attestation
gh attestation verify mandu-bun-linux-x64 \
--repo konamgil/mandu
This confirms the binary was built by the expected workflow in the expected repo, not by a compromised mirror.
Atomic replacement
POSIX (macOS / Linux)
Plain rename(new, current) — the running process keeps its own file
descriptor open, so the swap is safe even while mandu upgrade itself
is executing.
/usr/local/bin/mandu ← old binary (running)
/usr/local/bin/mandu.new ← downloaded + verified
rename(mandu.new → mandu)
/usr/local/bin/mandu ← new binary (next invocation uses it)
Windows
Windows doesn't allow overwriting a running .exe directly — but
rename of the running .exe to a new name is allowed while the
image is loaded. Mandu takes advantage:
C:\mandu\mandu.exe ← running
rename(mandu.exe → mandu.old.<pid>.exe)
C:\mandu\mandu.old.12345.exe ← old, stashed
move(mandu.exe.new → mandu.exe)
C:\mandu\mandu.exe ← new binary
The old copy is moved into %USERPROFILE%\.mandu\bin\previous\. On
POSIX the same stash location is used (~/.mandu/bin/previous/).
Rollback
mandu upgrade --rollback
Restores the previously-stashed binary from ~/.mandu/bin/previous/.
If there's nothing to restore, exits with code 3.
Rollback only recovers the most recent swap — running --rollback
twice doesn't chain back further.
Release channels
| Channel | npm tag | Purpose |
|---|---|---|
stable (default) |
latest |
Default; safe for production. |
canary |
next |
Pre-release builds, ~weekly. |
alpha |
alpha |
Experimental; opt-in for early testing. |
mandu upgrade --channel=canary
Channels affect both package and binary mode — the binary release
workflow publishes canary artifacts as separate GitHub releases
tagged canary-<version>.
Exit codes
| Code | Meaning |
|---|---|
0 |
upgrade applied (or --check) |
1 |
network / integrity / I/O failure |
2 |
usage error |
3 |
rollback requested but nothing to restore |
Troubleshooting
SHA-256 mismatch: expected X, got Y — the download was corrupted
or tampered with. Retry. If it persists, verify the attestation with
gh attestation verify.
rollback refused: no previous binary stashed — --rollback was
called before any binary upgrade had been performed. Nothing to
restore.
CLI_E040: upgrade requires network access — mandu upgrade
needs https access to api.github.com. In air-gapped environments,
download the release + SHA256SUMS.txt manually and swap by hand.
Package mode: @mandujs/* packages are not upgraded — check that
@mandujs/cli is actually listed as a dev dependency. mandu upgrade
reads from package.json, not the global bun cache.
CI integration
# .github/workflows/bump-mandu.yml
name: Bump Mandu
on:
schedule:
- cron: "0 13 * * 1" # Mondays 13:00 UTC
jobs:
bump:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- run: bunx @mandujs/cli upgrade --check
- run: bunx @mandujs/cli upgrade
- run: bunx @mandujs/cli test
- uses: peter-evans/create-pull-request@v6
with:
branch: chore/mandu-bump
title: "chore: bump @mandujs/* to latest"
🤖 Agent Prompt
Apply the guidance from the Mandu docs page at https://mandujs.com/docs/cli/upgrade to my project.
Summary of the page:
`mandu upgrade` auto-detects package vs binary mode via process.execPath. Binary mode: downloads, verifies SHA256 from SHA256SUMS.txt, atomically swaps (rename on POSIX; rename-then-replace on Windows). Stashes the old binary in ~/.mandu/bin/previous/ so --rollback works. SLSA L2 provenance attached.
Required invariants — must hold after your changes:
- Package mode (`bun run mandu`): runs `bun update @mandujs/*`
- Binary mode (`mandu.exe` / `mandu-bun-linux-x64`): downloads + verifies + swaps
- SHA-256 verified against `SHA256SUMS.txt` released alongside each binary
- Windows: rename running `.exe` to `.old.<pid>.exe` first (allowed while loaded), then move new binary into place
- Previous binary stashed in `~/.mandu/bin/previous/` — `--rollback` restores it
- SLSA Build L2 provenance is attached via `actions/attest-build-provenance`
Then:
1. Make the change in my codebase consistent with the page.
2. Run `bun run guard` and `bun run check` to verify nothing
in src/ or app/ breaks Mandu's invariants.
3. Show me the diff and any guard violations.
Related
- CLI —
db seed— replay fixture data. - CLI —
mcp register— wire Mandu MCP into Claude / Cursor / Continue / Aider. - CLI Reference — every command + flag.
For Agents
{
"schema": "mandu.upgrade/v0.25",
"command": "mandu upgrade",
"modes": {
"package": "bun update @mandujs/*",
"binary": "download + verify + atomic swap"
},
"mode_detection": "via process.execPath",
"integrity": {
"algorithm": "SHA-256",
"sidecar": "SHA256SUMS.txt",
"provenance": "SLSA Build L2 via actions/attest-build-provenance"
},
"stash_path": "~/.mandu/bin/previous/",
"channels": ["stable", "canary", "alpha"],
"exit_codes": {
"0": "success",
"1": "network / integrity / I/O",
"2": "usage",
"3": "rollback with nothing to restore"
},
"rules": [
"Binary mode refuses to swap on SHA-256 mismatch — never yolo-overwrite",
"Rollback only recovers the most recent swap",
"Use `gh attestation verify` for defense-in-depth before `mandu upgrade`"
]
}For Agents
`mandu upgrade` auto-detects package vs binary mode via process.execPath. Binary mode: downloads, verifies SHA256 from SHA256SUMS.txt, atomically swaps (rename on POSIX; rename-then-replace on Windows). Stashes the old binary in ~/.mandu/bin/previous/ so --rollback works. SLSA L2 provenance attached.
- Package mode (`bun run mandu`): runs `bun update @mandujs/*`
- Binary mode (`mandu.exe` / `mandu-bun-linux-x64`): downloads + verifies + swaps
- SHA-256 verified against `SHA256SUMS.txt` released alongside each binary
- Windows: rename running `.exe` to `.old.<pid>.exe` first (allowed while loaded), then move new binary into place
- Previous binary stashed in `~/.mandu/bin/previous/` — `--rollback` restores it
- SLSA Build L2 provenance is attached via `actions/attest-build-provenance`