# Update channel How installed Crux daemons learn that a newer release exists, without ever phoning home by default. ## Posture (non-negotiable) - **Notification, never automatic action.** Nothing updates in the background. The upgrade is always an explicit operator command that re-verifies artifacts (`install.sh --version vX.Y.Z`, `brew upgrade crux`, `dpkg -i`, image tag bump). - **Opt-in check.** The daemon makes no outbound connections by default (`scripts/assert-no-phone-home.sh`). An update *check* is an explicit command (or an explicitly enabled config), not a background default for binary installs. - **No tracking.** The manifest is a static file served by GitHub Releases — a plain GET with no query parameters, no instance id, no version-in-URL. We cannot distinguish a check from a download, and that is the point. ## The manifest Each release attaches `update-manifest.json` (generated by `scripts/generate-update-manifest.sh`, signed like every other artifact). The stable URL always points at the newest release: ``` https://github.com/CueCrux/Crux/releases/latest/download/update-manifest.json ``` Shape (`crux.update_manifest.v2`): ```json { "schema": "crux.update_manifest.v2", "tag": "v0.5.0", "version": "0.5.0", "published_at": "2026-06-20T00:00:00Z", "notes_url": "https://github.com/CueCrux/Crux/releases/tag/v0.5.0", "verify_doc": "https://github.com/CueCrux/Crux/blob/v0.5.0/docs/verify-release.md", "artifacts": [ {"name": "standalone-crux-linux-amd64", "asset_name": "crux-linux-amd64", "sha256": "…"}, {"name": "standalone-crux-darwin-arm64", "asset_name": "crux-darwin-arm64", "sha256": "…"}, {"name": "standalone-crux-darwin-amd64", "asset_name": "crux-darwin-amd64", "sha256": "…"} ] } ``` Consumers compare `version` against their own `crux --version` and print the upgrade hint. `name` is the standalone-updater selector; `asset_name` is the actual GitHub Release file. The distinct logical name is a compatibility fence: pre-M5 updaters search only for `crux-`, find no match, and fail before mutation. That prevents packaged installs from crossing without the new hook/CLI; an old standalone install also takes the verified installer for this one transition. The sha256 list lets a current standalone consumer pre-pin what it expects before downloading; full verification remains the cosign/SLSA flow. ## Today's checking surfaces - **Repo-checkout deploys** (host crux pattern): the daemon's git-posture probe (`update.rs`, `CORECRUXD_UPDATE_CHECK_ENABLED`) compares the checkout to its tracked branch and reports via `/v1/version` `.update` and the MCP `update_status` tool. Egress is to *your* configured git remote, on a checkout you deployed from. This probe is inert for binary installs (no repo to compare) and installers pin it `=0`. - **Binary installs**: check manually against the manifest URL above, or run `crux self update --check`. Re-run the installer with a pinned `--version` when you decide to move. ## `crux self update` (implemented, explicit-only) `crux self update --check` performs the manifest GET, compares versions, and prints the result without writing. `crux self update` can download, sha256-pin, and atomically replace a **standalone daemon binary**. It is never invoked by the daemon in the background. Packaged installs deliberately refuse that daemon-only replacement when `crux-hook` or `corecruxctl` is installed beside the daemon. A partial update would create version skew, and replacing several executables cannot be one filesystem-atomic operation. Upgrade the complete verified set instead: - installer: re-run `install.sh --version vX.Y.Z` - Homebrew: `brew upgrade crux` - Debian: install the new signed `.deb` This complete-bundle route is also required for the first upgrade into an M5 release: the v2 logical artifact name deliberately fences pre-M5 self-updaters before they can perform a partial transition. The in-process standalone path verifies the downloaded daemon against the hash in the HTTPS-fetched manifest. The signed installer remains the stronger cosign/SLSA path and the required route for managed bundles.