# Releasing This is the maintainer's guide to versioning and the release automation. End users do not need it; they want the [README](README.md) and the setup guide. ## Versioning Releases are dated, not semantic. The version is `YY.MM.PATCH`: - `YY` is the two-digit year. 2026 is `26`. - `MM` is the month with no leading zero. August is `8`, not `08`. The version has to parse as SemVer (Cargo insists), and SemVer rejects leading zeros in a numeric field, so `26.08.0` is invalid and `26.8.0` is the form to use. - `PATCH` starts at `0` in a new month and counts up for any further releases that month. So the sequence across a few releases reads `26.8.0`, `26.8.1`, `26.9.0`. These sort correctly both as dates and as SemVer, because each field is compared as a number. The number is a date, not a compatibility contract. Any release can change behavior; the [CHANGELOG](CHANGELOG.md) is where that is written down. This is separate from `rust-version` in `Cargo.toml`, which is the oldest Rust that compiles the crate (currently `1.85`, the edition-2024 floor). The pixi manifest pins a specific recent toolchain for reproducible builds. The two numbers answer different questions and are allowed to differ. ## Cutting a stable release The version lives in two files, `Cargo.toml` and `pixi.toml`. bump-my-version keeps them in step and computes the next number from today's date; it is configured in `.bumpversion.toml` and installed in the `release` pixi environment. 1. Record what changed: move the `Unreleased` notes in `CHANGELOG.md` under a heading for the new version, and commit that. A clean working tree is required, so this commit comes first. 2. Preview the number the bump would produce: ```sh pixi run bump-show ``` 3. Cut it: ```sh pixi run bump ``` This rewrites the version in both manifests, makes a `Release ` commit, and tags it. The number follows the calendar: the first release in a month is `.0`, and a later one that month is `.1`. To see every edit before it happens, run `pixi run --environment release bump-my-version bump patch --dry-run --verbose`. 4. Push the commit and its tag: ```sh git push --follow-tags ``` The pushed tag triggers `.gitea/workflows/release.yml`, which rebuilds from the tagged commit, checks that the tag matches the `Cargo.toml` version (the bump has just made them agree), and publishes a Gitea release with the packaged binary and its checksum attached. A `v` prefix on the tag is tolerated if you ever tag by hand. ## The workflows All three live in `.gitea/workflows/` and build through pixi, the same way the site deploy does, so the runner needs pixi rather than a hand-installed Rust toolchain. Each workflow installs pixi if it is not already on the runner. - `ci.yml` runs on every push to `main` and every pull request. It runs `pixi run check`: formatting, clippy, the full test suite, and a docs build. This is the gate. - `nightly.yml` runs on every push to `main`, so the nightly build tracks the branch. It also carries an optional daily `cron`. It builds the binary and publishes it as a single rolling prerelease tagged `nightly`, replacing the previous one so the tag always points at the current tip. - `release.yml` runs on a version tag. It builds, regenerates the third-party license notices, packages the full bundle, and publishes a normal (non-prerelease) release named after the tag. ## Publishing the API docs `.gitea/workflows/docs.yml` builds the rustdoc and publishes it in two channels: `release/`, built from a version tag, and `nightly/`, built from `main`. The site root redirects to the latest release, falling back to nightly until the first release exists. Each page carries a small switcher to flip between the two channels. It runs on the `pixi-build-rust` runner, so the doc build reuses the baked toolchain and the crate cache rather than compiling cold. That runner builds inside a container, so give its job containers access to the docs directory by adding it to the runner's `config.yaml` alongside the cache volumes.