Skip to content

chore: generate release notes with Claude in Simplified Technical English - #792

Merged
nklmilojevic merged 1 commit into
mainfrom
chore/release-notes
Oct 6, 2026
Merged

nklmilojevic merged 1 commit into
mainfrom
chore/release-notes

Conversation

@nklmilojevic

Copy link
Copy Markdown
Owner

GitHub's generated notes only list PR titles, so a release did not say
what changed for the user. The release recipe now asks claude -p
(Sonnet 5.5) to summarize the commits since the previous tag in ASD-STE100
Simplified Technical English and keeps the PR list and changelog link
below. Notes are written before the version bump, so a failure stops the
release before anything is pushed.

just release notes [tag] previews the notes for a tag or for unreleased
commits, and just release renote <tag> replaces the notes of a published
release. The gh wrappers use plain gh when GH_TOKEN is set, because
op plugin run needs an interactive prompt.

…lish

GitHub's generated notes only list PR titles, so a release did not say
what changed for the user. The release recipe now asks claude -p
(Sonnet 5.5) to summarize the commits since the previous tag in ASD-STE100
Simplified Technical English and keeps the PR list and changelog link
below. Notes are written before the version bump, so a failure stops the
release before anything is pushed.

`just release notes [tag]` previews the notes for a tag or for unreleased
commits, and `just release renote <tag>` replaces the notes of a published
release. The gh wrappers use plain gh when GH_TOKEN is set, because
op plugin run needs an interactive prompt.
@nklmilojevic
nklmilojevic merged commit afe844d into main Oct 6, 2026
3 of 4 checks passed
@kritikal-github

kritikal-github Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Re-runKritika Review

Adds Claude-written release notes to release and renote recipes.

3 findings · 3 important

Confidence 1/5 · critical risk: The reported shell interpolation lets a fetched tag execute commands during release-note generation, a security break that warrants a 1. The reported first-release preview failure and mismatched feature-branch notes also need fixes; risk is critical because this changes release infrastructure.

Findings

Summary

The release recipe now writes notes before the version bump and publishes them with the release. Preview and renote commands reuse the generator. The new paths need safer argument handling and better alignment between local commits and GitHub's generated notes.

Flow
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["Release or preview request"] --> B["Select previous tag and target"]
  B --> C["Read local commits"]
  B --> D["Request GitHub PR list and changelog"]
  C --> E["Ask Claude for short user-facing summary"]
  D --> F["Combine summary and generated links"]
  E --> F
  F --> G["Print preview or publish release notes"]
Loading

What's good

  • Generates notes before changing the version or pushing.
  • Reuses one notes generator for publication, preview, and renote.

Reviews (1) · Last reviewed commit: "chore: generate release notes with Claud..." · kritika with chatgpt/gpt-6-sol

Comment thread .just/release.just
#!/usr/bin/env bash
set -euo pipefail
cd "{{ root }}"
tag="{{ tag }}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[important · security] Do not interpolate tag arguments into shell source

Just substitutes {{ tag }} before Bash parses this line, so a tag argument such as $(touch /tmp/marker) runs the command before the tag validation. The same pattern occurs in renote and in _notes for tag-derived from and to values; a fetched tag containing shell syntax reaches those assignments too. Pass these values as data rather than inserting them into Bash source.

Suggested fix

Use shell-safe argument passing for tag, from, and to throughout these recipes, including the nested just calls and the gh release edit argument; avoid direct {{ ... }} substitution into the script.

Prompt for a coding agent
In .just/release.just at lines 71, 94, 96, 103, and 104, and the renote-to-notes invocation, change the `notes`, `renote`, and `_notes` recipes to pass tag, from, and to values as shell-safe data instead of interpolating `{{ tag }}`, `{{ from }}`, or `{{ to }}` into Bash source. Ensure a tag containing shell metacharacters is rejected or handled literally without executing commands.

