How-to: self-update
Keep the crm CLI current. See the CLI reference for every flag.
Check for a newer release
crm self-update --check
--json it emits the standard envelope (data.current, data.latest,
data.update_available); if the release server is unreachable it returns a clean
error envelope rather than hanging or crashing.
Upgrade (install-method-aware)
crm self-update
self-update detects how crm was installed and upgrades it the right way:
- Install-script binary (frozen) — downloads the platform archive, verifies
it against the published
SHA256SUMS(the same integrity check the install script uses), and swaps the bundle in place — thecrmlauncher on your PATH keeps working. A checksum mismatch or download failure leaves the existing install untouched and exits non-zero. - uv tool / pipx — force-reinstalls from the latest release tag
(
uv tool install --force git+https://github.com/Gharib89/crm@vX.Y.Z, or the pipx equivalent).--forceis used because uv/pipx pin the git commit and a plain upgrade can silently no-op. On a terminal it prints the command and asksProceed? [y/N](default No); non-interactively it runs only with--yes. Ifuv/pipxisn't on your PATH, it falls back to printing the command. - editable /
pip install git+…/ unknown — prints the correct git-based upgrade command and never runs anything.
crm self-update --yes # run the uv/pipx reinstall without the prompt (scripts/CI)
The --json contract
Under --json, a non-frozen self-update emits these data fields:
install_method—frozen|uv-tool|pipx|editable|pip-git|unknown.current,latest,update_available— the version comparison.command— the exact upgrade command string for this install method.executed— whetherself-updateran that command.exit_status— the command's exit code (present only whenexecutedis true).reason— why nothing ran (present whenexecutedis false):up-to-date,manual-install-method,no-tty-without-yes,declined, ortool-not-on-path.
If an attempted uv/pipx upgrade command itself exits non-zero, self-update
emits an ok:false envelope (exit 1) — so a script sees a non-zero process exit
on a failed upgrade — while still carrying the same data fields
(install_method, command, executed:true, exit_status) alongside the
error message, so you can inspect what ran.
--check is unchanged and method-agnostic (data.current, data.latest,
data.update_available).
Keeping installed skills in sync
Every non---check self-update re-syncs the agent skills you installed with
crm skill install, so the shipped SKILL.md never lags the CLI. It
reads the install registry (${CRM_HOME:-~/.crm}/installed-skills.json) and, for
each recorded destination whose version is stale, re-copies the bundled skill
tree. This fires on both install types — after a frozen bundle swap, and on a
pip/uv install once the upgraded wheel is in place.
The per-destination outcome is reported under data.skills (a list of
{dest, from_version, to_version, status}, status ∈ refreshed | skipped |
pruned | error):
- refreshed — the skill was re-copied to the current version.
- skipped — already current; no copy.
- pruned — the folder was deleted out-of-band, so its registry entry is dropped (the folder is not recreated).
- error — copying that destination failed (e.g. permissions); the entry is kept for a later retry.
A skill-refresh failure never aborts the binary update — the command still
reports ok:true when the upgrade itself succeeded.
The passive update notice
On an interactive terminal, crm checks at most once every 24 hours whether a
newer release exists and prints a one-line notice on stderr after a command
finishes — at most once per 24 hours (tracked via notified_at in the cache),
so it does not reprint on every command. A newly discovered version resets that
gate so the new release is surfaced promptly. The probe runs in the background
and never delays a command.
It is silent — and skips the network entirely — in any of these cases:
--jsonoutput mode (machine-readable output is never polluted),- stderr is not a terminal (pipes, redirects, agents),
- the
CIenvironment variable is set, - the
CRM_NO_UPDATE_CHECKenvironment variable is set, - the command being run is
self-updateitself (it owns its own update messaging; the running process still reports the pre-update version, so the notice would otherwise tell you to upgrade to the release you just installed).
Set CRM_NO_UPDATE_CHECK=1 to opt out permanently:
export CRM_NO_UPDATE_CHECK=1
The last check result is cached under ${CRM_HOME:-~/.crm}/update-check.json.