River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

Product Release Notes and Changelog

Release notes get written from the ticket list, which records what engineers did. This register starts by asking what a customer can see.

Free download  ·  No account needed

A release of 143 merged pull requests contains 25 things a customer can observe. The other 118 are driver upgrades, refactors, test coverage, deleted dead code and added tracing: real work, no visible effect. Write the notes from the ticket list and all 143 arrive with equal weight, which is how a page ends up reading "fixed an issue where" nine times. Marking the invisible ones is not busywork. It is the step that makes the remaining list short enough for anyone to finish.

Then the 25 get ranked by how many accounts will notice, and that order disagrees with the one the release was discussed in. Single sign-on with automatic provisioning reaches 64 accounts of 2,180. A queue rewrite filed as internal infrastructure reaches all 2,180, because it took tracking updates from fifteen minutes to ninety seconds, and nobody files a user-facing ticket for that. Reach is a number, so it settles the running-order argument without anyone having to win it.

Anything requiring the customer to act leaves the release note entirely and gets its own message, its own list and a date, ahead of the release. What is left cuts three ways from the same rows: the email, the in-app message and the changelog entry, which cannot contradict each other. Generating notes straight from a commit range is release notes from commits; the launch around one bet is the launch brief pack.

The release, sorted by who will notice

Change Register, Publication Calendar, and the customer note cut from them.

Change Register

Illustrative rows for a fictional freight visibility platform, Foldbridge. Release 24.9: 143 merged pull requests, 2,180 accounts.

TicketTitle as mergedSeenWhat the user can now doReachAct
PLAT-2841Replace polling ingest with event stream consumerIndirectTracking updates arrive within 90 seconds instead of up to 15 minutes100%
2,180
No
WEB-1190Persist filter state to localStorageYesThe shipment list keeps your filters when you come back to it94%
2,050
No
WEB-1204Add ETA confidence band to shipment detailYesEvery ETA shows how confident it is, so you know which to chase88%
1,918
No
RPT-0442Scheduled report deliveryYesReports can email themselves on a schedule76%
1,656
No
API-0771Add cursor pagination to /shipmentsYesAccounts above 10,000 records can page through all of them12%
262
No
EXP-0155Rename Est. Delivery column to ETA in CSV exportYesThe CSV column Est. Delivery is now ETA. Imports by column name break10%
210
14 Oct
API-0688Remove v1 shipment endpointsYesThe v1 shipment endpoints are switched off. v2 shipped March 20254%
88
1 Nov
SEC-0310SAML SSO with SCIM provisioningYesSingle sign-on with automatic provisioning and deprovisioning3%
64
Setup
WEB-1177Fix timezone offset on delivery timestamps for AEST accountsYesDelivery times display in the right timezone for Australian accounts2%
41
No
PLAT-2799Upgrade Postgres driver to 15.4No---
WEB-1188Refactor ShipmentCard into three componentsNo---
QA-0233Add Playwright coverage for the booking flowNo---

25 observable, 118 not. Of the 25: four reach above 75%, eight between 10% and 75%, thirteen below 10%, and five need the customer to act. The top row is the whole argument for the Seen column: it was logged as internal infrastructure, it has the highest reach in the release, and a note written from the ticket list omits it.

The same release, cut three ways

Three documents, three different cut rules, one set of statements. Nothing gets rewritten between them, only compressed.

ChangeReachCustomer emailIn-appChangelogWhy
Tracking latency100%LeadYesYesHighest reach in the release and the subject line
ETA confidence band88%YesYesYesVisible on the screen the announcement appears on
Filters persist94%YesYesYesNobody asked for it and everybody notices it
Scheduled reports76%YesCutYesNo route to reporting from the shipment list, so the impression is wasted
Cursor pagination12%CutCutYesBelow the email threshold. The people who need it read changelogs
SSO and SCIM3%CutCutYes64 accounts got their own email. 2,116 did not need a paragraph to skip
CSV column rename10%CutBannerYesAction required. Own email on 2 Oct, banner to 210 accounts, deadline in the changelog line
v1 endpoints removed4%CutCutFirstBreaking. Third notice since March 2025, and it leads the changelog
AEST timezone fix2%CutCutYes41 accounts, and every one of them filed a ticket about it
TOTALS-4 items3 items25 itemsSubject line names the change, not the version

Scheduled reports is the row worth staring at. It is in the email and out of the in-app message purely because of placement, which looks inconsistent and is correct: an announcement the reader cannot act on from where they are standing teaches them to dismiss the next one.

Publication Calendar

Every artifact the register implies, dated, owned, and tracked to done. The deadline rows carry migration progress.

