For AI agents: this page as Markdown · llms.txt · JSON Schema

Releasing Rerail

How core is built, versioned and published. Rule packs release separately; see pack-format.md.

Release

Merging the Release pull request tags a version; the tag builds, checks and publishes core.

Build

.github/workflows/release.yml builds the package the updater installs, via .github/workflows/package.yml, and test-installs it on each platform before publishing.

Build and check steps
  1. Compile the native kernel for macOS, Linux glibc and Windows MSVC, on arm64 and x64.
    • Linux builds against glibc 2.17 with napi-rs's cross toolchain; a kernel needing glibc newer than 2.28 is rejected.
    • A Windows kernel importing the Visual C++ runtime is rejected. The kernels link it statically, so a clean Windows install needs no redistributable.
  2. Smoke-test native loading and device storage on each host.
  3. Build the runtime and bundled UI; pack only if all six native/*.node files are present.
  4. Install the tarball into a scratch prefix; check rerail --help, the bundled UI and nativeHealth().
  5. On Windows x64, Linux x64 and macOS arm64, install it as a user would and exercise the managed runtime: scripts/host/windows-install-smoke.ps1 on Windows, the environment matrix's scripts/host/azure/guest.sh through matrix.mjs local on Linux and macOS. Nothing publishes unless all three pass.

Release pull request

.github/workflows/release-pr.yml refreshes the Release pull request on every push to main. It also carries the rule pack bumps (docs/pack-format.md).

Exact bump and tag details

Installer plugins

The same bump re-pins the installer plugins (plugins/claude, plugins/codex, plugins/cursor) to the version just released. Publish a new plugin version only once the release is on npm.

Per-store publishing, pins and stamping

Tags and channels

A v<version> tag, equal to package.json's version, publishes @neralabs/rerail to npmjs on the channel it names, after a reviewer approves.

Tag Channel
v0.2.0 latest (stable)
v0.2.0-beta.1 beta
v0.2.0-next.1 next
Publishing rules and checks

Manual runs and put-back

workflow_dispatch builds a trial tarball, retries a failed release, or puts latest back to an earlier version.

Retrying a failed release

Release tags can't be moved or deleted, and re-running a failed run reuses the tag's scripts. So when a release fails before publishing because of something that doesn't ship, such as a workflow or a release script, fix that on main and run:

bash
gh workflow run release.yml --ref main -f publish=<version>

The run builds main, runs every check and publishes behind the same approval. The tag stays where it is, and npm's provenance names the main commit. It is refused unless all of these hold, so core's own code is the tag's:

How the package is built and its changelog can still differ from the tag, so that a fix to the build can be retried too. The run summary lists every path changed since the tag, starting with those that can change the tarball (PACKAGE_INPUTS): the build workflow and its actions, the shrinkwrap step, .gitattributes and CHANGELOG.md. Check that list before approving.

If the fix changes what ships, it takes the next version: the Release pull request offers one as soon as the fix is on main. Say in that version's lead that the failed version was never published, since its notes won't reach anyone updating past it.

What a put-back also does

The put-back uses trusted publishing behind the same approval as a release, so no one needs an npm login to put core back. If next is older than that version, it raises next to it too. The run's GitHub Release job then makes that version's Release the repository's latest.

Build cache

.github/workflows/release-cache.yml keeps the native builds' cargo caches warm. After changing Cargo.lock, the Cargo manifests, .cargo/config.toml or rust-toolchain.toml, let it finish before merging the Release pull request. Otherwise the release builds cold.

How the caches are used

Environment matrix

.github/workflows/env-matrix.yml builds the same package after each push to main that can change what ships. It installs it as a user would; see docs/environment-matrix.md for environments, checks and manual runs.

Machines and user path

Each follows a user's path: npx @neralabs/rerail setup, the managed runtime, PATH in a new shell, the coding-agent hooks, daemon restart and removal.

Release notes

Release notes pitch the release to people who opt into each update; the GitHub Release publishes them unchanged.

Why, assembly and CI checks

Entry files mean pull requests never edit the same lines of CHANGELOG.md. Entries leave detail to the docs they link, and leave out commit hashes, ticket ids, pull request numbers and repository-internal maintenance. The lead goes before the first entry; add the ## Unreleased heading if the last release took it. It belongs on main because every push rewrites the Release pull request.

Assembly. The Release pull request renames the heading ## <version> (<date>), dated the day it last updated from main. It puts pending entries under the lead, under a ### <type> heading for each change type that has one (Added, Changed, Deprecated, Removed, Fixed, Security, in that order, file-name order within a type), and deletes their files. With neither lead nor entry, the section says no entries were written. Should an entry with no type reach main, core is left out of the Release pull request, and its description says why, until the file is renamed; the packs still release.

CI (scripts/release/core-changelog-check.mjs, in ci.yml's lint job) fails:

GitHub Releases

Every released version, core's and each pack's, gets a GitHub Release on its tag, with its CHANGELOG.md section as notes.

Backfill creates Releases for tags without one, such as older releases or runs that failed before their Release:

  1. Sync tags: git fetch --tags --prune --prune-tags (add --force for a tag rejected as changed).
  2. Preview: node scripts/release/github-release.mjs --backfill --dry-run.
  3. Run it without --dry-run; your gh login needs repository write access.
How Releases are made, and which tags backfill skips

Shrinkwrap

The tarball ships an npm-shrinkwrap.json, so installs get exactly the dependencies package-lock.json pinned.

How the shrinkwrap is written and checked

The managed install (src/setup/updater.ts) runs no install scripts (--ignore-scripts). A new dependency needing an install script would break after rerail update; check before adding one.

Install-time verification