Skip to content
AI & Agents
Skill

/github-release

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

From plugin
awesome-copilot
39k200 skills200 agents
Install
$ npx -y skills add github/awesome-copilot --skill github-release --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/github-release

Context preview

The summary Claude sees to decide when to auto-load this skill.

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

SKILL.md

github-release.SKILL.md
name: github-release
description: >
  Guides IA through releasing a new version of a GitHub library end-to-end.
  Handles SemVer versioning and Keep a Changelog formatting automatically.
compatibility: "requires: gh CLI and git"

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:

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

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.

# 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"
# 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):

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.

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)

# 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'
# 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 t

Read more
Ships withawesome-copilot

A community-created collection of custom agents, instructions, skills, hooks, workflows, and plugins to supercharge your GitHub Copilot experience.

Get the whole plugin

Other skills on awesome-copilot.