Project
Releasing Renox
How a new version is published.
How a release goes to crates.io. Only a maintainer with publish rights on the nine crates
(renox, renox-core, renox-macros, renox-cli and the plugins renox-2fa,
renox-editors, renox-oauth, renox-admin and renox-billing) can do it. All nine share the workspace's
version and are released together.
#The machine that publishes
- A crates.io account with a verified email address (crates.io refuses to publish without
one), and publish rights on the nine names. The release candidates (
1.0.0-rc.1torc.4) created them; a new crate (a new plugin) gets its name at its firstcargo publish, which gives the publisher those rights. cargo loginon the machine that publishes. The token stays in~/.cargo/credentials.toml: never put it in the repository, an issue, a chat or an environment variable that a script prints.- A release candidate is worth it before a big release: publish
x.y.0-rc.1, check that docs.rs builds the API reference and thatcargo install renox-cli --version x.y.0-rc.1 && rnx new demoworks from crates.io, then publishx.y.0. Cargo never picks a pre-release unless asked (renox = "1.0.0-rc.1").
#Every release
- Main is green. The last CI run on
mainpassed, including PostgreSQL, chaos, the CLI jobs and the semver checks. - Choose the version (see docs/stability.md): a fix is a patch,
anything new a minor, a breaking change a major. Set it in the workspace
Cargo.tomlin nine places that must agree:[workspace.package] versionand theversionofrenox,renox-core,renox-macros,renox-2fa,renox-editors,renox-oauth,renox-adminandrenox-billingunder[workspace.dependencies](written=1.2.0: the crates are released in lockstep and pin each other exactly, since the macros write code against renox-core's items of the same release). While 1.0 is a release candidate, other places name the version too; change all of them:- the install lines in
README.md(quick start) anddocs/tutorial.md(cargo install renox-cli --version …); - the
git clone --branch v…line inREADME.md("Use Renox with Claude Code"); - the version in
README.md's "Status" section; - the example dependency line in
docs/stability.md(renox = "…").grep -rn "1.0.0-rc" README.md docsfinds them.
- the install lines in
- The changelog. In
CHANGELOG.md, rename "Unreleased" to## 1.2.0 · 2026-11-01(the version and the date) and start a new empty "Unreleased" above it. - Check everything (as in CONTRIBUTING.md), then a dry run of the
crates that don't need another Renox crate on crates.io first:(
cargo publish --dry-run -p renox-macros cargo publish --dry-run -p renox-core cargo publish --dry-run -p renox-clirenox-clidoesn't depend on the other Renox crates.)renoxcan't be dry-run before this version ofrenox-coreandrenox-macrosis on crates.io, andrenox-2fa,renox-editors,renox-oauth,renox-adminandrenox-billingnot beforerenoxis: they depend on them. - Commit and merge the version and changelog as a pull request, as for any change.
- Publish in this order from an up-to-date
main(each waits until the previous one is in the index):cargo publish -p renox-macros cargo publish -p renox-core cargo publish -p renox cargo publish -p renox-cli cargo publish -p renox-2fa # plugins depend on renox, so they go after it cargo publish -p renox-editors cargo publish -p renox-oauth cargo publish -p renox-admin cargo publish -p renox-billingrenox-coreandrenox-macrosuserenoxonly as a path dev-dependency, whichcargo publishleaves out, so the order has no cycle. - Tag the commit:
git tag v1.2.0 && git push origin v1.2.0. Apps made byrnx newfrom crates.io link theirAGENTS.mdto the docs at that tag. - Check the release:
- docs.rs shows
renoxandrenox-core(built withpostgres,uuidandxlsx), andrenox-2fa,renox-editors,renox-oauth,renox-adminandrenox-billing; cargo install renox-clithenrnx new demo:demo/Cargo.tomlhasrenox = { version = "1.2" }andcargo testpasses in it.
- docs.rs shows
- A GitHub release for the tag, with the version's changelog section as its notes.
#After the first release
- The README gets the crates.io and docs.rs badges, and the quick start becomes
cargo install renox-cli(keep the--gitline for the latestmain). - The
semverCI job compares with the release on crates.io instead of the base branch, and stops being informational: drop--baseline-revandcontinue-on-errorin.github/workflows/ci.yml. rnx newkeeps pinning git commits whenrnxitself is installed from git, so the development flow doesn't change.
#A broken release
Yank it (cargo yank --version 1.2.0 renox-core, and the other four of that version), fix
it, and publish the next patch version. A yanked version stays for apps that already lock it,
but new apps don't get it. Never reuse a version number.