Releasing GridBash
July 16, 2026 ยท View on GitHub
This repo has an agent-friendly release path:
- Land and verify the product change.
- Create a devlog.
- Run the
ReleaseGitHub Actions workflow. - For a versioned release, GitHub Actions creates the release commit and tag; nightly builds stamp only their ephemeral build workspace.
- GitHub Actions publishes npm and creates the GitHub release.
The release workflow can be run manually from GitHub Actions, runs nightly from
main, and also responds to pushed tags named v*.
One-Time Setup
Prefer npm Trusted Publishing for the Release workflow. Configure the root
package and all five native packages on npmjs.com to trust this repository's
Release workflow (owner jasonsuhari, repository gridbash). New package
names must be bootstrapped once with a short-lived npm token before npm can
attach their trusted publisher settings.
After creating a package or receiving one from npm Support, confirm that
jasonmatthewsuhari is an owner and configure the trusted publisher before the
first GridBash release:
npm owner ls gridbash-win32-x64
npm trust github gridbash-win32-x64 \
--repo jasonsuhari/gridbash \
--file release.yml \
--allow-publish
npm trust list gridbash-win32-x64
Repeat the trust setup for gridbash and every package under npm/platforms/.
The trust command requires an interactively authenticated npm account with 2FA.
Use only the workflow filename (release.yml), not its full repository path.
The release workflow runs node npm/scripts/release-preflight.js before the
native build matrix. It fails early when a package is absent, is not owned by
jasonmatthewsuhari, or advertises a different source repository. A package
that npm transferred from its 0.0.1-security holder is allowed once ownership
is correct; its first GridBash publish replaces the placeholder repository
metadata. The public preflight cannot inspect trusted-publisher settings, so
npm trust list remains the authenticated setup check for each new package.
As a fallback, add an npm automation token as a GitHub repository secret:
NPM_TOKEN
If NPM_TOKEN exists, the workflow uses it. If it does not exist, the workflow
tries npm Trusted Publishing through GitHub Actions OIDC. GitHub release
creation uses the built-in GITHUB_TOKEN.
Create A Devlog
Generate a new draft:
npm run devlog -- --title "Startup grid picker"
Fill in the generated file under docs/devlogs/. Keep it factual:
- what changed
- why it matters
- what was validated
- any known risk
Release From GitHub Actions
After the change is merged to main:
- Open the
Releaseworkflow in GitHub Actions. - Select
Run workflowand leavechannelset torelease. - Set
versiontopatch,minor,major, or an exact version. A plain version such as0.2.0becomes GitHub's Latest release and npm'slatestdist-tag. A hyphenated prerelease uses npm'snextdist-tag instead. - Optionally set
notesto a devlog path such asdocs/devlogs/YYYY-MM-DD-title.md. - Run the workflow.
The workflow runs node npm/scripts/release.js on main. That script creates
and pushes the release commit and vX.Y.Z tag. A separate publish job in the
same workflow run then builds Windows x64, Linux x64/arm64, and macOS arm64/x64
native packages, publishes those packages before the platform-neutral npm
launcher, and creates or updates one GitHub release.
Stable releases publish unsigned macOS artifacts until Developer ID signing and notarization are configured. macOS users may therefore see Gatekeeper warnings. This packaging limitation no longer prevents Windows and Linux users from receiving stable releases through the shared GitHub and npm release workflow.
The channel mapping is automatic:
- plain versions such as
0.2.0: GitHub Latest and npmlatest - prereleases such as
0.3.0-beta.1: GitHub prerelease and npmnext - scheduled nightlies: GitHub prerelease and npm
nightly
Promoting an existing GitHub prerelease manually does not change npm dist-tags. Run the workflow with a plain stable version to update both release channels.
Before creating the release commit, the script fetches origin branch refs and
fails if any unmerged task branches remain under chore/, docs/, feat/,
fix/, refactor/, or test/. Review, merge, or delete those branches before
releasing. Use --allow-unmerged-branches only when the branch queue was
explicitly reviewed and the release is intentionally shipping without those
changes.
If publishing fails after the tag exists, rerun the failed publish job after
fixing credentials. The publish job skips npm when that exact package version
is already live and updates an existing GitHub release with --clobber assets.
If the whole workflow needs to be dispatched again for an exact version whose
tag already exists, the prepare job skips version preparation and publishes the
existing tag.
Registry Publication Incident
When GitHub artifacts exist but npm publication is delayed or blocked by the registry:
-
Treat npm as unavailable for the affected version or platform. Do not claim that
npm install -g gridbashdelivers the GitHub release until it does. -
Keep the existing release tag immutable. Do not create replacement tags or bump versions solely to retry an external registry incident.
-
Put a temporary, factual notice in the website or launch material and pause broad promotion. Direct testers may use matching GitHub release artifacts.
-
Record the failing workflow URL and the external support case privately; never put credentials or private support correspondence in the repository.
-
After npm confirms resolution, rerun the existing exact-version workflow or failed publish job. The publish step is intentionally idempotent and skips package versions that are already live.
-
Verify the root launcher and every native package before clearing the notice:
npm view gridbash version npm view gridbash-win32-x64 version npm view gridbash-linux-x64 version npm view gridbash-linux-arm64 version npm view gridbash-darwin-arm64 version npm view gridbash-darwin-x64 version
The GitHub release succeeding does not make a failed npm publish workflow green. Keep the failure visible until the registry-side work is complete; do not weaken release checks to improve the status signal.
Nightlies
The same Release workflow runs daily from main and supports a manual
channel: nightly dispatch. It stamps an immutable version such as
0.2.0-nightly.20260713.42.gabcdef123456 only in the build workspace, so
nightlies do not create commits or tags on main. The workflow skips a nightly
when the same commit already has a published nightly, unless force_nightly is
selected.
Install the rolling channel with:
npm install --global gridbash@nightly
Prerelease builds use npm's next channel instead:
npm install --global gridbash@next
Separately, if a v* tag is pushed from a local release fallback, the tag push
path in the same workflow publishes npm and creates the GitHub release.
Local Fallback
Use this only when GitHub Actions is unavailable:
npm run release -- patch --notes docs/devlogs/YYYY-MM-DD-title.md --push --yes
Use minor or major instead of patch when appropriate. You can also pass an exact version:
npm run release -- 0.2.0 --notes docs/devlogs/YYYY-MM-DD-title.md --push --yes
The script will:
- require a clean working tree
- require
mainormasterunless--allow-branchis passed - require reviewed/merged origin task branches unless
--allow-unmerged-branchesis passed - bump
package.jsonandCargo.toml - update
Cargo.lock - copy the devlog to
docs/releases/vX.Y.Z.md - run
cargo fmt --check - run
cargo clippy -- -D warnings - run
cargo test - run
node npm/scripts/prepare.js - run
npm pack --dry-run - commit
chore: release vX.Y.Z - create tag
vX.Y.Z - push the commit and tag when
--push --yesis passed
When the tag reaches GitHub, .github/workflows/release.yml builds each native
package, publishes the native packages before gridbash, and creates or updates
one GitHub release with all artifacts and the release notes.
Local Release Without Push
To create the release commit and tag locally without pushing:
npm run release -- patch --notes docs/devlogs/YYYY-MM-DD-title.md
Delete them manually if you were only experimenting:
git tag -d vX.Y.Z
git reset --hard HEAD~1
Only do that for a local release experiment that has not been pushed.
Common Blocker
node npm/scripts/prepare.js assembles the native package for the current host.
On macOS it builds GridBash.app and the nested Apple Speech helper. On Windows,
close running GridBash windows before a local reinstall; Windows can lock the
currently installed executable and make npm fail with EBUSY.
For local testing, use:
npm run install:local
Do not use npm install -g . from worktrees. npm creates a global junction to the worktree that ran it, so a later agent can accidentally make the gridbash command launch an older branch.