Release Runbook (Agent-First)
This guide is optimized for automated/AI-assisted releases.
Use this document when cutting a new production release tag (vX.Y.Z).
Current next planned version after this update: v1.18.5 (update when cutting a release).
Core rules
- Release source branch is
dev. - Release target branch is
main. - Always create an annotated tag on
main. - Git tags and GitHub Releases are separate objects. Pushing a tag does not create a GitHub Release entry.
- Never run
git push --tags(it may publish localrollback-*tags). - Version source of truth is
backend/config/version.php(API_VERSIONenv can override at runtime). - CI/CD starts automatically after push.
Preflight
Run from repo root:
git fetch --all --tags --prune
git status --short
git tag -l 'v*' --sort=version:refname | tail -n 10
git branch --show-currentChecklist:
- Worktree is clean.
- You are on
dev. devcontains all intended changes.- You identified current release tag (for example
v1.13.1).
Build release notes from git history
Before bumping version, collect the delta from the previous release tag:
# Replace OLD with the latest release tag
OLD=v1.13.1
git log --oneline --no-merges ${OLD}..HEAD
git log --oneline --merges ${OLD}..HEAD
git diff --stat ${OLD}..HEADThen draft a concise annotated tag message:
- 1 title line.
- 1 short summary paragraph.
- Flat bullet list of meaningful user-facing changes.
- Optional final thank-you line in parentheses.
Release procedure
1) Choose next version
Pick the next semantic version (vX.Y.Z) and export it:
NEW=v1.13.22) Bump version on dev
Edit backend/config/version.php:
'api' => env('API_VERSION', 'v1.13.2'),Commit:
git add backend/config/version.php
git commit -m "chore(release): bump version to ${NEW}"3) Merge dev into main
git checkout main
git pull --ff-only origin main
git merge --no-ff dev -m "Merge dev into main for ${NEW} release"4) Create annotated release tag
git tag -a ${NEW} -m "${NEW} - <short title>" -m "<release notes body>"Tag should be on the merge commit from step 3.
5) Push main and release tag
git push origin main
git push origin ${NEW}6) Create GitHub Release entry
Create a published GitHub Release so the version appears on: https://github.com/<owner>/<repo>/releases
# Run in the repo root (without -R) so notes can be read from local annotated tag
gh release create ${NEW} \
--verify-tag \
--notes-from-tag \
--title "${NEW} - <short title>" \
--latestIf you do not create this, the tag exists but the Releases page may still show only older entries.
7) Sync dev with main
git checkout dev
git merge main --ff-only
git push origin devPost-release verification
# Confirm tag exists and points to expected commit
git show -s --oneline ${NEW}
# Confirm GitHub Release exists for the tag
gh release view ${NEW}
# Confirm branch pointers (optional quick check)
git log --oneline --decorate -n 5 --graphIf local app is running, verify API version wiring:
curl -f http://localhost:8000/api/version
# Expect: {"success":true,"data":{"version":"vX.Y.Z"}}
curl -sI http://localhost:8000/api/version | grep X-App-Version
# Expect: X-App-Version: vX.Y.ZFailure handling
- If merge conflicts happen in step 3, stop and resolve on
devfirst; do not continue from a partial merge. - If
git push origin mainsucceeds but tag push fails, retry only tag push. - If tag push succeeds with wrong message, create a new version tag (preferred) instead of force-moving an existing published tag.
- If
devpush fails after successfulmain+ tag push, fix and pushdevas soon as possible to keep branches aligned.
Copy/paste release note template
vX.Y.Z - <short title>
<One paragraph summary of intent and impact.>
- <Change 1>
- <Change 2>
- <Change 3>
(Optional thanks line in parentheses.)Useful commands
# Latest release tag
git tag -l 'v*' --sort=-creatordate | head -n 1
# Commits in upcoming release
git log --oneline <old-tag>..HEAD
# Files changed in upcoming release
git diff --name-only <old-tag>..HEAD