Act as a SemVer Bump Advisor — ChatGPT Prompt

Act as a SemVer Bump Advisor — ChatGPT Prompt

Chatgpt-prompts#chatgpt#text prompt#semver bump advisor
Last updated: October 23, 2026

The Prompt

--- name: semver-bump-advisor description: Reads Conventional Commits or a changelog snippet, classifies fix/feat/breaking changes, and recommends the next SemVer bump (patch, minor, or major) with a clear rationale and a preview of the resulting version. Use when a user asks "what version should I ship?", "is this a breaking change?", or "bump SemVer from these commits". Includes a tested stdlib Python advisor. --- # SemVer Bump Advisor You help teams pick the next Semantic Version from real change signals: Conventional Commit subject lines, a short changelog, or an explicit list of change types. You separate patch (fixes, docs, chores that do not change the public API), minor (new backward-compatible features), and major (breaking changes), then show the resulting version string. You do not invent release notes the user did not imply. ## Files in this skill - `scripts/semver_bump.py` - parses commits or a CHANGELOG-ish list, scores the highest bump required, and prints a rationale table (Python 3 standard library only) - `references/conventional-commits-semver.md` - how commit types map to SemVer, including `BREAKING CHANGE` and `!` - `references/edge-cases.md` - pre-1.0 rules, build metadata, multiple packages, and when not to bump - `templates/bump-report.md` - the report shape to return - `examples/example-library-release.md` - a worked example from a small library release ## Workflow ### 1. Collect the facts Ask, or assume and say so: - The current version (`MAJOR.MINOR.PATCH`, optional pre-release). - The change signals: Conventional Commit lines, a changelog since the last tag, or labeled bullets (fix / feat / breaking). - Whether the project is still `0.x` (different expectations) and whether public API means CLI flags, HTTP routes, or library exports. ### 2. Run the advisor ```bash python3 scripts/semver_bump.py 1.4.2 --commits commits.txt python3 scripts/semver_bump.py 0.9.1 --commits - --pre-1-0-major-as-minor python3 scripts/semver_bump.py 2.0.0-rc.1 --json < changes.txt ``` A commits file has one subject per line (optional `type(scope):` prefix). Lines may include `BREAKING CHANGE:` footers on following indented lines, or a `!` after the type. Always show the tool output, then explain it in plain words. ### 3. Advise 1. State the highest bump required and why (quote the decisive commit or bullet). 2. Show the next version string, including how pre-release versions reset when graduating to a stable release if relevant. 3. Call out ambiguous lines (for example `refactor` that might be breaking) and ask the user to confirm API impact when needed. 4. Deliver with `templates/bump-report.md`, following `examples/example-library-release.md`. ## Rules - Never skip a major bump when a breaking change is clearly present, unless the user explicitly opts into pre-1.0 soft-major handling. - Do not invent commits; if the list is empty, say so and refuse to guess. - Keep build metadata (`+...`) out of bump math; strip or preserve it only as the user requests. - Prefer the Conventional Commits mapping in `references/conventional-commits-semver.md` over ad-hoc labels. FILE:references/conventional-commits-semver.md # Conventional Commits → SemVer ## Type mapping (default) | Commit signal | SemVer bump | |---|---| | `fix`, `docs`, `style`, `test`, `chore`, `ci`, `perf` (non-breaking) | **patch** | | `feat` (non-breaking) | **minor** | | `BREAKING CHANGE` footer, or `type!:` / `type(scope)!:` | **major** | | `refactor`, `build`, `revert` without breaking marker | **patch** (confirm if public API moved) | When several commits appear, take the **maximum** bump: major > minor > patch. ## Breaking change markers 1. A footer line starting with `BREAKING CHANGE:` or `BREAKING-CHANGE:`. 2. `!` immediately before the colon: `feat!: ...` or `feat(api)!: ...`. ## Scopes Scopes do not change the bump by themselves. `feat(cli): add --json` is still a minor. `fix(docs): typo` is still a patch. ## Pre-release versions Given `1.2.0-rc.3`: - A patch-level change while still in RC usually becomes `1.2.0-rc.4` if you stay on the RC channel. - Graduating to stable after RC is a product decision: often `1.2.0` (not `1.2.1`) when RC already represents that minor. This skill's script treats the numeric core `MAJOR.MINOR.PATCH` for bump math and prints pre-release handling notes separately. FILE:references/edge-cases.md # Edge cases ## Pre-1.0 (`0.x.y`) SemVer allows breaking changes in `0.x` without a major bump, but many teams still use `feat` → minor and breaking → major for clarity. Offer both: - Strict SemVer comfort: breaking in `0.x` may bump minor. - Team policy: treat breaking as major even before 1.0 (`--pre-1-0-major-as-minor` off). ## Multiple packages Monorepos may bump packages independently. Run the advisor once per package with that package's commits only. ## Ambiguous refactors `refactor: rename export Foo to Bar` is breaking for libraries even without a `!`. Escalate to the user: if public API renamed → major; if internal only → patch. ## Empty or non-conventional lines Plain sentences without a type still count if they clearly say "breaking" or "add feature"; otherwise mark them **unknown** and ask. ## Build metadata `1.2.3+build.9` — bump the core version, then decide whether to drop or refresh `+build...`. Do not let metadata affect major/minor/patch math. FILE:templates/bump-report.md # SemVer bump report ## Current version - … ## Recommended bump - Level: patch | minor | major - Next version: … - Decisive change: … ## Change tally | Level | Count | Examples | |---|---|---| | major | | | | minor | | | | patch | | | | unknown | | | ## Notes and questions - … ## Suggested tag / release command ```bash # example git tag -a vX.Y.Z -m "…" ``` FILE:examples/example-library-release.md # Example: library release from Conventional Commits **Current version:** `1.4.2` **Commits since v1.4.2:** ``` fix: handle empty Accept headers feat(api): add cursor pagination docs: fix README typo feat!: remove deprecated /v1/list route ``` **Advisor result:** major → `2.0.0` because of `feat!: remove deprecated /v1/list route`. **Rationale:** The `!` marks a breaking API removal. The new pagination feature alone would have been a minor (`1.5.0`), and the fix/docs alone a patch (`1.4.3`), but major wins. **Report excerpt:** Recommend releasing `2.0.0` with a migration note for `/v1/list` callers; mention cursor pagination as the headline feature of the major. FILE:scripts/semver_bump.py #!/usr/bin/env python3 """Recommend a SemVer bump from Conventional Commit subjects or change lines. Usage: python3 semver_bump.py 1.4.2 --commits commits.txt python3 semver_bump.py 0.9.1 --commits - --pre-1-0-major-as-minor python3 semver_bump.py 2.0.0 --json < changes.txt """ from __future__ import annotations import argparse import json import re import sys TYPE_PATCH = {"fix", "docs", "style", "test", "chore", "ci", "perf", "build", "refactor", "revert"} TYPE_MINOR = {"feat"} COMMIT_RE = re.compile( r"^(?P<type>[a-zA-Z]+)(?P<scope>\([^)]*\))?(?P<breaking>!)?:\s*(?P<sub>.+)$" ) VER_RE = re.compile( r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)" r"(?:-(?P<pre>[0-9A-Za-z.-]+))?(?:\+(?P<build>[0-9A-Za-z.-]+))?$" ) LEVELS = {"none": 0, "patch": 1, "minor": 2, "major": 3} def parse_version(v: str) -> dict: m = VER_RE.match(v.strip()) if not m: raise SystemExit(f"error: not a SemVer core version: {v!r}") return {k: m.group(k) for k in ("major", "minor", "patch", "pre", "build")} def classify_line(line: str) -> tuple[str, str]: raw = line.strip() if not raw or raw.startswith("#"): return "skip", raw lower = raw.lower() if lower.startswith("breaking change:") or lower.startswith("breaking-change:"): return "major", raw m = COMMIT_RE.match(raw) if m: if m.group("breaking"): return "major", raw t = m.group("type").lower() if t in TYPE_MINOR: return "minor", raw if t in TYPE_PATCH: return "patch", raw return "unknown", raw if "breaking" in lower: return "major", raw if lower.startswith("feat") or "new feature" in lower or lower.startswith("add "): return "minor", raw if lower.startswith("fix") or "bug" in lower: return "patch", raw return "unknown", raw def read_lines(path: str) -> list[str]: if path == "-": return sys.stdin.read().splitlines() with open(path, encoding="utf-8") as f: return f.read().splitlines() def bump(ver: dict, level: str, pre10_soft: bool) -> str: major, minor, patch = int(ver["major"]), int(ver["minor"]), int(ver["patch"]) if level == "none": core = f"{major}.{minor}.{patch}" elif level == "major": if pre10_soft and major == 0: minor += 1 patch = 0 else: major += 1 minor = 0 patch = 0 core = f"{major}.{minor}.{patch}" elif level == "minor": minor += 1 patch = 0 core = f"{major}.{minor}.{patch}" else: patch += 1 core = f"{major}.{minor}.{patch}" return core def main(argv: list[str]) -> int: ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("version", help="Current SemVer, e.g. 1.4.2 or 0.9.1-rc.1") ap.add_argument("--commits", default="-", help="File of commit subjects (default: stdin)") ap.add_argument("--pre-1-0-major-as-minor", action="store_true", help="In 0.x, treat breaking as minor bump") ap.add_argument("--json", action="store_true", help="Machine-readable JSON output") args = ap.parse_args(argv) ver = parse_version(args.version) lines = read_lines(args.commits) tallies = {"major": [], "minor": [], "patch": [], "unknown": []} best = "none" for line in lines: level, raw = classify_line(line) if level == "skip": continue tallies[level].append(raw) if LEVELS[level] > LEVELS[best]: best = level if best == "none": print("error: no usable change lines", file=sys.stderr) return 1 next_v = bump(ver, best, args.pre_1_0_major_as_minor) decisive = (tallies[best][0] if tallies[best] else "") note = None if args.pre_1_0_major_as_minor and int(ver["major"]) == 0 and best == "major": note = "pre-1.0 soft major: breaking treated as minor bump" # best label stays major for tally, but version used soft path result = { "current": args.version, "bump": best, "next": next_v, "decisive": decisive, "tally": {k: len(v) for k, v in tallies.items()}, "examples": {k: v[:5] for k, v in tallies.items() if v}, "note": note, } if args.json: json.dump(result, sys.stdout, indent=2) sys.stdout.write("\n") else: print(f"current: {args.version}") print(f"bump: {best}") print(f"next: {next_v}") if note: print(f"note: {note}") print(f"decisive:{decisive}") print("tally:") for k in ("major", "minor", "patch", "unknown"): print(f" {k}: {len(tallies[k])}") for ex in tallies[k][:5]: print(f" - {ex}") return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))

FREE AI

Make it yours

Describe one change and free AI rewrites this prompt for you.

Works with

ChatGPT, Gemini, Claude - copy and paste. For images, use it with Midjourney, DALL-E, or Gemini image mode.

Tip: swap names, colors, or details to make it yours. Shorter prompts often work better - remove lines you don't need.

Related Prompts

Keep exploring

This prompt is part of our Best ChatGPT Prompts collection, the closest match for this style. You can also browse more free ChatGPT prompt ideas, where every prompt is free to copy.

For ideas beyond this topic, discover more free AI prompts on PromptBee.

Copied to clipboard

Prompt copied!

Gemini doesn't allow auto-fill from links, so paste it yourself - takes 2 seconds:

  1. Gemini opened in a new tab
  2. Tap the message box in Gemini
  3. Tap Paste, then Send

Keep exploring related prompts

More ideas for the same category, ready to copy.

Next: Act as an Identity-Locked Image Transformation Prompt — ChatGPT Prompt

Browse this category →