Releases and Upgrades
Versioning, release automation, and upgrading a deployment.
Octo releases are automated: Conventional Commits drive release-please, a version tag triggers the build pipelines, and published artifacts roll out to deployments by bumping a tag.
How a release is cut
Commits land on main
Commit messages follow Conventional Commits. The version bump is derived from
the types: feat bumps minor, fix/perf/refactor bump patch, and ! or
BREAKING CHANGE bumps major (pre-1.0, breaking and feature changes bump
minor/patch per the release-please config).
release-please maintains a release PR
The release-please workflow (.github/workflows/release-please.yml) runs on
every push to main and keeps a release PR up to date with the accumulated
changelog and the next version. Do not hand-edit CHANGELOG.md or the manifest
version; release-please owns them.
Merging the release PR tags a version
Merging creates the GitHub release, the CHANGELOG.md entry, and the clean
vX.Y.Z tag. release-please pushes the tag with the default GITHUB_TOKEN,
which cannot cascade-trigger tag workflows, so it invokes the release workflow
directly, passing the fresh tag.
The release workflow builds and publishes
.github/workflows/release.yml runs release-check first: it checks out the
tag and runs task release-check (governance and release-readiness files) and
task build (all Go modules plus the pnpm workspace). Then the publish jobs run
in parallel:
publish-standalonebuilds the standalone editor image fromapps/standalone/Dockerfileas a multi-arch build (linux/amd64+linux/arm64) and pushes it to Docker Hub asjuancavallotti/octo:<version>andjuancavallotti/octo:latest.publish-runtimebuildsruntime/DockerfilewithGOTAGS=(the default, standalone-services build) and pushes the same two tags forjuancavallotti/octo-runtime, so integrations can be run from Docker without a cluster.octo-devruntime-paasis tagged off that same build, because it is byte-for-byte the standalone runtime. See Docker images.publish-api-runtimebuildsruntime/DockerfilewithGOTAGS=apiand pushesjuancavallotti/octo-apiandjuancavallotti/octo-api-paasoff that one build, so the public image and the private-registry one share a digest. This is the runtime whose platform capabilities come from a server you implement. See The platform API.build-paas-imagesbuilds the nine platform images per architecture (octo-platform-paas,octo-orchestrator-paas,octo-observability-paas,octo-schema-paas,octo-runtime-paas,octo-devsidecar-paas,octo-statssidecar-paas,octo-agenticrunner-paas,octo-embeddings-paas), andpublish-paas-imagesassembles the multi-arch manifests on Docker Hub. These are what the Helm chart installs by default.publish-chartspackages both Helm charts and pushes them tooci://ghcr.io/juancavallotti/charts. The job first fails the build if either chart'sversion, or the application chart'sappVersion, disagrees with the tag (see below).publish-cliruns GoReleaser (.goreleaser.yaml), which cross-compiles both CLIs (octoanddolphin) for macOS, Linux, and Windows (amd64 and arm64 each) and attaches the twelve archives, plus one combinedchecksums.txt, to the GitHub release. Both are pure Go, soCGO_ENABLED=0builds every target from one Linux runner. release-please created the release and wrote its notes before this job runs, so GoReleaser works inkeep-existingmode and only uploads the assets. The archives are what Installation links to.
Cloud Build publishes the platform artifacts
In the GCP reference deployment, a Cloud Build
trigger (created by the infra root with enable_cloudbuild = true) fires on
the same version tag and runs cloudbuild.yaml:
- Builds the eleven platform images (
octo-platform-paas,octo-orchestrator-paas,octo-observability-paas,octo-schema-paas,octo-runtime-paas,octo-devsidecar-paas,octo-statssidecar-paas,octo-devruntime-paas,octo-agenticrunner-paas,octo-embeddings-paasandocto-api-paas) and pushes each to Artifact Registry tagged with both the git tag andlatest. - Reads back the digest of each pushed image and renders
dist/values.images.yamlpinning them, so the deploy installs exactly what this build produced rather than whatever the tag points at later. The file is archived to the state bucket beside the release. - Packages both Helm charts (versions from their
Chart.yamlfiles, kept in step with the repo release by release-please) and pushes them as OCI artifacts. - With
_DEPLOY=true(the default whencloudbuild_auto_deployis on), applies the Terraformreleaseroot, rolling the cluster to the new tag automatically.
Upgrading a deployment
GCP reference deployment
If cloudbuild_auto_deploy is on, version tags roll out on their own. To
deploy a published tag by hand:
task deploy TAG=v0.2.0This fetches a fresh kubeconfig, derives the chart version from
helm/Chart.yaml, and applies the release root, pre-pulling the images onto
the node and upgrading the Helm release. See
GCP with Terraform.
Plain Helm deployment
Point the release at the new chart version and image tag:
helm upgrade octo oci://ghcr.io/juancavallotti/charts/octo \--version 0.11.7 \--namespace octo \--reuse-valuesThere is no second tag to remember: image.tag defaults to empty and falls back
to the chart's appVersion, which release-please keeps equal to the release
version. Bumping the chart moves the images with it.
The application Deployments roll automatically, the schema hook Job re-applies
sql/schema.sql idempotently, and Postgres data is untouched: nothing in the
chart can remove it, since the StatefulSet retains its claim on uninstall.
Integrations keep running on the runtime image they were deployed with, so
redeploy them from the editor to move them to the new octo-runtime. See
Helm chart.
CLI
Download the new archive for your platform from the
latest release and
replace the binary on your PATH, as in
Installation. octo version
reports what you are on.
Standalone editor and runtime images
Pull the new tag and restart the container:
docker pull juancavallotti/octo:latest # editor
docker pull juancavallotti/octo-runtime:latest # runtime aloneFlows live in your mounted directory, so nothing is lost across upgrades. See Running from Docker and Running flows locally.
Compatibility
Octo is pre-1.0 and makes no external API stability guarantee. The project explicitly prefers complete refactors over backwards compatibility: when a change improves the design, every call site, test, and document is updated in the same change rather than keeping compatibility shims or dual code paths. Read the release notes before upgrading, and pin versions for reproducible setups.
The database schema is the exception in practice: sql/schema.sql is written
idempotently (IF NOT EXISTS / ON CONFLICT) so the schema Job can re-run on
every upgrade against existing data.
Charts and images are versioned together
Both Helm charts and the application chart's appVersion are stamped by
release-please and carry the same version as the release. The release workflow
fails if any of them disagrees with the tag, because appVersion is what
image.tag falls back to: a stale one would silently ship a chart that installs
the wrong images.
So a chart at version X is tested against the images of release X, and installs
them by default. Pinning image.tag to an older release while running a newer
chart is untested: the security contexts in the cloud profiles are the most
likely thing to break, since they pin the UIDs the current images run as. See
image and chart compatibility.
Where to watch releases
GitHub Releases carries every version tag with its notes and the CLI archives
for macOS, Linux, and Windows. CHANGELOG.md at the repo root is the
accumulated, release-please-maintained changelog. On Docker Hub,
juancavallotti/octo
(standalone editor) and
juancavallotti/octo-runtime
(runtime alone) track releases.