# Releasing This project ships through tag-driven CI. A tag of the form `v{REPO_VERSION}+claude{CLAUDE_DESKTOP_VERSION}` on `main` triggers the release job in [`.github/workflows/ci.yml`](.github/workflows/ci.yml), which builds for both architectures, attaches the artifacts to a GitHub Release, and updates the APT, DNF, and AUR repositories. There are two flavors of release: - **Upstream-tracking retag.** A `check-claude-version` workflow runs daily, detects new Claude Desktop releases, bumps the `CLAUDE_DESKTOP_VERSION` repo variable, patches URLs and SRI hashes in `scripts/setup/detect-host.sh` and `nix/claude-desktop.nix`, and pushes a new tag with the same `REPO_VERSION` and a new `+claude{X.Y.Z}` suffix. **No human action required.** These do not get CHANGELOG entries — they're tracked in the tag suffix. - **Project release.** You bumped `REPO_VERSION` because you shipped project changes. Follow the checklist below. ## Pre-release checklist 1. **CI is green on `main`.** All required workflows (CI, tests, shellcheck) passed on the commit you're about to tag. ```bash gh run list --branch main --limit 5 ``` 2. **`CHANGELOG.md` is updated.** The `[Unreleased]` section now reflects what you're about to ship. Move it under a new `[v{REPO_VERSION}]` heading with today's date. 3. **Local tests pass.** ```bash bats tests/ shellcheck scripts/**/*.sh build.sh ``` See [`CLAUDE.md`](CLAUDE.md#linting) for the canonical lint command. 4. **AppImage artifact boots on a clean system.** The `test-artifacts.yml` reusable workflow already runs a `--doctor` smoke test against each format in CI (#592), but if you've touched the launcher or patch surface, build locally and confirm: ```bash ./build.sh --build appimage --clean no ./test-build/claude-desktop-*.AppImage --doctor ``` 5. **The version variables are in sync.** ```bash gh variable get REPO_VERSION gh variable get CLAUDE_DESKTOP_VERSION grep -oP 'x64/\K[0-9]+\.[0-9]+\.[0-9]+' scripts/setup/detect-host.sh | head -1 ``` The grep value should match the `CLAUDE_DESKTOP_VERSION` variable. If not, pull the latest URLs from `main` — the `check-claude-version` workflow may have updated them on `main` without rebasing your branch ([`CLAUDE.md`](CLAUDE.md#common-gotchas) has the recipe). ## Bumping and tagging ```bash # 1. Bump the project version (this is a GitHub Actions variable, not a file). gh variable set REPO_VERSION --body "2.0.13" # 2. Tag with both versions in the tag name. git tag "v2.0.13+claude$(gh variable get CLAUDE_DESKTOP_VERSION)" # 3. Push the tag — this is what kicks off the release build. git push origin "v2.0.13+claude$(gh variable get CLAUDE_DESKTOP_VERSION)" ``` The `REPO_VERSION` variable bump can happen before or after the tag push; CI reads neither directly. The variable exists so future workflow runs know the current project version. ## What CI does on tag push The [`release`](.github/workflows/ci.yml) job in `ci.yml` is gated on `startsWith(github.ref, 'refs/tags/v')`. After `test-flags`, `build-amd64`, `build-arm64`, and `test-artifacts` pass: 1. Downloads all nine assets (six packages -- amd64 + arm64, each in deb/rpm/AppImage -- plus two `.zsync` delta files and a `reference-source.tar.gz`). 2. Pulls release notes from the separate [`aaddrick/claude-desktop-versions`](https://github.com/aaddrick/claude-desktop-versions) repo if available; falls back to the autogenerated changelog otherwise. 3. Creates the GitHub Release and attaches the nine assets. 4. Hands off to `update-apt-repo`, `update-dnf-repo`, and `update-aur-repo`, which publish to the Cloudflare-fronted package repos ([`docs/learnings/apt-worker-architecture.md`](docs/learnings/apt-worker-architecture.md) for the redirect chain). ## After the release lands - **Verify the Release page.** Nine assets attached, sizes look right, release notes rendered. - **Smoke-test one artifact.** Download the AppImage and run `--doctor` against it. - **Watch `apt-repo-heartbeat`.** The next daily run validates the redirect chain end-to-end. If it opens a tracking issue, walk the chain in [`docs/learnings/apt-worker-architecture.md`](docs/learnings/apt-worker-architecture.md#heartbeat-failure-runbook). ## If something goes wrong mid-release - **Build fails.** Push the fix to `main`, then re-tag with a new `+claude` suffix (or a `+rebuild.N` suffix if upstream hasn't moved). The original tag stays — releases are append-only. - **A bad release shipped.** Mark the GitHub Release as a pre-release / draft and ship a follow-up. Don't delete artifacts that may already be cached by the APT/DNF Worker. - **The `check-claude-version` workflow conflicts with your local branch.** Pull URL changes from `main` before pushing your tag — the workflow autobumps `scripts/setup/detect-host.sh` between your work and your tag.