A semantic-release plugin that turns the generated changelog into release notes people want to read. It is a drop-in replacement for @semantic-release/release-notes-generator:
- It generates the standard notes with the same options.
- It sends them, the full commit messages and the descriptions of the merged pull requests to an OpenAI model or to Claude.
- It publishes the model's summary under the version heading, and keeps the standard list in a collapsed All changes block.
The result has this shape (the summary text is illustrative):
## [2.41.0](…/compare/v2.40.0...v2.41.0) (2026-10-06)
Spatial Runtime now reserves its ports so Windows can't hand them to Hyper-V, WSL2 or Docker.
### New
- The foveated streaming and REST ports are reserved at install and on every start … (#484)
<details>
<summary>All changes</summary>
### Features
* **foveated:** reserve the foveated TCP port against Windows dynamic exclusions ([f2fb022](…))
…
</details>It never fails a release. Without a credential, when the standard notes are empty, or when the model call fails, it returns the standard notes unchanged and logs why.
The plugin isn't on the npm registry. Install it from this repository's release tags:
npm install --save-dev "github:Innoactive/semantic-release-ai-notes#semver:^1"With cycjimmy/semantic-release-action, put the same github:Innoactive/semantic-release-ai-notes#semver:^1 in extra_plugins. #semver:^1 picks the newest v1.x.y tag. Pin #v1.2.3, or a commit SHA, to stay on one version.
Then replace the standard notes generator in your config. Its options (preset, presetConfig, writerOpts, …) work as before.
{
"plugins": [
["@semantic-release/commit-analyzer", { "preset": "conventionalcommits" }],
[
"@innoactive/semantic-release-ai-notes",
{
"preset": "conventionalcommits",
"product": "Spatial Runtime: Windows tray app that streams OpenXR apps to Apple Vision Pro. Readers: customer IT admins and VRED users."
}
],
"@semantic-release/github"
]
}The plugin uses whichever @semantic-release/release-notes-generator semantic-release itself has installed (a peer dependency), so presets and version pins behave as they did before.
| Option | Default | Description |
|---|---|---|
product |
— | What the project is and who reads its release notes. The most useful option: it decides what counts as user-facing. |
instructions |
— | Extra rules for this project, appended to the prompt, e.g. "Call out every port and firewall change." |
provider |
first with a credential | openai, anthropic or claude-code. See Providers. |
model |
per provider | Model ID for the chosen provider. Set provider too when you set it, so the model and the credential match. |
Every other option is passed to the standard notes generator.
Set the credential for one provider. Without a provider option the plugin uses the first one, in this order, whose credential is set:
provider |
Credential | Default model | How it calls the model |
|---|---|---|---|
openai |
OPENAI_API_KEY |
gpt-5.4-mini |
Chat Completions API. OPENAI_BASE_URL points it at a compatible endpoint (proxy, gateway, Azure). |
anthropic |
ANTHROPIC_API_KEY |
claude-opus-5-5 |
Messages API through the official SDK, with adaptive thinking and Anthropic's server-side refusal fallback. ANTHROPIC_BASE_URL overrides the endpoint. |
claude-code |
CLAUDE_CODE_OAUTH_TOKEN |
claude-opus-5-5 |
Runs the Claude Code CLI headless. See below. |
CLAUDE_CODE_OAUTH_TOKEN is a Claude subscription token from claude setup-token, the one anthropics/claude-code-action takes as claude_code_oauth_token. The Messages API does not accept it; Claude Code does, so this provider runs claude --print:
- Install
@anthropic-ai/claude-codenext to the plugin (for example in the semantic-release action's extra plugins, with a pinned version), or putclaudeonPATH. Its install step links a native binary, so don't install with--ignore-scripts. - Claude Code runs in an empty temporary directory with no tools, no MCP servers and no
CLAUDE.mdfiles.ANTHROPIC_API_KEY,ANTHROPIC_AUTH_TOKENand the Bedrock, Vertex and Foundry switches are removed from its environment, because Claude Code would prefer them over the token. - Use counts against the subscription's limits rather than API billing.
- Anthropic intends subscription OAuth for ordinary use of Claude Code by the subscriber, and points products and services at API keys. Use this provider in your own repositories with your own subscription, and
ANTHROPIC_API_KEYotherwise.
| Variable | Description |
|---|---|
| One credential from the table above | Required for the rewrite. Without one, the standard notes are published. |
GITHUB_TOKEN or GH_TOKEN |
Used to look up the pull requests behind the release's commits. Needs read access to pull requests. semantic-release on GitHub already has it. Without it, only commits are sent. |
GITHUB_API_URL |
For GitHub Enterprise Server. Set automatically in GitHub Actions. |
The model gets the product text, the standard notes, every commit message in the release, and the title and description of each merged pull request (HTML comments stripped, long descriptions shortened to fit). For a private repository this content leaves GitHub for OpenAI or Anthropic, so check that fits your data policy.
It is asked for one or two sentences on what the release means for readers, then bullets under Breaking changes, New, Improved and Fixed. It is told to keep every breaking change, merge fixes to features that are new in the same release into those features, leave out changes readers can't notice (refactoring, CI, tests, build), and state only what the input supports. The full prompt is in lib/prompt.js.
semantic-release generates notes a second time when a prepare step creates a commit, as @semantic-release/git does. The plugin answers that second call from the first, so each release costs one model call and the published text matches the logged one.
Nothing is tagged or published:
GITHUB_TOKEN=$(gh auth token) OPENAI_API_KEY=<key> node scripts/preview.js ../my-repo v1.4.0 v1.5.0Any provider credential works in place of OPENAI_API_KEY. Options are read from the repository's JSON .releaserc and can be overridden with --provider, --model, --product and --instructions. --prompt prints what would be sent to the model instead of calling it, which needs no credential.
Merges to main are released by release.yml: semantic-release tags vX.Y.Z and creates a GitHub release, using this checkout of the plugin for its own release notes. There is no npm publish; consumers install from the tags. package.json is private so it can't be published by accident, and its version stays a placeholder.
A tag is what consumers run inside their release jobs, so protect v* tags against deletion and force-updates with a tag ruleset. Add one provider credential (OPENAI_API_KEY, ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN) as a repository secret for the plugin's own notes.
MIT