Claude
Skills
Sign in
Back

github-release

Included with Lifetime
$97 forever

Guides IA through releasing a new version of a GitHub library end-to-end. Handles SemVer versioning and Keep a Changelog formatting automatically.

General

What this skill does


# GitHub Release Skill

This skill automates the full release workflow for a single-package GitHub repository,
from analysis through changelog authoring and PR creation. It relies exclusively on
`gh` (GitHub CLI) and `git` no other tools needed.

Steps 1 - 4 are **read-only reconnaissance** nothing is written to the repo until
Step 5, once the version number is confirmed.

## When to Use This Skill

Use this skill whenever the user wants to cut a new release, publish a new version,
bump a version, create a release branch, generate a changelog, or open a release PR
on a GitHub repository. Trigger even if the user says something casual like "let's
ship a new version" or "time to release".

---

## Prerequisites

Examples below include both Bash and PowerShell variants; Windows users should prefer
the PowerShell blocks.

Before starting, verify the environment:

```bash
gh auth status                        # must be authenticated
gh repo view --json nameWithOwner     # must be inside a GitHub repo
git status                            # working tree should be clean
```

If any check fails, stop and tell the user what to fix before continuing.

Then ask the user one question:

> *"Which directory contains your library's public-facing source code?
> (e.g. `src/`, `lib/`, `pkg/` - used to focus the diff on what consumers
> actually see. Press Enter to scan the whole repo.)"*

Store the answer as `PUBLIC_PATH`. If empty, `PUBLIC_PATH` is `.` (repo root).
Exclude these paths from all diffs regardless: `tests/`, `test/`, `spec/`,
`__tests__/`, `docs/`, `*.lock`, `*-lock.json`, `*.sum`, generated files
(files with a "do not edit" header comment), and build artefacts.

---

## The 9-Step Release Workflow

Work through every step in order. Show the user what command you're about to run and
its output. Pause and ask for confirmation only when explicitly noted.

---

### Step 1 - Ensure main is up to date

```bash
git checkout main
git pull origin main
```

Stay on `main` for now. The release branch is created in Step 5, after the version
is confirmed.

---

### Step 2 - Grab the latest version tag

> **Why not `gh release list`?** GitHub Releases are an optional layer on top of Git
> tags. Many repos tag releases with `git tag` without ever creating a GitHub Release,
> so `gh release list` can return empty even when version tags exist. Reading tags
> directly from git is the reliable source of truth.

```bash
# Fetch all tags from remote to ensure local view is current
git fetch --tags

# Find the latest version tag, sorted semantically
# --sort=-version:refname handles 1.10.0 > 1.9.0 correctly (unlike alphabetical)
PREV_TAG=$(git tag --sort=-version:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+' | head -1)
echo "Latest tag: $PREV_TAG"
```

```PowerShell
# Fetch all tags from remote to ensure local view is current
git fetch --tags

# Find the latest version tag, sorted semantically
# --sort=-version:refname handles 1.10.0 > 1.9.0 correctly (unlike alphabetical)
$prevTag = git tag --sort='-version:refname' | `
  Select-String '^[vV]?\d+\.\d+\.\d+' | `
  Select-Object -First 1 -ExpandProperty Line

if ($prevTag) {
  $prevSha = git rev-list -n 1 $prevTag
} else {
  $prevSha = git rev-list --max-parents=0 HEAD
}

Write-Output "Latest tag: $prevTag"
```

Then verify the tag exists on the remote (not just locally):

```bash
git ls-remote --tags origin | grep "refs/tags/$PREV_TAG$"
```

If the remote check returns nothing, warn the user that the tag appears to be local-only
and hasn't been pushed - they may want to push it before continuing.

- `PREV_TAG` is the tag name exactly as found (e.g. `v1.4.2`). Strip any leading `v`
  when doing arithmetic; preserve it when naming things.
- If **no tags exist at all**, treat `PREV_TAG` as `(none)`, set `PREV_SHA` to the
  first commit, and default the new version to `1.0.0` (skip Step 4 versioning logic;
  go straight to Step 5).
- If the tag does not point to a real commit (orphaned tag), fall back to
  `git rev-list --max-parents=0 HEAD` and warn the user.

```bash
PREV_SHA=$(git rev-list -n 1 "$PREV_TAG" 2>/dev/null || git rev-list --max-parents=0 HEAD)
```

---

### Step 3 - Analyse what changed since the last release

This step uses **two complementary signals**. The code diff is the primary source of
truth; commit messages provide supporting context about intent.

#### 3a - Code diff (primary signal)

```bash
# Focused diff on the public source path, excluding noise
git diff "$PREV_SHA"..HEAD -- "$PUBLIC_PATH" \
  ':(exclude)tests/' ':(exclude)test/' ':(exclude)spec/' \
  ':(exclude)__tests__/' ':(exclude)docs/' \
  ':(exclude)*.lock' ':(exclude)*-lock.json' ':(exclude)*.sum'
```

```PowerShell
# Focused diff on the public source path, excluding noise
git diff "$($prevSha)..HEAD" -- $publicPath `
  ':(exclude)tests/' ':(exclude)test/' ':(exclude)spec/' `
  ':(exclude)__tests__/' ':(exclude)docs/' `
  ':(exclude)*.lock' ':(exclude)*-lock.json' ':(exclude)*.sum'
```

Read the full diff output. For each changed file, identify:

1. **Removed symbols** - functions, classes, methods, constants, exported names that
   existed before and are now gone. ? Strong signal for MAJOR.
2. **Changed signatures** - functions that exist in both versions but with different
   parameters, return types, or thrown errors. ? Strong signal for MAJOR.
3. **New exported symbols** - public functions, classes, constants that didn't exist
   before. ? Signal for MINOR.
4. **Internal-only changes** - modifications that don't touch any public interface
   (private helpers, unexported functions, algorithm internals). ? PATCH.
5. **Bug fixes** - corrections to logic that was provably wrong (e.g. off-by-one,
   null check, wrong condition), without changing the public API. ? PATCH.

If the diff is very large (thousands of lines), first run the stat summary to
prioritise which files to read in full:

```bash
git diff "$PREV_SHA"..HEAD --stat -- "$PUBLIC_PATH"
```

Focus your detailed reading on files with the most changes and files whose names
suggest they define public interfaces (e.g. `index.*`, `api.*`, `exports.*`,
`public.*`, `mod.*`, `__init__.*`).

#### 3b - Commit log (secondary signal)

```bash
git log "$PREV_SHA"..HEAD --oneline --no-merges
```

Use this to:
- Understand the **intent** behind code changes that aren't self-explanatory from
  the diff alone (e.g. a one-line security fix labelled as such).
- Catch changes that may be in paths outside `PUBLIC_PATH` but are still user-visible
  (e.g. a CLI flag change in a `cmd/` directory).
- Fill in context for changelog entries where the code alone doesn't tell the whole
  story.

See `references/commit-classification.md` for mapping message patterns to change types.

#### 3c - Reconcile the two signals

When signals agree ? use that classification with confidence.

When signals conflict ? **prefer the code diff**. Examples:
- Commit says `fix: typo` but the diff shows a removed public method ? treat as MAJOR.
- Commit says `feat: new API` but the diff only touches private internals ? treat as PATCH.
- Commit says `chore: refactor` but the diff adds new exported symbols ? treat as MINOR.

Document any conflicts you notice - flag them to the user during the changelog review
in Step 6.

---

### Step 4 - Determine the next SemVer version

Apply these rules to your analysis from Step 3 (full rules in `references/semver-rules.md`):

| Condition | Bump |
|---|---|
| Any breaking change to public API (removal, signature change, behaviour change) | MAJOR |
| New exported symbol or feature, no breaking changes | MINOR |
| Bug fix, perf improvement, security fix, docs, chore only | PATCH |

When a release contains a mix, the **highest precedence wins**:
`MAJOR > MINOR > PATCH`.

Compute `NEXT_VERSION`:
- Split `PREV_TAG` into `MAJOR.MINOR.PATCH` integers.
- Apply the appropriate bump.
- Format as `vMAJOR.MINOR.PATCH`.

**Present the proposed version to the user** with a brief rationale that cites
specifi
Files: 3
Size: 19.7 KB
Complexity: 38/100
Category: General

Related in General