Release workflow¶
AdaptiveLearner cuts a release on every major sub-phase
completion. The full process is automated by make sync-versions
and a release-gate CI job; the human steps are just version
choice, CHANGELOG, and tag.
Versioning convention¶
AdaptiveLearner follows Semantic Versioning 2.0.0:
- Major (X.0.0) — breaking changes in API or architecture. Rare in the 0.x phase.
- Minor (0.X.0) — new features, backward-compatible. The default for each phase completion.
- Patch (0.X.Y) — bug fixes, backward-compatible. Hotfix chains.
Pre-release tags (-alpha, -beta, -rc) are not used.
Releases are always stable.
The 8-step release¶
1. Capture state¶
git log --oneline $(git describe --tags --abbrev=0)..HEAD
git diff --stat $(git describe --tags --abbrev=0)..HEAD
Review what landed since the last tag. Decide the bump tier.
2. Update the CHANGELOG entry¶
Add a top-block entry to docs/CHANGELOG.md (currently
unstructured prose; the project plan tracks per-version notes
under "Phase history"). Group by Added / Changed / Fixed.
3. Hand-edit the canonical version¶
The only hand-edited version field in the entire repo:
4. Propagate¶
Updates 12 files automatically:
frontend/package.jsonlauncher/pyproject.tomllauncher/adaptive_learner_launcher/__init__.pylauncher/adaptive-learner-launcher.spec(CFBundle plist)- 7×
plugins/adaptive-learner-plugin-*/pyproject.toml install.sh(regenerated from template)install.ps1(regenerated from template)
5. Verify¶
make sync-versions-check # exits non-zero on drift
make test # 1312 tests must pass
cd frontend && npm run build # must succeed
The release-gate CI workflow (.github/workflows/release-gate.yml)
runs the same sync-versions-check on every tag push. If
local agrees but CI fails, the drift was introduced between
your local check and the push — investigate.
6. Commit + tag¶
git add -A
git commit -m "chore(release): bump to v0.X.Y + docs sweep"
git tag -a v0.X.Y -m "v0.X.Y — phase headline + summary"
Tag messages are annotated, multi-line, and summarise the release. They become the GitHub Release notes when the next step runs.
7. Push¶
Triggers:
ci.ymlon the new commit (tests)release-gate.ymlon the new tag (version-pin drift check)coverage.ymlon the new commit (coverage HTML)deploy-gh-pages.ymlon the new commit (publish public site)launcher-{linux,macos,windows}.ymlwhen GitHub creates the Release from the tag
8. Create the GitHub Release¶
--generate-notes pulls the commit list since the last tag.
You can edit the release notes after creation to highlight
the headline changes.
Plugin versions¶
Plugins lock-step with the canonical app version since v0.2.0
— the same number across all 7 plugin pyproject.toml files.
A future "core vs third-party plugin" decision may unlink
them, but the v0.7.0 setup is uniform.
Hotfix flow¶
Patch-level releases (0.X.1, 0.X.2) follow the same 8 steps. The "Hotfix history" section of the release CHANGELOG records the chain when multiple hotfixes land back-to-back.
Discrete pre-release dep-sweep commits¶
When the release cycle bumps dependencies (Vite, React, manuscripta, etc.), keep each bump as its own commit. Reasons:
- Bisect granularity — a regression isolates to one bump.
- CHANGELOG legibility — readers see the actual motivation for each bump.
- Rollback — a bad bump can be reverted independently.
The full pattern is documented in
.claude/rules/release-workflow.md. The rules-as-docs
discipline keeps the human-readable docs (this page) and the
machine-readable rules in sync.