Skip to content

chore(release): replace AI release scripts with a Claude Code release skill - #1300

Closed
dangrondahl wants to merge 1 commit into
mainfrom
release-skill
Closed

dangrondahl wants to merge 1 commit into
mainfrom
release-skill

Conversation

@dangrondahl

@dangrondahl dangrondahl commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

💊 Red pill. One of two alternative PRs that remove the shared Anthropic API key from the release flow. Only one should merge; the other is the blue pill, #1299.

The scripted AI step is replaced by a Claude Code skill, .claude/skills/release/. Run /release (or ask Claude to cut a release) and it:

  1. Checks you're on an up-to-date, clean main and finds the last tag.
  2. Classifies every commit since then as user-facing CLI change or not.
  3. Suggests the major/minor/patch bump and checks the tag doesn't exist.
  4. Drafts dist/release_notes.md (same scope and heading rules as the old prompt).
  5. Revises the notes with you until you approve.
  6. Asks once more, then runs make release tag=vX.Y.Z and shows the release workflow run.

make release tag= stays the only path that creates the annotated tag. Also in this PR:

  • Deletes bin/suggest-version-ai.sh, bin/release-interactive.sh and the suggest-version-ai target.
  • make release now requires tag= and points at /release when it's missing.
  • Updates CLAUDE.md and release-guide.md.

Choose this if you're happy for releasing with AI help to require Claude Code. In return, the release notes are drafted in conversation, and Claude can read commit messages and PR titles, not only a diff capped at 50k characters.

Not yet exercised end to end: the skill only runs from main, and its last step pushes a tag. It loads, and make help shows the new target text. A leftover dist/release_notes.md would end up in a hand-run make release tag=; the guide warns about this.

Checklist

  • Docs are autogenerated from CLI help — make sure the help text reflects your changes (n/a: no CLI changes)
  • Helm chart (charts/k8s-reporter/) updated, if needed (n/a)
  • Terraform provider and related changes updated, if needed (n/a)

… skill

The release skill drafts the next semver tag and dist/release_notes.md with
the releaser, then hands off to `make release tag=vX.Y.Z`, which remains the
only path that creates and pushes the annotated tag.

This removes bin/suggest-version-ai.sh, bin/release-interactive.sh and the
suggest-version-ai make target, and with them the shared Anthropic API key
in 1Password: the skill runs under the releaser's own Claude login.
`make release` now requires tag=.
@github-actions github-actions Bot added chore documentation Improvements or additions to documentation labels Oct 24, 2026
@claude

claude Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @dangrondahl's task in 1m 52s —— View job


PR review: replace AI release scripts with a Claude Code release skill

  • Static checks: go build ./... ✅, go vet ./... ✅. No Go code changed, so go mod tidy isn't affected.
  • Read the diff: SKILL.md, Makefile, CLAUDE.md, release-guide.md and the two deleted scripts
  • Inline comments posted

Summary

A clean, well-scoped change. Removing the shared Anthropic key from the release flow is a real security improvement. Keeping make release tag= as the only way to create a tag holds on to the important pipeline rule (annotated tags only, never gh release create). I found no blocking issues. Searching the repo turned up no leftover references to suggest-version-ai, release-interactive or suggested_version.

Suggestions (inline)

  1. The base tag can be a pre-release tag (SKILL.md:19). git describe --tags --abbrev=0 will choose a vX.Y.Z-rcN tag if one is the nearest, and the repo already has several. Adding --match 'v[0-9]*' --exclude '*-*' keeps the base on the last stable release.
  2. Leftover dist/release_notes.md (SKILL.md:52-54). Having the skill delete the file after a successful push fixes the problem the guide currently only warns about. The old script cleaned up after itself in a similar way.
  3. The run report can show the previous release (SKILL.md:54). gh run list --limit 1 straight after a push can return the last release's run. Use --branch <tag>, and retry briefly if it isn't listed yet.
  4. Optional: add disable-model-invocation: true to the frontmatter, since the skill pushes a tag. This conflicts with the "just ask Claude" path, so it's your call.
  5. Nit (Makefile:226): put the tag= usage check before the main branch check, so a bare make release shows the /release hint wherever it's run.

