How versioning, releases, and publishing work across the project.
All published artifacts share the same version and follow semver:
| Artifact | Where | Version source |
|---|---|---|
| nteract desktop app | GitHub Releases | crates/notebook/tauri.conf.json |
runt CLI |
GitHub Releases | crates/runt/Cargo.toml |
runtimed daemon |
Bundled in app + Python wheel | crates/runtimed/Cargo.toml |
runtimed Python package |
PyPI | python/runtimed/pyproject.toml |
Standard semver rules apply:
- Major — breaking changes to user-facing APIs or behavior
- Minor — new features, additive protocol/schema changes
- Patch — bug fixes
Two independent version numbers handle compatibility, separate from the artifact version:
- Protocol version (
PROTOCOL_VERSIONincrates/notebook-protocol/src/connection.rs) — governs wire compatibility. Validated by the magic bytes preamble at connection time. Bump when the framing, handshake shape, or message serialization format changes. - Schema version (
SCHEMA_VERSIONinnotebook-doc/src/lib.rs) — governs Automerge document compatibility. Stored in the doc root. Bump when the document structure changes (v2 switched cells from an ordered list to a fractional-indexed map).
These are just incrementing integers. They evolve independently from each other and from the artifact version. A protocol bump doesn't force a major version bump — it depends on whether the change is user-facing.
All four version sources must stay in sync. When preparing a release:
# Update all of these to the same version:
# crates/runtimed/Cargo.toml
# crates/runt/Cargo.toml
# crates/notebook/Cargo.toml
# crates/notebook/tauri.conf.json
# python/runtimed/pyproject.toml
# Then let Cargo.lock catch up:
cargo checkCommit the version bump, then tag to trigger the release.
Push a v* tag to main:
git tag v2.1.0
git push origin v2.1.0This triggers release-stable.yml → release-common.yml, which:
- Builds the desktop app (macOS, Windows, Linux)
- Builds
runtCLI binaries - Builds Python wheels at the version in
pyproject.toml(no alpha stamp) - Publishes wheels to PyPI (stable release)
- Creates a GitHub Release with all artifacts
- Updates the
stable-latestTauri updater channel - Posts to Discord
The stable release publishes the Python package to PyPI at the exact version from pyproject.toml. This means tagging v2.1.0 also ships runtimed==2.1.0 on PyPI — no separate Python tag needed.
Runs automatically at 9am UTC daily via release-nightly.yml, or manually via workflow dispatch.
Same pipeline as stable, but:
- Desktop version gets a
-nightly.{timestamp}suffix - Python wheels get an alpha stamp:
2.0.1a202507150900(PEP 440) - App is branded "nteract Nightly" with a separate bundle ID (side-by-side install)
- GitHub Release is marked as prerelease
- CLI binary is named
runt-nightly
Nightly Python wheels are installable with:
pip install runtimed --preFor Python-specific fixes that don't need a full desktop release, use the dedicated python-package.yml workflow:
# Bump python/runtimed/pyproject.toml (and Cargo.tomls if Rust changed)
git tag python-v2.1.1
git push origin python-v2.1.1This builds macOS + Linux wheels and publishes to PyPI. Use this when you need to ship a Python patch without cutting a new desktop release.
| Tag pattern | Workflow | What it publishes |
|---|---|---|
v* |
release-stable.yml |
Desktop app + CLI + Python (stable) |
python-v* |
python-package.yml |
Python wheels only |
| (cron) | release-nightly.yml |
Desktop app + CLI + Python (pre-release) |
When making a breaking wire protocol change:
- Bump
PROTOCOL_VERSIONincrates/notebook-protocol/src/connection.rs - Update
PROTOCOL_V2string constant if the version string changes - Update
contributing/protocol.md - Decide whether this warrants a major, minor, or patch version bump based on user impact
The magic bytes preamble rejects connections with mismatched protocol versions at the wire level, before any JSON parsing.
When changing the Automerge document structure:
- Bump
SCHEMA_VERSIONincrates/notebook-doc/src/lib.rs - Add migration logic in the daemon's doc loading path (detect old schema, convert in-place)
- Update the document schema comment in
notebook-doc/src/lib.rs
Schema changes don't necessarily require a protocol bump — the wire format for sync frames stays the same, only the doc content changes.
See contributing/protocol.md for the full versioning contract.
The reusable release-common.yml accepts inputs from the nightly/stable callers:
github_release_prerelease: true→ applies PEP 440 alpha stamp to Python versiongithub_release_prerelease: false→ usespyproject.tomlversion as-is
Python wheels are always built (macOS arm64, Linux x64, Windows x64) and always published. continue-on-error: true on the PyPI step handles duplicate version conflicts (e.g., re-running a workflow).
Desktop version is computed as {runt-cli version}-{suffix}.{timestamp} where suffix is nightly or stable. This is stamped into tauri.conf.json and Cargo.toml at build time — not committed.
PyPI publishing uses OIDC trusted publishing (no API tokens). The GitHub Actions workflow identity is registered as a trusted publisher on PyPI for the runtimed package. Both release-common.yml and python-package.yml use this.
Before tagging a stable release:
- All version sources bumped and in sync
-
cargo checkpasses (Cargo.lock updated) -
PROTOCOL_VERSIONandSCHEMA_VERSIONare correct for this release - CI is green on
main - Changelog-worthy items use conventional commit prefixes (
feat,fix,perf)