Releasing Precursor
Precursor ships from git tags. The version is CalVer — YYYY.M.MICRO — resolved automatically by hatch-vcs from the latest v<version> tag. There is no version literal to bump by hand.
Versioning policy — CalVer YYYY.M.MICRO
YYYY— four-digit year of the release.M— month, no leading zero (6, not06).MICRO— release counter within that month, starting at0; resets to0on the first release of a new month.
Examples: first June 2026 release 2026.6.0, a follow-up the same month 2026.6.1, the first July release 2026.7.0. The format is valid under both PEP 440 (Python) and semver (npm), sorts chronologically, and is human-readable. Untagged/dev builds get a suffix, e.g. 2026.6.1.dev3+g0f3ad9f.d20260615.
Cutting a release
Make sure
mainis green andCHANGELOG.md's[Unreleased]section captures what's shipping.Pick the next CalVer per the policy above, and verify what the build would produce:
bashuv version # or: uv run python -c "from precursor import __version__; print(__version__)"Promote the
[Unreleased]changelog section to a dated release heading and commit it:markdown## [2026.6.0] - 2026-06-15Tag and push — the leading
vis required (the release workflow triggers onv*):bashgit tag v2026.6.0 git push origin v2026.6.0The Release workflow (
.github/workflows/release.yml) then:- builds the frontend and bundles it into the wheel,
- runs
uv build(hatch-vcs stamps the version from the tag), - verifies the built version matches the tag,
- creates a GitHub Release with the wheel + sdist and auto-generated notes, and
- publishes the wheel + sdist to PyPI via Trusted Publishing (OIDC — no API token).
PyPI Trusted Publishing (one-time setup)
Publishing uses PyPI Trusted Publishing (OpenID Connect), so there is no API token to store or rotate. Configure it once:
- On PyPI, create a trusted publisher for the
precursor-aiproject (the plainprecursorname is already taken) — PyPI Project Nameprecursor-ai, Ownerlrivallain, Repositoryprecursor, Workflowrelease.yml, Environmentpypi. - In this repo, add a GitHub Environment named
pypi(Settings → Environments); optionally require a reviewer to approve each publish.
The pypi-publish job runs in the pypi environment and requests an id-token — both must match the publisher registered on PyPI.
Verifying a build locally
make wheel # builds the SPA, then `uv build` → dist/*.whl + *.tar.gz
# or by hand:
cd frontend && npm ci && npm run build && cd ..
uv buildThe built filename encodes the resolved version (the precursor-ai distribution normalises to precursor_ai in the filename). The wheel is self-contained: the SPA is bundled inside the package (precursor/frontend_dist/), so an installed build serves the UI with no extra files:
uvx precursor-ai # run the published wheel directly
uv tool install precursor-ai # or install the `precursor-ai` commandNotes
- Commit messages follow Conventional Commits — the GitHub Release notes are generated from them.
- PyPI: each tagged release publishes the wheel + sdist to PyPI via Trusted Publishing (OIDC) — see the one-time setup above. The GitHub Release ships the same artifacts as attached assets.
- Distribution name: the PyPI project is
precursor-ai; it ships a matchingprecursor-aicommand (souvx precursor-aineeds no--from) plus aprecursoralias, and the import package is unchanged.