What works well

  • The skill keeps the scope and heading rules from the old prompt, and each step has a clear "Done when" condition.
  • Reading the commit list and each commit's diff, instead of one diff capped at 50k characters, should give better bump decisions on large releases.
  • It asks for confirmation twice before the step that can't be undone (pushing the tag).
  • The Makefile comment explaining --cleanup=verbatim is a useful note on why.
  • release-guide.md gives clear instructions for people releasing without Claude Code, including the leftover-notes warning.

Not verified

As the PR description says, the full skill flow, which ends in a tag push from main, can't be exercised from CI.


**1. Check the starting point.** Run `git fetch origin --tags`. Confirm the current
branch is `main`, it matches `origin/main`, and the working tree has no tracked changes.
Find the base with `git describe --tags --abbrev=0`. If any check fails, stop and tell

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git describe --tags --abbrev=0 returns the nearest tag, and that includes pre-release tags. The repo has some already (v2.0.0-rc3, v2.10.3-rc5, …). Once a v2.49.0-rc1 exists, the base becomes the rc. Step 3's "base + bump" then gives an unclear answer (v2.49.0-rc1 + minor = ?), and the notes leave out everything that shipped before the rc. The old script had the same problem, but this is an easy place to fix it:

Suggested change
Find the base with `git describe --tags --abbrev=0`. If any check fails, stop and tell
Find the base with `git describe --tags --abbrev=0 --match 'v[0-9]*' --exclude '*-*'` (the last stable release; pre-release tags are skipped). If any check fails, stop and tell

Comment on lines +52 to +54
**6. Tag and push.** Pushing the tag starts the release pipeline, so ask once more:
"Create and push `<tag>`?". On a yes, run `make release tag=<tag>`. Then report the run
with `gh run list --workflow release.yml --limit 1`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small issues with the last step:

  1. Leftover notes file. After a successful push, dist/release_notes.md stays on disk. The next hand-run make release tag= quietly uses it as the tag body. The PR description and the guide both mention this, but the skill can prevent it by deleting the file. The old script had a trap that did a similar cleanup.
  2. Wrong run reported. gh run list --workflow release.yml --limit 1 runs straight after the push. GitHub often hasn't registered the new run yet, so this can show the previous release. A tag push's run has headBranch set to the tag name, so filtering on the tag avoids that.
Suggested change
**6. Tag and push.** Pushing the tag starts the release pipeline, so ask once more:
"Create and push `<tag>`?". On a yes, run `make release tag=<tag>`. Then report the run
with `gh run list --workflow release.yml --limit 1`.
**6. Tag and push.** Pushing the tag starts the release pipeline, so ask once more:
"Create and push `<tag>`?". On a yes, run `make release tag=<tag>`, then delete
`dist/release_notes.md` so a later hand-run `make release` can't reuse it. Report the run
with `gh run list --workflow release.yml --branch <tag> --limit 1` (retry for a few seconds if it isn't listed yet).

@@ -0,0 +1,54 @@
---
name: release
description: Cut a Kosli CLI release - suggest the next semver tag from the changes since the last tag, draft the release notes with the user, then tag and push via `make release`. Use when asked to "release", "cut a release", "tag a new version", or "draft release notes".

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something to consider: the last step of this skill pushes a release tag, and the description triggers on loose phrases like "draft release notes" and "tag a new version". If you want it to run only on an explicit /release, add disable-model-invocation: true to the frontmatter. Steps 5 and 6 already ask for confirmation twice, so this is optional. It does mean Claude won't load the skill by itself, though, which goes against the "or ask Claude to cut a release" path in the PR description. Your call.

Comment thread Makefile
([ -f dist/release_notes.md ] && git tag -a $(tag) --cleanup=verbatim -F dist/release_notes.md) || git tag -a $(tag) -m"$(tag)"; \
git push origin $(tag); \
fi
if [ -z "$(tag)" ]; then echo "Usage: make release tag=vX.Y.Z (or run /release in Claude Code to draft version and notes)"; exit 1; fi; \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this check comes after the main branch check. So running a bare make release from a feature branch prints "must be run from main" rather than the usage line that points to /release. Putting the tag check first would show the usage hint wherever it's run. It's harmless either way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant