OT-2 external releases
Customer-facing OT-2 releases. The app uses calendar semver
(vYY.M.N) in
opentrons-ot2.
Robot OS uses an independent traditional semver line (for example v1.19.9) in
buildroot.
Calendar semver (external app)
Versions use US Eastern calendar components:
| Part | Meaning | Example |
|---|---|---|
| YY | Two-digit year | 26 for 2026 |
| M | Month, no leading zero | 6 for June |
| N | Monthly build counter, 0–9 | 0 = first external build that month |
External app tags use a v prefix: v26.6.0, v26.6.1, …
Stack repos
| Repo | Role | Tag pattern |
|---|---|---|
opentrons-ot2 | App (taggable) | vYY.M.N (+ alpha/beta prereleases) |
buildroot | OT-2 robot OS | vX.Y.Z independent line (for example v1.19.9) |
Robot-stack tooling
just go, just track-builds, and just invalidate-cloudfront
are advisory: they sync local clones under this workspace, print tables and analysis,
and emit copy-paste commands. A human (or agent) runs git tag -a, git push,
and aws cloudfront create-invalidation elsewhere. Nothing here pushes tags, triggers CI,
or invalidates CloudFront by itself.
robot-stack-infra is always cloned for reference; it is not included in release
tagging tables.
Plan a release non-interactively, for example:
just go --non-interactive --skip-assumptions --path flex --release-type external --stability stable
Release branch
OT-2 external tags default-branch HEAD. No
chore_release branch is used.
| Repo | Default branch |
|---|---|
opentrons-ot2 | edge |
buildroot | opentrons-develop |
When does just go say a new tag is needed?
For each repo, automation/go.py uses the release branch described
above and the coordinated stack tag for the selected stability lane. It compares branch tip commit
to whether that coordinated tag already points at HEAD.
New tag needed when the coordinated tag for this release is missing on the branch or branch HEAD has moved since that tag.
No new tag needed when branch HEAD already matches the coordinated tag.
Flex app tag numbers come from the app monorepo tag catalog
(opentrons or opentrons-ot2). At one semver base, stable, alpha, and beta
are independent lanes (for example ot3@4.0.0-alpha.3 and
ot3@4.0.0-beta.0 can coexist). Change logs compare against the prior tag in the
same lane on the release branch.
Tags must be annotated (git tag -a … -m 'chore(release): …').
When the release branch differs from the repo default, tag blocks print
git checkout <release-branch> first.
Pushing a tag triggers CI builds in the tagged repo. The app monorepo tag drives app artifacts; stack repo tags drive robot OS and firmware builds.
How the next tag is chosen
In just go, OT-2 uses Stability: stable, alpha,
or beta.
go infers the next calendar base from existing app tags on the release branch
(defaults to the current month in Eastern time when no tags exist yet).
App stable
Patch N counts stable releases in the calendar month. If alpha or beta tags
exist on a base but no stable tag yet (for example v26.6.0-alpha.1), the next stable reuses that
base (v26.6.0) because stable outranks prereleases in semver. Otherwise bump N for the
next stable in the month. More than 10 stable releases in one month (N > 9) is treated as an error.
App alpha / beta
Alpha and beta use numbered prereleases on a monthly YY.M.N base. Increment
-alpha.N or -beta.N on the same base during QA. After
v26.6.0 stable, start a new build line at the next N:
v26.6.1-alpha.0, v26.6.1-beta.0, etc.
buildroot stable
Patch-bump from the latest merged traditional v* tag on
opentrons-develop (for example v1.19.9 → v1.19.10).
Calendar app tags such as v26.6.0 are ignored when choosing the next buildroot tag.
buildroot only receives a new tag when its branch is ahead of the latest traditional external tag.
Tag push order
Push annotated tags in this order. Dependent stack repos first, app monorepo last.
just go prints this reminder at the end of a release run.
| Step | Repo | Notes |
|---|---|---|
| 1 | buildroot | Robot OS, if a new tag is needed |
| 2 | opentrons-ot2 | App monorepo, always last |
OT-2 stack repos only get a new tag when their release branch tip is ahead of the latest channel tag on that branch.
Track release builds
After pushing the app tag, run (non-interactive form):
just track-builds --non-interactive --path ot2 --tag v26.6.0 --wait
automation/track_builds.py locates GitHub Actions runs for:
- App workflow on the monorepo (
App test, build, and deploy) - Kickoff cross-repo dispatch (
Start OT-2 build) - Robot OS build in
buildroot
The Rich table lists key jobs (deploy, desktop builds, dispatch spawn, robot image build). The Slack copy block includes only two links:
OT-2 release `v26.6.0` - app: <app workflow run URL> - ot2: <robot OS workflow run URL>
--wait polls every 15 seconds until app, kickoff, and robot OS
workflow runs all appear (default timeout 900 seconds). Polling checks workflow runs only; job
details are fetched afterward with retries for transient GitHub 404s. Exit code 2 if
a run is still missing after the timeout.
CloudFront invalidation
CI does not invalidate CloudFront automatically. After builds finish, print a copy-paste command (it does not run invalidation):
just invalidate-cloudfront --non-interactive --path ot2 --tag v26.6.0
Invalidates /app/* and /ot2-br/* on the channel host.
Uses AWS profile robotics_robot_stack_prod-admin when credentials allow distribution
lookup; otherwise the script prints a lookup command and placeholder ID.
Validate published artifacts
Optionally regenerate live manifest inventories:
just assets-pages
Or per-platform reports: just flex-assets / just ot2-assets.
Pages: external assets,
internal assets.
Where to find published releases
External OT-2 artifacts live on ot2.builds.opentrons.com.
| Artifact | URL |
|---|---|
App releases.json |
https://ot2.builds.opentrons.com/app/releases.json |
Robot releases.json (source of truth) |
https://ot2.builds.opentrons.com/ot2-br/releases.json |
Robot releases.json is the source of truth for on-robot updates.
Desktop app updates use channel YAMLs (latest.yml, prerelease YAMLs) via
electron-updater; those YAMLs are authoritative.
App releases.json is parsed by a CloudFront edge function to pick the latest stable
semver from production and route latest* requests accordingly.
Electron-updater channel YAMLs:
alpha.ymlalpha-mac.ymlalpha-linux.ymlbeta.ymlbeta-mac.ymlbeta-linux.ymllatest.ymllatest-mac.ymllatest-linux.yml
See also: OT-2 external assets.
Alpha and beta on OT-2 external
In just go, choose Release type: external and
Stability: alpha or beta.
| Stability | Tag example | Notes |
|---|---|---|
| Stable | v26.6.0, v26.6.1 (app) | N bumps only for each stable release in the month; buildroot patch-bumps its own line (for example v1.19.10) |
| Alpha | v26.6.0-alpha.0, v26.6.1-alpha.0 | Same N as the build line; increment prerelease on the same base |
| Beta | v26.6.0-beta.0 | Same monthly N as alpha on that build line; increment -beta.N on the same base |
Alpha and beta do not consume the stable N slot: v26.6.0 stable can follow
v26.6.0-alpha.N on the same base. After v26.6.0 stable, the next alpha cycle is
v26.6.1-alpha.0, not v26.6.0-alpha.0. QA cycles on the same base increment the
prerelease number only. See release channel hierarchy for how alpha,
beta, and stable updater YAMLs interact.