← Blog

How to Build a Claude-Powered Changelog Generator

2026-11-02 · 5 min read · SubToAPI Team

Building a Claude-powered changelog generator means feeding raw commit messages, pull request titles, or diffs into Claude and having it return structured, human-readable release notes — categorized by feature, fix, and breaking change, written in a consistent tone, every time you ship.

The core workflow is simple: pull the git log or merged PRs since the last release, send that text to Claude with a prompt that defines your changelog format, and save the output to CHANGELOG.md or post it to Slack/your release page. The rest of this guide walks through exactly how to wire that up, including the API setup, prompt design, and automation in CI.

Why generate changelogs with Claude instead of templates

Most teams either write changelogs by hand (slow, inconsistent) or use commit-message conventions like Conventional Commits with a templating tool (rigid, requires discipline from every contributor). Claude sits in between: it can read messy, inconsistent commit history — including commits that don't follow any convention — and still produce clean, categorized output because it understands intent, not just syntax.

This matters especially for teams with:

Step 1: Collect the raw input

Start with git log output or merged PR data. A simple git-based approach:

git log v1.2.0..HEAD --pretty=format:"%s (%an)" > commits.txt

If you use GitHub, pulling merged PR titles and descriptions via the GitHub API usually gives richer, better-structured input than raw commits — PR descriptions often already explain the "why," which Claude can use to write better summaries.

Step 2: Design the prompt

The quality of your changelog depends almost entirely on prompt structure. Be explicit about format, tone, and categorization rules. Don't just say "summarize these commits" — give Claude a template to fill in.

You are generating a changelog for a developer tool.
Group the following commits into these sections: Features, Fixes, Breaking Changes, Internal.
Ignore commits that are purely internal (CI config, formatting, test-only changes) unless they affect users.
Write each bullet in plain English, no more than one sentence, starting with a verb.
Output valid Markdown with ## headings for each section.

Commits:
{{commits}}

Pin the output format in the prompt rather than hoping Claude infers it — this is what makes the output usable in automated pipelines instead of needing manual cleanup every time.

Step 3: Call the API

Here's a minimal example using SubToAPI's Claude endpoint, which gives you a standard HTTPS API with an sub_live_... key instead of managing Claude access directly:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "Generate a changelog from these commits:\n\nfix: null pointer on checkout\nfeat: add dark mode toggle\nchore: bump deps"
      }
    ]
  }'

In Node.js, wiring this into a release script looks like:

import fs from "fs";

const commits = fs.readFileSync("commits.txt", "utf8");

const res = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "claude-sonnet-4",
    max_tokens: 1024,
    messages: [
      {
        role: "user",
        content: `Generate a changelog from these commits, grouped into Features, Fixes, Breaking Changes:\n\n${commits}`,
      },
    ],
  }),
});

const data = await res.json();
const changelog = data.content[0].text;

fs.appendFileSync("CHANGELOG.md", `\n## ${new Date().toISOString().slice(0,10)}\n${changelog}\n`);

If you haven't set up API access yet, check the quickstart guide for key creation and your first request, or the messages docs for full request/response structure.

Step 4: Automate it in CI

Once the script works locally, drop it into a GitHub Actions workflow that runs on release tags:

name: Generate Changelog
on:
  push:
    tags:
      - "v*"
jobs:
  changelog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Get commits since last tag
        run: git log $(git describe --tags --abbrev=0 HEAD^)..HEAD --pretty=format:"%s" > commits.txt
      - name: Generate changelog
        run: node generate-changelog.js
        env:
          SUBTOAPI_KEY: ${{ secrets.SUBTOAPI_KEY }}
      - name: Commit changelog
        run: |
          git config user.name "release-bot"
          git config user.email "bot@yourdomain.com"
          git add CHANGELOG.md
          git commit -m "docs: update changelog for $GITHUB_REF_NAME"
          git push

This gives you a changelog that updates itself on every tagged release with no manual writing step.

Step 5: Handle streaming for long release notes

If a release spans hundreds of commits, the generated changelog can get long. Rather than waiting on a single blocking response, you can stream the output and render it incrementally — useful if you're building this into a dashboard or release UI rather than a CI script. See the streaming docs for implementation details.

Tips for better output quality

Where this fits for teams

If your release process spans multiple repos or several engineers are triggering releases, running this through a shared API key with usage visibility is worth setting up early rather than retrofitting later. SubToAPI's Team plan gives every engineer their own sub_live_... key under one billing account, so you can see exactly which service or person is generating changelog calls without sharing a single raw API key across the team.

questions

Do I need a Claude account to use this setup, or can I go straight through an API? You need access to Claude's models either directly or through a service like SubToAPI, which turns your existing Claude access into a standard HTTPS API with API keys, so you can call it from CI without managing provider-specific auth.

Will Claude's changelog output always follow my exact format? Mostly, if the prompt is explicit about headings, bullet style, and categorization rules. For strict formatting, validate the output (e.g., check for expected ## headings) before writing it to a file, and retry with a stricter prompt if validation fails.

Can this handle multiple repositories in one changelog? Yes — collect commits or merged PRs from each repo, label them by repo name in the input, and ask Claude to group the final output both by repo and by category in the same prompt.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →