Skip to main content
AI/MLWaterplanAI

ac-release

Release workflow: branch, changelog, PR, tag, GH release. Triggers on keywords: release, create release, publish release, tag release

Stars
31
Source
WaterplanAI/agentic-config
Updated
2026-05-25
Slug
WaterplanAI--agentic-config--ac-release
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/WaterplanAI/agentic-config/HEAD/.claude/skills/ac-release/SKILL.md -o .claude/skills/ac-release.md

Drops the SKILL.md into .claude/skills/ac-release.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Release Skill

Automated release workflow: pre-flight, branch, changelog+version update, PR, merge, tag, GH release.

Arguments

  • --auto — Skip all confirmation gates (pre-flight + PR merge)
  • --preview — Create GH release as prerelease instead of latest

Phase 1: Pre-flight

1.1 Read Current State

CURRENT_VERSION=$(cat VERSION)
# Parse semver: MAJOR.MINOR.PATCH
NEXT_PATCH=$((PATCH + 1))
NEXT_VERSION="$MAJOR.$MINOR.$NEXT_PATCH"
TODAY=$(date +%Y-%m-%d)

Read CHANGELOG.md and extract the ## [Unreleased] section content (everything between ## [Unreleased] and the next ## [ header).

1.2 Validate

  • CHANGELOG [Unreleased] section MUST have content (not empty)
  • If empty: STOP — "No unreleased changes in CHANGELOG.md. Nothing to release."
  • Current branch MUST be main
  • Working tree MUST be clean (git status --porcelain empty)

1.3 Explain Procedure

Display to user:

Release v{NEXT_VERSION}

Current: v{CURRENT_VERSION}
Next:    v{NEXT_VERSION}

Unreleased changes:
{unreleased content summary — first 10 lines}

Procedure:
1. Create branch release/v{NEXT_VERSION}
2. Update CHANGELOG.md and VERSION
3. Create PR, squash-merge to main
4. Tag v{NEXT_VERSION} on main
5. Create GH release ({"prerelease" if --preview else "latest"})

Proceed?

Confirmation gate: Use AskUserQuestion (yes/no). Skip if --auto.

Phase 2: Branch

git checkout -b release/v{NEXT_VERSION}

Phase 3: Update Files

3.1 CHANGELOG.md

Replace the ## [Unreleased] section:

Before:

## [Unreleased]

### Added
- item A
...

After:

## [Unreleased]

## [{NEXT_VERSION}] - {TODAY}

### Added
- item A
...

The [Unreleased] section becomes empty (just the header), and a new versioned section is inserted immediately below it with all the previous unreleased content.

3.2 VERSION

Write {NEXT_VERSION} to VERSION file (single line, no trailing newline beyond what exists).

3.3 Plugin Versions

Update the version field in every plugins/*/.claude-plugin/plugin.json to {NEXT_VERSION}:

for f in plugins/*/.claude-plugin/plugin.json; do
  # Update "version": "..." to new version
done

Use the Edit tool (not sed) for each file. Only change the version field — leave everything else untouched.

3.4 Commit

git add CHANGELOG.md VERSION plugins/*/.claude-plugin/plugin.json
git commit -m "chore(release): prepare v{NEXT_VERSION}"

Phase 4: PR + Merge

4.1 Push Branch

git push -u origin release/v{NEXT_VERSION}

4.2 Create PR

Create a concise PR:

gh pr create --title "chore(release): v{NEXT_VERSION}" --body "$(cat <<'EOF'
## Release v{NEXT_VERSION}

{Concise 2-5 bullet summary of unreleased changes — high-level only, not the full changelog}
EOF
)"

Capture the PR number from output.

4.3 Confirmation Gate

Display PR URL. Ask user to confirm merge via AskUserQuestion. Skip if --auto.

4.4 Merge

gh pr merge {PR_NUMBER} --squash --admin

Phase 5: Checkout Main

git checkout main
git pull origin main

Phase 6: Tag

6.1 Extract Changelog Entry

Extract the ## [{NEXT_VERSION}] section content from CHANGELOG.md (everything between ## [{NEXT_VERSION}] header line and the next ## [ header). Include the ### sub-headers (Added, Changed, Fixed, Removed) but NOT the ## [{NEXT_VERSION}] line itself.

6.2 Create Annotated Tag

git tag -a "v{NEXT_VERSION}" -m "$(cat <<'EOF'
{changelog entry content with ### headers}
EOF
)"

The tag message mirrors the changelog entry content — same format as existing tags (e.g., v0.1.18).

6.3 Push Tag

git push origin "v{NEXT_VERSION}"

Phase 7: GH Release

gh release create "v{NEXT_VERSION}" \
  --title "v{NEXT_VERSION}" \
  --notes "$(cat <<'EOF'
{changelog entry content — same as tag message}
EOF
)" \
  {--prerelease if --preview, otherwise --latest}

Default: --latest. If --preview argument provided: --prerelease instead.

Phase 8: Summary

Release complete: v{NEXT_VERSION}

- Branch: release/v{NEXT_VERSION} (merged)
- PR: {PR_URL}
- Tag: v{NEXT_VERSION}
- Release: {RELEASE_URL}

Cleanup (optional):
  git branch -d release/v{NEXT_VERSION}
  git push origin --delete release/v{NEXT_VERSION}

Abort Conditions

Condition Action
Empty [Unreleased] STOP — nothing to release
Dirty working tree STOP — commit or stash first
Not on main STOP — checkout main first
PR creation fails STOP — show error
Merge fails STOP — show error, branch still exists
Tag push fails Retry with --force if tag exists on remote from failed attempt
User declines at any gate STOP — clean up branch if created