Comment thread .just/release.just
cd "{{ root }}"
tag="{{ tag }}"
if test -z "$tag"; then
from="$(git describe --tags --abbrev=0 HEAD)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[important · correctness] Handle previews before the first release tag exists

The release path explicitly supports a repository with no published release by using v0.0.0, but notes without an argument exits at git describe when there are no tags. Thus the advertised unreleased-notes preview cannot be used for the first release, although _notes already has sentinel-range handling.

Suggested change
from="$(git describe --tags --abbrev=0 HEAD)"
from="$(git describe --tags --abbrev=0 HEAD 2>/dev/null || echo v0.0.0)"
Prompt for a coding agent
In .just/release.just line 73, update the `notes` recipe's no-tag branch to fall back to `v0.0.0` when `git describe` finds no tag, matching `_release` and `_notes`, so first-release notes can be previewed.

Comment thread .just/release.just
repo="$(gh repo view --json nameWithOwner -q .nameWithOwner)"
previous=()
if test "$from" != "v0.0.0"; then previous=(-f previous_tag_name="$from"); fi
changes="$(gh api "repos/$repo/releases/generate-notes" -f tag_name="$to" "${previous[@]}" -q .body)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[important · correctness] Pin GitHub's generated notes to the selected local target

For an unreleased target, this request supplies only a new tag_name; GitHub generates its PR list against its default branch while commits comes from the local HEAD. Running just release notes on a feature branch therefore combines a feature-branch Claude summary with a default-branch PR list and changelog. Send the selected commit as target_commitish so both parts describe the same target.

Suggested fix

Resolve the local target commit ($to if it exists, otherwise HEAD) and include it as target_commitish in the generate-notes API request; retain previous_tag_name for the start of the range.

Prompt for a coding agent
In .just/release.just around lines 111-119, update `_notes` to resolve the selected local target to a commit SHA and pass it as `target_commitish` to `gh api repos/$repo/releases/generate-notes`. Keep the existing previous-tag handling so preview notes on a branch and release notes use the same endpoint as the local git log.

@greptile-apps

greptile-apps Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium risk] Release automation now generates notes with Claude instead of GitHub.

The PR appears safe to merge, with non-blocking improvements needed for local previews and release setup documentation.

Findings

  1. P2 Preview sections can disagree ▶
  2. P2 Release setup is undocumented ▶

Summary

The release recipe now asks Claude to write short user-facing notes and appends GitHub's generated PR list. It prepares the notes before changing the version or pushing.

  • Adds notes for previews and renote for published releases.
  • Uses plain gh when GH_TOKEN is set.
  • Two non-blocking improvements remain: align the preview's two commit sources and document the required Claude setup.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Check clean and current main] --> B[Generate notes with Claude and GitHub]
  B --> C{Notes succeed?}
  C -->|No| D[Stop before version bump]
  C -->|Yes| E[Bump version and run checks]
  E --> F[Commit and push]
  F --> G[Create release with saved notes]
Loading

Reviews (1) · Last reviewed commit: "chore: generate release notes with Claud..."

Comment thread .just/release.just
repo="$(gh repo view --json nameWithOwner -q .nameWithOwner)"
previous=()
if test "$from" != "v0.0.0"; then previous=(-f previous_tag_name="$from"); fi
changes="$(gh api "repos/$repo/releases/generate-notes" -f tag_name="$to" "${previous[@]}" -q .body)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Preview sections can disagree

just release notes reads commits from local HEAD, but this GitHub request does not pass target_commitish. If the local branch differs from the remote default branch, the summary and appended PR list can describe different changes. Use the same commit for both parts when GitHub can resolve it; otherwise omit the GitHub list from the local preview.

Comment thread .just/release.just
else
gh() { command gh "$@"; }
fi
command -v claude >/dev/null || { echo "claude is required to write release notes" >&2; exit 1; }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Release setup is undocumented

The release commands now require an installed and authenticated Claude CLI, but the release guide does not explain that setup. Maintainers following the guide discover the requirement only when their release stops. Document the required setup, the selected model, and the notes and renote commands.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant