Skip to main content

Versioning

Three things have versions. They are distinct and move on different cadences.

ThingSchemeExampleMoves when
Launchersemverv0.1.43Launcher code changes
Bundlecalver2026.04.1bundle.yaml / bundle.lock.json changes
Componentsupstreamv1.33.1+rke2r1, v3.17.3Upstream releases

And one thing has a schema version, which is separate from all of the above:

ThingCurrentMoves when
manifest.json schema1Breaking manifest shape changes (rare)

Launcher — semver

MAJOR.MINOR.PATCH
v0.1.43
  • MAJOR — bumped on a breaking launcher interface change (flags, state schema, manifest schema). Stays 0 through the Alpha line.
  • MINOR — bumped on a new feature or significant behavior change. Roughly, "the docs changed substantially."
  • PATCH — bumped on bug fixes and small internal changes.

Launcher versions are git-tagged. The tag drives GoReleaser, which in turn drives the release workflow. Tagging is the only way a launcher release gets cut.

-dirty / -N-gSHA suffixes appear on non-tagged builds; they come straight from git describe and indicate "this was built from a non-tagged commit."

Bundle — calver

YYYY.MM.N
2026.04.1
  • YYYY.MM — the year and month of the release.
  • N — an integer, starting at 1, incremented for each bundle released in that month.

Bundle versions live in bundle.yaml's bundle_version: field and are written into manifest.json. They are not git tags — the bundle version is a label attached to the bundle, not to the repo state.

In practice, the bundle version is bumped in the same commit that updates bundle.yaml or bundle.lock.json, which is usually the same commit that gets a launcher tag. But the two can move independently if needed:

  • Launcher-only bug fix → launcher tag moves, bundle stays on the same version.
  • Lockfile refresh with no launcher change → bundle version moves (manually bumped), new bundle ships with the existing launcher.

The in-tree spec uses 0.0.0-dev as a placeholder during development — the release workflow replaces this automatically at tag time.

Component versions — upstream

Components are labeled with whatever the upstream project uses:

  • RKE2 — v1.33.1+rke2r1 (Kubernetes version + RKE2 revision).
  • Helm — v3.17.3.
  • aether-ops — v0.1.43 (aether-ops' own semver, independent of this project's).

These are recorded in manifest.json exactly as upstream names them. The bootstrap never invents component versions or normalizes them.

Manifest schema version

A single integer in manifest.json:

{ "schema_version": 1, ... }

The launcher compares this to its hardcoded SchemaVersion constant on every read. A mismatch aborts preflight. The schema version moves only on breaking shape changes — additive changes stay on the same version.

Same principle applies to state.json (schema_version in internal/state) and bundle.lock.json.

Which version should I bump?

ChangeLauncherBundleManifest schema
Fix a bug in the RKE2 component✓ PATCH
Add a new launcher subcommand✓ MINOR
Bump RKE2 to v1.34.0✓ new calver
Add a new .deb to the bundle✓ new calver
Update the docs site only
Add a new field to manifest (additive)✓ MINOR✓ new calver
Rename a field in manifest✓ MAJOR✓ new calver✓ bump
Bump the state file schema✓ MINOR/MAJOR

(Docs-only changes deploy via docs.yml without a tag.)

Why this split

A monolithic version would be simpler to remember and harder to get wrong, but it would couple two cadences that don't actually align. RKE2 bumps happen on RKE2's cadence; launcher bug fixes happen on ours. Pretending they share a schedule creates either:

  • fake releases (a new launcher tag just to ship a lockfile refresh), or
  • suppressed releases (a real RKE2 bump that can't ship because the launcher hasn't changed).

Separating the two means each can move when it's actually ready.

The same logic argues for keeping the manifest schema separate from either of them: the manifest shape rarely changes, and when it does, neither a launcher tag nor a bundle version is the right place to signal it.