Repository navigation
Releasing
Downstream projects consume Atlas as a repository, often as a Git submodule (Reusing Atlas as Infrastructure). They need stable points to pin to and to upgrade from. This page defines the tag convention and the release procedure.
- Tags are semantic versions:
vMAJOR.MINOR.PATCH(e.g.v0.1.0), cut onmain. -
MAJOR — breaking changes to the reuse and customization contract. The contract is the
*_SOURCEset,PROJECT_NAME/BASE_PORTsemantics, the shared network name and in-network service addresses. It also covers theatlas.consumer.ymlschema and theservices/_user/overlay contract. - MINOR — new services or capabilities, backward-compatible.
- PATCH — fixes, image pin bumps, docs.
main stays the rolling tip; tags are the pinnable checkpoints.
A release tag pushed to origin is immutable: do not move, delete or reuse
it. To correct a released checkpoint, cut a new semantic-version tag. A tag name
then always names one annotated tag object and one commit, so submodule pins
stay reproducible.
# add (or move) the submodule to a tag or a reviewed main commit
git -C infra fetch --tags origin
git -C infra checkout <tag-or-reviewed-main-sha>
git add infra && git commit -m "infra: pin Atlas to <tag-or-sha>"
# later, upgrade deliberately
git -C infra fetch --tags origin && git -C infra checkout <new-tag-or-sha>
git add infra && git commit -m "infra: bump Atlas to <new-tag-or-sha>"Pin to a fixed point, not to the moving main branch, so each infra upgrade is
an explicit, reviewable commit in your project. Use a tag when one covers the
features you need, or a commit SHA between tags.
The only release tag is v0.1.0 (June 2026); the repository's other tags are
not releases. v0.1.0 predates the consumer manifest (atlas.consumer.yml,
--consumer, doctor, endpoints). Until a newer tag is cut, pin a reviewed
main commit.
-
Finalize release notes — on the release branch, move the relevant
[Unreleased]material under a dated, linked[X.Y.Z]changelog heading. Review the complete notes that the tag will contain. -
Review the license inventory — on the release branch, run
uv run --project bootstrapper python -m scripts.docs.license_inventory --check. Re-read the supply-chain license inventory rows for every image and model this release adds or moves. Some releases ship third-party artifacts, such as an appliance bundle or a prebuilt image set. Do not publish one while an open item leaves any artifactunresolvedfor redistribution. -
Promote through Gitflow — merge the release-notes branch into
developby pull request. Then cutrelease/<slug>-to-mainfromorigin/mainand mergeorigin/developinto it. Land it onmainby a merge-commit pull request with every required check green. The versioned changelog and release notes must be onmainbefore the tag is created. -
Create the tag — update local
mainand verify that its changelog contains the version heading. Then create and push the immutable annotated tag:git switch main git pull --ff-only git show HEAD:docs/CHANGELOG.md | grep -F "[X.Y.Z]" git tag -a vX.Y.Z -m "Atlas vX.Y.Z" git push origin vX.Y.Z
-
Record immutable object IDs — after the tag exists, capture both object IDs and the tag date. Add a row to the record below on a follow-up branch. Promote that branch through
developandmainby pull request:git rev-parse refs/tags/vX.Y.Z git rev-parse 'refs/tags/vX.Y.Z^{}' git for-each-ref --format='%(creatordate:short)' refs/tags/vX.Y.Z
The record is updated after tagging because an annotated tag object's SHA
does not exist until the tag is created. The release-history guard therefore
permits exactly one brief automatic transition state. One unrecorded linked
release heading is allowed while it is the newest classified history entry and
its matching vX.Y.Z tag does not yet exist. There is no separate "pending"
heading label, so the tagged tree contains the final release heading.
When the tag exists, the full-history CI checkout fails until the follow-up pull request records the object IDs. Every other unrecorded heading fails. A missing, extra, malformed, lightweight or moved release tag also fails.
This is the canonical offline record that the documentation test reads. Tag object is the annotated tag object's SHA. Target commit is its peeled commit
SHA. Target changelog records whether the tagged tree contains its own
versioned heading. The test also checks the markers and the table structure.
| Tag | Tagged | Tag object | Target commit | Target changelog |
|---|---|---|---|---|
v0.1.0 |
2026-06-21 |
e894bc9db328af4801981b5b54f84a1949f1077f |
12f32135850731bbbe7d0cd4aa3ff5f1783f4387 |
legacy-unreleased-exception |
-
v0.1.0is Atlas's first release-style tag. It establishes the reuse contract: standalone shared-network and submodule consumption,services/_user/overlay auto-launch, andPROJECT_NAME/BASE_PORT/BRAND_*/*_SOURCEcustomization. It also includes the Phase 0 production-hardening profile. -
v0.1.0is the only target-changelog exception. Its tagged tree kept the checkpoint's changes under[Unreleased], and a later history reconciliation added the versioned0.1.0heading. Every later tag must contain its own dated release heading before it is created. - The older changelog labels
1.0.0,1.5.0,2.0.0and3.0.0predate the tag convention. They name historical project milestones, not Git tags or published releases. The semantic-version tag line starts atv0.1.0; the earlier labels stay in the changelog to keep their chronology and content.
scripts/release_notes.py renders release notes from a local commit range. It
classifies each first-parent commit by its Conventional Commits subject. It
installs no release framework, needs no credentials and publishes nothing.
Changelog block. The [Unreleased] section of docs/CHANGELOG.md starts
with a generated block between the GENERATED RELEASE NOTES markers. The block
lists breaking changes, security fixes and features one by one, and counts the
other entries. The curated entries below the block are the detailed history;
the tool never changes them.
The block records its range (<!-- generated-range: v0.1.0..<commit> -->), so
it is reproducible. --check-changelog fails when the block differs from what
that range renders. The Bootstrapper and Backend suites job (part of the
required Manifest lint + unit tests gate) and
test_committed_changelog_block_is_current run it. Refresh the block at release
time (§3 step 1), or when you want a summary of newer work:
uv run --project bootstrapper python -m scripts.release_notes --update-changelog --range v0.1.0..origin/develop
uv run --project bootstrapper python -m scripts.release_notes --check-changelogKeep the block as the first ### 1.1. entry of [Unreleased]. Otherwise the
numbering tool rewrites its heading and make docs-check reports drift.
Stand-alone output is numbered ## 1., ## 2., … without gaps.
Pull-request titles. Pull-request titles must be Conventional Commits
subjects (type(scope)!: summary); the required job runs
scripts/release_notes.py --check-title. Title edits rerun the full workflow.
Under the current squash policy, a multi-commit pull request defaults to its title.
A single-commit pull request defaults to its commit subject, which the title gate does not check.
Before merging, ensure the final squash subject matches the checked title.
Accepted types: build, chore, ci, deps, docs, feat, fix,
maintenance, perf, refactor, release, security, style, test.
Subjects that are not Conventional Commits appear verbatim under
Unclassified. About one subject in five since v0.1.0 is unclassified.
uv run --project bootstrapper python -m scripts.release_notes --range v0.1.0..origin/main
uv run --project bootstrapper python -m scripts.release_notes --since-tag --format json
uv run --project bootstrapper python -m scripts.release_notes --range A..B --overrides notes-overrides.yaml --output /tmp/notes.mdPromotions. Each change appears once, under the develop pull request that
squashed it (the last (#N) of its subject). Entries are de-duplicated by that
number; subjects are never matched.
- A promotion merge (a merge commit whose subject names
develop, thenmain) is replaced by thedevelopcommits it carries. Release branches (release/<slug>-to-main, landed by a merge-commit pull request) use this shape. - A release squash (
chore(release): merge develop into main for #A and #B (#R)) is folded into the entries it names and rendered as(#A, #R). A named source outside the range is looked up onorigin/develop, elsedevelop, unless it was released before the range starts. - Older promotion squashes that repeat a
developsubject without its number are mapped inREVIEWED_PROMOTIONSin the script. A future promotion that cannot name its sources needs a reviewed entry there, not a subject rule. - A promotion stays one Promotions entry only when a source is neither in the
range nor found on
develop. A source merged intodevelopby a merge commit has no(#A)and is not found.
The changelog block is rendered from a develop range. A range on main can
list some develop changes again, because main still holds earlier squash
promotions whose sources are not its ancestors.
Corrections. To fix a misclassified entry, pass an overrides file
(--overrides, {pr: {bucket, subject}}, keyed by the develop pull request).
History is never rewritten, so the same range and overrides always render the
same notes.
Version choice. Atlas does not use semantic-release and does not derive
versions from commits. MAJOR, MINOR or PATCH stays the maintainer's decision
under §1, based on the block's Breaking changes and Features lists. The
reasons:
- Tags are cut on
main, butmain's first-parent history holds only promotions: release merges and olderchore(release)squashes. A commit analyzer that reads first-parent subjects sees neither thefeat/fixtypes nor the breaking markers of the changes they carry. Ondevelop, where the typed squashes are, no tag is cut. -
mainanddevelopaccept changes only by pull request, and every Atlas workflow runs with acontents: readtoken. Publishing notes or tags from CI would need a write credential. - An analyzer skips unclassified subjects without a warning.
Before v0.1.0. The generator never reads before v0.1.0. The earlier
entries, including the 1.0.0–3.0.0 milestone labels (§5), stay hand-written.
Atlas documentation.
- 1. Overview
- 2. Quick Start
- 3. Core Concepts
- 4. Tracks
-
5. Services
- 5.1. Service Catalog
-
5.2. Service Guides
- 5.2.1. airflow
- 5.2.2. asset-baker
- 5.2.3. asset-worker
- 5.2.4. backend
- 5.2.5. backup
- 5.2.6. blender-mcp
- 5.2.7. celery
- 5.2.8. chatterbox
- 5.2.9. cloud-providers
- 5.2.10. cloudflared
- 5.2.11. comfyui
- 5.2.12. crawl4ai
- 5.2.13. doc-processor
- 5.2.14. docling
- 5.2.15. docling-lightrag-adapter
- 5.2.16. fal
- 5.2.17. globals
- 5.2.18. grafana
- 5.2.19. hermes
- 5.2.20. iceberg-rest
- 5.2.21. jenkins
- 5.2.22. jupyterhub
- 5.2.23. kong
- 5.2.24. label-studio
- 5.2.25. langfuse
- 5.2.26. lightrag
- 5.2.27. litellm
- 5.2.28. llm-graph-builder
- 5.2.29. local-deep-researcher
- 5.2.30. loki
- 5.2.31. mcp-servers
- 5.2.32. minio
- 5.2.33. mlflow
- 5.2.34. multi2vec-clip
- 5.2.35. n8n
- 5.2.36. neo4j
- 5.2.37. ollama
- 5.2.38. open-webui
- 5.2.39. openclaw
- 5.2.40. otel-collector
- 5.2.41. parakeet
- 5.2.42. prometheus
- 5.2.43. ray
- 5.2.44. redis
- 5.2.45. redpanda
- 5.2.46. searxng
- 5.2.47. spark
- 5.2.48. speaches
- 5.2.49. stt-provider
- 5.2.50. supabase
- 5.2.51. supavisor
- 5.2.52. tei-reranker
- 5.2.53. tempo
- 5.2.54. tika
- 5.2.55. trino
- 5.2.56. trueforge
- 5.2.57. tts-provider
- 5.2.58. verba
- 5.2.59. vllm-metal
- 5.2.60. weaviate
- 5.2.61. zeppelin
- 5.3. Provider And Extension Guides
- 6. Configuration
- 7. Operations
- 8. Architecture
- 9. Development
- 10. Reference