---
title: "Release notes"
description: "Write a Node script that drafts release notes from everything merged since the last release, with the AI SDK and the release-manager preset."
canonical_url: "https://github-tools.com/guides/release-notes"
---
# Release notes

> Write a Node script that drafts release notes from everything merged since the last release, with the AI SDK and the release-manager preset.

To generate release notes with AI, give a model the `release-manager` preset and ask it to compare the latest release with the current state of the repository: `getReleaseContext` returns the latest release, the previous one and the comparison between their tags, and the model groups the merged pull requests into notes. This guide does it in one [AI SDK](https://github-tools.com/integrations/ai-sdk) script that only reads.

## What you'll build

A script you run with a repository name. It prints draft release notes for everything merged since the latest release, grouped into features, fixes and other changes, with one bullet per pull request linking its number. Paste the draft into a GitHub release, or edit it first.

The script never publishes anything. The one write in its preset, `createRelease`, can't run, because nothing in the script answers an approval request.

<release-notes-draft>



</release-notes-draft>

## Before you start

- Node.js 22 or later.
- A GitHub connector named `github/my-connector` in [Vercel Connect](https://github-tools.com/auth#create-a-github-connector), with its token pulled into `.env` as `VERCEL_OIDC_TOKEN`. A `GITHUB_TOKEN` with Contents (read) and Pull requests (read) works instead, as shown below.

## 1. Install the packages

<code-group>

```bash [pnpm]
pnpm add @github-tools/sdk @vercel/connect ai zod
pnpm add -D tsx
```

```bash [npm]
npm install @github-tools/sdk @vercel/connect ai zod
npm install -D tsx
```

```bash [yarn]
yarn add @github-tools/sdk @vercel/connect ai zod
yarn add -D tsx
```

```bash [bun]
bun add @github-tools/sdk @vercel/connect ai zod
bun add -d tsx
```

</code-group>

The project has three files:

```text
release-notes/
├── package.json                       # "type": "module", "generate" script
├── .env                               # VERCEL_OIDC_TOKEN
└── scripts/
    └── generate-release-notes.ts      # the whole agent
```

```json [package.json]
{
  "type": "module",
  "scripts": {
    "generate": "tsx --env-file=.env scripts/generate-release-notes.ts"
  }
}
```

## 2. Write the script

```ts [scripts/generate-release-notes.ts]
import { connectGithubTools } from '@github-tools/sdk/connect'
import { generateText, stepCountIs } from 'ai'

const [owner, repo] = process.argv.slice(2)
if (!owner || !repo) {
  console.error('Usage: tsx scripts/generate-release-notes.ts <owner> <repo>')
  process.exit(1)
}

const { text } = await generateText({
  model: 'anthropic/claude-opus-5.5',
  tools: connectGithubTools('github/my-connector', {
    preset: 'release-manager',
    context: { owner, repo },
  }),
  stopWhen: stepCountIs(10),
  prompt: `
    Find what changed since the latest release, or since the previous tag if there is no release.
    Draft release notes grouped into "Features", "Fixes" and "Other", one bullet per pull request,
    each linking its number. Do not create the release. Print the draft only.
  `,
})

console.log(text)
```

`connectGithubTools` builds the same tools as `createGithubTools`, with a token minted by the Vercel Connect connector and scoped to the preset. To use `GITHUB_TOKEN` instead, import `createGithubTools` from `@github-tools/sdk` and call it with the same options, without the connector name.

`context` fills in `owner` and `repo` on every call, so the prompt doesn't repeat them ([Context](https://github-tools.com/context)). `generateText` stops after one step unless you set `stopWhen`, so `stepCountIs(10)` lets the model read, then write the draft.

The `release-manager` [preset](https://github-tools.com/presets) has `getReleaseContext`, which returns the latest release, the one before it and the comparison between their tags in one call, plus `compareCommits` and `listPullRequests` for the details.

## Run it

<code-group>

```bash [pnpm]
pnpm generate vercel-labs github-tools
```

```bash [npm]
npm run generate -- vercel-labs github-tools
```

```bash [yarn]
yarn generate vercel-labs github-tools
```

```bash [bun]
bun run generate vercel-labs github-tools
```

</code-group>

The draft prints to the terminal. Nothing is posted to GitHub.

## FAQ

<accordion>
<accordion-item label="Can the agent publish the release too?">

Yes, after someone reads the draft. Move the prompt to [`createGithubAgent`](https://github-tools.com/integrations/ai-sdk#creategithubagent) with the same preset, and answer the `createRelease` approval request once the draft is approved, as in the [quick start](https://github-tools.com/start/quick-start#_3-approve-the-write).

</accordion-item>

<accordion-item label="Can I run it in CI on every tag?">

Yes. Run the same script in a GitHub Actions job with `createGithubTools`, the job's `GITHUB_TOKEN`, and your model provider's key as a secret. The script only reads, so nothing waits for approval.

</accordion-item>

<accordion-item label="What if the repository has no releases yet?">

The prompt tells the model to compare against the previous tag instead. With no tags at all, ask for the changes since a date or a commit.

</accordion-item>

<accordion-item label="How do I change the sections?">

Edit the prompt. The grouping comes from the instructions, so "Breaking changes", "Features" and "Fixes" work as well as the three above.

</accordion-item>
</accordion>


## Sitemap

See the full [sitemap](https://github-tools.com/sitemap.md) for all pages.
