marcus / release-sidecar
Release new versions of sidecar. Covers version tagging with semver, td dependency updates, go.mod validation, CHANGELOG updates, GoReleaser automation, Homebrew tap updates, and verification steps. Use when preparing or executing a release.
Releasing a New Version
Operator contract: docs/guides/active/releasing.md. Enforcement lives in scripts/ andBUMP=minor make release (or RELEASE_VERSION=vX.Y.Z make release for an explicit
version). Prefer the one-shot command over replaying this checklist by hand.
Prerequisites
- Go matching
go.mod - Clean working tree;
mainidentical to liveorigin/main Tests and Go CI green on the commit you will tag (tests and lint) —
check-release-state.shnow checks this itself via `gh run list
--workflow=go-ci.yml` and fails closed if it's red/running/missing, so you
don't have to remember to look- GitHub CLI authenticated with push access to
marcus/homebrew-tap - No
replacedirectives ingo.mod HOMEBREW_TAP_TOKENsecret present in the GitHub repo (CI tap job)
Beware of go.work: always use GOWORK=off when updating dependencies and
when validating install paths.
Local lint must match CI's golangci-lint v2.12.2, or trust CI:
gh run list --workflow=go-ci.yml --limit=1Prepare (sidecar-specific)
1. Version
git tag -l 'v*' | sort -V | tail -1SemVer: major / minor / patch as usual.
2. Sibling dependencies (td, tasks)
make sync-deps # pins every github.com/marcus/* requirement to its latest tagcheck-release-state.sh enforces this and refuses to tag when one is behind.go.work resolves those imports to the local checkouts, so drift is invisible
locally — both the gate and sync-deps use GOWORK=off. If a sibling jumped
several minors, decide deliberately (pin for a focused release vs take latest
and note it under Dependencies) and smoke its tab in the app.
3. CHANGELOG
## [Unreleased]
### Features
- …
### Bug Fixes
- …
### Dependencies
- …Commit the changelog (and any dependency bump) on main, then push soHEAD == origin/main. Leave the heading as ## [Unreleased] — make release
stamps it to ## [vX.Y.Z] - YYYY-MM-DD for you.
Publish
# Dry-run (optional but recommended for tooling changes)
make release-snapshot
./scripts/verify-release-archives.sh dist
./scripts/test-release-guards.sh dist
./scripts/test-release-publication.sh
make release-dry-run BUMP=minor # prints the derived version + plan, no mutation
# Cut the release: derive the version, stamp the changelog, commit, push,
# then the fail-closed preflight → tag → CI → formula verify/publish
BUMP=minor make releaseThe version is stated exactly once — via BUMP derived from the latest tag, or
by setting RELEASE_VERSION=vX.Y.Z yourself (also works if you stamped the
CHANGELOG heading by hand). scripts/release.sh refuses an empty [Unreleased]
section, a tree dirty beyond CHANGELOG.md, a tag that already exists, and aRELEASE_VERSION that contradicts an already-stamped heading, before handing off
to scripts/publish-release.sh. What it enforces and does end to end is
documented in docs/guides/active/releasing.md.
Resume only the tap step if the tag/release already exists:
RELEASE_VERSION=vX.Y.Z make release-tapCI jobs (on tag push)
verify— tag points at livemain, tests, snapshot archives, release guardsrelease— GoReleaser publishes GitHub release + binariesupdate-homebrew-tap— renderspackaging/homebrew/sidecar.rb.tmpland
pushesFormula/sidecar.rbwith downgrade/idempotency/race guards
td/nightshift formulas are not auto-bumped; edit them by hand when co-releasing.
Verify
gh run list --workflow=release.yml --limit=1
gh release view vX.Y.Z --json assets -q '.assets[].name'
GOBIN=$(mktemp -d) GOWORK=off go install github.com/marcus/sidecar/cmd/sidecar@vX.Y.Z
"$GOBIN/sidecar" --versiongo install @vX.Y.Z can 500 from the checksum DB for a minute or two after the
tag — wait and retry. Prefer a throwaway GOBIN so verification does not
clobber a dev machine's sidecar.
Dev machine after release
# Return to the canonical main development build:
make install-local
# Or keep the released Homebrew build active:
make use-homebrew
# In either case, prove the managed link and both login-shell modes:
make install-statusRecovery
Prefer a new patch release. Keep tags. Resume tap with make release-tap.
See docs/guides/active/releasing.md.
Checklist
- [ ] Go CI green (tests + lint) on the commit to tag — enforced automatically by
check-release-state.sh - [ ] Working tree clean;
main==origin/main - [ ] td bump considered; td tab smoke if td moved
- [ ] No
replacein go.mod;GOWORK=offbuild works - [ ] Agent integration assets: if any bundled asset's bytes changed, its version constant,
internal/agentlifecycle/capabilities.json, and the golden ininternal/agentintegration/asset_golden_test.goall moved with it (the golden test fails if they did not) - [ ] CHANGELOG bullets under
## [Unreleased] - [ ]
BUMP=minor make release(orRELEASE_VERSION=vX.Y.Z make release) succeeded - [ ] Release assets present; formula URL/sha match (automatic)
- [ ]
go installverified into throwawayGOBIN - [ ]
make install-statusproves the dev machine is on the intended binary