Claude Code Now Drafts Our Changelog on Every Release Tag
Every SeggWat release tag now runs Claude Code in GitHub Actions and leaves changelog drafts for me to publish. Here's the setup, the bug that made it silently do nothing, and why we didn't build an AI button instead.
When I push a release tag for SeggWat, a GitHub Action starts Claude Code, reads the commits since the last tag, and writes one draft changelog entry per user-facing change. I open the dashboard, read the drafts, fix a word here and there, and click Publish.
This post covers the setup, the bug that had the whole thing quietly doing nothing for its first few runs, and why this lives in an agent skill instead of a button inside SeggWat.
The setup
The work is described in an agent skill called seggwat-changelog. A skill is a Markdown file that tells Claude Code how to do one job: which commits to keep, how to write for customers, which SeggWat tools to call, and what it must never do. It lives in our public CLI repo, so you can install it the same way we do:
npx skills add SeggWat/cli-seggwat --skill seggwat-changelogThat puts it in .agents/skills/seggwat-changelog/ with a symlink from .claude/skills/, so Claude Code and other agents share one copy. Commit both, and headless Claude Code in CI picks it up from there.
The workflow runs on every v* tag. The core of it is one claude -p call with the SeggWat MCP server and a short list of allowed tools:
claude -p "Use the seggwat-changelog skill to draft changelog entries for tag $TAG in SeggWat project \"Acme Web\". Drafts only: do not publish and do not update feedback." \
--mcp-config "$RUNNER_TEMP/mcp.json" \
--output-format stream-json --verbose \
--allowedTools "Bash(git describe:*)" "Bash(git log:*)" "Bash(git tag:*)" \
"mcp__seggwat__list_projects" "mcp__seggwat__list_changelog" \
"mcp__seggwat__create_changelog_entry" "mcp__seggwat__update_changelog_entry"The mcp.json file points at https://seggwat.com/mcp with an Organization Access Token as a Bearer header. The full workflow file is in the Automate with Claude Code guide.
Two tools are missing from that list on purpose: set_changelog_status and update_feedback. Without the first, CI can't flip an entry to published. Without the second, it can't resolve feedback, which would email the people who reported the bug. One honest caveat: create_changelog_entry has a publish flag, and an allowlist can't take a single parameter away from a tool. The skill never sets it and the prompt says drafts only, and that has held in every run so far. Publishing stays a human click, and I still read every draft before I press it.
What a draft looks like
The skill drops chore, ci, docs, test and refactor commits, because users don't see them. It writes in customer language, leaves out commit hashes and PR numbers, and gives every entry from one release the same vX.Y.Z version so they render as one release block. Before writing anything, it calls list_changelog, so a rerun on the same tag doesn't create a second set.
The v1.9.8 release today produced one draft:
That entry is about the bug in the next section, which is a little recursive: the fix for the pipeline was the first thing the pipeline wrote about.
The bug: green runs, zero drafts
The first runs after I set this up all went green. The changelog had nothing new in it.
The log explained why, once I read it. Claude had politely reported that the SeggWat tools weren't available, so it couldn't create entries, and then exited with status 0. From GitHub's point of view, the job did exactly what it was asked.
The cause was on our side. Claude Code 2.1.x validates the server's tools/list response, and ours lacked a ttlMs field. The client rejected the response, so the server showed as connected but exposed zero tools. Nothing in the normal output said "validation failed". It only showed up with MCP debug logging:
claude -p "..." --debug='mcp' --debug-file mcp.log
grep "Failed to fetch tools" mcp.logThe fix was server-side: SeggWat now sends ttlMs and cacheScope with the tool list. That shipped in v1.9.8 today. If you connect Claude Code to SeggWat, you don't need to change anything.
Two lessons I'm keeping:
- "Connected" is not "tools loaded". An MCP client can hold a perfectly healthy connection to a server and still have nothing to call.
- Headless agents fail politely. A person would have noticed that nothing happened. A model in CI explains the problem in a friendly sentence and finishes successfully. If a run matters, put a deterministic check after it.
The gate
So the workflow now ends with a check that doesn't involve a model. Claude Code writes its output as JSON lines, and one jq command looks for at least one call to a tool whose name starts with mcp__seggwat__:
jq -e 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use" and (.name|startswith("mcp__seggwat__")))' \
"$RUNNER_TEMP/out.jsonl" >/dev/null \
|| { echo "::error::Claude never called a SeggWat MCP tool: check the MCP connection and SEGGWAT_API_KEY"; exit 1; }If Claude never touched SeggWat, the job fails and says why. That covers the bug above, an empty SEGGWAT_API_KEY secret, and whatever breaks next in the same way. It doesn't prove the drafts are good. That's still my job when I review them. It only proves the run did something, which was exactly the part I couldn't take for granted.
Why not an AI button in SeggWat
I could have built a "Generate changelog with AI" button into the dashboard. I decided not to, for three reasons.
You already have an agent. If you're the kind of team that wants this, you probably use Claude Code already. It can read your git history, which SeggWat can't. It just needed a way to write to SeggWat (the MCP server) and instructions for this job (the skill).
The cost and the data stay with you. A built-in button means we pay for inference, pass that cost on, and send your commit history to a model provider we picked. With the skill, the model runs on your own Claude account or API key, and your data goes to the provider you already chose. We run zero inference for this.
You can read and change the rules. The skill is a Markdown file in your repo. If you want entries in German, or want perf commits dropped, you edit a line. A button would make those decisions for you.
And the human keeps the publish button either way.
Try it
Install the skill with npx skills add SeggWat/cli-seggwat --skill seggwat-changelog, connect Claude Code with claude mcp add --transport http seggwat https://seggwat.com/mcp, and the guide walks you through the rest. For how drafts, categories and release blocks work on the board itself, see the changelog docs.
The changelog is the end of the feedback loop: shipping things and telling people. The start of the loop is triage, and I'm running that the same way, as a Claude Code loop over the MCP server. That recipe isn't ready to share yet. When it is, it will land in the same repo.
Related Posts
Your API has users you never hear from
Coding agents hit your API, docs and CLI all day and work around what breaks without telling anyone. SeggWat projects can now accept structured reports from those agents, no key required.
Your visitors' AI agents can now draft feedback in the widget
The SeggWat feedback widget now offers a WebMCP tool to AI agents in the visitor's browser. The agent writes the bug report, the visitor reviews it and clicks Send.
Your feedback board is now agent-ready, with WebMCP
WebMCP lets a web page hand tools to the AI agent driving the browser. SeggWat's dashboard and public boards now do exactly that, built on a small open-source Rust crate.
