Aug 26, 2026ENGINEERING

How We Ship With Claude Code

How We Ship With Claude Code

Someone asked last week how we ship now that Claude writes most of our code. It's four steps:

  1. Claude writes the code. We review it, open a PR, merge to main.
  2. We cut a tag.
  3. We push.
  4. We ask Claude to write the Onset release note for everything since the last tag.

Step four does more work than it looks like it does.

You don't remember code you didn't type

Throughput went up, which is the part everyone tells you about. We also started losing track of our own product, which I did not see coming.

Write a function by hand and you carry it around for weeks. Read a diff, nod, merge it, and it's gone by Thursday. Now point an agent at the repo that can land four PRs before lunch. The code is usually fine. What drifts is the picture in your head of what's actually deployed.

It shows up in dumb ways. Support answers with last month's behavior. Somebody re-files a bug that got fixed on Tuesday. Two of us wrote the same little helper in the same week.

None of that is a crisis. It just accumulates until nobody quite trusts their own sense of what's live, and then people start hedging in customer conversations, which is worse.

So the release note turned into an internal document that we also happen to publish.

The tag is ours

Cutting the tag is the one step we won't hand off.

A tag says this batch adds up to something worth telling people about. Some weeks we merge for four days and never tag, because it doesn't add up to anything. Some weeks one PR gets a tag to itself because it fixed something that had been quietly irritating people for a month. That call needs someone who remembers what we told customers in June.

Everything after it is mechanical. The range between the last tag and this one is the whole handoff.

Ask the thing that wrote it

Step four, in full:

Write up the Onset release notes since the last tag.

Claude pulls the merged PRs in that range with the GitHub CLI, reads the bodies and the diffs, and files a draft release in our own workspace through the MCP server. One-liners go in the changes list. The body gets prose when something needs a migration note.

We tried label mapping before this. It turns feat into New and fix into Fixed and then it's out of ideas, because a commit subject isn't a description of a change. A PR titled refactor tokenizer in search index comes back from Claude as:

Improved — Search matches partial words. Typing "subs" now finds "subscribers".

No lookup table gets you from the first string to the second. You have to have read the code.

I like that the tool that wrote the change is the one explaining it, but the symmetry isn't doing the work. Something that reads a diff can tell an internal refactor from a thing a customer will notice. fix: can't.

Somebody still reads it

The draft stays a draft. Nothing goes out until a person opens it.

Most releases I cut one line that turns out to be internal-only, and rewrite one that's true but written for us instead of for whoever's reading it. Call it five minutes. The version of this job I used to do was opening an empty text box on a Friday afternoon and trying to reconstruct two weeks from memory, which I did badly, and then didn't do at all for a month at a stretch.

Then it publishes, subscribers get the email, and so does everyone here.

If you want to copy it

The tools matter less than the shape. Let the agent draft it. Keep the tag human, because deciding where a release starts and stops is an editorial call. Keep the last read human, because that part is taste.

The piece I'd argue for hardest is writing the note for your own team first. We backed into that one, and now the note gets read internally before anyone outside sees it. The customer version is the same document with two lines taken out, which is a much easier thing to produce than whatever you'd write from scratch when someone asks what shipped this month.

Make every release count

Want to see Onset in action? Try it for free today. No credit card required.

Get started