# How we write release notes straight from merged PRs

Our Machine release-notes agent works from GitHub. Each time we ship, it reads what merged since the previous release, sorts it by area, writes the notes and opens a changelog PR.

Canonical page: https://themachine.myapps.ai/use-cases/release-notes

When a deadline is close, release notes are the first chore to go. Everything
you'd need is sitting in the merged PRs. But shaping it into something people
can actually read, sorted by area, written plainly, with the clutter taken
out, is hand work. And it usually happens after the release has already
shipped.

So an agent on Machine writes them for us from the PR history. Every time we
release, it reads each PR merged since the previous release, sorts them by
area, writes notes a person can follow, and opens a PR against the changelog
for someone to review. Below is how it's set up: what starts it, how each
session works, and the limits we put on it.

- **Team:** Machine
- **Runs on:** Each new tag or release
- **Connected systems:** GitHub
- **Mode:** Started by events · opens a changelog PR for review

## The problem

To write good notes you have to reread everything that's merged since the
previous release, decide which bits a reader cares about, and explain them to
someone who never saw the PRs. That's exactly the kind of job that gets put
off. So the changelog lags, or it gets one vague line that tells nobody
anything.

The usual shortcuts each fall short. A generated list of PR titles is
correct but hard to read: internal jargon, no grouping, and every dependency
bump thrown in. Writing them yourself reads better, but it's slow and it
fights for time with shipping. Either way the notes show up after the
release, if they show up.

## What we built

Every release on Machine sets off an agent. Pushing a tag starts an isolated
session: a sandbox, which is a fresh cloud computer just for that run, with
scoped access to the repo. The agent finds the previous release, reads each
PR merged since then, sorts them by area, writes plain-English notes, and
opens a PR against the changelog. A person reviews it and merges.

## How it works

### Let the release start each run

GitHub sends a signed webhook to the project. Pushing a tag or publishing a
release sets it off, and each time a new **session** starts in its own
sandbox, already holding the new tag. One release, one session, one
throwaway machine, so nothing leaks from one release to the next.

### Hand it the notes playbook

How we write release notes is kept as **skills** and **memory**, the
playbook the agent carries and improves. It covers how to group changes by
area, which labels mean internal-only work that should be left out, the tone
our changelog uses, and the format the file needs. When we change how a
section should read, we note it down and the agent follows it from the next
release on.

### Plug in what the notes need

Scoped **connectors** link the agent to GitHub. Machine keeps the tokens on
its own servers, so the model never sees one. With them the agent can:

- **Work out the range.** Find the previous release tag and every commit
between it and the new one.
- **Read what merged.** The title, description, labels and author of each PR
merged in that range, so it understands what really changed.
- **Sort and write.** Group the PRs by area and write notes in plain
language, leaving out internal busywork and dependency noise.
- **Open a changelog PR in GitHub.** The draft notes arrive as a pull request
against the changelog file.

### Draw the lines

What the agent produces is **a PR against the changelog** and nothing else.
It doesn't publish, tag or announce anything. A person checks the wording and
merges. Credentials are stored encrypted in the Secrets Manager, added at run
time, and only handed to the agents you grant them to.

### Let every release write its own first draft

Put together, pushing a tag makes the release read its own history. The agent
works out the range, reads what merged, sorts it by area, writes the notes,
and opens a changelog PR that's grouped, readable and free of internal
clutter. Your team edits the words instead of building the notes from
nothing.

> **The pattern**
> Every release fires a **trigger** that opens a session with a scoped
> **connector** into the repo. **Skills** and **memory** hold the notes
> playbook. The agent drafts a changelog PR, and a person owns both the
> wording and the merge.

## Guardrails

The agent reads the repo and writes a draft, so what it can reach is kept
narrow and fenced in:

- **Kept apart.** Each release gets its own sealed-off sandbox. The session
  reads the PR history and drafts the notes. The changelog branch is the only
  thing it sends back out.
- **Locked-down keys.** The GitHub credentials are stored encrypted in the
  Secrets Manager, added to the sandbox at run time, and only handed to the
  agents you grant them to.
- **Gated by a PR.** It opens a pull request against the changelog, then
  stops. Publishing and announcing the release are never its job. A person
  reviews the wording and merges.
- **All of it lives in code.** The agent's setup, skills and permissions are
  files in the repo. They're versioned, and you change them with a reviewed
  **change request**, not a setting on a dashboard.

## The outcome

- **Every release:** Notes drafted from the PR history with nobody prompting
- **Grouped:** Changes sorted by area, internal clutter left out
- **Human review:** The agent writes the draft, your team owns the words

Our changelog keeps up now. The notes that reach review are already grouped
and easy to read, not a bare dump of PR titles. Reviewers tidy the wording
instead of piecing together what shipped from the git log.
