Back to blog
·5 min read·Cell Webb

A Release Note Needs a Destination

What an opt-in GitHub Release integration taught us about event seams, ownership markers, and leaving human notes alone.

A release note has a small identity problem: it can be accurate and still be in the wrong place.

The page where a project keeps its changelog is useful. Developers also look at the repository and the release that introduced a change. A release note needs a destination that follows the work.

On July 21, 2026, KittyLog added an opt-in path for that destination. When a repository turns on publish_to_github_release, a generated changelog can be written to the matching GitHub Release in tag mode. The integration was shipped as a separate event handler rather than folded into the main publish function.

The publish event is the seam

The useful part of this change is the seam around the GitHub API call.

KittyLog already has a publish event. The release integration listens for ChangelogPublishedEvent, checks the repository setting, and checks that the event has a version. A scheduled changelog has no Git tag to identify a GitHub Release, so the handler skips it. A tag-mode publish has the identity needed to find or create the corresponding release.

That keeps the existing publish flow from knowing every place a changelog might go. Adding a destination becomes an event subscriber with its own gates, tests, and failure path. The same shape is useful outside changelogs. A successful payment or a completed build often needs several follow-up actions. An event gives those actions a place to attach without turning the original operation into a list of unrelated integrations.

Do not overwrite the room

The difficult case is a release that somebody has already edited.

The integration stamps every body it writes with an invisible kittylog-release marker. If the existing body is empty, KittyLog can fill it. If the marker is present, KittyLog recognizes content it owns and can update it on a later run. If the body is non-empty and has no marker, the integration skips it and warns instead of replacing a human-authored release note.

That policy is intentionally narrower than “keep the release synchronized.” Synchronization sounds tidy until two systems both believe they own the same paragraph. The marker makes ownership explicit enough to avoid a silent clobber. It also leaves an operator with a visible decision when a release has been edited by hand.

The integration only reacts to a tag-mode publish and targets the release associated with that version. That keeps it from manufacturing a release for a scheduled period or guessing what a repository considers a version.

Failure should stay local

GitHub can be unavailable. A release can collide with a human edit. The installation token can fail. None of those should turn a successful changelog publish into a failed publish.

The release handler catches expected failures, logs the outcome, and routes failures and collision skips through the existing notification path. That gives the repository owner a follow-up while the primary publish operation remains independent of the secondary destination. The notification path applies a per-repository cooldown, so a temporary problem does not become an email storm.

This is a useful trade-off to make explicit. A changelog can be published even when its optional copy to a GitHub Release did not happen. The system reports the missing copy, but it does not pretend that the two writes were one atomic transaction.

A page is not the whole workflow

The original instinct for a changelog product is to build a good public page and stop there. The repository is where a lot of the surrounding work already happens, though. Issues and tags live there, and releases are inspected there. Putting a generated note in the matching release removes one copy-and-paste step without asking the release page to become a second source of truth.

That last part is the boundary I like. KittyLog owns the body only when it can prove that it wrote the body. A repository owner can keep an existing note, edit it manually, or leave the integration off. The feature is useful because it fills a gap while leaving every other release surface in the owner's hands.

The implementation is small enough to explain in a paragraph, but the collision policy is the part worth keeping. Destinations multiply as a product grows, and the ownership marker is the piece I expect to reuse for the next one.

Source records

  • Issue #1069 and PR #1344, the KittyLog repository records for publishing generated changelogs to GitHub Releases (merged 2026-07-21).
  • GitHub Releases documentation

Ready to automate your changelogs?

Try KittyLog free - no credit card required.

Get Started Free