Skip to main content

Versioning and Releases

AgentArea uses a build-once / promote-on-tag release model:
  • ci.yml builds immutable per-commit Docker images on every merge to main.
  • release-publish.yaml never rebuilds. On a semver git tag (vX.Y.Z), it retags an already-built image with the stable release tags and creates the GitHub Release.
  • release-helm.yml publishes the Helm chart on the same tag push.
A local script, scripts/release.sh, validates pre-conditions and pushes the tag.

Version Architecture

Application Version (VERSION file)

  • Location: VERSION at repo root.
  • Purpose: Single source of truth for the application’s version.
  • Managed by: scripts/bump-version.py via the Prepare Release workflow.
  • Propagated to: all pyproject.toml, package.json, Chart.yaml appVersion, .bumpversion.yaml, Go const version in agentarea-mcp-manager and agentarea-event-service.

Chart Version (Chart.yaml version)

  • Location: charts/agentarea/Chart.yaml version field.
  • Bumped automatically by release-helm.yml on every v* tag push (patch by default; manual dispatch lets you choose patch/minor/major).
  • Independent of application version. Do not edit manually.

Docker Image Tags

What gets pushed when

EventWorkflowTags pushed for each of 7 components
Merge to mainci.ymldocker-build-push.yml<version>-<sha> (e.g. 0.0.8-a8eaf7b) — immutable
Git tag push vX.Y.Zrelease-publish.yaml<version>, <maj.min>, <maj>, latest — all pointing to the same digest as <version>-<sha> (retag, no rebuild)

Tag semantics

  • 0.0.8-a8eaf7bImmutable per-commit. Built once by ci.yml. Safe to pin in prod.
  • 0.0.8Immutable semver. Created once by release-publish on tag v0.0.8. Points to the same digest as the <version>-<sha> of that commit. Never overwritten.
  • 0.0Rolling minor. Moves forward to the latest 0.0.x release.
  • 0Rolling major. Moves forward to the latest 0.x.y release.
  • latest — Always points to the most recent release.

Tag usage guidelines

Use caseTagWhy
Production pin0.0.8-a8eaf7bFully traceable, guaranteed not to change
Production (auto patch)0.0Gets patch-level fixes automatically
Staging0.0.8-<latest-main-sha>Test unreleased main builds
”Show me the latest”latestMost recent release

Components

Seven Docker images are published: api, worker, frontend, bootstrap, mcp-manager, mcp-runner, events

Registry

All images go to Docker Hub: agentarea/agentarea-<component>.

Release Process

1. Prepare Release (bump VERSION)

Via GitHub UI: Actions → “Prepare Release” → Run workflow → select patch/minor/major. The release-prepare.yaml workflow:
  1. Runs CI validation (lints, tests, build).
  2. Runs scripts/bump-version.py <type> — bumps VERSION and propagates to all version files.
  3. Creates branch release/vX.Y.Z and opens a PR labelled release.
Release types:
  • patch — bug fixes (0.0.8 → 0.0.9)
  • minor — new features, backward compatible (0.0.8 → 0.1.0)
  • major — breaking changes (0.0.8 → 1.0.0)

2. Review and merge the release PR

  • Verify all version files updated.
  • Add release notes to CHANGELOG.md if you keep one.
  • Merge. The merge to main triggers ci.yml, which builds and pushes 0.0.9-<sha> for all 7 components.
Merging the PR does not publish the release. It only bumps versions and builds images.

3. Publish the release with scripts/release.sh

Once ci.yml is green on the release PR merge commit:
The script performs these checks before creating the tag:
  1. Working tree is clean.
  2. On main (or confirms override).
  3. Local main is up-to-date with origin/main.
  4. VERSION contains a valid semver; tag v<version> doesn’t already exist locally or on origin.
  5. scripts/verify-version-sync.sh passes (all version files agree).
  6. ci.yml is green on HEAD (via gh CLI).
  7. All 7 agentarea-<component>:<version>-<sha> images exist on Docker Hub.
  8. Shows a summary with commit list since the previous tag.
  9. Asks y/N confirmation.
  10. Creates an annotated tag v<version> and pushes it to origin.
Flags:

4. Automated: retag + GitHub Release + Helm chart

The tag push triggers two workflows in parallel: release-publish.yaml:
  1. Validates tag matches VERSION on the tagged commit.
  2. For each of 7 components, waits for <version>-<sha> to appear in Docker Hub (retries up to 15 min if ci.yml is still running).
  3. Uses docker buildx imagetools create to add tags <version>, <maj.min>, <maj>, latest to the existing image. No rebuild. Same digest.
  4. Creates a GitHub Release with auto-generated notes from git log <prev-tag>..HEAD.
release-helm.yml:
  1. Bumps chart version (patch by default).
  2. Packages the chart and publishes to the agentarea/helm-charts repo.

TL;DR Release Checklist

Key Invariants

  • <version> (bare semver) is published exactly once, via retag. It is never overwritten.
  • <version>-<sha> is built by ci.yml on every merge to main. Immutable per-commit.
  • <version>-<sha> and <version> on the release commit share the same digest — they are the exact same image under different tags.
  • VERSION always contains a stable semver (no -rc, -beta). Pre-release testing uses <version>-<sha> directly.
  • Chart version is owned by release-helm.yml; do not edit it manually.

Why This Model

Problem (before): ci.yml pushed both <version> and <version>-<sha> on every merge to main. The bare <version> tag was overwritten on every merge, breaking immutability (prod and staging could both run 0.0.8 but be different images) and making rollback unreliable. Fix: ci.yml pushes only <version>-<sha>. Promotion to the stable <version> tag happens exactly once, via retag, when someone pushes a semver git tag. The image is never rebuilt — semver tag and dev tag are bit-identical.

Verification

Manual CI check anyone can run:
Verifies:
  • .bumpversion.yaml current_version matches VERSION
  • All pyproject.toml files match VERSION
  • package.json matches VERSION
  • Chart.yaml appVersion matches VERSION
  • Go const version matches VERSION (mcp-manager, event-service)
  • Chart version is not checked (intentionally independent)
CI runs this on every push and PR via the version-check job in ci.yml.

Troubleshooting

Versions out of sync

verify-version-sync.sh or ci.yml fails with a mismatch.

release.sh says “tag already exists on origin”

Someone (or a prior run) already pushed v<version>. If you need to re-release the same version:
Prefer bumping VERSION to a new patch instead of re-using a tag.

release.sh says images are missing in Docker Hub

ci.yml hasn’t finished building the release commit yet, or some component’s build failed.

Helm dev release needs testing before a full release

Use manual dispatch on release-helm.yml via the Actions UI. That path is not covered by release.sh.

Hotfix on an older release

  • VERSION — source of truth
  • scripts/bump-version.py — bumps VERSION + all consumers
  • scripts/release.sh — pre-flight + tag push
  • scripts/verify-version-sync.sh — consistency check
  • scripts/sync-versions.py — emergency resync
  • scripts/update-appversion.py — sync Chart.yaml appVersion to VERSION
  • scripts/bump-chart-version.py — chart version bumper (used by release-helm.yml)
  • .github/workflows/release-prepare.yaml — opens release PR
  • .github/workflows/ci.ymldocker-build-push.yml — builds <version>-<sha> on main
  • .github/workflows/release-publish.yaml — retags on tag push, creates GitHub Release
  • .github/workflows/release-helm.yml — publishes Helm chart on tag push