Skip to main content
HyperFrames publishes two release channels:
  • Stable releases use versions like 0.4.24 and publish to the npm latest dist-tag.
  • Prereleases use versions like 0.4.24-alpha.1 and publish to the npm dist-tag named by the prerelease suffix, such as alpha.

Branch policy

Use branch separation to decide what code is eligible for each release channel. Dist-tags only control npm install defaults; they do not remove code from a package.
  • main is stable/releasable. Anything merged to main is eligible for latest.
  • release/v* branches are for stable patch releases and hotfixes.
  • next, alpha, beta, rc, canary, and prerelease/* branches are for prerelease integration.
If a feature should ship in alpha only, merge or retarget that PR to a prerelease branch instead of main.

Stable release

Stable releases publish only when a reviewed release/vX.Y.Z PR merges into protected main. Prepare and review release notes before creating the release commit:
On the first run, release:prepare drafts missing changelog artifacts and exits non-zero for review so chained release commands stop before tagging. After the generated TODO summary is rewritten, rerun the same command to create the release commit and tag. See Changelog process for the full workflow. For stable releases, bun run set-version <version> still enforces this checkpoint when maintainers run the lower-level release command directly. Push the release branch without its local tag, open a PR to main, and merge it after approval and CI. The publish workflow checks out the exact PR merge SHA, verifies it before publishing, creates the stable tag at that commit, publishes npm packages, and creates the GitHub release. If that workflow needs recovery, rerun its original merged-PR event. Stable tag pushes and manual dispatches do not publish, so recovery cannot select a different commit. For hotfixes, branch from the last stable tag, cherry-pick only the fix, publish the patch release, then merge or cherry-pick the same fix back into the prerelease branch.

Alpha release

Alpha releases must be reachable from a prerelease branch such as origin/next or origin/alpha. Use the same changelog draft workflow when the prerelease contains changes that users should know about.
Consumers can install alpha builds explicitly:

CI guardrails

The publish workflow validates release channel boundaries before publishing:
  • Stable versions must publish with latest.
  • Prerelease versions must publish with the prerelease dist-tag, such as alpha.
  • Stable releases must come from a merged, reviewed release/vX.Y.Z PR.
  • Prerelease tags must be reachable from a prerelease branch.
  • Merged release/vX.Y.Z PRs publish stable releases only.
  • Every publish job verifies that its checkout matches the immutable event SHA.
This prevents an alpha-only feature from being included in a stable hotfix by accident.

Stable guard maintenance

Stable publishing requires the repository secret RELEASE_GUARD_TOKEN. Its named owner must provision and rotate a dedicated fine-grained personal access token with an explicit expiry and only these repository permissions: Administration (read-only) and Pull requests (read-only). Metadata read access is added automatically by GitHub. Scope the token to this repository only; do not grant Contents, Packages, Workflows, or organization write access. The publish workflow passes this credential only to the read-only stable guard; checkout, tag creation, npm provenance, and GitHub Release writes continue to use their existing credentials. After provisioning or rotation, an administrator must run the read-only capability check from a protected environment that injects the secret without putting its value on the command line:
The protected environment must supply RELEASE_GUARD_TOKEN. The check reads effective main rules, repository rule suites, reviews for the probe PR, and check runs for the probe SHA. Public check-run reads may not expose a separate fine-grained permission in GitHub’s PAT UI, so this same-client capability proof is authoritative. It reports only endpoint/status/request-ID classification on failure and never prints response bodies, headers, or the credential. Record a successful check before merge. If the secret is missing, expired, incorrectly scoped, or the capability check does not pass, this PR must not merge and the stable workflow will fail before creating a tag. The separate release-guard credential health workflow repeats these reads every Monday and supports a safe manual run after provisioning or rotation. It discovers a recent merged main pull request and verifies effective rules, its exact month-window rule suite, reviews, and check runs. It has only contents: read on the built-in token, passes RELEASE_GUARD_TOKEN only to the health step, and has no release, tag, package, or publish path. Required checks remain dynamically sourced from effective rules, but each must identify a concrete GitHub App integration so the guard can reduce actual check runs. A new required context without a positive integration ID is unsupported and fails closed; the guard never falls back to legacy commit statuses. Configured stable-guard timeouts must be 15–40 minutes, with a 25-minute default. The stable guard intentionally fails closed when GitHub adds a rule type it does not recognize. If a release reports Unsupported effective repository rule, inspect the effective rules for main and decide whether the new rule needs an explicit check or is already enforced by the exact update rule-suite result. Add a rule to NON_CHECK_RULES only when a pass rule suite fully covers it; never soften the unknown-rule failure into a warning. After updating and reviewing the guard, rerun the original merged-PR workflow for recovery. Do not push a stable tag, select a different SHA, or introduce a manual publish path. Bypass rejection is intentional: a ruleset result of bypass permanently blocks that merge SHA from publishing. Release PRs must merge normally with their required approval and checks. If a release PR was bypass-merged, prepare a fresh release PR and merge it normally; rerunning the bypassed event cannot turn its historical rule-suite result into pass.