Release Process#

This document describes how to prepare, publish, and follow up on a Newton release. It is intended for release engineers and maintainers.

Overview#

Newton follows PEP 440 versioning; see Versioning in the compatibility guide for details.

Releases are published to PyPI and documentation is deployed to GitHub Pages.

Version source of truth#

The version string lives in the [project] table of pyproject.toml. All other version references (PyPI metadata, documentation) are derived from this file. At runtime, newton/_version.py reads the version from installed package metadata via importlib.metadata.

Dependency versioning strategy#

pyproject.toml specifies minimum compatible versions (e.g. warp-lang>=1.12.0). uv.lock pins the latest known-good versions for reproducible installs.

Exception: on the release branch, mujoco and mujoco-warp use compatible-release pins (e.g. mujoco~=3.5.0) to allow 3.5.x updates while excluding 3.6.0 and later. MuJoCo follows custom versioning from 3.5.0 onward; its third component is MINOR_OR_PATCH and guarantees API backward compatibility. main uses a version floor like other dependencies.

Deprecation and removal timeline#

The user-facing deprecation and removal policy lives in Deprecation Policy. Release engineers should ensure that every deprecation, removal, or other breaking change in a minor release is reflected in CHANGELOG.md and the API documentation, and that deprecations emit a runtime DeprecationWarning where applicable.

Pre-release planning#

Determine target version (X.Y.Z).

Confirm dependency versions and availability: warp-lang, mujoco, mujoco-warp, newton-usd-schemas.

Set timeline: code freeze → RC1 → testing window → GA.

Conduct public API audit:

  • Review all new/changed symbols since the last release for unintended breaking changes.

  • Confirm intended public API changes and breaking changes have maintainer approval.

  • Verify deprecated symbols carry proper deprecation warnings and migration guidance (see Deprecation Policy).

  • Verify experimental public API is explicitly marked with .. experimental:: in API or concept documentation, following the developer guidance.

  • Confirm new public API has complete docstrings and is included in Sphinx docs (run uv run docs/generate_api.py).

Run the release-audit Claude Code skill (.claude/skills/release-audit) in pre-release mode to automate this audit.

Code freeze and release branch creation#

Create release-X.Y branch from main and push it.

On main: bump the version in pyproject.toml to X.(Y+1).0.dev0 and run uv run docs/generate_api.py.

On release-X.Y: bump the version in pyproject.toml to X.Y.ZrcN and run uv run docs/generate_api.py.

On release-X.Y: update dependencies in pyproject.toml from dev to RC versions where applicable and remove the NVIDIA package index ([[tool.uv.index]] entry for nvidia and the warp-lang entry in [tool.uv.sources] that references it) so the release wheel installs purely from PyPI, then regenerate uv.lock (uv lock) and commit.

Run the release-audit skill in release-candidate mode against release-X.Y; address or acknowledge flagged entries before tagging.

Manually trigger the minimum-dependency and multi-GPU CI workflows on the release-X.Y branch (the nightly orchestrator only runs on main). Verify both pass before tagging.

# Minimum-dependency tests (lowest compatible PyPI versions)
gh workflow run minimum_deps_tests.yml --ref release-X.Y

# Multi-GPU tests (g7e.12xlarge = 4× L40S GPUs)
gh workflow run aws_gpu_tests.yml --ref release-X.Y \
    -f instance-type=g7e.12xlarge

Push tag vX.Y.Zrc1. This triggers the release.yml workflow (build wheel → PyPI publish with manual approval).

RC1 published to PyPI (approve in GitHub environment).

Release candidate stabilization#

Bug fixes merge to main first, then are cherry-picked to release-X.Y. Cherry-pick relevant commits from main onto a feature branch and open a pull request targeting release-X.Y — never push directly to the release branch.

For each new RC (rc2, rc3, …) bump the version in pyproject.toml and run uv run docs/generate_api.py, then tag and push. Resolve any cherry-pick conflicts or missing dependent cherry-picks that cause CI failures before tagging.

Testing criteria#

The release engineer and maintainers decide which issues must be fixed before GA and which can ship as known issues documented in the release materials. Features marked experimental have a lower bar — regressions in experimental APIs do not necessarily block a release.

As a guideline, an RC is typically ready for GA when:

  • All examples run without crashes, excessive warnings, or visual artifacts (uv run -m newton.examples <name>).

  • Testing covers Windows and Linux, all supported Python versions, and both latest and minimum-spec CUDA drivers (see system requirements in the installation guide).

  • PyPI installation of the RC works in a clean environment: pip install succeeds, import newton works, and examples and tests can be run from the installed wheel (pip install newton==X.Y.ZrcN).

  • No unexpected regressions compared to the previous release have been identified.

All release-targeted fixes cherry-picked from main.

Re-run the release-audit skill after final cherry-picks; confirm no new flags since the last RC.

Prepare draft GitHub Release notes: summary, a few highlights, link to CHANGELOG.md, acknowledgments.

Testing criteria satisfied.

No outstanding release-blocking issues.

Final GA release#

Before proceeding, obtain explicit go/no-go approval from the maintainers. Do not start the final release steps until sign-off is confirmed.

All steps below are performed on the release-X.Y branch unless noted otherwise.

Go/no-go approval obtained from maintainers.

Finalize CHANGELOG.md: rename [Unreleased][X.Y.Z] - YYYY-MM-DD. Review the entries for:

  • Missing entries — cross-check merged PRs since the last GA release (or micro release) to catch changes that were not recorded in the changelog.

  • Redundant entries — consolidate or remove duplicates for changes within the same release period (e.g. a bug fix for a feature added in the same cycle should not appear as both an “Added” and a “Fixed” entry).

The release-audit skill’s CHANGELOG language review is a useful first pass before this manual sweep.

Update README.md documentation links to point to versioned URLs (e.g. /X.Y.Z/guide.html instead of /latest/).

Verify all dependency pins in pyproject.toml use stable (non-pre-release) versions.

Regenerate uv.lock (uv lock) and verify that no pre-release dependencies remain in the lock file.

Bump the version in pyproject.toml to X.Y.Z (remove the RC suffix) and run uv run docs/generate_api.py.

Commit and push tag vX.Y.Z. Automated workflows trigger:

  • release.yml: builds wheel, publishes to PyPI (requires manual approval), creates a draft GitHub Release.

  • docs-release.yml: deploys docs to /X.Y.Z/ and /stable/ on gh-pages, updates switcher.json.

PyPI publish approved and verified: pip install newton==X.Y.Z.

Review the draft GitHub Release notes before publishing. Keep them concise: summary, a few highlights, link to CHANGELOG.md, acknowledgments.

GitHub Release un-drafted and published.

Docs live at /X.Y.Z/ and /stable/: verify links and version switcher.

Release announcement posted.

Post-release#

Merge back the changelog from release-X.Y to main: move entries included in the release from [Unreleased] to a new [X.Y.Z] section. ([Unreleased] is a permanent header in the changelog that always exists on main.)

Verify PyPI installation works in a clean environment.

Verify published docs render correctly.

Micro releases#

Micro releases continue cherry-picking fixes to the existing release-X.Y branch. For example, 1.0.1 follows 1.0.0. Follow the same Final GA release flow — bump version, update changelog, tag, and push. There is no need to create a new branch or bump main.