ideas.
July 05, 2026 3 min read clidev-toolsautomation

Git-aware changelog generator for release day

A CLI that reads commits and merged PRs since your last tag, groups them by type, and drafts a changelog and release notes post for you to edit and ship.

The idea

A command-line tool, relnotes, that runs at release time: it diffs the current branch against the last git tag, pulls in commit messages and merged PR titles/descriptions, and produces a categorized changelog (features, fixes, breaking changes, internal) plus a longer-form release notes draft in Markdown. You run relnotes draft v2.4.0, skim the output, edit the two or three lines that need a human voice, and paste it into GitHub Releases or your docs site.

Why build this

Changelogs are one of those chores every team means to do well and usually does badly — either skipped entirely or reduced to a dump of raw commit messages nobody wants to read. Conventional Commits and squash-merge PR titles already contain most of the structure needed to group changes; the missing piece is turning that structure into prose a user would actually want to read, and doing it in the two minutes between "tests pass" and "cut the release." Every team already has the git history; the LLM step is what makes machine-readable diffs read like a changelog a person wrote.

Stack sketch

  • Language: Go, distributed as a single static binary via go install and Homebrew tap — release tooling needs to be a fast, dependency-free CLI, not a script requiring a Python venv.
  • Git access: shell out to git log, git tag, git diff rather than a git library, to stay compatible with whatever git version is already installed.
  • PR metadata: GitHub REST API (gh api under the hood, or direct calls with a personal token) to pull PR titles, labels, and descriptions for merge commits, since raw commit messages often lose context that lived in the PR body.
  • Categorization: first pass via Conventional Commit prefixes (feat:, fix:, chore:) and PR labels; anything uncategorized gets bucketed and sent to an LLM (Claude API) with the diff stat and PR body to classify and write a one-line summary.
  • Output: Markdown to stdout by default, with flags to write directly to CHANGELOG.md (prepending the new section) or open a pre-filled GitHub Release draft via API.
  • Config: a single .relnotes.yml for category labels, ignored authors (bots), and a style guide snippet fed into the LLM prompt so tone stays consistent release over release.

Scope for v1

  • relnotes draft <tag> — generate changelog + release notes between two refs, print to stdout.
  • Conventional Commit parsing plus a fallback LLM categorization pass for unlabeled commits.
  • GitHub PR title/label enrichment for squash-merged repos.
  • --write flag to prepend into CHANGELOG.md with correct heading format.
  • Support for exactly one LLM provider (Claude) to start — no provider abstraction layer yet.
  • Out of scope for v1: GitLab/Bitbucket support, multi-repo/monorepo package-scoped changelogs, and a hosted web dashboard.

Where it could go

The natural next step is monorepo awareness — scoping changelogs to a specific package path (packages/api/**) so a Turborepo or Nx workspace can generate per-package release notes instead of one undifferentiated wall of text. After that, a "release notes as a service" mode makes sense: a GitHub Action that runs relnotes draft on every tag push and opens a PR against a docs repo with the drafted post, so writing release notes becomes a review step instead of a writing step.

Further out, feeding the categorized diff into a second pass that flags likely breaking changes by scanning for removed public function signatures or changed API response shapes would turn this from a summarizer into an actual safety net for semver bumps.

Watch out for

The biggest failure mode is teams with messy commit hygiene — no Conventional Commits, no PR descriptions, squash merges that collapse ten commits into "fix stuff" — where the LLM has nothing good to categorize from and the output is only as useful as the input discipline. Set expectations that this drafts a changelog, it doesn't launder a bad git history into a good one.