---
name: 0xjitsu/changelog-gen
source: https://app.decimal.ai/s/0xjitsu-changelog-gen@1/SKILL.md
source_sha256: 16c651692620
---

# changelog-gen

Generate a structured CHANGELOG entry from git commit history using conventional commit conventions.

---

## When to Trigger

Activate this skill when the user:
- Asks to **generate a changelog** or **update CHANGELOG.md**
- Wants to **prepare release notes**
- Asks "what changed since last release" or "summarize recent commits"
- Is invoked by the `npm-publish` skill during the release pipeline

---

## Commit Parsing

### Fetch Commits Since Last Tag

```bash
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null)
```

If a tag exists:

```bash
git log ${LAST_TAG}..HEAD --oneline --no-merges
```

If no tags exist (first release), use all commits:

```bash
git log --oneline --no-merges
```

### Categorize by Conventional Commit Prefix

| Prefix | Changelog Section |
|--------|-------------------|
| `feat:` / `feat(scope):` | **Added** |
| `fix:` / `fix(scope):` | **Fixed** |
| `refactor:` / `perf:` | **Changed** |
| `docs:` | **Documentation** |
| `BREAKING CHANGE:` or `!:` in subject | **Breaking Changes** |
| `chore:` / `ci:` / `build:` / `test:` | **Internal** |

Rules:
- Strip the prefix and scope from the description (e.g., `feat(auth): add OAuth flow` becomes `Add OAuth flow`)
- Capitalize the first letter of each entry
- Append the short commit hash in parentheses: `(a1b2c3d)`
- If a commit body contains `BREAKING CHANGE:`, promote it to the Breaking Changes section regardless of prefix

### Non-Conventional Fallback

If fewer than 50% of commits follow conventional format, switch to AI categorization:

1. For each commit, read the diff: `git show --stat <hash>`
2. Categorize based on the files changed and diff content:
   - New files added to `src/` -> Added
   - Modified test files -> Internal
   - Modified docs -> Documentation
   - Bug-related keywords in message (fix, resolve, patch, correct) -> Fixed
   - Everything else -> Changed
3. Flag in the output that AI categorization was used

---

## Output Format

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

### Breaking Changes
- Description of breaking change and migration steps (hash)

### Added
- New feature description (hash)

### Fixed
- Bug fix description (hash)

### Changed
- Refactor or performance improvement description (hash)

### Documentation
- Documentation update description (hash)

### Internal
- Chore, CI, build, or test change description (hash)
```

Rules:
- Omit any section that has zero entries
- Use the version from `package.json` if available, otherwise prompt the user
- Date is always today in `YYYY-MM-DD` format
- Use `---` as the date separator (em dash style)

---

## Actions

### 1. Generate Entry

Build the changelog entry following the output format above. Display it to the user for review before writing.

### 2. Prepend to CHANGELOG.md

If `CHANGELOG.md` exists, insert the new entry immediately after the `# Changelog` header line (preserving any preamble text between the header and the first version entry).

If `CHANGELOG.md` does not exist, create it:

```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/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

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

### 3. Write Temp File for GitHub Release

Write just the current version's entry (without the `## [version]` header) to `/tmp/CHANGELOG_ENTRY.md` for use by the `npm-publish` skill or `gh release create`.

---

## Edge Cases

| Scenario | Behavior |
|----------|----------|
| No git tags exist | Use all commits from repo inception |
| No commits since last tag | Report "No changes since vX.Y.Z" and exit |
| No conventional commits | Use AI categorization with a warning |
| Merge commits | Skip by default (`--no-merges`) |
| Single commit since last tag | Still generate a full entry |
| Monorepo with multiple packages | Filter commits by path if user specifies a package directory |

---

## Integration

This skill is designed to be invoked standalone or as part of the `npm-publish` pipeline. When called from `npm-publish`, the version number is already determined and should be passed in rather than read from `package.json`.