Changelog Automation with Claude Code

Draft changelog entries on every release tag with Claude Code, the SeggWat MCP server and an open agent skill.

Overview

Push a release tag, and a GitHub Action runs Claude Code, reads the commits since the previous tag, and leaves one draft changelog entry per user-facing change in SeggWat. You review the drafts in the dashboard and publish them.

SeggWat has no built-in "AI changelog" button. The work is done by Claude Code over the SeggWat MCP server, following an agent skill: a Markdown file named seggwat-changelog that tells Claude which commits to keep, how to write for customers, and which SeggWat tools to call. You can read and edit it.

What that means for you:

  • No inference cost on our side. The model runs on your Claude account or API key.
  • Your data goes to your own model provider, not to one we picked.
  • You keep the publish button. The run is set up to create drafts only; publishing is your click.

Prerequisites

  • A SeggWat project, and admin or owner access to its organization
  • Claude Code installed locally, to test the skill before putting it in CI
  • Two credentials, which are easy to mix up:
    • A SeggWat Organization Access Token (oat_...) so Claude can write to your changelog. Create it under Dashboard → Settings → API Tokens → Create New Token and copy it right away; it is shown once.
    • An Anthropic credential so Claude Code can run in CI: an API key from the Claude Console (pay per token), or a token from claude setup-token to bill a Claude subscription.

Install the Skill

The skill lives in the public repo SeggWat/cli-seggwat. Run this in your project:

bash
npx skills add SeggWat/cli-seggwat --skill seggwat-changelog

If the installer asks, choose Claude Code, project scope and symlink. It puts the skill in .agents/skills/seggwat-changelog/ and symlinks it from .claude/skills/seggwat-changelog, so Claude Code and other agents share one copy. Check that the file is there:

bash
ls .claude/skills/seggwat-changelog/SKILL.md

Headless Claude Code in CI reads the skill from the checked-out repo, so commit both paths plus skills-lock.json before you tag.

The skill is plain Markdown. Change the rules to fit your team, for example which commit types to drop.

Connect Claude Code

No API key needed:

bash
claude mcp add --transport http seggwat https://seggwat.com/mcp

Run /mcp in Claude Code and sign in to SeggWat. Then try the skill on your last release:

Use the seggwat-changelog skill to draft changelog entries for tag v1.4.0 in SeggWat project "Acme Web"

Claude lists the drafts it created. Delete them in the dashboard afterwards if you only wanted a test.

See the MCP guide for other clients and connector details.

Draft the Changelog on Release Tags

1

Add repository secrets

In your GitHub repository, go to Settings → Secrets and variables → Actions and add:

  • SEGGWAT_API_KEY: your oat_... Organization Access Token
  • ANTHROPIC_API_KEY: your Anthropic API key

To bill a Claude subscription instead, run claude setup-token locally, store the result as CLAUDE_CODE_OAUTH_TOKEN, and replace the ANTHROPIC_API_KEY line in the workflow with:

yaml
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
2

Add the workflow

Save as .github/workflows/changelog-draft.yml and replace Acme Web with your project name:

yaml
# .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; }
3

Commit, then tag

The tag has to point at a commit that already contains the workflow and the skill:

bash
git add .github/workflows/changelog-draft.yml .agents/skills .claude/skills skills-lock.json
git commit -m "ci: draft changelog on release tags"
git push
git tag v1.4.0 && git push origin v1.4.0

Open Actions → Changelog draft on GitHub to watch the run. It takes about a minute.

What the run does:

  • Reads the commits between the previous v* tag and this one, and drops chore, ci, docs, test and refactor commits that users don't notice. On a first release with no earlier tag, it uses the whole history up to the tag.
  • Checks list_changelog first. If some entries for this version already exist, from an earlier run or a GitHub release sync, it updates the matching drafts and creates only what is missing, so a rerun after a partial failure completes the release. It never changes published entries.
  • Creates one draft per user-facing change, all sharing the tag as version (vX.Y.Z), written for customers: no commit hashes, no PR numbers.

The allowlist. set_changelog_status and update_feedback are deliberately not on --allowedTools, so the run can't flip an entry to published or resolve feedback, which would email the submitter. create_changelog_entry does accept a publish flag; the skill never sets it, and the prompt repeats "drafts only". Review the drafts before publishing either way.

The gate. A headless run that can't reach the SeggWat tools says so politely and exits 0, so the job would go green with nothing drafted. The last jq step checks that Claude called at least one mcp__seggwat__ tool and fails the run if it didn't. It proves the run attempted a SeggWat call, not that every call succeeded or that the drafts are good. Read the run's last message either way.

Review and Publish Drafts

Open Dashboard → your project → Changelog. The page opens on the Draft bucket. Edit any entry, then click Publish. Publish all publishes every draft in the project, including older ones, so check the list first. See Public Changelog for categories, components and release blocks.

Troubleshooting

The gate fired

The log shows Claude never called a SeggWat MCP tool. Check, in order:

  1. SEGGWAT_API_KEY exists under exactly that name and starts with oat_. An empty secret sends Bearer with no token, and Claude gets no SeggWat tools.
  2. The Anthropic credential is set (ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN). Without it, Claude Code stops before calling anything.
  3. The project name in the prompt matches a project in your organization.
  4. The MCP debug log, below.

Connected, but no tools

Claude reports that the SeggWat tools aren't available even though the server answers. "Connected" doesn't mean the tools loaded. Add two flags to the claude -p line in the workflow:

bash
--debug='mcp' --debug-file "$RUNNER_TEMP/mcp.log" \

and a step after it that prints the log even when the gate has failed the run:

yaml
- name: Show MCP debug log
        if: always()
        run: grep "Failed to fetch tools" "$RUNNER_TEMP/mcp.log" || true

A match means the client rejected the server's tool list. Claude Code 2.1.x did this with SeggWat before v1.9.8, which fixed it on our side. If you still see it, send us the log line.

No drafts, but the run passed

Claude reached SeggWat but no drafts appeared. Either every commit in the range was internal (chore, ci, ...), entries for that version already existed, or a SeggWat call failed after the first one went through (the gate only checks that a call was attempted). The run's last message says which; it is printed at the end of the step log.

Next Steps

Navigation