skills/release-management/SKILL.md
Release management with semantic versioning, changelogs, and release workflows. Use when: choosing version numbers, creating releases, writing release notes, writing changelogs, designing release branches, automating version bumps, tagging releases, defining release checklists, or deciding when to cut a release. Covers SemVer 2.0.0, pre-release versions, release notes with breaking/functional/non-functional tiers, release pipelines, and changelog automation.
npx skillsauth add michaelsvanbeek/personal-agent-skills release-managementInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Version format: MAJOR.MINOR.PATCH
Given a version 1.4.2:
| Segment | Value | Increment when |
|---------|-------|---------------|
| MAJOR | 1 | Breaking change — consumers must update their code |
| MINOR | 4 | New feature — backward-compatible addition |
| PATCH | 2 | Bug fix — backward-compatible correction |
| Change type | Bump | Example |
|-------------|------|---------|
| Fix a bug without changing API | PATCH | 1.4.2 → 1.4.3 |
| Add a new feature, existing behavior unchanged | MINOR | 1.4.3 → 1.5.0 |
| Change or remove existing behavior | MAJOR | 1.5.0 → 2.0.0 |
| Add deprecation warning (feature still works) | MINOR | 1.5.0 → 1.6.0 |
| Remove deprecated feature | MAJOR | 1.6.0 → 2.0.0 |
| Refactor internals without API change | PATCH | 1.4.2 → 1.4.3 |
| Update dependencies (no behavior change) | PATCH | 1.4.2 → 1.4.3 |
| Update dependencies (new features exposed) | MINOR | 1.4.3 → 1.5.0 |
| Documentation-only changes | No bump (or PATCH if versioned docs) | — |
0: 1.5.3 → 2.0.00: 1.4.3 → 1.5.0Use for testing before a stable release:
2.0.0-alpha.1 # early testing, API may change
2.0.0-beta.1 # feature-complete, fixing bugs
2.0.0-rc.1 # release candidate, final validation
Pre-release versions have lower precedence than the release: 2.0.0-alpha.1 < 2.0.0.
Increment the numeric suffix for subsequent pre-releases: 2.0.0-beta.1 → 2.0.0-beta.2.
Append with + for informational metadata (ignored in version precedence):
1.4.2+build.456
1.4.2+20260320
0.x.yMajor version zero (0.y.z) signals initial development — anything may change at any time. The public API should not be considered stable. Bump to 1.0.0 when the API is stable and used in production.
Every project must have one canonical location for its version. Never define the version in multiple places.
| Project type | Version source | How to read |
|--------------|---------------|-------------|
| Python | pyproject.toml → [project] version | python -c "import importlib.metadata; print(importlib.metadata.version('pkg'))" |
| Node.js | package.json → version | node -p "require('./package.json').version" |
| Generic | Git tag | git describe --tags --abbrev=0 |
| Docker | Image tag | Build-time from git tag or version file |
git tag -a v1.4.2 -m "Release v1.4.2"-a), not lightweight tags — annotated tags store author, date, and message.v: v1.4.2, not 1.4.2.main ──────────────────────────────── main
\ /
feat/my-feature ─────── ← development
\
PR merge to main
\
v1.5.0 tag ← release
main.chore(release): v1.5.0git tag -a v1.5.0 -m "Release v1.5.0"git push origin main --follow-tagsFor urgent fixes to production when main has unreleased changes:
v1.4.0 ──── hotfix/fix-crash ──── v1.4.1
git checkout -b hotfix/fix-crash v1.4.0git tag -a v1.4.1 -m "Release v1.4.1"main to keep it up to date.Breaking changes require extra care:
1.x.y → 2.0.0.Release notes are the primary communication artifact for every release. They must be clear enough for any consumer — developer, operator, or product stakeholder — to understand what changed, what might break, and what they need to do.
Every change in a release falls into one of three tiers. Group and label changes by tier in the release notes:
| Tier | Label | What it covers | Reader action |
|------|-------|---------------|---------------|
| Breaking | ⚠ BREAKING | Removed APIs, changed behavior, renamed fields, dropped support | Must update code or config before upgrading |
| Functional | Features & Fixes | New features, bug fixes, behavior changes that are backward-compatible | Review and adopt at their discretion |
| Non-Functional | Internal | Refactors, dependency updates, performance, docs, CI, test changes | No action required — informational only |
# v2.0.0 — 2026-03-20
## ⚠ Breaking Changes
Changes that require action from consumers before upgrading.
- **Auth: API key authentication removed** — All endpoints now require OAuth2
Bearer tokens. API keys are no longer accepted. See [Migration Guide](./docs/migrate-v2.md).
- **Config: `DATABASE_URL` renamed to `APP_DATABASE_URL`** — Update environment
variables in all deployment environments.
### Migration Guide
Step-by-step instructions for upgrading from v1.x:
1. Replace `X-API-Key` header with `Authorization: Bearer <token>` in all clients.
2. Rename `DATABASE_URL` → `APP_DATABASE_URL` in `.env` and deployment config.
3. Run `python -m myapp.migrate_v2` to update stored data formats.
## Features & Fixes
Backward-compatible additions and corrections.
### Added
- User search endpoint with fuzzy matching (`GET /api/users/search?q=`) (#142)
- Dashboard export to CSV (#156)
### Fixed
- Token refresh no longer fails silently when the session cookie is expired (#138)
- Chart tooltips render correctly in dark mode (#161)
### Deprecated
- `GET /api/users?name=` query parameter — use `/api/users/search?q=` instead.
Will be removed in v3.0.0.
## Internal
Changes with no user-facing impact. No action required.
- Upgraded FastAPI 0.109 → 0.115
- Added integration tests for payment webhook handler
- Reduced Docker image size from 340MB → 120MB via multi-stage build
- Migrated CI from GitHub Actions to Harness Drone
When using conventional commits (see git-workflow skill), map commit types to release note tiers:
| Commit type | Release note tier | Section |
|-------------|-------------------|---------|
| feat | Functional | Added |
| fix | Functional | Fixed |
| BREAKING CHANGE footer or ! suffix | Breaking | ⚠ Breaking Changes |
| deprecated in body | Functional | Deprecated |
| perf | Non-Functional (or Functional if user-visible) | Internal or Changed |
| refactor, build, ci, test, chore | Non-Functional | Internal |
| docs | Non-Functional (or Functional if user-facing docs) | Internal |
(#142).Before publishing release notes, verify:
| Check | Question | |-------|----------| | Complete | Does every merged PR appear in a tier? | | Categorized | Is each change in the correct tier (breaking / functional / non-functional)? | | Actionable | Does every breaking change have a migration path? | | Traceable | Does every entry link to an issue or PR? | | Consumer-readable | Would someone outside the team understand each entry? |
Maintain a CHANGELOG.md following the Keep a Changelog format (see git-workflow skill for full template). The changelog is the cumulative history of all release notes.
## [1.5.0] - 2026-03-20.[Unreleased] section at the top for in-progress changes.Run through before every release:
| Step | Check |
|------|-------|
| Tests pass | All tests green on the release commit (see testing skill) |
| Lint clean | No lint or format violations |
| Version bumped | Version source file updated to the new version |
| Changelog updated | [Unreleased] entries moved under the new version heading |
| No secrets | No credentials, keys, or tokens in the release |
| Dependencies audited | pip audit / npm audit clean (see security skill) |
| Breaking changes documented | Migration guide written if MAJOR bump |
| Tag created | Annotated tag matches the version: v1.5.0 |
| CI green on tag | Release pipeline triggered and completed successfully |
Configure CI to build and publish only when a semver tag is pushed (see cicd skill for full pipeline patterns):
---
kind: pipeline
name: release
trigger:
event: [tag]
ref: ["refs/tags/v*"]
steps:
- name: validate-tag
image: alpine:3.19
commands:
- |
TAG="${DRONE_TAG}"
if ! echo "$TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$'; then
echo "ERROR: Tag '$TAG' does not match semver format (vMAJOR.MINOR.PATCH)"
exit 1
fi
echo "Valid semver tag: $TAG"
- name: test
image: python:3.12-slim
commands:
- pip install pytest
- pytest -v --tb=short
depends_on: [validate-tag]
- name: build-and-publish
image: plugins/docker
settings:
repo: ${DRONE_REPO_OWNER}/my-service
tags:
- latest
- ${DRONE_TAG}
- ${DRONE_TAG##v}
username:
from_secret: docker_username
password:
from_secret: docker_password
depends_on: [test]
Tag images with both the v-prefixed tag and the bare version:
| Git tag | Docker tags |
|---------|-------------|
| v1.5.0 | latest, v1.5.0, 1.5.0 |
| v2.0.0-beta.1 | v2.0.0-beta.1, 2.0.0-beta.1 (not latest) |
Never tag pre-releases as latest — only stable releases.
For projects that derive version from git tags at build time:
# Get the latest version from git tags
VERSION=$(git describe --tags --abbrev=0 | sed 's/^v//')
echo "Building version: $VERSION"
For projects with a version file, use CI to validate that the tag matches the file:
FILE_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
TAG_VERSION="${DRONE_TAG#v}"
if [ "$FILE_VERSION" != "$TAG_VERSION" ]; then
echo "ERROR: pyproject.toml version ($FILE_VERSION) != tag ($TAG_VERSION)"
exit 1
fi
| Model | When to use | Trade-offs | |-------|-------------|------------| | Release when ready | Most projects, especially small teams | Simple, flexible, no artificial deadlines | | Scheduled releases | Products with external consumers or SLAs | Predictable for consumers, may delay features | | Continuous delivery | Mature CI/CD, high test confidence | Fastest feedback, requires strong automation |
For most projects, release when ready is the right default. Ship when the feature set is coherent and tests pass.
| Anti-pattern | Why it's bad | Do this instead |
|--------------|-------------|-----------------|
| Bumping MAJOR for every change | Consumers can't trust version stability | Reserve MAJOR for actual breaking changes |
| Skipping versions (1.0.0 → 1.5.0) | Confusing, implies missing releases | Increment sequentially |
| Tagging without tests passing | Broken releases erode trust | CI must validate before publish |
| Manual changelog from memory | Incomplete, error-prone | Derive from conventional commits |
| Version in multiple files | Drift between sources | Single source of truth + build-time injection |
| Deleting and re-creating tags | Breaks downstream caches and references | Bad release → new PATCH release |
| No changelog | Consumers can't assess upgrade risk | Maintain CHANGELOG.md for every release |
| v0.x.y forever | Signals instability, discourages adoption | Promote to 1.0.0 when API is stable |
development
TypeScript coding standards and type safety conventions. Use when: creating TypeScript files, defining interfaces and types, writing type-safe code, reviewing TypeScript for type correctness, auditing a codebase for type safety gaps, eliminating any or ts-ignore usage, or improving strict-mode compliance. Covers strict typing, avoiding any and ts-ignore, discriminated unions, Zod runtime validation, immutability patterns, and proper type definitions.
testing
Writing clear, actionable tickets in any issue tracker (Jira, Linear, GitHub Issues, ServiceNow, etc.). Use when: creating epics, stories, tasks, bugs, or spikes; writing acceptance criteria; decomposing work for a sprint; linking dependencies between tickets; auditing backlog items for clarity; or coaching a team on ticket quality. Covers title conventions, description templates, acceptance criteria, decomposition rules, dependency linking, and org-specific pluggable configuration.
development
Testing strategy, patterns, and evaluation for software and LLM/AI systems. Use when: writing tests, choosing test boundaries, designing test data, structuring test suites, evaluating LLM outputs, building evaluation pipelines, setting coverage thresholds, auditing test coverage gaps in existing projects, or improving test quality and structure.
development
Writing effective status updates for different audiences and cadences. Use when: writing a weekly status update, preparing a monthly summary, drafting a quarterly review, sending updates to leadership, sharing progress with stakeholders, or improving the clarity and impact of team communications. Covers weekly, monthly, and quarterly formats tailored for upward, lateral, and downward communication.