To generate release notes with AI, list the commits since your last release with git log, pipe them into a coding agent in script mode, and ask for grouped Markdown. The agent only formats what git gives it, so it needs no access to your files and no permission to run anything.
git log --oneline --no-merges v1.4.0..HEAD | claude -p "Group these commits into release notes under ## Features, ## Fixes and ## Other. Rewrite each line for users, not developers. Omit empty sections. Output only Markdown." > RELEASE_NOTES.md
What it looks like
The input, straight from git:
a41c9e2 fix(checkout): apply discount before tax
7d02b11 feat(export): add --json flag to export command
e5f8a30 chore: bump eslint to 9.x
1c77d0f feat: dark mode on settings page
The output:
## Features
- Export now supports JSON with the new `--json` flag.
- The settings page has a dark mode.
## Fixes
- Discounts are now applied before tax at checkout.
## Other
- Updated development tooling.
The commands for each agent
| Agent | Script mode | Reads piped input |
|---|---|---|
| Claude Code | claude -p "..." | Yes |
| Codex CLI | codex exec "..." | Yes, as context for the prompt |
| OpenCode | opencode run "..." | Pass a file with -f |
Claude Code
git log --oneline --no-merges v1.4.0..HEAD | claude -p "Group these commits into release notes under ## Features, ## Fixes and ## Other. Rewrite each line for users. Omit empty sections. Output only Markdown." > RELEASE_NOTES.md
Codex CLI
git log --oneline --no-merges v1.4.0..HEAD | codex exec "Group these commits into release notes under ## Features, ## Fixes and ## Other. Rewrite each line for users. Omit empty sections. Output only Markdown." -o RELEASE_NOTES.md
When you pipe input and give a prompt, Codex treats the piped text as context. -o writes only the final answer to the file. codex exec runs in a read-only sandbox by default, which is exactly right here.
OpenCode
git log --oneline --no-merges v1.4.0..HEAD > commits.txt
opencode run "Group the commits in this file into release notes under ## Features, ## Fixes and ## Other. Rewrite each line for users. Omit empty sections. Output only Markdown." -f commits.txt > RELEASE_NOTES.md
The PowerShell trap: in Windows PowerShell 5.1,
>writes the file as UTF-16, which many tools and GitHub render as garbage. Pipe toOut-File -Encoding utf8 RELEASE_NOTES.mdinstead, or use PowerShell 7, which writes UTF-8 by default.
A prompt that gives good notes
The one-liner works. This version gives notes people actually read:
Write release notes from these commits.
- Group under ## Features, ## Fixes and ## Other. Omit empty sections.
- Write for users of the product, not for developers. Say what changed for them.
- Merge commits that describe the same change into one line.
- Put dependency bumps, refactors and CI changes under Other, in one line, or drop them.
- Never invent a change that isn't in the list. If a commit is unclear, keep its wording.
- Output only Markdown, no introduction.
The “never invent” line matters. Asked to make notes sound good, a model will happily describe a feature in more detail than the commit supports.
Run it in CI
The same command works in a release job. With GitHub’s CLI, create the release with the generated notes:
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^)
git log --oneline --no-merges "$PREV_TAG"..HEAD | claude -p "$(cat .github/release-notes-prompt.txt)" > RELEASE_NOTES.md
gh release create "$GITHUB_REF_NAME" --notes-file RELEASE_NOTES.md
- Keep the prompt in the repo, as above, so changes to it are reviewed like code.
- Give the job only the model key it needs. The agent never needs write access to the repository for this; the
ghstep does that. - Fetch the tags. CI checkouts are often shallow, and
git describefails without the history. In GitHub Actions, setfetch-depth: 0on the checkout step.
Pipe it, or let the agent look?
You can also skip the pipe and ask an agent in a normal session: “Write release notes for everything since v1.4.0.” It will run git log itself, and can open the diffs to describe changes better than the commit messages do.
| Pipe the log | Let the agent explore | |
|---|---|---|
| Input | Exactly the commits you chose | Whatever the agent decides to read |
| Cost | One small request | Many requests, much more context |
| Permissions needed | None | Running git commands |
| Notes quality | As good as your commit messages | Better for vague commit messages |
For a release job, pipe. For a big release with messy commit history, let the agent look, and review the result.
You may not need a model at all
- Your commit messages already follow a convention such as Conventional Commits. A plain tool that groups by prefix is free, fast and never invents anything.
- You release from pull requests on GitHub.
gh release create v1.5.0 --generate-notesbuilds notes from the merged pull request titles, no model involved.
Related guides
- Terminal coding agents: install Claude Code, Codex CLI or OpenCode
- Git workflow with AI agents: commit habits that make good notes possible
- Write good tasks for coding agents: the same rules apply to prompts in scripts
- Keep secrets away from AI agents: what not to pass into a CI job