DateChannelArtifactAccountsOwnerStatus
2 OctDedicated emailCSV column rename notice210SupportSent 09:00
2 OctDedicated emailv1 removal, third notice88PlatformSent 09:00
7 OctChangelog24.9 entry, all 25 changesPublicProductPublished 08:00
7 OctCustomer emailRelease note, 4 changes2,180ProductSent 10:00
7 OctIn-appAnnouncement, 3 changes2,180ProductLive 10:05
7 OctIn-app bannerCSV rename, action required210SupportLive to 14 Oct
9 OctSupport macroCSV rename response template-SupportPublished
14 OctDeadlineCSV column rename takes effect210Support12 of 210 not migrated
16 OctSales enablementTalk track, ETA confidence band-Product MarketingNot started
21 OctWebinar24.9 walkthrough340Customer SuccessScheduled
1 NovDeadlinev1 endpoints switched off88Platform61 of 88 migrated

The two deadline rows are why this sheet exists. Twelve accounts are four days from a format change they have not made, and twenty-seven are still calling an endpoint that disappears on 1 November. Neither fact appears in a release note, a ticket queue or a changelog, and both of them turn into support volume on a date somebody already chose.

What is in the pack

01

Change Register

One row per change, carrying the title as merged, whether a customer can observe it, the statement rewritten as what the user can now do, the account reach, and whether it needs a response.

02

Publication Calendar

Every artifact the register implies, dated and owned, including the deadline rows that carry migration progress. Twelve of two hundred and ten unmigrated four days out is a fact that lives nowhere else.

03

Release Notes by Audience

The customer email cut to the changes above your reach threshold, plus the segment notes the cuts imply, with each cut rule written down so nobody relitigates it next month.

04

In-app Announcement

Cut by reachability rather than reach, plus the targeted banner for action-required changes that reappears for admins until the account has actually migrated rather than until somebody clicks dismiss. It also has to fit inside whatever interruption budget the rest of the product is already spending.

05

Changelog Entry

Every observable change, grouped with removals and breaking changes first, because the reader who needs the page most urgently is the one whose integration just broke.

06

Writing a User-visible Statement

The method, with worked translations and the banned constructions: fixed an issue where, improved performance with no number, internal component names, and various bug fixes.

How it works

  1. 1

    Send the change set

    Merged pull requests, a tag range, a Jira or Linear export, or a spreadsheet. Account counts by plan or flag if you have them.

  2. 2

    Mark what is visible

    Observable, indirect, or not. The indirect rows get the most attention, because that is where the biggest change in the release usually hides.

  3. 3

    Rank by reach

    Every survivor carries how many accounts will notice, so the running order stops being decided by whoever is most senior in the room.

  4. 4

    Cut three ways

    Email by reach, in-app by what the reader can reach from that screen, changelog by nothing. Action-required changes go out ahead with a date.

Frequently asked questions

What do I send it?

Merged pull requests, a git tag range, a Jira or Linear export, a board filtered to Done, or a spreadsheet somebody keeps by hand. Several at once is normal and duplicates get merged into one row with both references kept. Diffs or descriptions help most on the infrastructural changes.

How does it decide a change is invisible?

One test: if nobody wrote it up, would a customer notice something different. A driver upgrade, a refactor and new test coverage all fail it. A queue rewrite that moves an update from fifteen minutes to ninety seconds passes it indirectly, and those are the rows worth the most attention.

Where does the reach percentage come from?

Plan entitlements, feature flag exposure, or the count of accounts that touch the surface involved. Where none of that is available it says unknown rather than estimating, and unknown rows sort to the bottom visibly unranked. A guessed percentage would order the whole release.

Why not put the breaking change in the release note?

Because the people who must act are a small subset of the readers and the note is written for the majority who need not. Both action-required changes in the worked example went to their exact accounts five days ahead of the release, with a date. The release note mentions neither.

How does it handle version numbers and breaking changes?

By whatever scheme you already use, defaulting to semantic versioning and saying so, so somebody can overrule it once instead of every month. Removals lead the changelog, name the old string as well as the new one, and carry their deadline in the line itself. A removal with a migration behind it needs the sunset pack rather than a changelog line.

Can it write for our voice?

Yes, and it reads your last several releases to get it rather than asking you to describe it. What it will not carry over is the constructions the space rule bans, so if your previous notes said fixed an issue where nine times, that specific habit does not survive the migration.

We ship continuously. Is a release even a thing?

The register does not care about release boundaries, only about date ranges. Point it at the last two weeks and the same three artifacts come out. Continuous shipping makes the reach ranking matter more, since without a release moment nothing else imposes an order. Rank the work itself with the prioritization pack.

Find out how much of your release is visible

Send the change set however it exports. The first number back is how many of those changes a customer could notice without being told.

Sort my release