release-flow
Dogfooded release ritual for ai-specs-cli: version bump, promote to main, tag, and GitHub release. Trigger: when cutting a release, shipping vX.Y.Z, promoting development to main, or tagging a version.
- License 许可
- MIT
- 最近更新
- 2026-11-08
- Stars
- ★ 0
- Forks
- 2
01 前言 Front Matter
- name
- release-flow
- license
- MIT
- metadata
- { "scope": [ "root" ], "author": "ai-specs", "version": "1.0", "auto_invoke": [ "Cutting a release or shipping vX.Y.Z", "Promoting development to main for a release", "Tagging a version and creating a GitHub release" ] }
- description
- Dogfooded release ritual for ai-specs-cli: version bump, promote to main, tag, and GitHub release. Trigger: when cutting a release, shipping vX.Y.Z, promoting development to main, or tagging a version.
03 SKILL.md 正文
Release Flow
Project-local playbook for shipping ai-specs-cli. This is not part of the
vcs-pr-flow capability — use the bound VCS skill for PR/merge primitives;
this skill owns product release policy (VERSION, CHANGELOG, promote, tag).
When to use
- User asks to release, cut a version, ship
vX.Y.Z, or promote tomain - After features land on
developmentand the tree is ready to publish - When recreating the release steps that agents otherwise rediscover from memory
Critical rules
- Never open the promote PR with
development(ormain/staging) as the head. Use a disposablerelease/vX.Y.Zhead intomain. - Never push directly to
mainordevelopment— PR + explicit approval. - Bump only
VERSIONandCHANGELOG.mdon the bump branch (no feature work). - Hard stop for explicit user approval before: promote merge, tag push, and publishing release notes. The tag push is the irreversible step — it is what builds and attaches the gate binaries.
- Before promote, run the VCS
delete_branch_on_mergepreflight (GitHub). If it istrue, warn — long-lived heads can be wiped when used as a PR head. - After merge, delete only feature heads (
chore/release-*,release/v*). Never delete protected heads.
Before the version bump (step 1 of the ritual), the isolated
clean-materialization gate must pass. Evidence is
tests/test_release_materialization.py (isolated temp consumer project
- in-tree CLI), not this repo's dogfood
ai-specs/.ai-specs.lock. Do not treat a stale dogfood lock as release evidence.
Ritual
decide bump → chore/release-vX.Y.Z (VERSION+CHANGELOG)
→ PR → development (squash OK)
→ reset release/vX.Y.Z from origin/development
→ PR → main (merge commit)
→ annotated tag + gh release
→ cleanup feature heads
1. Decide the bump
From repo root (or release worktree):
cat VERSION
git describe --tags --abbrev=0
git log "$(git describe --tags --abbrev=0)..origin/development" --oneline
Choose major / minor / patch from [Unreleased] in CHANGELOG.md and commits
since the last tag. Confirm with the user if unclear.
2. Bump branch
Worktree off development (do not edit protected branches in the main tree):
git fetch origin development
git worktree add .worktrees/release-vX.Y.Z -b chore/release-vX.Y.Z origin/development
In that worktree:
- Set
VERSIONtoX.Y.Z(novprefix). - Move
CHANGELOG.md[Unreleased]notes into## [X.Y.Z] — YYYY-MM-DD. - Leave a fresh empty
## [Unreleased]section at the top. - Decide whether this release needs an upgrade notice (see below).
- Commit:
chore(release): bump to X.Y.Z.
Upgrade notes (post-upgrade actions)
If a user must do something after upgrading, say so in an ### Upgrade notes
subsection under the new version heading. ai-specs upgrade replays it for
everyone who crosses this version, oldest release first.
## [X.Y.Z] — YYYY-MM-DD
### Upgrade notes
Run `ai-specs sync` in each project to acquire the verified Go worktree-gate
binary. Until you do, the gate keeps falling back to the Bash implementation.
Rules:
- Prose only.
upgraderuns against~/.ai-specsand has no consumer project in scope, so it cannot evaluate project-dependent conditions. Name the command; letai-specs doctorhandle anything conditional. - Nothing is executed. A notice is displayed verbatim.
- Write one only when an action is genuinely required. A notice on every release trains users to skip them.
Ask: would a user who upgrades and does nothing else be silently worse off? If yes, write the notice.
3. PR into development
git push -u origin chore/release-vX.Y.Z
gh pr create --base development --head chore/release-vX.Y.Z \
--title "chore(release): bump to X.Y.Z" \
--body "$(cat <<'EOF'
## Summary
- Bump VERSION to X.Y.Z
- Document changes in CHANGELOG.md
## Test plan
- [ ] VERSION reads X.Y.Z
- [ ] After merge: promote via release/vX.Y.Z → main, tag, gh release
EOF
)"
Squash-merge is fine for the bump PR (after user approval). Pull
origin/development after it lands.
4. Promote head (disposable local branch)
The promotion head is a local branch only so it can be pushed as the PR head;
it does not need its own worktree, and the canonical worktree stays on
development throughout the promotion and tag steps.
git fetch origin development main
git branch -f release/vX.Y.Z origin/development
git push -u origin release/vX.Y.Z
Run delete_branch_on_merge preflight via the bound VCS merge skill, then:
gh pr create --base main --head release/vX.Y.Z \
--title "chore(release): promote vX.Y.Z to main" \
--body "$(cat <<'EOF'
## Summary
Promote development tip (includes VERSION X.Y.Z) to main for release.
## Test plan
- [ ] Merge with merge commit (not squash)
- [ ] Tag vX.Y.Z on main
- [ ] Release workflow green and 4 gate assets attached
- [ ] gh release edit — title and notes
EOF
)"
Merge only after explicit user approval, using a merge commit (not squash):
gh pr merge <n> --merge --delete-branch
--delete-branch is safe here: release/vX.Y.Z is a feature head.
5. Tag and GitHub release
After the promote PR lands, tag the fetched origin/main commit directly. Do
not checkout main in the canonical worktree: Git tags point at commits, not
working directories, and the canonical checkout remains on development.
git fetch origin main
test "$(git rev-parse origin/main)" = "$(git rev-parse origin/development)" \
|| { echo "origin/main is not the current development tip" >&2; exit 1; }
git tag -a "vX.Y.Z" origin/main -m "vX.Y.Z"
git push origin "vX.Y.Z"
test "$(git rev-list -n1 "vX.Y.Z")" = "$(git rev-parse origin/main)"
The tag push creates the release — you do not. Pushing v* triggers
.github/workflows/release-worktree-gate.yml, which builds the four gate
binaries, verifies them against the committed
catalog/recipes/worktree-flow/bin/SHA256SUMS, and attaches them via
softprops/action-gh-release. That action creates the GitHub Release for the
tag, with an empty body and the bare tag as its title.
So gh release create fails with "already exists". Wait for the workflow,
then fill in the release:
gh run watch <run-id> --exit-status # 6 jobs, all must pass
gh release view vX.Y.Z --json assets # expect 4 worktree-gate-* assets
gh release edit "vX.Y.Z" --title "vX.Y.Z — <short summary>" \
--notes-file - <<'EOF'
## Highlights
- <from CHANGELOG>
## Install
curl -fsSL https://raw.githubusercontent.com/parada1104/ai-specs-cli/main/install.sh | bash
EOF
Verify the published assets match the trust root without downloading them — useful when a sandbox blocks the asset CDN:
gh api repos/parada1104/ai-specs-cli/releases/tags/vX.Y.Z \
--jq '.assets[] | "\(.digest) \(.name)"'
Before tagging, reproduce the digests locally with the CANONICAL toolchain
(go1.24.13): run scripts/build-gate.sh, then compare shasum -a 256 of the
four dist/worktree-gate-<os>-<arch> files against the committed SHA256SUMS.
Exclude dist/worktree-gate-current — CI does not build it. A mismatch means
the release workflow will fail and publish no assets, leaving every user on
the Bash fallback.
Installer default ref is main (AI_SPECS_REF=main). Point release notes at
repo-root install.sh, not a nested path.
6. Cleanup
git branch -D chore/release-vX.Y.Z release/vX.Y.Z 2>/dev/null || true
git push origin --delete chore/release-vX.Y.Z 2>/dev/null || true
# release/v* may already be deleted by --delete-branch on the promote PR
If a release branch was deliberately checked out in a worktree, remove that
worktree before deleting the branch. The normal flow creates no release
worktree. Do not delete development or main.
Post-release checklist
- [ ]
origin/maincontains the tagged release commit - [ ]
VERSIONonorigin/mainmatches the tag - [ ] Canonical worktree remains on
development - [ ] GitHub Release exists and notes look right
- [ ]
developmentstill exists on origin - [ ] Feature release branches/worktrees removed
- [ ] Optional: sync any post-tag fixes back to
developmentvia PR if needed
Relation to other skills
| Skill / capability | Role |
|---|---|
vcs-pr-flow (git-merge-workflow) |
PR create/merge, protected vs feature heads, account + delete_branch_on_merge preflight |
worktree-flow |
Isolated worktrees for bump and cleanup |
release-flow (this skill) |
Semver bump, promote shape, tag, GitHub release notes |
04 同仓库更多 Skills
test-skill
Test skill for fixture purposes.
obsidian-markdown
Fixture skill for obsidian-markdown.
obsidian-cli
Fixture skill for obsidian-cli.
obsidian-bases
Fixture skill for obsidian-bases.
json-canvas
Fixture skill for json-canvas.
defuddle
Fixture skill for defuddle.