Automate semantic versioning with Claude Code by configuring version detection rules that identify version bumps from commit messages and code changes. Claude Code analyzes commits and pull request labels to determine whether changes warrant MAJOR, MINOR, or PATCH version increments according to semantic versioning standards, eliminating manual version bumps and ensuring consistent releases.
Semantic versioning (SemVer) has become the standard for version numbering in modern software development. When combined with Claude Code’s powerful automation capabilities, you can create a version management system that eliminates manual version bumps and ensures consistent releases.
Understanding Semantic Versioning Basics
Semantic versioning follows the format MAJOR.MINOR.PATCH:
-
MAJOR version when you make incompatible API changes
-
MINOR version when you add functionality in a backward-compatible manner
-
PATCH version when you make backward-compatible bug fixes
Claude Code can help automate the detection of which version component should be bumped based on your commit messages, pull request labels, and code changes.
Setting Up Claude Code for Version Management
The first step in automating semantic versioning with Claude Code is to create a CLAUDE.md file that defines your versioning rules and expectations.
# Project Versioning Rules
## Version File Location
- Version is stored in: `package.json`, `pyproject.toml`, or `version.txt`
## Version Bump Rules
- Commits with `BREAKING CHANGE:` in body → MAJOR bump
- Commits with `feat:` prefix → MINOR bump
- Commits with `fix:`, `perf:`, or `refactor:` → PATCH bump
## Changelog Requirements
- Group changes by: Features, Fixes, Breaking Changes, Dependencies
- Include issue references when available
- Use present tense for descriptions
Automated Version Detection Patterns
Claude Code can analyze your codebase to automatically determine the appropriate version bump. Here’s a pattern for version detection:
# version_detector.py
import re
from pathlib import Path
def detect_version_bump(commit_messages: list[str]) -> str:
"""Determine version bump type from commit messages."""
has_breaking = any(
"BREAKING CHANGE" in msg or "BREAKING CHANGES" in msg
for msg in commit_messages
)
has_feature = any(
msg.startswith("feat:") or msg.startswith("feat(")
for msg in commit_messages
)
has_fix = any(
msg.startswith("fix:") or
msg.startswith("perf:") or
msg.startswith("refactor:")
for msg in commit_messages
)
if has_breaking:
return "major"
elif has_feature:
return "minor"
elif has_fix:
return "patch"
return "none"
Creating a Claude Code Command for Version Bumps
You can create custom Claude Code commands that handle the entire version bump process:
# .claude/commands/bump-version.sh
#!/bin/bash
# Get current version
CURRENT_VERSION=$(node -p "require('./package.json').version")
# Analyze commits since last tag
COMMITS=$(git log $(git describe --tags --abbrev=0)..HEAD --pretty=format:"%s")
# Determine bump type
BUMP_TYPE=$(echo "$COMMITS" | grep -E "(BREAKING CHANGE|feat:|fix:)" | head -1 | sed 's/.*\(BREAKING CHANGE\).*/major/; s/.*\(feat:\).*/minor/; s/.*\(fix:\).*/patch/')
# Apply version bump
if [ "$BUMP_TYPE" = "major" ]; then
npm version major -m "Bump version to %s"
elif [ "$BUMP_TYPE" = "minor" ]; then
npm version minor -m "Bump version to %s"
else
npm version patch -m "Bump version to %s"
fi
Integrating with Release Workflows
Here’s how to integrate semantic versioning automation with your release workflow:
GitHub Actions Integration
name: Semantic Version Release
on:
push:
branches: [main]
jobs:
version:
runs-on: ubuntu-latest
outputs:
new_version: ${{ steps.version.outputs.new_version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine Version
id: version
run: |
# Use CLAUDE.md rules to determine version
echo "new_version=$(node scripts/detect-version.js)" >> $GITHUB_OUTPUT
- name: Create Release
if: steps.version.outputs.new_version != ''
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.version.outputs.new_version }}
release_name: Release v${{ steps.version.outputs.new_version }}
Automated Changelog Generation
// scripts/generate-changelog.js
function generateChangelog(commits, version) {
const changes = {
features: [],
fixes: [],
breaking: [],
other: []
};
for (const commit of commits) {
if (commit.message.includes('BREAKING CHANGE')) {
changes.breaking.push(commit);
} else if (commit.message.startsWith('feat:')) {
changes.features.push(commit);
} else if (commit.message.startsWith('fix:')) {
changes.fixes.push(commit);
} else {
changes.other.push(commit);
}
}
return formatChangelog(changes, version);
}
Best Practices for Version Automation
When implementing semantic versioning automation with Claude Code, follow these best practices:
-
Define Clear Commit Conventions: Use Conventional Commits format to make automatic version detection reliable.
-
Maintain a Single Source of Truth: Store version in one place (package.json, pyproject.toml) and reference it consistently.
-
Validate Before Bumping: Always verify that the proposed version bump matches your actual changes.
-
Include Rollback Procedures: Have a plan for reverting version bumps if issues are discovered.
-
Test Automation Thoroughly: Run your version detection logic against historical commits to ensure accuracy.
Using Claude Code to Enforce Versioning Rules
Claude Code can actively enforce versioning rules during development:
# Development Context for Claude Code
## Versioning Enforcement Rules
- All PRs must follow Conventional Commits format
- Breaking changes require MAJOR version bump + migration guide
- New features require MINOR version bump + documentation update
- Bug fixes require PATCH version bump
- Version files must be updated before merging to main
## Before Submitting PR
1. Verify commit messages follow convention
2. Run `npm run version:dry-run` to preview version bump
3. Ensure changelog entries are added
4. Update version in appropriate files
Multi-Language Version File Synchronization
Projects often have version strings in multiple files: package.json for npm, pyproject.toml for Python packages, Chart.yaml for Helm charts, and potentially a VERSION file for shell scripts to consume. A single version bump must update all of them atomically.
Claude Code can generate the synchronization script from your project layout:
# Prompt Claude Code:
# "Read the repository and identify all files that contain version strings.
# Generate a script that bumps them all simultaneously from the current
# version to a new version provided as an argument."
# Generated: scripts/sync-versions.sh
#!/bin/bash
set -euo pipefail
NEW_VERSION="${1:?Usage: sync-versions.sh <new-version>}"
# Validate SemVer format
if ! [[ "$NEW_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Error: version must be in X.Y.Z format" >&2
exit 1
fi
# Update package.json
jq --arg v "$NEW_VERSION" '.version = $v' package.json > package.json.tmp
mv package.json.tmp package.json
# Update pyproject.toml
sed -i "s/^version = .*/version = \"$NEW_VERSION\"/" pyproject.toml
# Update Chart.yaml
sed -i "s/^appVersion: .*/appVersion: \"$NEW_VERSION\"/" charts/myapp/Chart.yaml
# Update plain VERSION file
echo "$NEW_VERSION" > VERSION
echo "Version bumped to $NEW_VERSION across all files"
git diff --stat
The key advantage is that Claude Code generates this script from your actual project structure rather than a generic template — it scans for version patterns before writing the sync logic.
Pre-Commit Hooks for Conventional Commits Enforcement
Automated version detection only works if commit messages consistently follow the convention. Use commitlint with a Git pre-commit hook to enforce format before commits land in history:
# Install commitlint
npm install --save-dev @commitlint/config-conventional @commitlint/cli husky
# Configure commitlint
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
# Initialize husky and add commit-msg hook
npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
Claude Code can help generate custom commitlint rules for your project if you have domain-specific scopes or prefixes that the conventional config doesn’t cover:
// commitlint.config.js - extended with project-specific scopes
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-enum': [2, 'always', [
'api', 'auth', 'database', 'ui', 'infra', 'docs', 'deps', 'ci'
]],
'body-max-line-length': [1, 'always', 100],
}
};
Dry-Run Mode Before Publishing
Before any automated release publishes a package, run a dry-run that previews what will change without making network calls:
# npm dry run — prints what would be published
npm publish --dry-run
# For Python packages using hatch or build + twine:
python -m build --sdist --wheel
twine check dist/*
# Confirm package contents before upload
# Preview GitHub release notes without creating the release:
gh release create v${NEW_VERSION} --draft \
--title "Release v${NEW_VERSION}" \
--notes "$(node scripts/generate-changelog.js)"
Claude Code handles dry-run generation well — prompt it with “Add a dry-run mode that previews version changes without modifying files or making network calls” and it correctly adds --dry-run flags or conditional logic that skips write operations.
Related Articles
- Claude Code Parallel Testing Configuration - Complete
- Writing CLAUDE MD Files That Define Your Project’s API
- AI Code Review Automation Tools Comparison 2026
- Best AI Tools for Code Review Automation 2026
- AI Tools for Detecting Duplicate GitHub Issues Using
Built by theluckystrike — More at zovo.one