Skip to content
CodeVetter docs
Esc
navigateopen⌘Jpreview
On this page

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’s version field on main. The paths: filter in auto-release.yml enforces this.
  • Manual workflow_dispatch of auto-release.yml is 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.yml
  • apps/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)

Was this page helpful?