Release pipeline
How a desktop version bump becomes a signed GitHub Release with auto-update.
Release pipeline
The desktop app ships as a Tauri 2 macOS binary distributed through GitHub
Releases with @tauri-apps/plugin-updater auto-update. Three workflows
cooperate.
The chain
tauri.conf.json version bumped on main
│
▼
auto-release.yml (on push to main, paths: tauri.conf.json)
├─ read version → tag v<version>
├─ if release exists → no-op (idempotent)
├─ gh release create v<version> --generate-notes
└─ gh workflow run release.yml -f tag=v<version> ← explicit dispatch
│
▼
release.yml (on release.created OR workflow_dispatch with tag)
├─ checkout the tag (not main head)
├─ pnpm install --frozen-lockfile
├─ prepare:mcp-sidecar:release + universal Agent Island helper + vite build
├─ tauri build (macos-latest) → DMG + signed updater archive
├─ upload assets to the release
└─ upload latest.json manifest (consumed by the updater)
│
▼
installed apps poll latest.json → auto-update
Why the explicit dispatch
auto-release.yml creates the release using GITHUB_TOKEN. Workflows
triggered by GITHUB_TOKEN do not cascade to other workflows — this is a
documented GitHub anti-recursion safeguard. workflow_dispatch is the one
event that fires even from GITHUB_TOKEN, so auto-release.yml dispatches
release.yml explicitly with gh workflow run release.yml -f tag=….
Idempotency
auto-release.yml checks gh release view v<version> first; if it exists,
the whole job no-ops. Re-pushing the same version is safe.
What triggers a release
- Only a change to
apps/desktop/src-tauri/tauri.conf.json’sversionfield onmain. Thepaths:filter inauto-release.ymlenforces this. - Manual
workflow_dispatchofauto-release.ymlis also possible.
Cut a release
See runbooks/cut-a-release.md.
Signing
release.yml uses Apple signing/notarization secrets (APPLE_*) stored as
GitHub Actions secrets. Signed release publication is the last gate; the
graph + MCP budget qualification runs before the build (see
development/performance.md).
The optional Native Agent Island is bundled as a nested universal sidecar. Release verification checks arm64 and x86_64 slices plus its nested code signature before assets are uploaded.
Auto-updater
- Endpoint:
https://github.com/Codevetter/codevetter/releases/latest/download/latest.json - Pubkey: pinned in
tauri.conf.json(plugins.updater.pubkey). dialog: false— the app applies updates without a prompt dialog.
Key files
.github/workflows/auto-release.yml.github/workflows/release.ymlapps/desktop/src-tauri/tauri.conf.json(version + updater config)apps/desktop/src-tauri/tauri.macos.conf.json(macOS-only Agent Island sidecar)apps/desktop/scripts/prepare-mcp-sidecar.mjs(sidecar bundling)apps/desktop/scripts/prepare-agent-island.mjs(universal native helper)scripts/verify-release-manifest.mjs(post-upload manifest linkage check; see automation-contract.md)