πŸ“ Tutorials
Β· 3 min read

Build an AI Changelog Generator From Git History


Release day. You need a changelog. You open the git log, stare at 47 commits, and start manually sorting them into β€œFeatures,” β€œBug Fixes,” and β€œBreaking Changes.” This takes 30 minutes every release.

In this tutorial, we’ll build changelog-ai β€” a CLI that reads your git history between two tags and generates a formatted changelog automatically.

What we’re building

$ changelog-ai v1.2.0 v1.3.0

# Changelog β€” v1.3.0 (2026-03-25)

## ✨ New Features
- Add rate limiting to all API endpoints (#142)
- Support dark mode in dashboard (#138)
- Add CSV export for reports (#135)

## πŸ› Bug Fixes
- Fix race condition in WebSocket reconnection (#141)
- Resolve null pointer when user profile is incomplete (#139)
- Fix timezone offset in scheduled reports (#136)

## πŸ”§ Improvements
- Reduce Docker image size from 1.2GB to 340MB (#140)
- Migrate from moment.js to date-fns (#137)

## ⚠️ Breaking Changes
- API response format changed for /api/reports endpoint (#135)
  - `data` field renamed to `results`
  - Pagination now uses cursor instead of offset

## πŸ‘₯ Contributors
@sarah, @jake, @alex

The code

#!/usr/bin/env node
// index.js
import Anthropic from '@anthropic-ai/sdk';
import { execSync } from 'child_process';

const [,, fromTag, toTag] = process.argv;
if (!fromTag || !toTag) {
  console.log('Usage: changelog-ai <from-tag> <to-tag>');
  console.log('Example: changelog-ai v1.2.0 v1.3.0');
  process.exit(1);
}

// Get commits between tags
const log = execSync(
  `git log ${fromTag}..${toTag} --pretty=format:"%h %s (%an)" --no-merges`,
  { encoding: 'utf-8' }
);

if (!log.trim()) {
  console.log(`No commits between ${fromTag} and ${toTag}`);
  process.exit(0);
}

// Get the diff stats for context
const stats = execSync(
  `git diff ${fromTag}..${toTag} --stat`,
  { encoding: 'utf-8' }
);

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const response = await anthropic.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 1500,
  messages: [{
    role: 'user',
    content: `Generate a changelog from these git commits.

From: ${fromTag}
To: ${toTag}
Date: ${new Date().toISOString().split('T')[0]}

Commits:
${log}

File changes:
${stats.slice(0, 3000)}

Format as markdown with these sections:
# Changelog β€” ${toTag} (date)
## ✨ New Features
## πŸ› Bug Fixes  
## πŸ”§ Improvements
## ⚠️ Breaking Changes (if any, otherwise omit)
## πŸ‘₯ Contributors

Rules:
- Group commits by category based on the commit message content
- Include PR/issue numbers if present in commit messages
- For breaking changes, explain what changed and how to migrate
- List unique contributors at the end
- Skip merge commits and version bumps
- Be concise β€” one line per change`
  }],
});

console.log(response.content[0].text);

Setup

mkdir changelog-ai && cd changelog-ai
npm init -y && npm install @anthropic-ai/sdk
chmod +x index.js && npm link

Usage

# Between two tags
changelog-ai v1.2.0 v1.3.0

# Save to file
changelog-ai v1.2.0 v1.3.0 > CHANGELOG.md

# Between a tag and HEAD
changelog-ai v1.2.0 HEAD

Making it better

  • Conventional commits: If your team uses conventional commits (feat:, fix:, chore:), parse them directly instead of using AI for categorization
  • GitHub integration: Fetch PR descriptions for richer context using the GitHub API
  • Append mode: Prepend to existing CHANGELOG.md instead of overwriting
  • CI integration: Run automatically on tag push in GitHub Actions

CI integration (GitHub Actions)

Add this to .github/workflows/changelog.yml to auto-generate on every release:

name: Generate Changelog
on:
  push:
    tags: ['v*']
jobs:
  changelog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npm install -g changelog-ai
      - run: |
          PREV_TAG=$(git describe --tags --abbrev=0 HEAD^)
          changelog-ai $PREV_TAG ${{ github.ref_name }} > RELEASE_NOTES.md
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          body_path: RELEASE_NOTES.md

Now every time you push a tag, a GitHub Release is created with AI-generated release notes.

Total build time: ~15 minutes. API cost: ~$0.01 per changelog.

Related: Git cheat sheet Β· Build a Git Diff Summarizer Β· Best AI Coding Tools 2026

πŸ“˜