Every time I merged a PR I had to write a changelog entry manually. It took two minutes but I kept forgetting to do it. So I automated it with Claude.
When a PR merges to main, a GitHub Actions workflow reads the PR title, description, and changed files, sends them to the Claude API, and gets back a structured changelog entry. That entry gets committed to CHANGELOG.md automatically. The whole thing runs in about 10 seconds.
What MCP has to do with this
Nothing, directly. But this pipeline lives inside my MCP Kubernetes Manager project, which already lets Claude manage Kubernetes clusters through natural language. Adding AI-generated release notes felt like a natural fit. The project now manages its own changelog the same way it manages deployments.
If you want context on the MCP server itself, I wrote about it here: https://dev.to/aftabkh4n/i-built-an-mcp-server-in-net-that-lets-claude-manage-my-kubernetes-cluster-through-natural-language-3cji
How the pipeline works
A GitHub Actions workflow triggers on pull_request with type closed. The first thing it checks is whether the PR was actually merged, not just closed:
if: github.event.pull_request.merged == true
That condition is important. Without it the workflow runs on every closed PR including ones that were rejected.
Then it collects the PR metadata:
env:
PR_TITLE: ${{ github.event.pull_request.title }}
PR_BODY: ${{ github.event.pull_request.body }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
PR_MERGED_AT: ${{ github.event.pull_request.merged_at }}
And gets the list of changed files from git:
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD | head -20 | tr '\n' ', ')
Calling the Claude API
The API call is a standard POST to the Anthropic messages endpoint. The key part is building the payload with jq so special characters in PR titles and descriptions do not break the JSON:
PAYLOAD=$(jq -n \
--arg model "claude-haiku-4-5-20251001" \
--arg pr_num "$PR_NUMBER" \
--arg pr_title "$PR_TITLE" \
--arg pr_body "$PR_BODY_SAFE" \
--arg files "$CHANGED_FILES" \
'{
model: $model,
max_tokens: 1024,
messages: [{
role: "user",
content: ("Generate a changelog entry for PR #" + $pr_num + ": " + $pr_title)
}]
}')
RESPONSE=$(curl -s https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d "$PAYLOAD")
ENTRY=$(echo "$RESPONSE" | jq -r '.content[0].text')
The model is claude-haiku-4-5-20251001 which is the fastest and cheapest Claude model. For a changelog entry it produces the same quality as larger models at a fraction of the cost.
The API key is stored as a GitHub Actions secret called ANTHROPIC_API_KEY. Never hardcode it.
Writing the changelog entry back
Once Claude returns the entry, the workflow prepends it to CHANGELOG.md so the newest entry is always at the top:
TEMP=$(mktemp)
head -4 CHANGELOG.md > "$TEMP"
echo "$ENTRY" >> "$TEMP"
tail -n +5 CHANGELOG.md >> "$TEMP"
mv "$TEMP" CHANGELOG.md
Then commits and pushes as github-actions[bot]:
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git pull --rebase origin main
git add CHANGELOG.md
git commit -m "docs: AI-generated changelog for PR #${{ github.event.pull_request.number }}"
git push
The git pull --rebase before the push is important. The PR merge itself updates main, so without pulling first the push gets rejected.
What the output looks like
After merging a PR that adds Kubernetes tools documentation, Claude wrote this:
## [PR #5] docs: add tools list to README
*2026-04-16T05:13:52Z by @aftabkh4n*
### Changes
- Added documentation describing the AI-powered changelog automation workflow
- Documented how Claude generates structured changelog entries automatically when PRs merge to main
- Explained the process of reading PR metadata to produce changelog entries
### Files changed
- README.md
It reads the PR description and infers what actually changed. The better your PR description, the better the changelog entry.
What it costs
The Anthropic API is not free but it is very cheap for this use case. Haiku costs $0.80 per million input tokens. A typical PR payload is around 500 tokens. That works out to roughly $0.0004 per changelog entry, less than a cent per merge.
Setting it up in your repo
- Get an API key from console.anthropic.com
- Add it as a secret in your repo: Settings, Secrets and variables, Actions, New repository secret, name it
ANTHROPIC_API_KEY - Create
.github/workflows/release-notes.ymlwith the full workflow
Full source code: https://github.com/aftabkh4n/mcp-kubernetes-manager
What I would add next
A way to skip the changelog for trivial PRs would be useful. Something like checking whether the PR title starts with chore: or wip: and skipping the API call entirely. That keeps the changelog clean without adding friction to the merge process.
Top comments (0)