Skip to content

Universal Library Release Process

This document describes the release process for the Universal Numbers Library (v4+). The process uses conventional commits, git tags, and git-cliff for changelog generation.

Development and releasing are fully decoupled. No files on main are modified during a release — you simply push an annotated tag and CI handles the rest. This eliminates rebase cascades for in-flight branches.

feature branch → PR (squash merge) → main → git tag → GitHub Release + Docker

All PR titles must follow the Conventional Commits format. This is enforced by CI on every pull request.

<type>(<optional scope>): <description>
TypePurposeChangelog Section
featNew featureAdded
fixBug fixFixed
perfPerformance improvementPerformance
refactorCode change (no new feature/fix)Changed
docsDocumentation onlyDocumentation
testAdding or fixing testsTesting
buildBuild system changesBuild System
ciCI/CD changesCI/CD
styleFormatting, no logic changeStyling
choreMaintenance, deps, etc.Miscellaneous

Number systems: posit, cfloat, fixpnt, lns, integer, areal, valid, bfloat16, dfloat, hfloat, dd, qd, dd_cascade, td_cascade, qd_cascade, einteger, edecimal, erational, efloat, ereal

Building blocks: blockbinary, blockdecimal, blocksignificant, blocktriple, microfloat, e8m0, mxblock, nvblock

Infrastructure: blas, math, numeric, cmake, ci, docker, deps

Append ! after the type to signal a breaking change:

feat!: redesign number system API
feat(posit)!: change template parameter order
feat(dfloat): add decimal256 significand handling
fix(posit): correct rounding for subnormal conversion
docs: update installation instructions
test(cfloat): add exhaustive 8-bit verification
ci: add RISC-V cross-compilation target
refactor(blockbinary): simplify division algorithm
perf(blas): vectorize dot product inner loop
chore: update fallback version to 4.1.0
Terminal window
git checkout main && git pull
git checkout -b feat/decimal256

Branch naming is flexible — use descriptive names like feat/decimal256, fix/posit-rounding, docs/api-guide.

Use conventional commit messages:

Terminal window
git commit -m 'feat(dfloat): add decimal256 significand handling'
git commit -m 'test(dfloat): add decimal256 regression tests'
git commit -m 'fix(dfloat): correct overflow in wide multiply'
Terminal window
git push -u origin feat/decimal256
gh pr create --title 'feat(dfloat): add decimal256 support' --body '...'

The PR title must follow conventional commit format — CI will reject it otherwise.

Use squash merge on GitHub. The PR title becomes the single commit message on main, which feeds directly into the changelog.

Terminal window
git checkout main && git pull
git branch -d feat/decimal256
Terminal window
git checkout main && git pull

Verify CI is green on the latest commit.

Terminal window
git cliff --unreleased

Follow Semantic Versioning:

Change TypeVersion BumpExample
Bug fixes onlyPatchv4.0.0v4.0.1
New features (backward compatible)Minorv4.0.1v4.1.0
Breaking changesMajorv4.1.0v5.0.0

You decide the version when creating the tag. Conventional commit types are a guide, not automated enforcement.

Terminal window
git tag -a v4.1.0 -m 'feat: mixed-precision SDK and block format benchmarks'
git push origin v4.1.0

The release.yml workflow triggers on the tag push and automatically:

  1. Generates release notes from commit history using git-cliff
  2. Creates a GitHub Release with the changelog
  3. Builds and pushes a Docker image to Docker Hub (stillwater/universal)

The library version is determined at CMake configure time:

ContextSourceExample
Git checkoutgit describe --tags --abbrev=0v4.1.0 → 4.1.0
Source tarball (no .git)Fallback in CMakeLists.txt4.0.0
Manual override-DUNIVERSAL_VERSION_MAJOR=X ...Any version

The fallback version in CMakeLists.txt should be updated after major releases.

WorkflowTriggerPurpose
cmake.ymlPush to main, PRsBuild matrix (GCC, Clang, MSVC, macOS, ARM64, RISC-V, MinGW)
conventional-commits.ymlPR open/editValidates PR title format
release.ymlTag push (v*)Creates GitHub Release + Docker image
full-regression.ymlManualComplete test suite before release
sanitizers.ymlWeekly, PRsASan/UBSan testing

Changelogs are generated by git-cliff using the configuration in cliff.toml. The output groups commits by type and includes scope, PR number, and author:

## [4.1.0] - 2026-02-28
### Added
- **dfloat**: portable blockbinary storage and string I/O (#524) by @Ravenwater
### Fixed
- **posit**: correct subnormal rounding edge case (#525) by @contributor
### Documentation
- update installation guide (#526) by @contributor

Useful local commands:

Terminal window
git cliff --unreleased # Preview unreleased changes
git cliff --latest # Show latest release notes
git cliff v4.0.0..v4.1.0 # Between two tags
git cliff -o CHANGELOG.md # Generate full changelog file

Install git-cliff via cargo install git-cliff or brew install git-cliff.

  1. Check the Actions tab for the release.yml workflow run
  2. Verify the tag matches the pattern v[0-9]*
  3. Ensure the tag is annotated (git tag -a), not lightweight
Terminal window
# Delete and recreate
git tag -d v4.1.0
git push origin :refs/tags/v4.1.0
git tag -a v4.1.0 -m 'feat: release description'
git push origin v4.1.0
Terminal window
gh release create v4.1.0 --title "Universal v4.1.0" --generate-notes

Check that the title follows <type>(<scope>): <description> format. The type must be one of the 10 allowed types. The scope (if used) must be one of the allowed scopes listed above.