Tickd.ai
← The Tickd Guide

Tutorials & Guides

How to Build an Automated Changelog Generator from Git Diffs Using Claude 3.5 Sonnet and Bun

Tired of writing sloppy release notes? Use Claude 3.5 Sonnet's precise reasoning capabilities alongside Bun's lightning-fast shell runtime to generate structured, human-readable changelogs from raw git diffs.

Updated 10/14/2026

The Problem with Git Commits as Changelog Entries

We have all been there. You are ready to release a new version of your software, but your git history is a graveyard of "fix typo," "adjust styling," "debug test again," and "please work." Turning those raw commits into an elegant, human-readable CHANGELOG.md that your stakeholders, product managers, and users can actually understand is a painful manual chore.

While simpler models can handle basic text summaries, writing a proper changelog requires deep reasoning. You need an engine that can look at actual code differences (the raw git diff) and infer the functional impact of your changes without hallucinating features.

Claude 3.5 Sonnet is arguably the best model on the market for this type of precise, analytical code review. By pairing it with Bun—the blazing-fast JavaScript runtime that features a built-in shell execution engine—we can build a command-line changelog generator that takes a git diff of your workspace, groups changes by impact, and writes structured Markdown ready for production.

Prerequisites

Before diving in, make sure you have the following installed on your local development machine: Bun*: If you don’t have it yet, install it via curl -fsSL https://bun.sh/install | bash. Anthropic API Key*: Set up an account and grab your API key from the Anthropic console.

For deep dives into the Claude family and how it handles high-throughput token pipelines, check out our platform hub at /platforms/claude.

Step 1: Initialize Your Bun Utility

Bun handles TypeScript natively out of the box with zero configuration files, making it the perfect runtime for quick CLI scripts. Create a directory and install the official Anthropic SDK:

`bash mkdir bun-changelog-generator cd bun-changelog-generator bun init -y bun add @anthropic-ai/sdk `

Create a .env file in the root directory to store your credentials:

`env ANTHROPIC_API_KEY=your_anthropic_api_key_here `

Step 2: Grabbing the Git Diff via Bun's Shell

We need to extract the raw changes from our codebase. Bun provides a highly optimized, native shell runner called $ that makes running system commands painless and safe from injection attacks. Learn more about concepts like secure environment runtimes in our developer terminology resource at /glossary.

Create a file named generator.ts and add the code to grab git changes compared to your main development branch (typically main or master):

`typescript import { $ } from 'bun';

async function getGitDiff(targetBranch = 'main'): Promise<string> { try { // Ensure we are inside a git repo and retrieve the diff const diffOutput = await $git diff ${targetBranch}...HEAD.text(); return diffOutput.trim(); } catch (error) { console.error('Error fetching git diff. Is this a git repository?'); process.exit(1); } } `

Using the triple dot ... syntax ensures we are comparing the common ancestor of your current branch and the target branch, focusing purely on the changes introduced in your feature branch.

Step 3: Architecting the Prompt for Claude 3.5 Sonnet

Because git diffs can contain hundreds of lines of code modifications, our prompt must instruct Claude to ignore boilerplate modifications (like library lockfile adjustments) and concentrate strictly on core business logic changes. We will also enforce a strict Markdown output structure.

Add this integration step using the official Anthropic SDK to generator.ts:

`typescript import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY, });

async function generateChangelog(diff: string): Promise<string> { if (!diff) { return 'No changes detected between the current workspace and the target branch.'; }

// Diffs can get very large, so we slice them to stay within safe token budgets if needed const safeDiff = diff.length > 100000 ? diff.slice(0, 100000) + '\n\n[Diff truncated...]' : diff;

const systemPrompt = ` You are an expert technical writer and principal software engineer. Your job is to read a raw git diff and generate a clean, production-ready CHANGELOG in Markdown. Adhere strictly to these grouping rules: - Features: New user-facing capabilities. - Fixes: Bug resolutions and stability improvements. - Performance: Enhancements making the application faster. - Chores: Refactors, dependency updates, and test updates. Do not list individual commit hashes. Group changes logically based on the modified files and your analysis of the code. Be concise. If a change is minor (like updating a comment), ignore it. `;

try { const response = await anthropic.messages.create({ model: 'claude-3-5-sonnet-20241022', max_tokens: 1500, temperature: 0.1, // Low temperature for high precision and analytical consistency system: systemPrompt, messages: [ { role: 'user', content: Analyze this git diff and write the changelog:\n\n${safeDiff} } ], });

// Claude returns content blocks; extract the text content const textBlock = response.content.find(block => block.type === 'text'); return textBlock ? textBlock.text : 'Failed to generate changelog content.'; } catch (error) { console.error('Error calling Anthropic API:', error); process.exit(1); } } `

Step 4: Writing and Executing the Script

To round off our script, we will pull everything together, execute the tasks sequentially, and output the generated changelog directly to a local Markdown file.

Append the following execution code to generator.ts:

`typescript async function run() { const targetBranch = process.argv[2] || 'main'; console.log(Comparing current branch against: "${targetBranch}"...);

const diff = await getGitDiff(targetBranch); if (!diff) { console.log('Your local branch is completely in sync with the target branch. Nothing to do!'); return; }

console.log('Sending diff to Claude 3.5 Sonnet for analysis...'); const changelog = await generateChangelog(diff);

const fileName = 'UNRELEASED_CHANGES.md'; await Bun.write(fileName, changelog); console.log(\nSuccess! Your changelog has been compiled and saved to ${fileName}.); console.log('----------------------------------------------------\n'); console.log(changelog); }

run(); `

Running Your Generator

You can call this utility instantly using Bun's runner. To check your workspace's divergence from your local target branch, just run:

`bash bun run generator.ts main `

If you run into any rate limits or connection errors when handling massive repositories with heavy dependency file diffs, visit our troubleshooting guides at /platforms/claude/articles to learn how to parse down file targets using native Git excludes.

claudebuntypescriptgitautomation

Keep going

Build something with the prompt generator, decode the jargon in the glossary, or compare the tools on our platform deep-dives.

Which AI should I use for this?

Tickd is independent and not affiliated with any AI company.