Install-Channel Detection
Detection runs locally (no network) by combining the binaryβs real path, the Go build metadata and the version stamp injected by the release CI:The Homebrew check runs first on purpose: the bottle installed by the tap is the same stamped asset published on the GitHub release, so only the
Cellar path distinguishes the two channels.Why source builds are never auto-updated
A locally compiled binary may carry uncommitted patches. Replacing it with a release artifact would silently destroy that work, so ChatCLI only prints the way forward:The /update Command
Bare/update is an explicit request: when a newer release exists on an automatable channel, it applies immediately β the same semantics as brew upgrade.
/update check β ChatCLI shows the Whatβs new section: the highlights parsed straight from the GitHub release notes, which arrive in the same API response as the version check (no extra network call).
/update check reports the same status but never applies anything.
The same card backs /version and the -v/--version flag: installed build, detected install channel, latest release, the invitation to /update (plus the channel-native command when there is one) and the whatβs-new section whenever an update exists.
The command is also available from the interactive command palette and the tab completer, and /config update shows the resolved policy at any time.
Verified Self-Replace
When the binary came straight from a GitHub release, ChatCLI updates it in place with a hardened pipeline:- Downloads
checksums.txtfrom the target release. - Streams the platform asset to a staging file in the same directory as the binary (guaranteeing an atomic rename on the same filesystem) while computing its SHA-256.
- Refuses the install on any checksum mismatch β the download is discarded and the current binary is never touched.
- Swaps atomically: a plain rename on macOS/Linux (the running process keeps its old inode), or the rename-to-
.olddance on Windows with automatic rollback if activation fails. Leftover artifacts are cleaned on the next boot.
/usr/local/bin owned by root), the updater degrades to a copy-paste command:
Background Auto-Update (Staging)
SetCHATCLI_AUTO_UPDATE to control the boot-time behavior:
Auto mode uses staging, the same model as Claude Code: the running process is never restarted or interrupted. The new binary lands on disk while you work, and the next start opens on the new version β announced once on the welcome screen:
notify mode (the default) the welcome screen shows the invitation instead β the same one the /version card renders, including the native command of your detected install channel:
off mode skips the network entirely. Only when the check canβt finish inside the budget (slow or absent network) does the announcement fall back to the running session, at the next prompt turn β you still donβt have to restart (or run /version) to find out:
auto mode when the silent staging fails (for example, the module proxy is unreachable), so a broken background update never hides a new release from you.
Homebrew is deliberately excluded from silent background updates.
brew upgrade takes Homebrewβs global lock and can trigger a full brew update; ChatCLI only drives it when you explicitly run /update. Concurrent ChatCLI processes coordinate through a lock file, so only one performs the background update.