Update safety
rpi can update itself from GitHub releases and reconcile configured rpi packages.
Both paths are designed so a failed update never leaves the installation in an
unusable state.
Update notifications
When you start an interactive session (TUI or REPL), rpi checks GitHub
releases in the background. If a newer release exists, a non-fatal status
message is shown:
Update available: current v0.2.6, latest v0.2.7 — summary — URL (run `rpi update --self`)
Source: crates/pi-cli/src/self_update.rs:187-213.
Two environment variables control this check:
PI_OFFLINE=1|true|yesdisables all updater networking.PI_SKIP_VERSION_CHECKdisables only the interactive startup version check.
Self-update
rpi update # update rpi itself (default when no package flags are given)
rpi update --self # explicit
rpi update --self --force # reinstall even when version and checksum match
Source: crates/pi-cli/src/args.rs:270-288, crates/pi-cli/src/lib.rs:85-94.
rpi update --self downloads the latest GitHub release for the current platform,
verifies it, smoke-tests it, and activates it atomically. It fails early if
PI_OFFLINE is enabled. The updater expects a managed install layout rooted at
$PI_HOME (default ~/.rpi on Unix, %USERPROFILE%\.rpi on Windows; the
self-updater otherwise derives the root from the running executable's location)
with an update-state.json file.
Source: crates/pi-cli/src/self_update.rs:211-223, crates/pi-cli/src/self_update.rs:480-524.
What the self-update does
- Selects the release. Stable versions query
/releases/latest. Prerelease versions pick the newest published prerelease. Drafts and unpublished releases are rejected. - Locates the platform archive (
rpi-<version>-<triple>.tar.gzor.zip) and the release'sSHA256SUMSfile. - Enforces size limits: archives are capped at 1 GiB and
SHA256SUMSat 1 MiB. - Downloads
SHA256SUMS, looks up the expected digest, and skips the download when the installed digest already matches (unless--forceis used). - Downloads the archive, verifies its SHA-256 digest against
SHA256SUMS, and extracts the binary to a staged path. - Runs a smoke test: the staged binary must print exactly
rpi <version>from--version. - Atomically installs the versioned binary and swaps the active symlink, then
writes
update-state.jsonatomically.
Sources: crates/pi-cli/src/self_update.rs:223-304,
crates/pi-cli/src/self_update.rs:705-723,
crates/pi-cli/src/self_update.rs:725-770,
crates/pi-cli/src/self_update.rs:795-875,
crates/pi-cli/src/self_update.rs:874-889.
Safety guarantees
- Checksum verification — every archive is checked against the release's
SHA256SUMSmanifest. - Size limits — archives and extracted binaries are capped at 1 GiB;
SHA256SUMSis capped at 1 MiB. - Smoke test — the downloaded binary must print exactly
rpi <version>from--versionbefore activation; exit status alone is not proof of identity. - Atomic activation — the active symlink is swapped with
rename(2)on Unix andMoveFileExon Windows, so the activerpipath is never missing during an update. - Rollback — if smoke testing, activation, or state writing fails, the
previous active symlink and
update-state.jsonare restored. - Serialized installs — a lockfile prevents concurrent installers from
racing on the same
PI_HOME. - No partial install — a failed transaction removes staged files and leaves the previous binary active.
Source: crates/pi-cli/src/self_update.rs:250-253,
crates/pi-cli/src/self_update.rs:280-284,
crates/pi-cli/src/self_update.rs:601-728,
crates/pi-cli/src/self_update.rs:705-770,
crates/pi-cli/src/self_update.rs:795-875,
crates/pi-cli/src/self_update.rs:897-929,
crates/pi-cli/src/self_update.rs:1081-1147.
Windows deferred activation
On Windows the running executable cannot be replaced while it is executing, so
the self-updater writes a deferred activation script and a
last-update-result.json status file. The new binary is moved into place by a
short-lived PowerShell process after the current rpi process exits. The
deferred activation then re-verifies that the moved binary prints exactly
rpi <version> and restores the previous binary on any mismatch or rollback
failure.
Source: crates/pi-cli/src/self_update.rs:798-875,
crates/pi-cli/src/self_update.rs:987-1025.
Update state
After a successful install the updater writes $PI_HOME/update-state.json. It
records the installed version, asset name, archive digest, versioned binary
path, and install timestamp. On the next update the digest is used to detect
republished tags that point to a different archive.
Source: crates/pi-cli/src/self_update.rs:62-73,
crates/pi-cli/src/self_update.rs:285-295.
Update packages
rpi update --extensions # reconcile every configured package (--all is an alias)
rpi update OWNER/REPO # update one configured git or local package
rpi update local:./my-tools # update a configured local package
rpi update --self --extensions # update packages, then update rpi itself
Source: crates/pi-cli/src/args.rs:270-288,
crates/pi-cli/src/package_commands.rs:69-94.
rpi update --extensions re-clones or checks out every configured git package
and re-discovers every configured local package. Git packages are checked out
into a content-addressed directory under the agent directory. Pinned git refs
are honored; unpinned sources follow the remote's default branch. Local
packages are validated from their configured paths.
Source: crates/pi-coding/src/packages.rs:470-708,
crates/pi-coding/src/packages.rs:1118-1253.
Package updates use the same safety patterns as install:
- Operations are serialized with a per-scope lock.
- Git is invoked directly with an argv vector, never through a shell.
- New checkouts are staged next to the existing one and activated with an atomic directory swap. If validation fails, the swap is rolled back.
- Settings and package state files are written atomically (temp file + rename) and rolled back if either write fails.
Source: crates/pi-coding/src/packages.rs:656-708,
crates/pi-coding/src/packages.rs:1874-1955,
crates/pi-coding/src/packages.rs:2033-2133.
npm: package sources are deliberately not supported. They are rejected with a
clear error (npm package sources are not supported yet; use a local path or git source). See packages.md for the supported package sources and
manifest format.
Source: crates/pi-coding/src/packages.rs:948-954.
Update environment variables
| Variable | Default | Purpose |
|---|---|---|
PI_HOME | ~/.rpi (Unix) / %USERPROFILE%\.rpi (Windows) | Install root for the binary and update state |
PI_UPDATE_BASE_URL | https://api.github.com/repos/0x8f701/rpi/releases | Release API base (must match the installer scripts) |
GITHUB_TOKEN | (none) | Authenticate GitHub API calls for release metadata |
PI_OFFLINE | (none) | Disables all updater networking |
PI_SKIP_VERSION_CHECK | (none) | Disables only the nonfatal interactive startup version check |
Source: crates/pi-cli/src/self_update.rs:1-13,
crates/pi-cli/src/self_update.rs:95-103.
Release policy
- Tags must be semantic versions of the form
vX.Y.Z(optionally with+buildmetadata). - Prerelease tags (
vX.Y.Z-alpha.N) are published as prereleases and are not made "latest", so the default/releases/latestendpoint never points to them. - The release workflow refuses to overwrite an already-published release and verifies the asset inventory before publishing.