Universal release automation skill. Works with any project.
Quick Reference
- "release" →
/release-har - "bump version" →
/release-har patch - "minor release" →
/release-har minor - "preview only" →
/release-har --dry-run
References
| Document | Content |
|---|---|
| references/release-notes-template.md | GitHub Release Notes template (4-section structure) |
| references/changelog-format.md | CHANGELOG.md format (Keep a Changelog compliant) |
| .claude/rules/github-release.md | Release Notes format rules (source of truth) |
Branch Policy
In solo development projects, direct pushes to main are allowed.
- CI が
push: branches: [main]Since all verification is run with , the quality gate functions even without a PR release.ymlがv*Operates as a safety net that guarantees the existence of a GitHub Release when a tag is pushed- force push(
--force/--force-with-lease) is prohibited
For projects with collaborators, switch to merging via PR.
Execution Flow
Pre-flight: Preliminary check (required)
Confirm the following before starting the release. If any fail, stop the release and prompt for correction.
# 1. gh コマンドの存在確認
if ! command -v gh &>/dev/null; then
echo "⚠️ gh コマンドが見つかりません。GitHub Release の作成はスキップします。"
GH_AVAILABLE=false
else
GH_AVAILABLE=true
fi
# 2. 未コミット変更の確認
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "❌ 未コミットの変更があります。コミットまたはスタッシュ後にリリースしてください。"
git status --short
exit 1
fi
# 3. バージョンファイル同期確認(VERSION と plugin.json が存在する場合)
if [ -f "VERSION" ] && [ -f ".claude-plugin/plugin.json" ]; then
V_VERSION=$(cat VERSION | tr -d '[:space:]')
V_PLUGIN=$(grep '"version"' .claude-plugin/plugin.json | sed 's/.*"version": "\([^"]*\)".*/\1/')
if [ "$V_VERSION" != "$V_PLUGIN" ]; then
echo "❌ バージョン不一致: VERSION=$V_VERSION, plugin.json=$V_PLUGIN"
echo " 修正: ./scripts/sync-version.sh sync"
exit 1
fi
fi
| Check | Behavior on failure |
|---|---|
| gh command exists | Warning only, continue (skip only GitHub Release) |
| Uncommitted changes | Stop(prompt to commit or stash) |
| Version file synchronization | Stop(prompt to run sync-version.sh sync) |
Step 1: Change analysis
Retrieve the following in parallel.
# 前タグを取得
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null \
|| git tag --sort=-v:refname | head -1 2>/dev/null \
|| echo "")
# 構造化コミットログ(フォーマット: {hash}|{subject}|{author}|{date})
if [ -n "$PREV_TAG" ]; then
LOG=$(git log --format="%h|%s|%an|%ad" --date=short "${PREV_TAG}..HEAD")
else
LOG=$(git log --format="%h|%s|%an|%ad" --date=short --all | head -20)
fi
# OWNER/REPO 取得(gh 優先 → git remote フォールバック)
if command -v gh &>/dev/null; then
REPO_FULL=$(gh repo view --json nameWithOwner -q '.nameWithOwner' 2>/dev/null || echo "")
fi
if [ -z "${REPO_FULL:-}" ]; then
REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")
REPO_FULL=$(echo "$REMOTE_URL" \
| sed -E 's|https://github\.com/||; s|git@github\.com:||; s|\.git$||')
fi
Conventional Commits classification
| Prefix | CHANGELOG Category |
|---|---|
feat: / feat(...): |
Added |
fix: / fix(...): |
Fixed |
docs: / perf: / refactor: / test: / chore: |
Changed |
| Other / Unclassifiable | Changed |
BREAKING CHANGE detection: feat!: / fix!: such as ! with type, or commits containing BREAKING CHANGE: in the body.
For projects not using Conventional Commits, Claude semantically judges and classifies the commit messages.
Display change analysis summary
📊 変更分析サマリ (vPREV → vNEW候補)
━━━━━━━━━━━━━━━━━━━━━━━━━
- feat : N 件 → Added
- fix : M 件 → Fixed
- other : L 件 → Changed
- breaking : K 件 → Breaking Changes ⚠️
─────────────────────────────────
- contributors: X 名
- compare: https://github.com/{OWNER}/{REPO}/compare/{PREV_TAG}...HEAD
━━━━━━━━━━━━━━━━━━━━━━━━━
Step 2: SemVer determination
Propose a version based on the analysis results from Step 1.
PREV_VERSION=${PREV_TAG#v} # "v1.2.3" → "1.2.3"
MAJOR=$(echo "$PREV_VERSION" | cut -d. -f1)
MINOR=$(echo "$PREV_VERSION" | cut -d. -f2)
PATCH=$(echo "$PREV_VERSION" | cut -d. -f3)
if [ "${BREAKING_COUNT:-0}" -ge 1 ]; then
SUGGESTED_VERSION="$((MAJOR+1)).0.0" # major
elif [ "${FEAT_COUNT:-0}" -ge 1 ]; then
SUGGESTED_VERSION="${MAJOR}.$((MINOR+1)).0" # minor
else
SUGGESTED_VERSION="${MAJOR}.${MINOR}.$((PATCH+1))" # patch
fi
Display example: 📦 SemVer 判定: MINOR (1.2.3 → 1.3.0) 理由: feat: 3件, fix: 2件, breaking: 0件
| Argument | Behavior |
|---|---|
/release-har patch |
Adopt PATCH without confirmation |
/release-har minor |
Adopt MINOR without confirmation |
/release-har major |
Adopt MAJOR without confirmation |
| No argument | Display the automatic determination result and confirm with the user |
0.x.y initial development stage: When MAJOR=0, according to SemVer 2.0.0 §4, even for a breaking change, have the user choose between a minor bump (0.x+1.0) or major (1.0.0).
Step 3: diff summary & Release Notes draft generation
Read not only the commit messages but also the actual code diffs to generate Highlights and the Before/After table.
# 変更ファイルを確認(テスト・ロックファイルは低優先)
git diff --stat "${PREV_TAG}..HEAD"
# 重要ファイルの diff を読む(src/ 配下を優先)
git diff "${PREV_TAG}..HEAD" -- <重要ファイルパス> | head -100
What Claude generates (up to 3 items):
- Highlights: Value from the user's perspective (1-3 sentences)
- Before / After Table: State before and after the change
Template details: references/release-notes-template.md
Step 4: dry-run preview (default preliminary step)
Always display a preview before the actual run(--dry-run (same applies to normal execution without ).
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔍 リリースプレビュー: v{PREV} → v{NEW}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📦 タグ: vX.Y.Z
📁 更新ファイル: CHANGELOG.md, VERSION, package.json(存在する場合)
📄 CHANGELOG エントリ(全文):
{CHANGELOG エントリ}
🧹 Documentation Cleanup:
CHANGELOG: {正規化対象 N 件}(日付フォーマット、セクション見出し等)
README: {更新対象 M 件}(バージョン参照、機能一覧等)
📝 GitHub Release Notes(全文):
{4セクション構造の Release Notes}
🔗 Compare URL: {COMPARE_URL}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
この内容で実行しますか? (yes / no / 修正指示)
| Answer | Behavior |
|---|---|
yes |
Proceed to the actual run from Step 5 onward |
no |
Cancel |
| Correction instructions | Fix Release Notes and preview again |
--dry-run when option: Exit after preview (no actual execution).
Step 5: Update CHANGELOG (if present)
If CHANGELOG.md exists, update it. Format details: references/changelog-format.md
## [X.Y.Z] - YYYY-MM-DD
### 🎯 What's Changed for You
**{one-line バリュー要約}**
| Before | After |
|--------|-------|
| {旧状態} | {新状態} |
### Added
- **{Feature}**: {description}
### Fixed
- **{Fix}**: {description}
If CHANGELOG_ja.md exists, update the same content in Japanese.
If CHANGELOG does not exist, skip.
Step 5.5: Documentation Cleanup (maintenance of existing documentation)
At release time, also improve the quality of existing documentation.Not only add new entries, but also fix past issues.
Normalization of existing CHANGELOG entries
If past entries do not conform to Keep a Changelog 1.1.0, normalize them.
| Check items | Fix examples |
|---|---|
| Date format | 2026/02/23 → 2026-02-23 (ISO 8601) |
| Section headings | ### New Features → ### Added |
| Empty sections | Remove headings with no content |
| Broken links | Fix tag names in Compare URLs |
| Markdown syntax | Fix broken tables, unify list notation |
If CHANGELOG_ja.md exists, perform equivalent maintenance.
Updating README
| Check items | Fix details |
|---|---|
| Version number | Update badges, installation examples, and references to the new version |
| Feature list | Fix descriptions that diverge from reality |
| Command/API examples | Update deprecated or changed items |
| Broken links | Fix links to nonexistent files |
Criteria: Fix only clearly outdated or broken parts. Respect intentional style differences. If README does not exist, skip.
Step 6: Update version files
Update the version according to the project.
| File | Update method |
|---|---|
VERSION |
Rewrite file contents directly |
package.json |
"version": "X.Y.Z" Update |
pyproject.toml |
version = "X.Y.Z" Update |
Cargo.toml |
version = "X.Y.Z" Update |
.claude-plugin/plugin.json |
./scripts/sync-version.sh sync Run |
If the relevant file does not exist, skip.
Node.js Project: npm version patch --no-git-tag-version is also available.
Step 7: Commit & Tag
# 変更対象ファイルのみ明示的に追加(git add -A は使用しない)
git add CHANGELOG.md README.md VERSION package.json # 実際に変更したファイルのみ
# コミット(変更がある場合のみ)
git commit -m "chore: release vX.Y.Z"
# タグ作成
git tag -a vX.Y.Z -m "Release vX.Y.Z"
Step 8: Push
git push origin $(git branch --show-current)
git push origin vX.Y.Z
Step 9: GitHub Release (Optional)
Create a GitHub Release after user confirmation. Release Notes must be in English.
gh release create vX.Y.Z \
--title "vX.Y.Z - {release title}" \
--notes "$(cat <<'EOF'
## What's Changed
**{one-line バリュー要約}**
### Before / After
| Before | After |
|--------|-------|
| {旧状態} | {新状態} |
---
## Highlights
- **{Feature}**: {description}
## Notable Changes
### Added
- **{feature}**: {description}
### Fixed
- **{fix}**: {description}
## Full Changelog
**Full Changelog**: ${COMPARE_URL}
---
Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
Format Rules: .claude/rules/github-release.md Template details: references/release-notes-template.md
Requirements:
- Release Notes must be in English
- The Before/After table cannot be omitted
Generated with [Claude Code](https://claude.com/claude-code)The footer cannot be omitted- If there are no Breaking Changes, omit that section
- Highlights: maximum 3 items
Step 10: Generate X (Twitter) announcement text (--announce only when specified)
/release-har --announce When run with , automatically generate X announcement text after creating the GitHub Release.
Generation Logic
Compress the 1-2 most important points from the Highlights generated in Step 3 (diff summary) into one line each, and create an announcement text of 280 characters or less.
Format
🚀 v{VERSION} released!
{Highlights から抽出した1行要約(日本語または英語、プロジェクトの言語に合わせる)}
{2行目(任意)}
{GitHub Release URL}
Example:
🚀 v1.3.0 released!
Pre-flight checks + Claude diff summarization で配信品質が向上。
SemVer 自動判定と dry-run プレビューで事故を防止。
https://github.com/OWNER/REPO/releases/tag/v1.3.0
Constraints
| Constraint | Value |
|---|---|
| Maximum characters | 280 characters (X's limit) |
| Emoji | Minimal (🚀 only recommended) |
| Link | Required (GitHub Release URL) |
| Language | Match the project's primary language |
After generation, present it to the user in a format that can be copied as-is. Do not post via Claude (manual copy & paste).
Options
| Option | Description |
|---|---|
patch |
Automatically increment the patch version |
minor |
Automatically increment the minor version |
major |
Automatically increment the major version |
--dry-run |
Preview only (no file changes, commits, tags, or push) |
--announce |
Generate an announcement text for X (formerly Twitter) after release |
Related Skills
x-release-harness- Harness plugin dedicated release (local only)verify- Pre-release verification