DEV Community

Cover image for Nobody Reads My Release Notes. So I Stopped Writing Them Myself
PADMANABHA DAS
PADMANABHA DAS

Posted on

Nobody Reads My Release Notes. So I Stopped Writing Them Myself

When was the last time you actually read release notes?

I mean, really read them — not just skimmed for "breaking changes" before hitting update.

Probably never. And honestly? That's partly my fault. Because for years, my release notes looked like this: "Various bug fixes and performance improvements", which tells you absolutely nothing.

The Problem With "I'll Write It Later"

Here's what actually happens when you promise yourself you'll write proper release notes:

  1. You finish the release
  2. You tell yourself you'll document it tomorrow
  3. Tomorrow you start the next feature
  4. Two weeks later, someone asks, "what changed in v1.2.0?"
  5. You open the commit history and cry

The information exists. Every commit message, every PR description, every file change — it's all there in Git. The problem isn't missing data. It's that turning raw commits into readable release notes requires context switching from "building things" to "documenting things."

And after a long sprint, that switch is brutal.

What If I Just... Didn't?

I built a GitHub MCP server with 44+ tools. One day, I realized: Claude can read my commit history. It can see what files changed. It knows which PRs got merged.

Why am I manually doing what an AI can do in 30 seconds?

So now, when I'm ready to tag a release, I just ask Claude:

"List all commits on master since the last release tag. Analyze the changes and generate release notes."

And it works!

The Actual Workflow

Let me show you what this looks like with my GitHub MCP server (v1.3.0 release).

Step 1: Find the Last Release

First, I need to know where I'm starting from:

// Tool: list-releases
{
  owner: "chayan-1906",
  repository: "GitHub-MCP",
  perPage: 1,
  currentPage: 1
}
Enter fullscreen mode Exit fullscreen mode

This gives me:

{
  "tagName": "v1.2.0",
  "name": "v1.2.0",
  "publishedAt": "2025-09-14T...",
  "body": "..."
}
Enter fullscreen mode Exit fullscreen mode

Now I know: everything after v1.2.0 needs to be in my release notes.

Step 2: Get Commits Since That Release

// Tool: list-commits
{
  owner: "chayan-1906",
  repository: "GitHub-MCP",
  sha: "master",
  perPage: 50
}
Enter fullscreen mode Exit fullscreen mode

Claude gets back a list of commits with messages, authors, and timestamps. It filters to only commits after the v1.2.0 release date.

Step 3: Understand What Actually Changed

This is where it gets interesting. For commits with vague messages (we've all written "fix bug" at 2 AM), Claude digs deeper:

// Tool: get-commit-modifications
{
  owner: "chayan-1906",
  repository: "GitHub-MCP",
  commitSha: "abc123..."
}
Enter fullscreen mode Exit fullscreen mode

This returns the actual file changes:

[
  {
    "filename": "src/routes/SystemRoutes.ts",
    "status": "added",
    "additions": 45,
    "deletions": 0
  },
  {
    "filename": "src/routes/AuthRoutes.ts",
    "status": "modified",
    "additions": 12,
    "deletions": 8
  }
]
Enter fullscreen mode Exit fullscreen mode

Even if my commit message was useless, Claude can see that I added a new routing file and modified auth routes. That's enough context to understand what happened.

Step 4: Generate the Release Notes

After analyzing 15-20 commits, Claude synthesizes everything:

## v1.3.0 (2025-09-17)

### 🔄 Changes

- **Routing System**: Separated system and authentication routes
  - Created dedicated `SystemRoutes.ts` for homepage functionality
  - Moved authentication endpoints to `/auth` prefix

- **Error Handling**: Improved error reporting across GitHub tool integrations

- **Type Safety**: Added `ToolsMap` interface for better TypeScript definitions

### 📦 Dependencies

- axios: `^1.11.0``^1.12.2`
- mongodb: `^6.18.0``^6.19.0`
- typescript: `^5.8.3``^5.9.2`

### 🧹 Code Quality

- Removed legacy `toolHelpers.ts` in favor of `mcp-utils` package
- Centralized tool definitions with dynamic parameter descriptions
Enter fullscreen mode Exit fullscreen mode

That took about 45 seconds. Writing it manually would've taken 20 minutes of scrolling through commits and trying to remember why I changed that one file.

Step 5: Create the Release

If I'm happy with the notes, Claude can create the release directly:

// Tool: create-release
{
  owner: "chayan-1906",
  repository: "GitHub-MCP",
  tagName: "v1.3.0",
  name: "v1.3.0",
  body: "## v1.3.0 (2025-09-17)\n\n### 🔄 Changes\n...",
  draft: false,
  prerelease: false
}
Enter fullscreen mode Exit fullscreen mode

Done. Release published with proper documentation.

The Tools That Make This Work

Tool Purpose
list-releases Find the last release tag and date
list-commits Get all commits since that release
get-commit-modifications See actual file changes per commit
create-release Publish the release with generated notes
update-release Fix typos without recreating everything

Five tools. That's the entire workflow.

What Claude Actually Does Well Here

Pattern recognition. When Claude sees commits like:

  • refactor: extract routes to dedicated files
  • refactor: move auth endpoints
  • chore: update route imports

It understands these are related and groups them under "Routing System" instead of listing three separate line items.

Dependency tracking. If package.json changed, Claude reads the diff and extracts the actual version bumps. No more "updated dependencies" as a line item.

Categorization. Features vs. fixes vs. refactors vs. chores. Claude applies conventional commit patterns even when my messages weren't perfectly formatted.

The Honest Limitations

This isn't magic. There are gaps:

  1. Breaking changes — Claude can identify API changes in code, but it can't always know if they're breaking. I still review for that.
  2. User-facing impact — "Refactored database queries" doesn't tell users what got faster. I add context for significant performance changes.
  3. Security fixes — I don't put security details in public release notes anyway, but Claude doesn't know what to redact. Manual review required.
  4. First release — No previous tag to compare against. You'll need to specify a date range or commit range manually.

My Actual Prompt

Here's what I usually ask:

"Using my GitHub MCP tools, list all releases for [repo_url]. Then list commits on the master branch since the most recent release. For any commits that touch more than 3 files, get the file modifications. Finally, generate release notes grouped by: features, fixes, refactors, dependencies, and breaking changes (if any). Use emoji headers”

Claude handles the multi-step orchestration. I just review the output and hit publish.

Why This Actually Matters

Good release notes aren't just documentation theater. They're:

  • For your users: So they know if they should upgrade
  • For your future self: So you remember what v1.2.0 even was
  • For contributors: So they see their work acknowledged

I wasn't writing bad release notes because I didn't value them. I was writing bad release notes because the manual process was painful enough that I avoided it.

Automating the painful part means I actually ship proper documentation now.

Setting It Up

The GitHub MCP server is open source:

Repository: github.com/chayan-1906/GitHub-MCP

Download the executable, run it once, and Claude Desktop will recognize the tools automatically. Full setup takes about 2 minutes.


My release notes still aren't perfect. But they're a lot better than "bug fixes and improvements."

And honestly? That's enough.


Building AI tools for developer workflows. Find me on LinkedIn or check out my other projects on GitHub.

Top comments (0)