-
-
Notifications
You must be signed in to change notification settings - Fork 0
Upgrade command
Checks GitHub Releases for a newer CommitBrief and installs it, using the right
mechanism for however the running binary got there in the first place. One
command works whether you installed via Homebrew, Scoop, go install, or a raw
GitHub Releases tarball.
Introduced in v1.15.0 (ADR-0034).
commitbrief upgrade [--check]
- Resolves the running binary's real path (symlinks followed — Homebrew's
bin/commitbriefis a symlink into the Cellar) and classifies how it was installed. - Asks the GitHub Releases API for the latest published (non-prerelease) tag.
- Compares it against the running version.
- If a newer version exists, shows what it's about to do and asks for
confirmation (skipped by
--check,--json, or global--yes). - Acts — either delegating to a package manager or replacing the binary itself.
| Method | Detected by | What upgrade does |
|---|---|---|
| Homebrew | resolved path contains a Cellar/commitbrief/ segment |
runs brew upgrade commitbrief
|
| Scoop | resolved path under $SCOOP/apps/commitbrief/ (or %USERPROFILE%\scoop\apps\commitbrief\) |
runs scoop update commitbrief
|
go install |
resolved path is $GOBIN/commitbrief, $GOPATH/bin/commitbrief, or ~/go/bin/commitbrief
|
runs go install github.com/CommitBrief/commitbrief/cmd/commitbrief@latest
|
| Manual | anything else — including a distro package CommitBrief doesn't publish (nix, AUR, apt) | downloads, verifies, and swaps the binary in place (below) |
Why delegate instead of always self-replacing? Overwriting a Homebrew- or Scoop-owned binary desynchronizes that manager's own version bookkeeping — its next upgrade either conflicts with a file it doesn't recognize as its own, or silently reverts the swap. Delegating keeps every manager's metadata correct.
Delegated commands inherit stdout/stderr directly: their output is streamed
straight through, never parsed, so an upstream format change in brew/scoop/
go can't break CommitBrief. If the owning tool isn't on PATH, upgrade
errors naming which tool it expected.
Misclassification is safe. A package manager CommitBrief doesn't
specifically detect (nix, AUR, apt, a hand-built binary in /usr/local/bin)
falls into "Manual" by default. Those locations are typically read-only
(/nix/store) or root-owned (/usr/bin), so the permission gate below stops
the attempt — cleanly, before any download — rather than silently corrupting a
package-manager-owned file.
Only a manual install reaches this path.
- Permission gate — before any network I/O. CommitBrief probes whether the binary's directory is writable (replacement is a rename, and rename permission comes from the parent directory, not the file). If the probe fails, nothing is downloaded — see Permission gate below.
-
Download. The release archive for your
GOOS/GOARCH(commitbrief_<version>_<os>_<arch>.tar.gz, or.zipon Windows) pluschecksums.txt, over HTTPS with redirects followed. -
Verify. SHA-256 of the downloaded archive is compared against its line
in
checksums.txt. A mismatch aborts immediately — the temp file is deleted and the currently installed binary is left untouched. -
Extract. Only the single binary entry (
commitbrief/commitbrief.exe) is pulled from the archive, into a temp file in the same directory as the target (so the final rename stays on one filesystem and is atomic). The existing binary's file mode is preserved rather than forced to a default. - Replace — platform-specific (below).
-
Verify the result with two independent checks. Both run on the
manual path only — never after a delegated Homebrew/Scoop/
go installupgrade, since a package manager may relocate its own binary and neither check has anything fixed to compare against. Either way it's a warning only — it never turns a completed upgrade into a failure: the file swap already succeeded.-
Does the swapped binary itself report the right version?
CommitBrief re-runs it at the resolved path with
--versionand checks the output names the release just installed. Because this execs the resolved path directly, it bypassesPATHentirely — a mismatch here means the file itself is wrong, not that something else is shadowing it. A failure to re-run the binary at all (a sandboxed or hardened mount, for example) is reported the same way. -
Is
commitbriefonPATHactually this binary? Separately, CommitBrief resolvescommitbriefthe way your shell would (aPATHlookup, with symlinks resolved) and compares that against the binary it just upgraded. If they differ, it warns and names both paths — the one that was upgraded, and the one your shell will actually run next. This is the check that catches anothercommitbriefshadowing the one just replaced; the first check can't, since it never goes throughPATH.
-
Does the swapped binary itself report the right version?
CommitBrief re-runs it at the resolved path with
Unsigned checksums — the honest limit. checksums.txt itself carries no
signature. The trust anchor is TLS to github.com (and the CDN it redirects
downloads to). That defends against a truncated or corrupted download, or an
inconsistent CDN response — not against a compromised release: an attacker
who could publish a malicious release could publish a matching malicious
checksums.txt alongside it. Release-artifact signing (cosign or
goreleaser's signs: block) is listed as future work, not shipped today
(ADR-0034).
Only the binary is replaced. Bundled man pages are not installed or refreshed by a manual-install upgrade — if you placed man pages yourself, you manage them yourself too.
A single os.Rename swaps the temp file into place. This is atomic and legal
even while the process is running: the running binary keeps its own inode, so
the swap is invisible to it. On any failure, nothing has changed — no
rollback is needed.
Windows refuses to overwrite a running .exe, but does allow renaming it, so
the live binary is moved aside first (target → target.old), then the new
one is renamed into target's place. If that second rename fails, the
original is renamed back from .old.
If the rollback also fails — i.e. the swap-in failed and restoring the
original from .old also failed — the target directory is left with no
binary at all. The returned error names both failures and points you at
<binary>.old: rename it back to <binary> yourself to recover. This is a
rare failure mode, but the error message exists specifically to make it
recoverable instead of silent.
.old can't be deleted while the process that renamed it away is still
running. The next time you run commitbrief upgrade on Windows, it sweeps
away any stale .old left over from a previous run, best-effort, before doing
anything else.
Before any download, CommitBrief checks whether it can write to the directory holding the binary. If it can't:
- Nothing is downloaded. The abort happens before any network request.
- CommitBrief prints the exact
sudo commitbrief upgradecommand, plus the releases page URL, as copyable next steps. -
CommitBrief never runs
sudoitself. Whether to elevate is entirely your call.
This same gate is what makes an unrecognized distro-packaged install
(/nix/store, root-owned /usr/bin) safe: it's classified as "Manual" (no
matching marker), but the read-only or root-owned location trips this gate
before any file gets touched.
Reports what would happen and installs nothing:
commitbrief upgrade --check- Prints the current version, the latest version, the detected install method, and what action would be taken — but stops there.
- On a manual install, it also runs the permission gate
and prints the same not-writable warning and recovery hint if the target
can't be written — so
--checkreports the install a plainupgradewould actually refuse, rather than promising one that would never happen. Not run under--json(below), which prints only the report object. -
Always exits 0 on any non-error outcome, including "a newer version is
available" and the not-writable warning above. The exit-code contract has
only two codes (0/1, see Exit codes); making "an update
exists" a distinct exit code would be indistinguishable from a genuine
failure to any script checking
$?. Use the printed report (or--json'supdate_availablefield, not the exit code) to detect an available update programmatically.
--json implies --check. It prints exactly one report object to stdout
and installs nothing — whether or not --check was also passed:
commitbrief upgrade --json{
"current": "v1.14.0",
"latest": "v1.15.0",
"method": "homebrew",
"update_available": true,
"action": "brew upgrade commitbrief"
}action describes what would run for a package-managed method, or the asset
name that would be downloaded for a manual install. When there's no update,
update_available is false and action is empty. --json never triggers a
confirmation prompt or an actual install — a delegated package manager writes
its own human-shaped output that would corrupt a machine-readable stream, so
an automated caller that actually wants to install should invoke the package
manager directly.
On a development build (a locally built binary whose version string isn't
a parseable semver, e.g. dev), --json still emits a report rather than
silence: current carries the raw version string as-is, and
update_available is false. Without --json, the same case prints (or, for
a bare upgrade, errors with) a "this is a development build" message
instead.
Without --check/--json, an available update is confirmed before anything
is installed:
- The global
--yesflag skips the prompt. - A non-interactive run (no TTY) without
--yesaborts rather than proceeding unattended — the same non-interactive-abort behavior ascommitbrief commit.
| Code | Condition |
|---|---|
0 |
up to date, --check/--json ran cleanly (update available or not), or the upgrade installed successfully |
1 |
network/API error, no published release, checksum mismatch, unwritable target, missing package-manager tool, a delegated command exiting non-zero, or a development build with a bare upgrade
|
See Exit codes for the project-wide two-code contract this follows.
commitbrief upgrade is the only network request CommitBrief makes on
its own behalf, and it only happens when you run this command — there is no
passive or background version check, no nudge printed after a review, and no
config key that would turn one on. The request carries nothing about you: an
unauthenticated GET to api.github.com with a commitbrief/<version>
User-Agent and nothing else (ADR-0034).
- Installation — the four install methods this command detects and acts on.
-
Exit codes — the two-code contract
--checkrespects. -
Global flags —
--yes,--json.
Home · Installation · Quick start · Troubleshooting · GitHub repo · Issues
CommitBrief — local, LLM-powered code review for git diffs. This wiki documents only what ships in the binary.
Getting started
Commands · reviewing
Commands · summarizing
Commands · committing
Commands · setup
Commands · integration
Commands · inspect
Commands · maintenance
Configuration
Providers
Output
Operations
Reference