Release CLI
Tag-driven CLI release: git tag v* → GitHub Actions runs GoReleaser → cross-compiled binaries upload to Vercel Blob → install script (/cli/install) auto-detects OS/arch.
Default stance
Use the script. Don't tag manually. ./scripts/release-cli.sh v0.x.y validates branch state, runs goreleaser check, optionally does a snapshot dry-run, creates and pushes the tag, monitors the workflow, and verifies the binaries are downloadable. Manual git tag && git push skips all of those checks and is how broken releases reach cli/latest/.
Releases happen from main, after CLI changes are merged through normal PR flow. Don't release from a feature branch. Don't release from staging. The pipeline trusts that main is releasable.
Use this skill when
Releasing the CLI, tagging a v* version, debugging a failed release, or verifying that a release succeeded end-to-end (binaries on Blob, install script working).
Quick release
./scripts/release-cli.sh v0.2.0
This:
- Validates you're on
mainand clean. - Runs
goreleaser checkto validate.goreleaser.yml. - Optional
--snapshotdry-run build (locally, no upload). - Creates and pushes the git tag.
- Monitors the GitHub Actions release workflow.
- Verifies binaries are downloadable from Blob.
Manual sequence (when the script doesn't fit)
- Ensure all CLI changes are merged to
main. goreleaser check— validate config.- Optional dry run:
goreleaser build --snapshot --clean. git tag v0.2.0.git push origin v0.2.0.gh run watch— workflow triggers onv*tags.curl -sSf https://seed.unionstreet.ai/cli/install | sh— verify install works.
What the pipeline does
git tag v0.2.0 → push → GitHub Actions (Release CLI workflow):
1. GoReleaser cross-compiles 5 targets (linux amd64/arm64, darwin amd64/arm64, windows amd64)
2. Archives: tar.gz (linux/mac) + zip (windows)
3. @vercel/blob SDK uploads to:
- cli/v0.2.0/<arch>.tar.gz (versioned — immutable)
- cli/latest/<arch>.tar.gz (latest — overwritten each release)
Build targets
| OS | Arch | Archive |
|---|---|---|
| linux | amd64 | tar.gz |
| linux | arm64 | tar.gz |
| darwin | amd64 | tar.gz |
| darwin | arm64 | tar.gz |
| windows | amd64 | zip |
Blob storage layout
Binaries live at BLOB_BASE_URL/cli/.... The app serves them via:
| Route | Purpose |
|---|---|
/cli | Browser install page |
/cli/install | curl | sh script — auto-detects OS/arch |
/cli/download/[filename] | 302 redirect to Blob |
Hard rules
- Never tag from
stagingor a feature branch. Main only. - Never reuse a version. Tags are immutable; trying to overwrite a
v*tag breakscli/v*/consumers and the install script's version detection. - Never bypass
goreleaser check. A misconfigured.goreleaser.ymlwill produce broken or partial releases that look like they succeeded. - Don't skip the post-release verification step. A green Actions run doesn't prove the install script works — pull the binary and run it.
Version conventions
v0.x.y— pre-1.0, breaking changes allowed between minor versions.- Semantic versioning:
vMAJOR.MINOR.PATCH. - Tags must match
v*pattern to trigger the workflow.
Forking for a new product
When a fork ships its own CLI:
- Update
project_namein.goreleaser.yml. - Update
cliNameinlib/brand.ts. - Verify
BLOB_READ_WRITE_TOKENis available (inherited from org secret, or set per-repo). - First release:
git tag v0.1.0 && git push origin v0.1.0(or use the script).
Where things live
| File | Purpose |
|---|---|
.goreleaser.yml | GoReleaser config (build targets, archive format, Blob upload) |
.github/workflows/release-cli.yml | GitHub Actions workflow — triggers on v* |
scripts/release-cli.sh | One-shot release entrypoint |
lib/brand.ts | cliName (used in install script and binary naming) |
app/cli/ | Public install page + install script + download redirect |
cli/ | CLI source — see cli-development |
Auxiliary content
- references/original-guide.md — full canonical guide with pipeline details and fork checklist
- references/graph.md — handoff to
cli-development,run-quality-gates,promote-deployment - scripts/release-cli-check.sh — preflight: branch clean, on main,
goreleaser check, optional snapshot build; run beforerelease-cli.sh - assets/cli-release-checklist.md — pre-release checklist (changelog, version bump, smoke against new binary, install verification)
- assets/evals/basic.json — eval cases for skill regression