seggwat-changelog
Draft and publish SeggWat changelog entries from git history using the SeggWat MCP server. Trigger this skill whenever the user wants to write, draft, generate, or publish a changelog, release notes, or a "What's new" post from recent commits, merged PRs, or a release tag, keep the SeggWat changelog up to date, turn a release into customer-facing notes, close the loop on feedback that a release fixed, or wire changelog drafting into a release pipeline (GitHub Actions on tag push, headless `claude -p`). Also trigger on "what shipped since the last release", "write release notes for v1.4.0", or "update our public changelog". Covers picking the commit range, grouping Conventional Commits, writing customer-facing prose, creating draft entries, the explicit publish gate, duplicate checks, and resolving linked feedback.
npx skills add SeggWat/skills --skill seggwat-changelogTurn a release (a tag or a commit range) into customer-facing entries on the project's public SeggWat changelog. Entries always land as drafts. They're published only after the user explicitly says so.
Changelog tools exist only on the MCP server. The seggwat CLI has no changelog commands. Git and gh supply the input.
Connect
# OAuth: no token needed, run /mcp in Claude Code afterwards to sign in
claude mcp add --transport http seggwat https://seggwat.com/mcp
# Or a static Organization Access Token (headless, CI)
claude mcp add --transport http seggwat https://seggwat.com/mcp \
--header "Authorization: Bearer $SEGGWAT_API_KEY"The entry model
| Field | Notes |
|---|---|
title |
Required. Short headline: "Export to Excel", not a commit subject |
body |
Markdown, rendered on the public board |
version |
Semver with a v prefix, taken from the release tag (v1.4.0). Pure version only, no date or codename |
category |
One of added, improved, fixed, changed, removed, security |
component |
Optional slug from the project's component registry (cli, react-sdk). An unknown slug errors and lists the valid ones |
status |
draft (default), published, or hidden |
source |
manual for entries you create. github_release and completed_idea drafts can appear on their own |
One release = one entry per user-facing change, all with the same version (and the same component, if the project uses components). The board renders them as one release block, with a category badge on each change. An entry holds only one category, so a single combined entry would lose the badges. If the user wants a single entry anyway, set its category to whichever kind of change dominates the release.
Workflow
1. Resolve the project and check for existing entries
list_changelog returns every status, newest first. If entries already exist for this version (and component), reconcile per change: update the draft that covers a change with update_changelog_entry, create entries only for changes that have none, and never create a second entry for the same change. That way a rerun after a partial failure completes the release instead of duplicating it. Common case: the project syncs GitHub releases, so a github_release draft for the tag already exists; rewrite it to cover the first change. Only touch drafts; a published entry changes only when the user asks.
2. Pick the range
From a tag:
TAG=v1.4.0
PREV=$(git describe --tags --abbrev=0 --match 'v*' "$TAG^" 2>/dev/null) # empty on the first release
git log --no-merges --format='%h %s%n%b' "${PREV:+$PREV..}$TAG"--match keeps tags of other products in a monorepo from shortening the range. For component-prefixed tags such as cli-v1.4.0, use --match 'cli-v*' and set version to the part after the prefix (v1.4.0).
No tag yet: start from the newest published entry's published_at in list_changelog:
git log --no-merges --since="2026-09-12" --format='%h %s%n%b'
gh pr list --state merged --search "merged:>2026-09-12" --json number,title,body --limit 100Then propose the next semver from that entry's version and the changes in range: a ! or BREAKING CHANGE: bumps major, a feat bumps minor, only fix/perf bumps patch. Confirm the number with the user before using it as version.
3. Group by Conventional Commit type
| Commit | Category | Keep? |
|---|---|---|
feat (new capability) |
added |
yes |
feat (better existing capability), perf |
improved |
yes |
fix |
fixed |
yes |
! or a BREAKING CHANGE: footer |
changed, or removed if something went away |
always |
| security fix | security |
always |
chore, ci, docs, test, build, refactor, style |
— | drop, unless users notice the change |
Merge commits that describe one user-visible change into a single entry. Drop anything internal-only.
4. Write for customers
- Say what changed for the user, and where to find it, in the present tense: "You can now export feedback as an Excel file from the Export menu."
- Don't include commit hashes, PR numbers, ticket ids, internal module names, or author names.
- Breaking changes say exactly what the user has to do.
- 1 to 3 sentences per entry. Bullets only when a change has several parts.
5. Create as drafts
Use one call per change. Never pass publish: true.
Then show the user the full draft set as Markdown, grouped by category, with each entry's id.
6. Edit, then publish only on an explicit yes
Edits:
Only the fields you pass change. Pass "" to clear version, category, or component.
Publish only after the user says to publish (for example "publish it" or "ship the v1.4.0 notes"). Approving the wording isn't approval to publish:
Call it once per entry. draft unpublishes, and hidden soft-hides without deleting.
7. Optional: close the loop on feedback
Find feedback the release addressed:
git log --format='%h %s%n%b' "$PREV..$TAG" | grep -iE 'feedback[: #]*[0-9a-f]{24}'Matching by keyword gives you candidates only. List them for the user, and don't act on them yourself.
Resolving emails the submitter, and the note goes into that email. So do it only after the entries are published and the user confirms the list:
Write the note for the end user. Don't paste an internal id or a link you haven't verified. MCP returns no public changelog URL, so "see our changelog" is enough.
Rules
- Always draft first. Never use
publish: true, and never callset_changelog_statuswithpublishedwithout an explicit instruction. - Check before creating. Before writing anything, read
list_changelog. Existing entries for the version are reconciled per change: update the matching draft, create only what is missing, never duplicate. Only update drafts; a published entry changes only when the user asks for it. - One release block per version. Every entry for a release shares
version(andcomponent). - Customer prose only. Commit messages are input, not output.
- Resolve feedback only after publishing, and only with confirmation. It sends email.
- Never delete changelog entries or feedback. Use
hiddenfor entries.
Automate on release tags
This runs on every v* tag and leaves drafts for a human to publish. Install the skill into the repo (npx skills add SeggWat/cli-seggwat --skill seggwat-changelog lands it in .agents/skills/ with a .claude/skills/ symlink) and commit it so headless Claude Code finds it. Add the SEGGWAT_API_KEY repository secret plus ANTHROPIC_API_KEY, or CLAUDE_CODE_OAUTH_TOKEN from claude setup-token to bill a Claude subscription instead.
# .github/workflows/changelog-draft.yml
name: Changelog draft
on:
push:
tags: ['v*']
permissions:
contents: read
jobs:
draft:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history and tags for git describe/log
- name: Install Claude Code
run: |
curl -fsSL https://claude.ai/install.sh | bash
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
- name: Draft SeggWat changelog
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
SEGGWAT_API_KEY: ${{ secrets.SEGGWAT_API_KEY }}
TAG: ${{ github.ref_name }}
run: |
set -o pipefail
cat > "$RUNNER_TEMP/mcp.json" <<EOF
{"mcpServers":{"seggwat":{"type":"http","url":"https://seggwat.com/mcp",
"headers":{"Authorization":"Bearer ${SEGGWAT_API_KEY}"}}}}
EOF
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" \
| tee "$RUNNER_TEMP/out.jsonl" | jq -r 'select(.type=="result") | .result'
# Fail the run if Claude never reached the SeggWat MCP server.
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; }set_changelog_status and update_feedback are left off the allow list, so CI can't flip an entry to published or send email even if asked. create_changelog_entry still accepts publish: true; this skill never sets it, and the prompt says drafts only. A human reviews the drafts in the dashboard, or asks Claude to "publish the v1.4.0 notes".
The last jq is the safety net: a headless run prints a polite "the tools aren't available" message and exits 0 when the MCP server is unreachable or returns no tools, so without it the job goes green with nothing drafted. If the gate fires, rerun with --debug='mcp' --debug-file "$RUNNER_TEMP/mcp.log" and look for Failed to fetch tools.
Worked example
Input: git log --no-merges --format='%h %s' v1.3.2..v1.4.0
list_changelog shows no entry with version: "v1.4.0". The chore and ci commits are dropped.
Drafts created (4 calls to create_changelog_entry, all version: "v1.4.0"):
## v1.4.0 (draft)
**Added** · Export to Excel
You can now export feedback as an `.xlsx` file from the **Export** menu, next to CSV.
**Fixed** · Large image uploads
Uploading PNG screenshots larger than 5 MB no longer fails.
**Improved** · Faster dashboard
Project dashboards load noticeably faster, especially for projects with a lot of feedback.
**Removed** · Legacy v0 API
The v0 API endpoints are gone. If you still call `/api/v0/...`, switch to the
equivalent `/api/v1/...` endpoint. Request and response shapes are unchanged.Next, ask: "4 drafts created for v1.4.0. Publish them? Commit d4e5f6a references feedback 66f1c0a2e4b0c9d1a2b3c4d5 (Active). After publishing, should I resolve it with the note 'Fixed in v1.4.0: large PNG uploads no longer fail'? That emails the submitter."
Hit a problem with SeggWat itself?
category is one of bug, docs_mismatch, friction, feature_gap, quality_degradation, other. File one report per problem and keep going.
