Skip to content
Back to skills

Changelog Generator

ASecurity

Generate CHANGELOG.md from Conventional Commits with semantic grouping and Keep a Changelog format. Use when the user wants to generate, write, or update a CHANGELOG.md, see what changed since the last tag, or prepare the changelog portion of a release.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 2, 2026
ai-agentsshellbashgitsecurity

Security analysis

A100/100

Scanned October 2, 2026

npx -y skills add ogxo-io/plugins --skill changelog-generator --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Changelog Generator?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Changelog Generator
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ogxo-io-changelog-generator/badge)](https://www.skillsdirectory.com/skills/ogxo-io-changelog-generator)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: changelog-generator
description: Generate CHANGELOG.md from Conventional Commits with semantic grouping and Keep a Changelog format. Use when the user wants to generate, write, or update a CHANGELOG.md, see what changed since the last tag, or prepare the changelog portion of a release.
allowed-tools: Bash(git describe:*), Bash(git tag:*), Bash(git log:*), Bash(git rev-list:*), Bash(git remote:*), Read, Write, Glob, Grep
effort: low
---

# Changelog Generator

## Rules

Build every entry from the actual git log for the chosen range (Steps 1–2), not from memory or the conversation — the changelog is a record of what the commits contain.

For curated GitHub release notes, use the release-notes skill instead.

## Workflow Decision Tree

```
Is the user asking to:
├─ Generate changelog for a NEW release?
│  └─ Detect last tag → parse commits since tag → generate entry → prepend to CHANGELOG.md
│
├─ Generate FULL changelog from scratch?
│  └─ List all tags → generate entry per tag → write complete CHANGELOG.md
│
├─ Show what changed since last release?
│  └─ Detect last tag → parse commits → display summary (don't write file)
│
├─ Generate changelog between TWO versions?
│  └─ Parse commits between the two tags → generate entry
│
└─ Update existing CHANGELOG.md with new version?
   └─ Read existing file → generate new entry → prepend below header
```

**Default path:** Generate changelog for the next release (last tag → HEAD).

## Step 1: Determine Version Range

Establish the commit range before parsing.

```bash
# Get the most recent tag
git describe --tags --abbrev=0 2>/dev/null

# List recent tags with dates
git tag --sort=-creatordate | head -10

# Get commit count since last tag
git rev-list $(git describe --tags --abbrev=0 2>/dev/null)..HEAD --count 2>/dev/null
```

**Caution:** when no tags exist, the range commands above succeed with empty output (`0` commits) instead of erroring. Empty output with no tag means fall back to the full history (`git log --oneline`) and treat everything as the first release — it does not mean "no changes".

## Step 2: Parse Commits

```bash
# One call: resolve the range, then list commits with subject AND body.
# The body carries BREAKING CHANGE details and migration notes — %s alone misses them.
# %x1e emits a record separator so multi-line bodies stay parseable.
TAG=$(git describe --tags --abbrev=0 2>/dev/null); RANGE=${TAG:+$TAG..}HEAD
git log $RANGE --pretty=format:"%h%x09%s%x09%b%x1e" --no-merges

# Variant with author (for PR credit lines)
git log $RANGE --pretty=format:"%h %s (%an)" --no-merges

# For full changelog (all tags)
git log --pretty=format:"%h %s" --no-merges --decorate
```

Run the `TAG=`/`RANGE=` line in the **same Bash call** as the `git log` that uses it — shell variables do not persist between calls.

**Parse each commit line into:**
- **Type**: feat, fix, refactor, perf, docs, test, chore, ci, build
- **Scope**: Optional component in parentheses
- **Description**: The commit message after type/scope
- **Breaking**: Commits with `BREAKING CHANGE:` in body or `!` after type
- **Hash**: Short commit hash for linking

Merge commits are already excluded by `--no-merges`. Group commits that don't follow Conventional Commits under an "Other Changes" section.

## Step 3: Detect GitHub Remote

Detect GitHub repository for PR/issue linking:

```bash
# Get GitHub remote URL
git remote get-url origin 2>/dev/null | sed -E 's/.*github\.com[:/](.+)(\.git)?$/\1/' | sed 's/\.git$//'
```

If a GitHub remote is detected, generate links:
- Commit hashes: `[abc1234](https://github.com/owner/repo/commit/abc1234)`
- PR references: `#123` → `[#123](https://github.com/owner/repo/pull/123)`
- Issue references: `Closes #456` → linked automatically

## Step 4: Group and Format

Use [Keep a Changelog](https://keepachangelog.com/) format with Conventional Commits mapping:

```markdown
## [X.Y.Z] - YYYY-MM-DD

### Added
- feat commits listed here

### Fixed
- fix commits listed here

### Changed
- refactor, perf commits listed here

### Removed
- Commits that remove features/code

### Security
- Security-related fix commits

### Breaking Changes
- BREAKING CHANGE commits listed here with migration notes
```

**Type → Section mapping:**
| Commit Type | Changelog Section |
|-------------|------------------|
| `feat` | Added |
| `fix` | Fixed |
| `refactor` | Changed |
| `perf` | Changed |
| `docs` | (skip unless user requests) |
| `test` | (skip unless user requests) |
| `chore` | (skip unless user requests) |
| `ci`, `build` | (skip unless user requests) |
| `BREAKING CHANGE` | Breaking Changes (always include) |

**Formatting rules:**
- Each entry starts with a dash and space: `- `
- Include scope in bold if present: `- **auth:** add OAuth2 support`
- Append commit hash in parentheses: `([abc1234](link))`
- List breaking changes with migration instructions taken from the commit body (Step 2 captures `%b` for exactly this)
- Empty sections are omitted
- `Breaking Changes` is an intentional extension to the six canonical Keep a Changelog sections — include it whenever breaking commits exist

## Step 5: Determine Version Number

If the user hasn't specified a version, suggest one based on commits:

- **MAJOR** (X.0.0): Any `BREAKING CHANGE` commit exists
- **MINOR** (0.X.0): Any `feat` commit exists (no breaking changes)
- **PATCH** (0.0.X): Only `fix`, `refactor`, `perf`, `docs`, etc.

```bash
# Current version from last tag
current=$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//')

# Or from package.json
grep '"version"' package.json | head -1 | sed 's/.*"\([0-9.]*\)".*/\1/'
```

**Always present the suggested version and ask the user to confirm before writing.**

## Step 6: Write or Update CHANGELOG.md

**When updating an existing CHANGELOG.md:**
1. Read the existing file
2. Insert the new version entry after the `# Changelog` header
3. Preserve all existing entries below

**When creating from scratch:**
```markdown
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [X.Y.Z] - YYYY-MM-DD

### Added
- ...
```

**Present the changelog entry to the user before writing the file.**

## Quick Reference Checklist

When generating a changelog, complete these steps in order:

- [ ] **Step 1:** Determine version range (last tag → HEAD)
- [ ] **Step 2:** Parse git log for conventional commits
- [ ] **Step 3:** Detect GitHub remote for linking
- [ ] **Step 4:** Group by type with Keep a Changelog sections
- [ ] **Step 5:** Suggest version number (confirm with user)
- [ ] **Step 6:** Write/update CHANGELOG.md (present entry first)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.