feat(release-notes): agent-generated release notes action - #4
Merged
Merged
Conversation
Adds a composite action that writes user-facing release notes for a commit range with a headless agent, for `gh release create --notes-file`. Consumer repos keep a short step plus their own `notes-focus`, mirroring how claude-review is wired. Shape follows ci-triage's scripts/run-triage-agent.sh, which is the proven in-org pattern for running an agent non-interactively in CI: - A model fallback chain, best first: each Claude model, then each Codex model, overridable via inputs. A model the CI token cannot access fails fast and the next is tried, so a missing entitlement degrades rather than dead-ends. - Success is gated on a non-empty artifact, not an exit code, which also covers service-unavailable and unanticipated errors. A too-short result is treated as no result, so a refusal does not become the release notes. - The script never fails the job. Notes are not a gate: a caller that gets nothing is expected to fall back to `--generate-notes` rather than block a release on a model outage. `generated` is returned as an output so the caller can branch. Two deliberate differences from run-triage-agent.sh, both because this task is write-a-paragraph rather than investigate-and-fix: - Output is captured from stdout instead of the agent writing a file, so the agent needs no tools at all. Commit messages are author-controlled input and this runs in a release job holding the caller's token; an agent with no write access cannot be steered by instructions embedded in a commit message. The prompt therefore carries the whole range inline and says not to use tools. - No actions/checkout. This runs late in a release job, after the artifact is built and packaged, and a fresh checkout would wipe those untracked outputs. The caller's checkout is reused and only deepened, since release jobs check out at depth 1 and `git log from..to` needs history. Verified end to end against a real range (screen-recorder v0.1.0..main, 10 commits, 16.5 kB prompt): `claude --print` returned usable notes that grouped changes by theme, described behaviour rather than files, folded CI and refactor work into a closing line, and invented nothing — each claim checks out against the commits, including one whose effect is limited to unpacked installs. shellcheck is clean and both files parse.
Install .github/workflows/claude-code-review.yml so internal-tools gets the same severity-based PR review it ships to consumer repos. Unlike consumers (which pin ShiplightAI/internal-tools/claude-review@v1), this caller uses the local ./claude-review, so a PR that edits the action is reviewed by its own version instead of the older tagged copy. That needs an explicit actions/checkout first, since a local action must be on disk before `uses:` can resolve it. The review-focus targets this repo's actual risk surface: SHA-pinning and prompt injection in the composite action, the caller/action split invariant, permissions creep, and agent-skills/** prompts that execute verbatim in other repos. Also fix the copy-in template, which pointed at the nonexistent ShiplightAI/internal-agent-skills org path; the repo is ShiplightAI/ internal-tools, and shipyard's copy had already been corrected by hand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A composite action that writes user-facing release notes for a commit range using a headless agent, returning them as a file for
gh release create --notes-file. Consumer repos keep a short step plus their ownnotes-focus, mirroring howclaude-reviewis wired.Motivation:
gh release create --generate-notesproduces a list of merged PR titles, and a script like monots'gen-changelog.mjscan only reformat commit subjects. Neither can say what a release means for someone using the software. That is a writing task.Design
The shape follows
ci-triage/scripts/run-triage-agent.sh, the proven in-org pattern for running an agent non-interactively in CI:--generate-notesrather than blocking a release on a model outage.generatedis exposed as an output so the caller can branch.Two deliberate departures from
run-triage-agent.sh, both because this task is write a paragraph rather than investigate and fix:actions/checkout. This runs late in a release job, after the artifact is built and packaged — a fresh checkout would wipe those untracked outputs. The caller's checkout is reused and only deepened, since release jobs check out at depth 1 andgit log from..toneeds history.Verification
Run end to end against a real range —
screen-recorderv0.1.0..main, 10 commits, a 16.5 kB prompt — withclaude --print:Also:
shellcheckclean on the runner, and both files parse.Notes for reviewers
v1is not moved by this PR. The first consumer (screen-recorder) will pin to this PR's merge commit SHA, so the five repos onclaude-review@v1are untouched. Folding this intov1later is a separate decision.openai_api_keyis supplied, so repos without it simply run the Claude chain.