Specification
Skill ID
ilteoood/harness/github-release
Publisher
ilteoood
Repository
harness
Installs
0
Files
3
Requires
requires: gh CLI and git
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

ilteoood/harness/github-releaseInstalls these files
  • SKILL.md
  • references/commit-classification.md
  • references/semver-rules.md

What this skill tells the agent

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 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:

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

ConditionBump
Any breaking change to public API (removal, signature change, behaviour change)MAJOR
New exported symbol or feature, no breaking changesMINOR
Bug fix, perf improvement, security fix, docs, chore onlyPATCH

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

Use this skill in a project

Open any RiverX project, search the Skills panel for ilteoood/harness/github-release, and install it in one click.

Use this skill