| name | semantic-release |
| description | Automate versioning with Node.js semantic-release v25+. TRIGGERS - npm run release, version bump, changelog, conventional commits, release automation. |
| allowed-tools | Read, Bash, Glob, Grep, Edit, Write |
semantic-release
Overview
Automate semantic versioning and release management using semantic-release v25+ (Node.js) following 2025 best practices. Works with all languages (JavaScript, TypeScript, Python, Rust, Go, C++, etc.) via the @semantic-release/exec plugin. Create shareable configurations for multi-repository setups, initialize individual projects with automated releases, and configure GitHub Actions workflows with OIDC trusted publishing.
Important: This skill uses semantic-release (Node.js) exclusively, NOT python-semantic-release, even for Python projects. Rationale: 23.5x larger community, 100x+ adoption, better future-proofing.
When to Use This Skill
Invoke when:
- Setting up local releases for a new project (any language)
- Creating shareable semantic-release configuration for organization-wide use
- Migrating existing projects to 2025 semantic-release patterns
- Troubleshooting semantic-release setup or version bumps
- Setting up Python projects (use Node.js semantic-release, NOT python-semantic-release)
- Configuring GitHub Actions (optional backup, not recommended as primary due to speed)
- Rust workspaces using release-plz (see Rust reference)
Why Node.js semantic-release
22,900 GitHub stars - Large, active community
1.9M weekly downloads - Proven adoption
126,000 projects using it - Battle-tested at scale
35+ official plugins - Rich ecosystem
Multi-language support - Works with any language via @semantic-release/exec
Do NOT use python-semantic-release. It has a 23.5x smaller community (975 vs 22,900 stars), ~100x less adoption, and is not affiliated with the semantic-release organization.
Release Workflow Philosophy: Local-First
Default approach: Run releases locally, not via GitHub Actions.
Why Local Releases
Primary argument: GitHub Actions is slow
- ⏱️ GitHub Actions: 2-5 minute wait for release to complete
- ⚡ Local release: Instant feedback and file updates
- 🔄 Immediate workflow continuity - no waiting for CI/CD
Additional benefits:
- ✅ Instant local file sync -
package.json,CHANGELOG.md, tags updated immediately - ✅ No pull required - Continue working without
git pullafter release - ✅ Dry-run testing -
npm run release:dryto preview changes before release - ✅ Offline capable - Can release without CI/CD dependency
- ✅ Faster iteration - Debug release issues immediately, not through CI logs
GitHub Actions: Optional Backup Only
GitHub Actions workflows are provided as optional automation, not the primary method:
- Use for team consistency if required
- Backup if local environment unavailable
- Not recommended as primary workflow due to speed
Authentication Setup
gh auth login
# Browser authentication once
# Credentials stored in keyring
# All future releases: zero manual intervention
This is the minimum manual intervention possible for local semantic-release with GitHub plugin functionality.
Multi-Account Authentication via mise [env]
For multi-account GitHub setups, use mise [env] to set per-directory GH_TOKEN:
# ~/your-project/.mise.toml
[env]
GH_TOKEN = "{{ read_file(path=env.HOME ~ '/.claude/.secrets/gh-token-accountname') | trim }}"
GITHUB_TOKEN = "{{ read_file(path=env.HOME ~ '/.claude/.secrets/gh-token-accountname') | trim }}"
This overrides gh CLI's global authentication, ensuring semantic-release uses the correct account for each directory.
See the `mise-configuration` skill for complete setup.
Critical Standard: No Testing/Linting in GitHub Actions
This standard applies to ALL GitHub Actions workflows, not just semantic-release.
Forbidden Workflow Steps
GitHub Actions workflows must NEVER include:
❌ Test execution:
# ❌ FORBIDDEN - Do not add to any workflow
- run: pytest
- run: npm test
- run: cargo test
- uses: actions/upload-test-results # Implies testing
❌ Linting/Formatting:
# ❌ FORBIDDEN - Do not add to any workflow
- run: ruff check
- run: eslint .
- run: cargo clippy
- run: prettier --check
- run: mypy
Allowed Workflow Patterns
✅ Semantic-release (this workflow):
- run: npm run release # Version, changelog, GitHub release only
✅ Security scanning:
- run: npm audit signatures
- uses: github/codeql-action/analyze@v3
✅ Deployment:
- run: docker build && docker push
- run: aws s3 sync ./build s3://bucket
✅ Dependency updates:
- uses: dependabot/fetch-metadata@v2
Enforcement
Documentation-based: This standard is enforced through CLAUDE.md instructions, not pre-commit hooks.
When creating or modifying GitHub Actions workflows, Claude Code will check CLAUDE.md and this skill to ensure compliance.
Separation of Concerns (4-Level Architecture)
semantic-release configuration follows a hierarchical, composable pattern:
Level 1: Skill - ${CLAUDE_PLUGIN_ROOT}/skills/semantic-release/ (Generic templates, system-wide tool)
Level 2: User Config - ~/semantic-release-config/ (@username/semantic-release-config)
Level 3: Organization Config - npm registry (@company/semantic-release-config)
Level 4: Project Config - .releaserc.yml in project root
Configuration Precedence
Level 4 (Project) → overrides → Level 3 (Org) → overrides → Level 2 (User) → overrides → Defaults
Conventional Commits Format
semantic-release analyzes commit messages to determine version bumps:
<type>(<scope>): <subject>
Version Bump Rules (Default)
feat:→ MINOR version bump (0.1.0 → 0.2.0)fix:→ PATCH version bump (0.1.0 → 0.1.1)BREAKING CHANGE:orfeat!:→ MAJOR version bump (0.1.0 → 1.0.0)docs:,chore:,style:,refactor:,perf:,test:→ No version bump (by default)
Release Notes Visibility (Important)
Warning: The @semantic-release/release-notes-generator (Angular preset) only includes these types in release notes:
feat:→ Features sectionfix:→ Bug Fixes sectionperf:→ Performance Improvements section
Other types (docs:, chore:, refactor:, etc.) trigger releases when configured but do NOT appear in release notes.
Recommendation: For documentation changes that should be visible in release notes, use:
fix(docs): description of documentation improvement
This ensures the commit appears in the "Bug Fixes" section while still being semantically accurate (fixing documentation gaps is a fix).
Marketplace Plugin Configuration (Always Bump)
For Claude Code marketplace plugins, every change requires a version bump for users to receive updates.
Option A: Shareable Config (if published)
# .releaserc.yml
extends: "@terryli/semantic-release-config/marketplace"
Option B: Inline Configuration
# .releaserc.yml
plugins:
- - "@semantic-release/commit-analyzer"
- releaseRules:
# Marketplace plugins require version bump for ANY change
- { type: "docs", release: "patch" }
- { type: "chore", release: "patch" }
- { type: "style", release: "patch" }
- { type: "refactor", release: "patch" }
- { type: "test", release: "patch" }
- { type: "build", release: "patch" }
- { type: "ci", release: "patch" }
Result after configuration:
| Commit Type | Release Type |
|---|---|
feat: |
minor (default) |
fix:, perf:, revert: |
patch (default) |
docs:, chore:, style:, refactor:, test:, build:, ci: |
patch (configured) |
Why marketplace plugins need this: Plugin updates are distributed via version tags. Without a version bump, users running /plugin update see no changes even if content was modified.
MANDATORY: Every Release Must Increment Version
Pre-release validation: Before running semantic-release, verify releasable commits exist since last tag. A release without version increment is invalid.
Autonomous check sequence:
- List commits since last tag: compare HEAD against latest version tag
- Identify commit types: scan for
feat:,fix:, orBREAKING CHANGE:prefixes - If NO releasable commits found → STOP - do not proceed with release
- Inform user: "No version-bumping commits since last release. Use
feat:orfix:prefix for releasable changes."
Commit type selection guidance:
- Use
fix:for any change that improves existing behavior (bug fixes, enhancements, documentation corrections that affect usage) - Use
feat:for new capabilities or significant additions - Reserve
chore:,docs:,refactor:for changes that truly don't warrant a release
Why this matters: A release without version increment creates confusion - users cannot distinguish between releases, package managers may cache old versions, and changelog entries become meaningless.
MAJOR Version Breaking Change Confirmation
Trigger: When commits contain BREAKING CHANGE: footer or feat!: / fix!: prefix.
Why extra confirmation: MAJOR version bumps signal breaking changes that require consumers to update their code. False positives (accidental ! suffix) or unnecessary breaking changes can fragment the user base.
Phase 1: Detection (Automatic)
/usr/bin/env bash << 'MAJOR_CHECK_EOF'
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null)
MAJOR_COMMITS=$(git log "${LAST_TAG}..HEAD" --oneline | grep -E "(BREAKING CHANGE|^[a-f0-9]+ (feat|fix)!:)")
if [[ -n "$MAJOR_COMMITS" ]]; then
echo "MAJOR_DETECTED"
echo "$MAJOR_COMMITS"
fi
MAJOR_CHECK_EOF
Phase 2: Multi-Perspective Analysis (Claude Task Subagents)
When MAJOR is detected, spawn three parallel Task subagents for independent analysis:
MAJOR Version Confirmation
+-----------+ ----------------- spawn 3 agents +-------------+
| Migration | <-- | MAJOR Detected | ----------------> | User Impact |
+-----------+ ----------------- +-------------+
| | |
| | |
| v |
| +-----------------+ |
| | API Compat | |
| +-----------------+ |
| | |
| | |
| v |
| +-----------------+ |
+-------------> | Collect Results | <-------------------+
+-----------------+
|
|
v
#=================#
H AskUserQuestion H
#=================#
graph-easy source
graph { label: "MAJOR Version Confirmation"; flow: south; }
[ MAJOR Detected ] { shape: rounded; }
[ User Impact ] -> [ Collect Results ]
[ API Compat ] -> [ Collect Results ]
[ Migration ] -> [ Collect Results ]
[ MAJOR Detected ] -- spawn 3 agents --> [ User Impact ]
[ MAJOR Detected ] --> [ API Compat ]
[ MAJOR Detected ] --> [ Migration ]
[ Collect Results ] -> [ AskUserQuestion ] { border: double; }
Task subagent prompts (spawn in parallel):
User Impact Analyst (
subagent_type: "Explore"):Analyze the breaking changes in commits since last tag. Identify: - Which user personas are affected (library consumers, CLI users, API clients) - Approximate usage scope (core feature vs edge case) - Available workarounds before upgrading Return a 2-3 sentence impact assessment.API Compatibility Analyst (
subagent_type: "Explore"):Review the breaking changes for API compatibility: - What specific signatures, behaviors, or contracts are changing - Whether the change could be made backwards-compatible with feature flags - If deprecation warnings could have preceded this break Return a 2-3 sentence compatibility assessment.Migration Strategist (
subagent_type: "Explore"):Assess the migration path for this breaking change: - Effort level for consumers to update (trivial/moderate/significant) - Whether a migration guide is needed in release notes - Suggested deprecation timeline if change could be phased Return a 2-3 sentence migration assessment.
Phase 3: User Confirmation (AskUserQuestion with multiSelect)
After collecting subagent analyses, present consolidated findings:
AskUserQuestion:
questions:
- question: "MAJOR version bump (X.0.0) detected. How should we proceed?"
header: "Breaking"
multiSelect: false
options:
- label: "Proceed with MAJOR (Recommended)"
description: "Release as X.0.0 - breaking change is intentional and necessary"
- label: "Downgrade to MINOR"
description: "Amend commits to remove BREAKING CHANGE - change can be backwards-compatible"
- label: "Abort release"
description: "Review commits before releasing - need to reconsider approach"
- question: "Which mitigations should be included in release notes?"
header: "Mitigations"
multiSelect: true
options:
- label: "Migration guide"
description: "Step-by-step instructions for updating consumer code"
- label: "Deprecation notice"
description: "Warning that old behavior will be removed in future version"
- label: "Compatibility shim"
description: "Temporary backwards-compat layer with deprecation warning"
Decision Tree
MAJOR Release Decision Tree
--------------------- NO -------------------
| Proceed MINOR/PATCH | <------- | MAJOR detected? |
--------------------- -------------------
|
| YES
v
+-------------------+
| Spawn 3 Subagents |
+-------------------+
|
|
v
--------------------- abort +-------------------+ proceed ---------------
| Abort Release | <------- | AskUserQuestion | ---------> | Proceed MAJOR |
--------------------- +-------------------+ ---------------
|
| downgrade
v
+-------------------+
| Downgrade MINOR |
+-------------------+
|
|
v
+-------------------+
| Amend Commits |
+-------------------+
graph-easy source
graph { label: "MAJOR Release Decision Tree"; flow: south; }
[ MAJOR detected? ] { shape: rounded; }
[ Proceed MINOR/PATCH ] { shape: rounded; }
[ Spawn 3 Subagents ]
[ AskUserQuestion ]
[ Proceed MAJOR ] { shape: rounded; }
[ Downgrade MINOR ]
[ Abort Release ] { shape: rounded; }
[ Amend Commits ]
[ MAJOR detected? ] -- NO --> [ Proceed MINOR/PATCH ]
[ MAJOR detected? ] -- YES --> [ Spawn 3 Subagents ]
[ Spawn 3 Subagents ] -> [ AskUserQuestion ]
[ AskUserQuestion ] -- proceed --> [ Proceed MAJOR ]
[ AskUserQuestion ] -- downgrade --> [ Downgrade MINOR ]
[ AskUserQuestion ] -- abort --> [ Abort Release ]
[ Downgrade MINOR ] -> [ Amend Commits ]
Example Output
╔══════════════════════════════════════════════════════════════════╗
║ 🔴 MAJOR VERSION BUMP DETECTED ║
╠══════════════════════════════════════════════════════════════════╣
║ Commits triggering MAJOR: ║
║ • a1b2c3d feat!: change API to require authentication ║
║ • e4f5g6h fix!: rename config option from 'timeout' to 'ttl' ║
╠══════════════════════════════════════════════════════════════════╣
║ 📊 MULTI-PERSPECTIVE ANALYSIS ║
╠──────────────────────────────────────────────────────────────────╣
║ 👥 User Impact: All API consumers affected. Core authentication ║
║ flow changes. No workaround - update required. ║
║ ║
║ 🔌 API Compat: Authorization header now mandatory. Could add ║
║ optional fallback with deprecation warning for 1-2 releases. ║
║ ║
║ 📋 Migration: Moderate effort - add API key to all calls. ║
║ Migration guide recommended. 2-week notice suggested. ║
╠══════════════════════════════════════════════════════════════════╣
║ Current: v2.4.1 → Proposed: v3.0.0 ║
╚══════════════════════════════════════════════════════════════════╝
Configuration
To skip MAJOR confirmation (not recommended):
# .releaserc.yml
# WARNING: Disables safety check - use only for automated pipelines
skipMajorConfirmation: true
Default: MAJOR confirmation is ENABLED. This skill will always prompt for breaking changes unless explicitly disabled.
Examples
Feature (MINOR):
feat: add BigQuery data source support
Bug Fix (PATCH):
fix: correct timestamp parsing for UTC offsets
Breaking Change (MAJOR):
feat!: change API to require authentication
BREAKING CHANGE: All API calls now require API key in Authorization header.
Documentation Linking in Release Notes
Automatically include links to all documentation changes in release notes, with AI-friendly categorization.
Quick Setup (Hardcoded Path)
Add to .releaserc.yml before @semantic-release/changelog:
- - "@semantic-release/exec"
- generateNotesCmd: "node plugins/itp/skills/semantic-release/scripts/generate-doc-notes.mjs ${lastRelease.gitTag}"
What's Detected
The script categorizes all changed markdown files:
| Category | Pattern | Grouping |
|---|---|---|
| ADRs | docs/adr/YYYY-MM-DD-slug.md |
Status table |
| Design Specs | docs/design/YYYY-MM-DD-slug/spec.md |
List with change type |
| Skills | plugins/*/skills/*/SKILL.md |
Grouped by plugin (collapsible) |
| Plugin READMEs | plugins/*/README.md |
Simple list |
| Skill References | plugins/*/skills/*/references/*.md |
Grouped by skill (collapsible) |
| Commands | plugins/*/commands/*.md |
Grouped by plugin |
| Root Docs | CLAUDE.md, README.md, CHANGELOG.md |
Simple list |
| General Docs | docs/*.md (excluding adr/, design/) |
Simple list |
How It Works
- Git diff detection: All
.mdfiles changed since the last release tag - Change type tracking: Marks files as
new,updated,deleted, orrenamed - Commit parsing: References like
ADR: 2025-12-06-slugin commit messages - ADR-Design Spec coupling: If one is changed, the corresponding pair is included
Full HTTPS URLs are generated (required for GitHub release pages).
See Documentation Release Linking for detailed configuration.
Quick Start
Step 1: Verify Account (HTTPS-First)
CRITICAL: For multi-account GitHub setups, verify GH_TOKEN is set for the current directory.
Quick verification (2025-12-19+):
# Verify git remote is HTTPS
git remote get-url origin
# Expected: https://github.com/...
# Verify GH_TOKEN is set via mise [env]
gh api user --jq '.login'
# Expected: correct account for this directory
If remote is SSH (legacy):
# Convert to HTTPS
git-ssh-to-https
If wrong account:
Check mise [env] configuration:
# Verify mise config
mise env | grep GH_TOKEN
See Authentication Guide for HTTPS-first setup.
Step 2: Initialize Project
/usr/bin/env bash << 'CONFIG_EOF'
cd /path/to/project
# Environment-agnostic path
PLUGIN_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/marketplaces/cc-skills/plugins/itp}"
"$PLUGIN_DIR/skills/semantic-release/scripts/init_project.sh" --user
# Or --org mycompany/semantic-release-config
# Or --inline
CONFIG_EOF
Step 3: Run Release Locally
Follow the Local Release Workflow for the complete 4-phase process (PREFLIGHT → SYNC → RELEASE → POSTFLIGHT).
Quick commands:
npm run release:dry # Preview changes (no modifications)
npm run release # Create release (auto-pushes via successCmd + postrelease)
What happens automatically:
- Version bump determined from commits
CHANGELOG.mdupdated- Release commit + tag created
- Git push via successCmd (belt-and-suspenders)
- GitHub release created via API
- Tracking refs updated via postrelease
One-time setup (recommended for macOS):
# Install globally to avoid macOS Gatekeeper issues with npx
npm install -g semantic-release @semantic-release/changelog @semantic-release/git @semantic-release/github @semantic-release/exec
# Clear quarantine (required on macOS after install or node upgrade)
xattr -r -d com.apple.quarantine ~/.local/share/mise/installs/node/
Note: Use
semantic-releasedirectly (notnpx semantic-release) to avoid macOS Gatekeeper blocking.nodenative modules. See Troubleshooting.
Step 4: PyPI Publishing (Python Projects)
For Python packages: semantic-release handles versioning, use the `pypi-doppler` skill for local PyPI publishing.
Quick setup:
/usr/bin/env bash << 'SETUP_EOF'
# Install Doppler CLI for secure token management
brew install dopplerhq/cli/doppler
# Store token in Doppler (one-time)
doppler secrets set PYPI_TOKEN='your-pypi-token' --project claude-config --config prd
# Copy publish script from pypi-doppler skill (environment-agnostic)
PLUGIN_DIR="${CLAUDE_PLUGIN_ROOT:-$HOME/.claude/plugins/marketplaces/cc-skills/plugins/itp}"
cp "$PLUGIN_DIR/skills/pypi-doppler/scripts/publish-to-pypi.sh" scripts/
chmod +x scripts/publish-to-pypi.sh
# After semantic-release creates GitHub release:
./scripts/publish-to-pypi.sh # 30 seconds vs 3-5 minutes with GitHub Actions
SETUP_EOF
See `pypi-doppler` skill for complete workflow with CI detection guards.
Python __version__ Pattern
Always use importlib.metadata - never hardcode version strings:
# __init__.py
from importlib.metadata import PackageNotFoundError, version
try:
__version__ = version("your-package-name")
except PackageNotFoundError:
__version__ = "0.0.0+dev" # Development fallback
This reads from pyproject.toml at runtime, ensuring single source of truth. semantic-release updates pyproject.toml via prepareCmd, and importlib.metadata reads it at runtime - no manual sync required.
Anti-pattern (causes version drift):
# ❌ BAD - requires manual sync with pyproject.toml
__version__ = "1.2.3"
See Python Projects with Node.js semantic-release for complete Python automation guide.
Step 5: GitHub Actions (Optional)
Only if you want CI/CD backup (not recommended as primary due to 2-5 minute delay):
Repository Settings → Actions → General → Workflow permissions → Enable "Read and write permissions"
Common Pitfalls
Dirty Working Directory
Symptom: After release, git status shows version files as modified with OLD versions.
Cause: Files were staged before release started. semantic-release commits from working copy, but git index cache may show stale state.
Prevention: Always clear git cache before checking status:
# Step 1: Refresh git index (automatic in npm run release)
git update-index --refresh -q || true
# Step 2: Check for uncommitted changes (modified, untracked, staged, deleted)
git status --porcelain
# Should output nothing
# If dirty, either:
git stash # Stash changes
git commit -m "..." # Commit changes
git checkout -- . # Discard changes
Recovery: If you see stale versions after release:
git update-index --refresh
git status # Should now show clean
Automated guards: The cc-skills .releaserc.yml includes:
- verifyConditions preflight: Clears git cache first, then blocks release if working directory is dirty
- successCmd index refresh: Automatically refreshes git index after push
Pre-Release Checklist
Before running npm run release:
- ✅ All changes committed
- ✅ No staged files (
git diff --cachedis empty) - ✅ No untracked files in version-synced paths
- ✅ Branch is up-to-date with remote
Reference Documentation
For detailed information, see:
- Authentication - START HERE - SSH keys, GitHub CLI web auth (avoid manual tokens)
- Local Release Workflow - Step-by-step release process with issue resolution
- Workflow Patterns - Personal, Team, and Standalone project patterns
- Version Alignment - Git tags as SSoT, manifest patterns, runtime version access
- 2025 Updates - v25 changelog, Node.js 24+, OIDC trusted publishing, plugin versions
- Python Projects with Node.js semantic-release - Complete guide for Python package automation with @semantic-release/exec
- Rust Projects with release-plz - Rust-native release automation with cargo-rdme README SSoT
- `pypi-doppler` skill - Local PyPI publishing with Doppler credentials and CI detection guards
- Monorepo Support - pnpm/npm workspaces configuration
- Troubleshooting - Common issues and solutions
- ADR Release Linking - Auto-link ADRs and Design Specs in release notes
- Resources - Scripts, templates, and asset documentation