Release Runbook — Kata Agents
Overview
Releases are published to https://github.com/gannonh/kata-agents/releases via
.github/workflows/release.yml. The workflow has three triggers:
schedule— automatic nightly every 3 hours; only proceeds whenmainhas changed since the last nightly tag (seecheck_changesjob); no input neededworkflow_dispatch— manual dispatch withchannel(stable|nightly),version(required for stable, ignored for nightly), anddry_run(true|false)- Tag push — pushing a
v*.*.*tag (excludingv*-nightly.*) triggers a stable release automatically
Recommended order for a new release cycle:
- Nightly Dry Run
- Nightly Release
- Stable Dry Run
- Stable Release
You do not have to run all four. A dry-run failure is expected to be fixed before proceeding.
Release notes (automated)
The in-app What's New overlay reads versioned files at
apps/electron/resources/release-notes/<version>.md. PRs accumulate pending
bullets in next.md, and the workflow promotes them automatically —
no manual promotion commit is needed before dispatching.
build(both channels) writes<core-version>.mdinto the CI checkout only, so nightly bundles the pending notes for the upcoming version. Nothing is committed, so a cycle that later ships as a minor bump leaves no ghost file.finalize(stable, non-dry-run) writes<version>.mdand resetsnext.mdonmaininside thechore(release): prepare v<version>commit.release_meta(stable) fails fast only when there is nothing to ship: no bullets innext.mdand no existing<version>.md.
Nightly and stable of the same core version produce the identical filename
(0.10.11-nightly.20260622.40 → 0.10.11.md), so users who saw the notes on
nightly are not re-prompted when stable ships.
Optional: to give a stable release a human summary instead of the bare
# v<version> header, pre-create <version>.md with a
# v<version> — <summary> title — promotion preserves that title and merges the
pending bullets under it.
Pre-flight checks
Before dispatching any release:
# Confirm main is clean and pushed
git status
git log origin/main..HEAD # should be empty
# Check current development version in electron package (the nightly target
# is computed as X.Y.(Z+1) from this value; stable dispatch uses the version
# input instead)
bun --print "require('./apps/electron/package.json').version"
# Confirm secrets are configured
gh secret list --repo gannonh/kata-agents
# Required: CSC_LINK, CSC_KEY_PASSWORD, APPLE_ID, APPLE_APP_SPECIFIC_PASSWORD,
# APPLE_TEAM_ID, APPLE_SIGNING_IDENTITY
Stable-only: confirm there are notes to ship
Promotion is automatic, but a stable release still fails in release_meta when
there is nothing to promote. Verify locally with the same check the workflow
runs:
version=0.10.7 # the version you are about to release
bun run scripts/release/promote-release-notes.ts --version "$version" --check
If it fails, the pending changes were never written up — append the
user-visible bullets to apps/electron/resources/release-notes/next.md and push
before dispatching. Nightly dispatches skip this check entirely.
Dispatch commands
# Nightly runs automatically on schedule. To trigger one manually:
# Nightly Dry Run
gh workflow run release.yml --repo gannonh/kata-agents \
--field channel=nightly --field dry_run=true
# Nightly Release
gh workflow run release.yml --repo gannonh/kata-agents \
--field channel=nightly --field dry_run=false
# Stable Dry Run (version is required for stable)
gh workflow run release.yml --repo gannonh/kata-agents \
--field channel=stable --field version=0.10.4 --field dry_run=true
# Stable Release (dispatch — version is required)
gh workflow run release.yml --repo gannonh/kata-agents \
--field channel=stable --field version=0.10.4 --field dry_run=false
# Stable Release (tag push — alternative to dispatch)
git tag v0.10.4 && git push origin v0.10.4
For stable dispatch, the version input is the source of truth. It may be
0.10.4 or v0.10.4; the leading v is stripped and the tag becomes v<version>.
The version input is required — stable dispatch without it fails the release_meta
job. Stable dispatch no longer reads apps/electron/package.json.
For nightly, the version is computed automatically as
X.Y.(Z+1)-nightly.YYYYMMDD.N from the current apps/electron/package.json version.
This applies to both the scheduled run and any manual channel=nightly dispatch.
Polling for status
After dispatching, get the run ID and watch it:
# Get the most recent run
gh run list --repo gannonh/kata-agents --workflow=release.yml --limit 3
# View a specific run (replace RUN_ID)
gh run view RUN_ID --repo gannonh/kata-agents
# Fetch logs for a failed job (replace JOB_ID)
gh api repos/gannonh/kata-agents/actions/jobs/JOB_ID/logs | tail -80
The workflow has these jobs: check_changes (scheduled only) → release_meta →
signing_gate → build (matrix) → release → finalize (stable only) → publish_cli (disabled).
check_changesis skipped on non-schedule eventsbuildhas four matrix legs:macos-14 arm64(required),macos-14 x64(required),ubuntu-latest linux x64(best-effort,continue-on-error),windows-latest win x64(best-effort)- The
releasejob only runs whendry_run != true finalizeruns only for successful, non-dry-run stable releases and commits the version bump back tomain(see below)
What to verify at each stage
Dry Run (nightly or stable)
- All four build legs complete (macOS required; Linux/Windows best-effort)
- The
releasejob is skipped (shown as-or not triggered) - No new release appears at https://github.com/gannonh/kata-agents/releases
- No npm publish occurred
# Confirm no release was created
gh release list --repo gannonh/kata-agents --limit 5
Nightly Release
- GitHub release is a prerelease (
is_prerelease=true) - Tag format:
v<X>.<Y>.<Z+1>-nightly.<YYYYMMDD>.<N> - Release is not marked latest
- Assets include:
Kata-Agents-arm64.dmg,Kata-Agents-x64.dmg,.zipequivalents,nightly-mac.yml,nightly.yml(the auto-update manifests)
gh release view --repo gannonh/kata-agents <tag>
# Check: prerelease: true, assets list includes nightly*.yml
Stable Release
- GitHub release is not a prerelease (
is_prerelease=false) - Marked latest
- Assets include: DMGs, ZIPs,
latest-mac.yml,latest.yml
gh release view --repo gannonh/kata-agents <tag>
# Check: prerelease: false, latest: true, assets list includes latest*.yml
Common failures and fixes
| Symptom | Cause | Fix |
|---|---|---|
GitHub Personal Access Token is not set |
electron-builder trying to auto-publish | Add --publish never to the electron-builder invocation in the build script |
Release package manifest not found: D:\D:\... |
Windows path doubling from .pathname |
Use fileURLToPath(import.meta.url) instead of new URL(import.meta.url).pathname |
signing_gate fails |
Missing Apple secrets | Run gh secret list --repo gannonh/kata-agents and add missing secrets from .env |
| macOS build fails after 10+ minutes | Notarization timeout or Apple service issue | Retry; notarization can be rate-limited |
Stable release <version> has no release notes |
next.md has no bullets and no <version>.md exists |
Append the user-visible changes to apps/electron/resources/release-notes/next.md, push to main, then re-dispatch. Promotion itself is automatic. |
Could not push the post-release commit to main after 3 attempts |
finalize lost 3 rebase/push races, or main is protected |
Re-run the finalize job; if it keeps failing, apply the version bump + notes promotion manually with promote-release-notes.ts --version <v> --reset |
Secrets reference
All values are in /Volumes/EVO/dev/kata-agents/.env.
| Secret | Purpose |
|---|---|
CSC_LINK |
Base64 .p12 signing cert |
CSC_KEY_PASSWORD |
.p12 password |
APPLE_ID |
Notarization Apple ID |
APPLE_APP_SPECIFIC_PASSWORD |
App-specific password for notarization |
APPLE_TEAM_ID |
Apple Developer team ID (ZBZKKWF95G) |
APPLE_SIGNING_IDENTITY |
Developer ID Application identity |
GITHUB_TOKEN |
Auto-provided by Actions — no setup needed. Also used by finalize to push the post-stable version bump + notes promotion to main, so repo Workflow permissions must be Read and write |
To re-set a secret from .env:
gh secret set SECRET_NAME --repo gannonh/kata-agents --body "value"
After a successful release
- Verify the release page looks correct at https://github.com/gannonh/kata-agents/releases
- Stable releases: the
finalizejob automatically bumpsapps/electron/package.json+package.jsononmainto the shipped version, promotesnext.md→<version>.md, resetsnext.md, and commitschore(release): prepare v<version>, so the next nightly resolves toX.Y.(Z+1)-nightly.*. No manual bump or promotion needed. Iffinalizefails, apply both manually as a fallback and confirm the commit landed onmainbefore the next stable. - Confirm the What's New overlay shows the new version in the shipped build.
- Update
docs/specs/index.mdanddocs/log.mdif this release closes a project milestone