This document covers the unified release workflow for stable and nightly desktop releases.
- Workflow:
.github/workflows/release.yml - Triggers:
- push tag matching
v*.*.*for stable releases - scheduled nightly at
09:00 UTC - manual
workflow_dispatchfor either channel
- push tag matching
- Runs quality gates first: lint, typecheck, test.
- Builds four artifacts in parallel for both channels:
- macOS
arm64DMG - macOS
x64DMG - Linux
x64AppImage - Windows
x64NSIS installer
- macOS
- Publishes one GitHub Release with all produced files.
- Stable tags with a suffix after
X.Y.Z(for example1.2.3-alpha.1) are published as GitHub prereleases. - Only plain stable
X.Y.Zreleases are marked as the repository's latest release. - Nightly runs are always GitHub prereleases and never marked latest.
- Automatically generated release notes are pinned to the previous tag in the same channel, so stable compares to the previous stable tag and nightly compares to the previous nightly tag.
- Stable tags with a suffix after
- Includes Electron auto-update metadata (for example
latest*.yml,nightly*.yml, and*.blockmap) in release assets. - Publishes the CLI package (
apps/server, npm packaget3) with OIDC trusted publishing from the same workflow file:- stable releases publish npm dist-tag
latest - nightly releases publish npm dist-tag
nightly
- stable releases publish npm dist-tag
- Signing is optional and auto-detected per platform from secrets.
- Workflow:
.github/workflows/release.yml - Triggers:
- scheduled every day at
09:00 UTC - manual
workflow_dispatchwithchannel=nightly
- scheduled every day at
- Runs the same desktop quality gates and artifact matrix as the tagged release flow.
- Publishes a GitHub prerelease only:
- tag format:
nightly-vX.Y.Z-nightly.YYYYMMDD.<run_number> - release name includes the short commit SHA
make_latestis alwaysfalse
- tag format:
- Uses the current
apps/desktop/package.jsonsemver core (X.Y.Z) as the nightly base, then appends a nightly prerelease suffix. - Publishes Electron auto-update metadata to the dedicated
nightlyupdater channel, so desktop users can opt into that track independently from stable. - Publishes the CLI package (
apps/server, npm packaget3) to thenightlynpm dist-tag using the same nightly version. - Does not commit version bumps back to
main.
- Runtime updater:
electron-updaterinapps/desktop/src/main.ts. - Update UX:
- Background checks run on startup delay + interval.
- No automatic download or install.
- The desktop UI shows a rocket update button when an update is available; click once to download, click again after download to restart/install.
- Provider: GitHub Releases (
provider: github) configured at build time. - Repository slug source:
T3CODE_DESKTOP_UPDATE_REPOSITORY(formatowner/repo), if set.- otherwise
GITHUB_REPOSITORYfrom GitHub Actions.
- Temporary private-repo auth workaround:
- set
T3CODE_DESKTOP_UPDATE_GITHUB_TOKEN(orGH_TOKEN) in the desktop app runtime environment. - the app forwards it as an
Authorization: Bearer <token>request header for updater HTTP calls.
- set
- Required release assets for updater:
- platform installers (
.exe,.dmg,.AppImage, plus macOS.zipfor Squirrel.Mac update payloads) - channel metadata:
latest*.ymlfor stable releases,nightly*.ymlfor nightly releases *.blockmapfiles (used for differential downloads)
- platform installers (
- macOS metadata note:
electron-updaterreadslatest-mac.ymlon stable andnightly-mac.ymlon nightly, for both Intel and Apple Silicon.- The workflow merges the per-arch mac manifests into one channel-specific mac manifest before publishing the GitHub Release.
The workflow publishes the CLI with npm publish from apps/server after bumping
the package version to the release tag version.
Checklist:
- Confirm npm org/user owns package
t3(or rename package first if needed). - In npm package settings, configure Trusted Publisher:
- Provider: GitHub Actions
- Repository: this repo
- Workflow file:
.github/workflows/release.yml - Environment (if used): match your npm trusted publishing config
- Ensure npm account and org policies allow trusted publishing for the package.
- Create release tag
vX.Y.Zand push; workflow will:- set
apps/server/package.jsonversion toX.Y.Z - build web + server
- run
npm publish --access public --tag latest
- set
- Nightly runs from the same workflow file publish with
npm publish --access public --tag nightly.
Use this first to validate the release pipeline.
- Confirm no signing secrets are required for this test.
- Create a test tag:
git tag v0.0.0-test.1git push origin v0.0.0-test.1
- Wait for
.github/workflows/release.ymlto finish. - Verify the GitHub Release contains all platform artifacts.
- Download each artifact and sanity-check installation on each OS.
Required secrets used by the workflow:
CSC_LINKCSC_KEY_PASSWORDAPPLE_API_KEYAPPLE_API_KEY_IDAPPLE_API_ISSUER
Checklist:
- Apple Developer account access:
- Team has rights to create Developer ID certificates.
- Create
Developer ID Applicationcertificate. - Export certificate + private key as
.p12from Keychain. - Base64-encode the
.p12and store asCSC_LINK. - Store the
.p12export password asCSC_KEY_PASSWORD. - In App Store Connect, create an API key (Team key).
- Add API key values:
APPLE_API_KEY: contents of the downloaded.p8APPLE_API_KEY_ID: Key IDAPPLE_API_ISSUER: Issuer ID
- Re-run a tag release and confirm macOS artifacts are signed/notarized.
Notes:
APPLE_API_KEYis stored as raw key text in secrets.- The workflow writes it to a temporary
AuthKey_<id>.p8file at runtime.
Required secrets used by the workflow:
AZURE_TENANT_IDAZURE_CLIENT_IDAZURE_CLIENT_SECRETAZURE_TRUSTED_SIGNING_ENDPOINTAZURE_TRUSTED_SIGNING_ACCOUNT_NAMEAZURE_TRUSTED_SIGNING_CERTIFICATE_PROFILE_NAMEAZURE_TRUSTED_SIGNING_PUBLISHER_NAME
Checklist:
- Create Azure Trusted Signing account and certificate profile.
- Record ATS values:
- Endpoint
- Account name
- Certificate profile name
- Publisher name
- Create/choose an Entra app registration (service principal).
- Grant service principal permissions required by Trusted Signing.
- Create a client secret for the service principal.
- Add Azure secrets listed above in GitHub Actions secrets.
- Re-run a tag release and confirm Windows installer is signed.
- Ensure
mainis green in CI. - Bump app version as needed.
- Create release tag:
vX.Y.Z. - Push tag.
- Verify workflow steps:
- preflight passes
- all matrix builds pass
- release job uploads expected files
- Smoke test downloaded artifacts.
- macOS build unsigned when expected signed:
- Check all Apple secrets are populated and non-empty.
- Windows build unsigned when expected signed:
- Check all Azure ATS and auth secrets are populated and non-empty.
- Build fails with signing error:
- Retry with secrets removed to confirm unsigned path still works.
- Re-check certificate/profile names and tenant/client credentials.