Retroactive spec for the work in PR #73, which was implemented without an up-front issue. This captures the goal, the design decisions the implementing agent made, and the assumptions baked into the code so the decision trail exists.
Goal
Add agent-init upgrade — update the installed CLI binary in place from the latest GitHub release. Opt-in and manual; normal commands make no network calls.
What was implemented (PR #73)
- New
internal/selfupdate/ package (github.go, selfupdate.go), wired into internal/cli/cli.go, documented in docs/cli.md and README.md.
- Flags:
--check (report if a newer release exists, no download), --dry-run (download + verify checksum, don't swap), --force (reinstall when current, or upgrade a dev build).
- Reads
releases/latest via the GitHub API (uses GITHUB_TOKEN/GH_TOKEN if set to lift the anonymous rate limit), selects the asset matching host OS/arch, downloads it plus checksums.txt, verifies SHA-256 before touching anything, extracts from tar.gz/zip, resolves the real install path via os.Executable() + symlink resolution, and swaps via atomic write-temp-then-rename with a move-aside fallback. Checksum mismatch aborts and leaves the existing binary untouched.
- Stdlib-only, no new
go.mod dependencies. Hermetic tests cover semver compare, asset/binary naming, checksum match/mismatch/missing, tar.gz + zip extraction, and full flows.
Confirmed design decisions (see decisions.md)
- Manual-only, no automatic update check, ever. No background checks, no per-invocation network call, no nag. You opt in by running the command. Preserves the offline-first stance.
- In-place binary replacement as the update model (vs. telling the user to re-run the install script or
go install), with checksum-before-swap and atomic replace.
Assumptions baked into the code (verify / track)
- Release assets are named
agent-init-<os>-<arch>.tar.gz/.zip with a sibling checksums.txt. True today against release.yml, but now a silent coupling — any change to the release workflow's asset naming breaks upgrade.
- The supported platform set is exactly the release matrix (linux amd64/arm64, darwin arm64, windows amd64). Intel Macs (darwin/amd64) hit a "no asset for platform" error. Decide whether that's acceptable or needs a clearer message / matrix change.
dev builds refuse to upgrade without --force. Reasonable, but a behavior choice made by the agent.
Out of scope / separate items
- Go 1.26.4 toolchain bump to clear the stdlib vuln (GO-2026-5037/5039) surfaced by the new
net/http path — separate issue.
darwin/amd64 (Intel Mac) release coverage, if wanted — separate change to the release matrix.
Pre-merge cleanups for PR #73
- Reconcile the
.agent/CODEBASE.md drift (the regenerated codemap removes three internal/scaffold/color_test.go entries with no matching source change in the diff).
- Confirm the
check.sh / CI gate runs green on the PR head.
Milestone: CI/Release Hardening.
Retroactive spec for the work in PR #73, which was implemented without an up-front issue. This captures the goal, the design decisions the implementing agent made, and the assumptions baked into the code so the decision trail exists.
Goal
Add
agent-init upgrade— update the installed CLI binary in place from the latest GitHub release. Opt-in and manual; normal commands make no network calls.What was implemented (PR #73)
internal/selfupdate/package (github.go,selfupdate.go), wired intointernal/cli/cli.go, documented indocs/cli.mdandREADME.md.--check(report if a newer release exists, no download),--dry-run(download + verify checksum, don't swap),--force(reinstall when current, or upgrade adevbuild).releases/latestvia the GitHub API (usesGITHUB_TOKEN/GH_TOKENif set to lift the anonymous rate limit), selects the asset matching host OS/arch, downloads it pluschecksums.txt, verifies SHA-256 before touching anything, extracts from tar.gz/zip, resolves the real install path viaos.Executable()+ symlink resolution, and swaps via atomic write-temp-then-rename with a move-aside fallback. Checksum mismatch aborts and leaves the existing binary untouched.go.moddependencies. Hermetic tests cover semver compare, asset/binary naming, checksum match/mismatch/missing, tar.gz + zip extraction, and full flows.Confirmed design decisions (see decisions.md)
go install), with checksum-before-swap and atomic replace.Assumptions baked into the code (verify / track)
agent-init-<os>-<arch>.tar.gz/.zipwith a siblingchecksums.txt. True today againstrelease.yml, but now a silent coupling — any change to the release workflow's asset naming breaksupgrade.devbuilds refuse to upgrade without--force. Reasonable, but a behavior choice made by the agent.Out of scope / separate items
net/httppath — separate issue.darwin/amd64(Intel Mac) release coverage, if wanted — separate change to the release matrix.Pre-merge cleanups for PR #73
.agent/CODEBASE.mddrift (the regenerated codemap removes threeinternal/scaffold/color_test.goentries with no matching source change in the diff).check.sh/ CI gate runs green on the PR head.Milestone: CI/Release Hardening.