Agent Skills: semantic-release

Automate versioning with Node.js semantic-release v25+. TRIGGERS - npm run release, version bump, changelog, conventional commits, release automation.

UncategorizedID: terrylica/cc-skills/semantic-release

Install this agent skill to your local

pnpm dlx add-skill https://github.com/terrylica/cc-skills/tree/HEAD/plugins/itp/skills/semantic-release

Skill Files

Browse the full folder contents for semantic-release.

Download Skill

Loading file tree…

plugins/itp/skills/semantic-release/SKILL.md

Skill Metadata

Name
semantic-release
Description
Automate versioning with Node.js semantic-release v25+. TRIGGERS - npm run release, version bump, changelog, conventional commits, release automation.

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 pull after release
  • βœ… Dry-run testing - npm run release:dry to 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.

mise Task Detection

When .mise.toml has release tasks, prefer mise run over npm run:

| Priority | Condition | Command | | -------- | ------------------------------------ | -------------------------- | | 1 | .mise.toml has [tasks.release:*] | mise run release:version | | 2 | package.json has scripts.release | npm run release | | 3 | Global semantic-release | semantic-release --no-ci |

See Python Guide for complete mise workflow example.

GitHub Actions Policy

CRITICAL: No testing or linting in GitHub Actions. See CLAUDE.md for full policy.

| Forbidden | Allowed | | ------------------------------ | ---------------------- | | pytest, npm test, cargo test | semantic-release | | ruff, eslint, clippy, prettier | CodeQL, npm audit | | mypy | Deployment, Dependabot |


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: or feat!: β†’ 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 section
  • fix: β†’ Bug Fixes section
  • perf: β†’ 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:

  1. List commits since last tag: compare HEAD against latest version tag
  2. Identify commit types: scan for feat:, fix:, or BREAKING CHANGE: prefixes
  3. If NO releasable commits found β†’ STOP - do not proceed with release
  4. Inform user: "No version-bumping commits since last release. Use feat: or fix: 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: BREAKING CHANGE: footer or feat!: / fix!: prefix in commits.

When MAJOR is detected, this skill runs a 3-phase confirmation workflow:

  1. Detection: Scan commits for breaking change markers
  2. Analysis: Spawn 3 parallel subagents (User Impact, API Compat, Migration)
  3. Confirmation: AskUserQuestion with proceed/downgrade/abort options

See MAJOR Confirmation Workflow for complete details including subagent prompts, decision tree, and example output.

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

Auto-include doc changes in release notes. Add to .releaserc.yml:

- - "@semantic-release/exec"
  - generateNotesCmd: "node plugins/itp/skills/semantic-release/scripts/generate-doc-notes.mjs ${lastRelease.gitTag}"

Detects: ADRs, Design Specs, Skills, Plugin READMEs. See Doc Release Linking.

Note: The @semantic-release/exec plugin uses Lodash templates (${var}). This conflicts with bash default syntax (${VAR:-default}) and subshell syntax ($(cmd)). Preferred fix: remove successCmd entirely if your task runner already handles post-release steps. See Troubleshooting: Lodash Template Conflicts.


Quick Start

Prerequisites

| Check | Command | Fix | | ----------------------- | ----------------------------- | ----------------------------------------------------------------------------------------- | | gh CLI authenticated | gh auth status | gh auth login | | GH_TOKEN for directory | gh api user --jq '.login' | See Authentication | | Git remote is HTTPS | git remote get-url origin | git-ssh-to-https | | semantic-release global | command -v semantic-release | See Troubleshooting |

Initialize Project

./scripts/init-project.mjs --project   # Initialize current project
./scripts/init-project.mjs --user      # Create user-level shareable config
./scripts/init-project.mjs --help      # See all options

Run Release

| Priority | Condition | Commands | | -------- | ------------------------------ | ---------------------------------------------------- | | 1 | .mise.toml has release tasks | mise run release:version / mise run release:full | | 2 | package.json has scripts | npm run release:dry (preview) / npm run release | | 3 | Global CLI | semantic-release --no-ci |

See Local Release Workflow for the complete 4-phase process.

Python Projects

semantic-release handles versioning. For PyPI publishing, see pypi-doppler skill.

Version pattern (importlib.metadata - never hardcode):

from importlib.metadata import PackageNotFoundError, version
try:
    __version__ = version("your-package-name")
except PackageNotFoundError:
    __version__ = "0.0.0+dev"

See Python Projects Guide for complete setup including Rust+Python hybrids.

GitHub Actions (Optional)

Not recommended as primary (2-5 minute delay). Repository Settings β†’ Actions β†’ Workflow permissions β†’ Enable "Read and write permissions".


Reference Documentation

| Category | Reference | Description | | ------------- | ---------------------------------------------------------------- | -------------------------------------------------------- | | Setup | Authentication | HTTPS-first setup, multi-account patterns | | Workflow | Local Release Workflow | 4-phase process (PREFLIGHT β†’ RELEASE β†’ POSTFLIGHT) | | Languages | Python Projects | Python + Rust+Python hybrid patterns | | | Rust Projects | release-plz, cargo-rdme README SSoT | | Config | Version Alignment | Git tags as SSoT, manifest patterns | | | Monorepo Support | Polyglot monorepo with Pants + mise, pnpm/npm workspaces | | Advanced | MAJOR Confirmation | Breaking change analysis workflow | | | Doc Release Linking | Auto-link ADRs/specs in release notes | | Help | Troubleshooting | All common issues consolidated | | | Evolution Log | Skill change history |

Cross-skill references:


Post-Change Checklist

After modifying THIS skill (semantic-release):

  1. [ ] SKILL.md and references remain aligned
  2. [ ] New references documented in Reference Documentation table
  3. [ ] All referenced files in references/ exist
  4. [ ] Append changes to evolution-log.md
  5. [ ] Validate with bun scripts/validate-plugins.mjs
  6. [ ] Run npm run release:dry to verify no regressions

Troubleshooting

| Issue | Cause | Solution | | ---------------------------- | ------------------------------- | -------------------------------------------------------- | | No release created | No releasable commits since tag | Use feat: or fix: prefix for version-bumping commits | | Wrong version bump | Commit type mismatch | Check conventional commit format and releaseRules | | GitHub release not created | Missing GH_TOKEN or permissions | Check token is set and has repo scope | | CHANGELOG not updated | Missing changelog plugin | Add @semantic-release/changelog to plugins array | | "Authentication failed" | HTTPS vs SSH remote mismatch | Convert to HTTPS: git-ssh-to-https | | semantic-release not found | Not installed globally | npm install -g semantic-release | | Gatekeeper blocks on macOS | Unsigned Node files | See Troubleshooting | | dry-run shows no changes | Already released at HEAD | Make new commits before running release | | Multi-account token conflict | Wrong GH_TOKEN for directory | Configure mise [env] per-directory token |