/version-sdlc gitops

/version-sdlc

/version-sdlc — Semantic Versioning & Release Management

Overview

Manages the full semantic release workflow: detects the version source, bumps the version, creates an annotated git tag, optionally generates a CHANGELOG entry, and pushes the release. Supports file-based versioning (package.json, Cargo.toml, etc.) and tag-only projects. Run --init once per project to save configuration.


Usage

/version-sdlc [major|minor|patch] [flags]

Flags

FlagDescriptionDefault
major / minor / patchBump type (positional). If omitted, auto-detected from conventional commits.auto
--initRun the setup wizard and write .claude/version.json. Safe to re-run.
--pre <label>Create a pre-release version (e.g. beta, rc). Auto-increments the counter on repeated runs.
--no-pushCommit and tag locally, skip git push.
--changelogWith a bump type: generate a CHANGELOG entry as part of the release. Without a bump type: update the changelog for the already-tagged current version (no new tag created).off
--hotfixMark this release as a hotfix for DORA metrics tracking. Annotates the commit message with [hotfix] and the tag message body with Type: hotfix.off
--autoSkip interactive approval prompts. Release plan is still displayed for visibility; critique gates and pre-condition checks still run.off

Examples

First-time setup (run once per project)

/version-sdlc --init
Detected setup:
  Mode:         file
  Version file: package.json
  Version:      1.2.3
  Tag prefix:   v
  Changelog:    no

Suggested config:
  .claude/version.json — will be written

Does this look right? (yes / tag-only / changelog / cancel)

Bump the version

/version-sdlc patch          # 1.2.3 → 1.2.4
/version-sdlc minor          # 1.2.3 → 1.3.0
/version-sdlc major          # 1.2.3 → 2.0.0
/version-sdlc                # auto-detect bump type from conventional commits

Release with a CHANGELOG entry

/version-sdlc minor --changelog

Update changelog for already-tagged version

Run on the main branch after a squash-merge to reconcile the changelog with the actual commits:

/version-sdlc --changelog
Existing changelog entry for [1.3.0]:
──────────────────────────────────────────────
### Added
- Dark mode support for the dashboard

Updated changelog entry:
──────────────────────────────────────────────
### Added
- Dark mode support for the dashboard

### Fixed
- Dark mode toggle state now persists across page reloads

What changed: added 1 fix entry missing from original
Proceed with update? (yes / edit / cancel)

Tag locally without pushing

/version-sdlc patch --no-push

Hotfix release (DORA metrics tracking)

/version-sdlc patch --hotfix
Release Plan
────────────────────────────────────────────
Version:    1.4.2 → 1.4.3
Tag:        v1.4.3 (annotated)
File:       package.json
Push:       yes (to origin/main)
Changelog:  no
Hotfix:     yes
────────────────────────────────────────────

Proceed? (yes / edit / cancel)
> yes

✓ Release v1.4.3 complete (hotfix).
  Commit: d4e5f6a — chore(release): v1.4.3 [hotfix]
  Tag:    v1.4.3  (annotated with Type: hotfix)
  Pushed: yes → origin/main

Pre-release workflow

/version-sdlc minor --pre beta    # 1.2.3 → 1.3.0-beta.1
/version-sdlc --pre beta          # 1.3.0-beta.1 → 1.3.0-beta.2
/version-sdlc --pre rc            # 1.3.0-beta.2 → 1.3.0-rc.1  (label change resets counter)
/version-sdlc minor               # 1.3.0-rc.1 → 1.3.0         (graduate to release)

Example release session

/version-sdlc minor
Release Plan
────────────────────────────────────────────
Version:    1.2.3 → 1.3.0
Tag:        v1.3.0 (annotated)
File:       package.json
Push:       yes (to origin/main)
Changelog:  no
────────────────────────────────────────────

Proceed? (yes / edit / cancel)
> yes

✓ Release v1.3.0 complete.
  Commit: a1b2c3d — chore(release): v1.3.0
  Tag:    v1.3.0
  Pushed: yes → origin/main

CHANGELOG Generation

When --changelog is passed (or "changelog": true in config), generates a Keep a Changelog entry from commits since the last tag:

## [1.3.0] - 2026-03-04

### Added
- User authentication with OAuth2 PKCE flow

### Fixed
- Date parsing in reports now handles timezone offsets correctly

### Changed
- Configuration format migrated from INI to YAML

Conventional commit mapping:

Commit typeCHANGELOG section
featAdded
fixFixed
refactor, perfChanged
Commits with ! or BREAKING CHANGENoted with (BREAKING) in their section
chore, docs, ci, test, build, styleOmitted (unless user-facing)

DORA Metrics

The --hotfix flag enables DORA (DevOps Research and Assessment) metrics tracking by embedding hotfix metadata directly in git history.

What gets annotated:

  • Commit message: chore(release): v1.4.3 [hotfix] — queryable via git log
  • Tag message body: contains Type: hotfix — queryable via git tag

Querying hotfix releases:

# List all commits that are hotfixes
git log --oneline --grep='\[hotfix\]'

# Read the full annotation of a specific tag
git tag -l --format='%(refname:short)%09%(contents)' 'v1.4.3'

# List all tags and their metadata (filter by Type: hotfix in post-processing)
git tag -l --format='%(refname:short)%09%(contents:subject)%09%(contents:body)'

DORA metrics this supports:

DORA MetricHow --hotfix helps
Change Failure RateCount [hotfix] commits as failures relative to total deploys
Time to Restore ServiceDiff timestamp between incident and hotfix tag

Prerequisites

  • git — required for tagging and commit operations.
  • .claude/version.json — must exist before a release run. Created by --init.
  • No gh CLI required.

Harness Configuration

FieldValue
argument-hint[major|minor|patch] [--pre <label>] [--changelog] [--hotfix]
Plan modeGraceful refusal (Step 0)

What It Creates or Modifies

File / ArtifactDescription
.claude/version.jsonPer-project config (created by --init)
package.json / version fileVersion field bumped in-place
git tagAnnotated tag (e.g. v1.3.0) pushed to origin. With --hotfix, tag body includes Type: hotfix.
CHANGELOG.mdNew entry prepended (only with --changelog)

Configuration: .claude/version.json

Generated by --init. Edit manually or re-run --init to reconfigure.

File-based mode

{
  "mode": "file",
  "versionFile": "package.json",
  "fileType": "package.json",
  "tagPrefix": "v",
  "changelog": false,
  "changelogFile": "CHANGELOG.md"
}

Tag-only mode

For projects with no version file (the git tag is the version):

{
  "mode": "tag",
  "tagPrefix": "v",
  "changelog": false,
  "changelogFile": "CHANGELOG.md"
}

Config fields

FieldTypeDescription
mode"file" | "tag"Version source.
versionFilestringPath to version file (relative to project root). mode: "file" only.
fileTypestringVersion file format. Auto-detected by --init.
tagPrefixstringGit tag prefix. Usually "v". Set to "" for no prefix.
changelogbooleanGenerate CHANGELOG by default. Defaults to false.
changelogFilestringPath to the CHANGELOG file. Defaults to "CHANGELOG.md".
ticketPrefixstringOptional. Jira/project key prefix (e.g. "PROJ"). When set, ticket IDs matching this prefix are extracted from commit messages and appended to changelog entries: - Added webhook support (PROJ-123).

Supported version files

Auto-detected in this priority order:

PriorityFileVersion field
1package.json.version
2Cargo.tomlversion = "x.y.z" in [package]
3pyproject.tomlversion = "x.y.z" in [project] or [tool.poetry]
4pubspec.yamlversion: x.y.z
5.claude-plugin/plugin.json.version
6VERSIONEntire file content (trimmed)
7version.txtEntire file content (trimmed)

Changelog Accuracy

The automated changelog is a draft, not a source of truth. Squash merges, parallel branches, and post-tag commits mean the changelog generated at release time may be incomplete.

Recommended post-merge workflow when using squash merges:

  1. Merge to main
  2. git checkout main && git pull
  3. Run /version-sdlc --changelog to reconcile the changelog with the actual tag-to-tag commits
  4. The CI check-changelog.js (scaffolded during --init when changelog is enabled) validates that an entry exists on every push to main