I now have four things that ship releases: Codex, Codex Reader, Tsundoku and Idle Beekeepers. Their release notes were spread across GitHub releases, the App Store, and a private repository nobody else can see. So I built one page for all of them: updates.4sh.dev.

One card per project with its current version, and the latest updates across all of them.
How it works
It’s a static site. Once a day, a scheduled job imports new GitHub releases and App Store versions, keeps the features and fixes, and drops the noise (refactors, tests, chores). Each project gets a page with a short description and its full history.

A project page: what the app is, then every update.
The part that matters: a feed for Codex
The site also publishes a feed for each project, and Codex 2.7.0 now reads it.
Once a day, a Codex server downloads the Codex and Codex Reader feeds. Admins get a news icon in the header with an unread marker, and a drawer with the release notes. The sidebar shows the running version, and when a newer one exists it shows something like v2.6.3 → 2.7.0. Clicking it lists what changed in every version in between.
I was careful about privacy here, because every self-hosted Codex will make this request:
- It’s a plain download of a static file, with nothing that identifies the server or its version.
- “Is there an update?” and “what’s unread?” are worked out locally, on your server.
- If it fails, nothing breaks: a server without internet access just shows an empty drawer.
- One setting turns it off entirely, and then no request is made at all.
The feed is also a promise. Every Codex release with this feature will keep requesting it for years, so its address and format can’t change in a way that breaks them.
It’s a small project, but it closes a gap that matters for anything self-hosted: telling people a new version exists without learning anything about their server.
