doc-changelog
Changelog Generator
Generate CHANGELOG.md entries from git history following Keep a Changelog format.
Workflow
1. Detect range → 2. Collect commits → 3. Enrich with PRs → 4. Classify → 5. Format → 6. Update file
1. Detect Range
Determine what commits to include:
# Find latest version tag
git tag --sort=-v:refname | head -20
Range selection:
- If CHANGELOG.md has
## [Unreleased]— collect commits since last version tag - If user specifies a range — use that (
v1.0.0..HEAD,--since="2 weeks ago") - If no tags exist — collect all commits on the default branch
- If user says "release X.Y.Z" — collect unreleased commits, stamp with version and date
2. Collect Commits
# Commits since last tag (or all if no tags)
git log v1.0.0..HEAD --format="%H|%s|%an|%aI" --no-merges
For merge-based workflows, also collect merge commits to find PR numbers:
git log v1.0.0..HEAD --format="%H|%s" --merges
3. Enrich with PR/Issue Data
If the repo is on GitHub, enrich commits with PR metadata:
# Get PRs merged since last tag
gh pr list --state merged --base main --json number,title,labels,mergedAt --limit 100
Or for a specific date range:
gh pr list --state merged --search "merged:>2026-01-01" --json number,title,labels,body --limit 100
Match commits to PRs via:
- PR number in commit message (e.g.,
(#123)) - Merge commit references
gh pr listmerged date within range
4. Classify Changes
Map commits/PRs to Keep a Changelog categories using Conventional Commits prefixes and PR labels:
| Category | Conventional Commits | PR Labels |
|---|---|---|
| Added | feat:, feat(scope): |
feature, enhancement |
| Changed | refactor:, perf:, build: |
refactor, performance |
| Deprecated | deprecate: |
deprecation |
| Removed | commit message contains "remove", "delete" | removal |
| Fixed | fix:, fix(scope): |
bug, bugfix |
| Security | security: |
security, vulnerability |
Classification rules:
- Conventional Commit prefix takes priority over PR labels
- If no prefix and no label, classify as Changed
- Skip commits matching:
chore:,ci:,docs:(unlessdocs:adds user-facing docs) - Skip commits matching:
Merge branch,Merge pull request(metadata, not changes) - Group by scope when present:
feat(auth):→ group under auth
5. Format Entries
Follow Keep a Changelog format strictly:
## [X.Y.Z] - YYYY-MM-DD
### Added
- **scope**: Description of feature ([#123](link))
### Fixed
- Description of fix ([#456](link))
Formatting rules:
- One bullet per logical change (merge related commits into single entry)
- Start each entry with bold scope if scope is present in commit
- Link PR numbers:
([#123](https://github.com/OWNER/REPO/pull/123)) - Link issue numbers:
([#456](https://github.com/OWNER/REPO/issues/456)) - Use imperative mood for descriptions (Add, Fix, Remove — not Added, Fixed, Removed)
- Keep entries concise — one line per change, details belong in PR descriptions
- Order categories: Added → Changed → Deprecated → Removed → Fixed → Security
6. Update File
If CHANGELOG.md exists:
- Insert new version section below
## [Unreleased]header - If stamping a release, replace
## [Unreleased]content with versioned section, add empty## [Unreleased]above - Update comparison links at bottom of file
If CHANGELOG.md does not exist:
- Create with full Keep a Changelog header
- Include
## [Unreleased]section - Add comparison links
Comparison links (bottom of file):
[Unreleased]: https://github.com/OWNER/REPO/compare/vX.Y.Z...HEAD
[X.Y.Z]: https://github.com/OWNER/REPO/compare/vX.Y.Z-1...vX.Y.Z
Usage Patterns
Update Unreleased Section
Default behavior — collect all changes since last tag:
"Update the changelog"
Stamp a Release
Move unreleased entries to a versioned section:
"Release v2.1.0"
Result: ## [Unreleased] becomes empty, ## [2.1.0] - 2026-02-23 added with entries.
Changelog for Range
Generate entries for a specific commit range:
"Changelog for v1.0.0..v2.0.0"
First Changelog
Create CHANGELOG.md from scratch for a repo without one:
"Create a changelog for this project"
Edge Cases
- Squash merges: Commit message often contains full PR description — extract the title line only
- Monorepo: If user specifies a path, filter commits with
-- path/to/package - No Conventional Commits: Fall back to PR titles and labels for classification; if neither available, list all as Changed
- Amended/rebased history: Use
--first-parentto follow mainline only - Multiple tags on same commit: Use the highest semver tag
More from molechowski/claude-skills
res-price-compare
Polish market product price comparison: 20+ shops, shipping costs, manufacturer vs seller warranty, B2B/statutory warranty analysis, stock status, distribution chain. Export TXT/XLSX/HTML. Use when: looking for a product to buy, price comparison, where to buy cheapest. Triggers: cena, porównaj, gdzie kupić, najtaniej, sklep, price compare, best price, kup, ile kosztuje.
36doc-vault-project
Manage multi-note research projects in Obsidian vault with phased subdirectory structure (concept, research, design, implementation). Scaffold new projects, add component notes, track status, link existing research, promote topics to projects. Use when: creating a project, adding to a project, checking project status, linking research to a project, promoting a research topic to a full project. Triggers: project init, project add, project status, project link, project promote, create project, new project.
35res-deep
Iterative multi-round deep research with structured analysis frameworks. Use for: deep research on a topic, compare X vs Y, landscape analysis, evaluate options for a decision, deep dive into a technology, comprehensive research with cross-referencing. Triggers: deep research, compare, landscape, evaluate, deep dive, comprehensive research, which is better, should we use.
35doc-daily-digest
Process Obsidian daily notes: classify raw URLs and loose ideas, fetch content (X tweets, GitHub repos, web pages), run deep research on ideas, create structured vault notes, replace raw items with wikilinks. Orchestrates doc-obsidian, res-x, and res-deep skills. Use when: processing daily note links, digesting saved URLs into notes, turning ideas into research, daily note cleanup. Triggers: daily digest, process daily, daily links, triage daily, digest daily note.
35res-x
Fetch X/Twitter tweet content by URL and search X posts. Resolves tweet links that WebFetch cannot scrape. Use for: reading saved X/Twitter links, fetching tweet content from URLs, searching X for posts on a topic, batch-processing X links from notes. Triggers: x.com link, twitter.com link, fetch tweet, read tweet, what does this tweet say, X search, twitter search.
34doc-project
Update all project documentation in one pass: CLAUDE.md, AGENTS.md, README.md, SKILLS.md, CHANGELOG.md. Orchestrates doc-claude-md, doc-readme, doc-skills-md, and doc-changelog skills sequentially. Use when: project docs are stale, after major changes, initial project setup, sync all docs. Triggers: update all docs, update project docs, sync documentation, refresh docs, doc-project.
34