Open source AI projects with GitHub releases in the past day, and what actually happens after the tag is published
Everyone ranks projects by stars, tags, and recency. Almost nobody shows you what happens between the GitHub release page and the user's Applications folder. This guide walks the full path using one real open-source AI project I can point at line-by-line: Fazm, a macOS AI agent whose entire release pipeline (appcast, EdDSA signing, channel routing, crash-loop rollback) is readable source code in its public repo.
Fazm GitHub releases, past 13 days
The cadence
0 real GitHub releases in 0 days
Every list for this query answers "what is new in the past 24 hours." A stable-enough answer is: a project with a high release cadence almost always has a release in the past day. Fazm shipped nine versions between April 3 and April 16, 2026. Every one of them exists on github.com/mediar-ai/fazm/releases. Every one of them is reflected in CHANGELOG.json in the repo root.
The full path
From `git push --tags` to `/Applications/Fazm.app`
The loop on the left is the release pipeline. The loop on the right is what Sparkle does on an existing install. The backend in the middle is the thing that no listicle ever explains: it polls GitHub on every request and turns a GitHub release into a Sparkle appcast on the fly.
GitHub release -> Sparkle appcast -> user Mac
The anchor fact (uncopyable part)
150 lines of Rust turn GitHub releases into a Sparkle feed
This is the entire mechanism. On every request to `/appcast.xml`, the backend hits `api.github.com/repos/mediar-ai/fazm/releases?per_page=20`, maps each release to a Sparkle item, and extracts the EdDSA signature from the release body with a regex. No database of releases. No cron job. The source of truth is GitHub, not a pipeline's scratch bucket.
What comes back when you curl the live endpoint
One pattern any open-source AI Mac project can copy
The same three-piece pipeline (GitHub Release on the left, a backend appcast in the middle, Sparkle on the right) works for any open-source desktop AI project. The only project-specific part is the repo name and the EdDSA public key.
GitHub releases -> dynamic appcast -> end-user binary
What happens when a new Fazm GitHub release lands
release.sh pushes a tag like v2.3.2-macos
release.sh in the repo root drives Codemagic to build, sign with the Developer ID, notarize via apple-notarize-worker, and attach Fazm.zip + the EdDSA signature to the GitHub release body. The tag format is enforced by the regex in appcast.rs at line 99.
Within 60 seconds, /appcast.xml reflects the new release
appcast.rs line 47 sets `Cache-Control: public, max-age=60`. The next time any client (or CDN) requests /appcast.xml, the backend calls api.github.com/repos/mediar-ai/fazm/releases?per_page=20 and parses the 20 most recent releases. The JSON -> XML translation is line 81-212.
Sparkle on the client checks every 10 minutes
UpdaterViewModel.swift line 361 sets `updateCheckInterval = 600`. When a newer shortVersionString is found, the delegate fires didFindValidUpdate (line 62-83). If the user was below MIN_SUPPORTED_VERSION = 2.1.0, the criticalUpdate flag makes the prompt non-skippable.
Sparkle downloads the .zip and verifies the EdDSA signature
Against SUPublicEDKey in Info.plist. If verification fails, the install is aborted and nothing is written to /Applications/. This is the per-release integrity check that lets the backend trust the GitHub release body contents.
UpdateRollbackManager.backupCurrentApp() runs willInstallUpdate
/usr/bin/ditto copies the current /Applications/Fazm.app into ~/Library/Application Support/Fazm/UpdateBackup/Fazm.app. This preserves code signature, xattrs, and resource forks. Backup happens before Sparkle overwrites the app, not after.
On relaunch, the rollback manager samples the launch pattern
Two UserDefaults keys, rollback_launchCount and rollback_launchTimestamp, track how many launches happened in the last 60 seconds. If launchCount reaches 3 within that window, the new version is declared a crash-loop and rolled back.
Rollback restores the backup and blocks the bad version
ditto again, this time from UpdateBackup/Fazm.app back to /Applications/Fazm.app. rollback_blockedVersion is written with the crashing shortVersionString. Sparkle's shouldProceedWithUpdate delegate (UpdaterViewModel.swift lines 92-101) then refuses that version on future checks.
The other uncopyable part
3 crashes, 60 seconds, rollback
The most interesting line is the timestamp threshold. Not a feature flag. Not a config value. A compiled constant. Changing it requires a release, which has to survive the rollback it configures, which is the kind of self-referential pressure that keeps the threshold sane.
What the log file looks like during a rollback
“const GITHUB_REPO = "mediar-ai/fazm"; one line of Rust that turns every new GitHub release into a Sparkle feed item, on every request, no cron.”
Backend/src/routes/appcast.rs, line 12
Standard listicles vs. this guide
Same query, two very different answers. One ranks tag names. The other explains the path between a tag and a running binary.
| Feature | Standard listicles | This guide (Fazm) |
|---|---|---|
| Answers 'what tagged in the past 24h' | Yes, usually a table of tag names | Yes, with 9 dated entries |
| Walks the full release pipeline line by line | Stops at the tag name | Seven timeline steps tied to source files |
| Quotes the exact Rust/Swift source that runs | None | appcast.rs + UpdateRollbackManager.swift |
| Shows the real curl output of the live appcast | None | Full terminal trace of /appcast.xml |
| Explains EdDSA signing and verification | Not mentioned | Extraction regex + SUPublicEDKey flow |
| Documents the crash-loop rollback thresholds | Not mentioned | 3 crashes in 60s, compiled constants |
| Links to a single OSI-licensed repo that has everything | Links out to many repos, no depth on any | github.com/mediar-ai/fazm |
Enforcement in a const
const MIN_SUPPORTED_VERSION: &str = "2.1.0";
Line 19 of appcast.rs. Any client running below 2.1.0 sees the latest update marked with Sparkle's criticalUpdate tag, which disables the 'remind me later' option and re-prompts aggressively on relaunch. This is how the Fazm team forces a minimum version floor without a migration script.
The floor was raised to 2.1.0 after the v2.1.0 release shipped the paywall and an auth change that must not be bypassable by running an older binary. Raising the floor is a one-line change in appcast.rs and a backend redeploy, same blast radius as changing the paywall logic itself.
What every other past-day-releases listicle skips
The plumbing between a tag and a running binary
- How a GitHub release body's edSignature line becomes the Sparkle sparkle:edSignature attribute
- Why the appcast polls GitHub live on every request with a 60s CDN cache, instead of running a cron
- How channel routing works when Firestore and GitHub's isPrerelease flag disagree
- What ditto does before Sparkle overwrites the .app (preserves code signature, xattrs, resource forks)
- How two UserDefaults keys (launchCount, launchTimestamp) detect a crash loop without Sentry or Firebase
- Why MIN_SUPPORTED_VERSION is a compiled const and what changing it actually costs
Frequently asked questions
Frequently asked questions
What qualifies as an 'open source AI project with a GitHub release in the past day'?
For this guide the bar is: (1) source code publicly available on GitHub under an OSI-approved license, (2) a GitHub Release (not just a commit or a tag) published within the past 24-48 hours, (3) the release ships a usable binary or package, not just a version bump. A lot of lists that surface for this query skip the binary requirement. The interesting projects are the ones that actually deliver something a user can run, not just projects that cut a tag and walk away.
Why is this page anchored on one specific Mac app instead of listing many projects?
Because the listicles already list the projects. What the listicles never explain is what happens after the tag is published: how the signed zip moves from github.com/owner/repo/releases/download/... to the user's /Applications/ directory, how signatures are verified, how the channel routing works, and what happens when a release crashes on boot. Fazm is a useful case because its release pipeline is entirely in the open repo and every step of 'what happens when a new GitHub release drops' is readable source, not a black box.
What is the anchor fact for this guide? Where can I verify it?
Two source files. Backend/src/routes/appcast.rs lines 12-19 declare `const GITHUB_REPO: &str = "mediar-ai/fazm";`, `const GITHUB_API: &str = "https://api.github.com";`, and `const MIN_SUPPORTED_VERSION: &str = "2.1.0";`. Lines 239-255 are the GitHub releases fetch. Line 47 sets `public, max-age=60` on the appcast response. Line 151 is the regex that extracts the EdDSA signature from the GitHub release body. Desktop/Sources/UpdateRollbackManager.swift lines 25-27 set `crashThreshold = 3` and `rapidCrashWindow = 60`. All four facts come from github.com/mediar-ai/fazm, open source.
How many releases did Fazm actually ship in the past 13 days?
Nine. From CHANGELOG.json: v2.0.1 (April 3), v2.0.6 (April 4), v2.0.7 (April 5), v2.0.9 (April 5), v2.1.2 (April 7), v2.1.3 (April 9), v2.2.0 (April 11), v2.2.1 (April 12), and v2.3.2 (April 16). One 'past day' release is common. Nine in 13 days means there is almost always one within the past 24-48 hours. The cadence is not accidental: the appcast backend polls GitHub releases on every request with a 60-second cache, so the moment a new tag with a .zip asset is published, every existing Fazm install will discover it within 10 minutes (the Sparkle `updateCheckInterval`, UpdaterViewModel.swift line 361).
How does the backend actually turn a GitHub release into a Sparkle appcast?
appcast.rs at generate_appcast() does it in one pass. It calls `api.github.com/repos/mediar-ai/fazm/releases?per_page=20` in parallel with a Firestore fetch for channel routing, finds the release asset whose name ends in .zip and does not contain 'appcast', parses the tag via the regex `v?(\d+\.\d+\.\d+)(?:\+(\d+))?(?:-macos)?(?:-(staging|beta))?`, pulls the EdDSA signature out of the release body with another regex, converts the 'What's New' section of the release body into HTML list items, and emits one <item> per (release, channel) pair. No cron job, no webhook. Every appcast.xml request does the live fetch with a 60-second CDN cache.
What does 'channel routing via Firestore' mean and why does it exist alongside GitHub's isPrerelease flag?
Firestore holds a `desktop_releases` collection where each document is a tag-to-channel assignment (stable, beta, staging). On every appcast request, the backend fetches that map in parallel with GitHub and uses Firestore as the authoritative source. If Firestore is unreachable, it falls back to the tag suffix heuristic: `-staging` suffix means staging channel, otherwise stable. The reason Firestore exists on top of GitHub's isPrerelease flag is that Fazm supports three channels (stable / beta / staging), not two, and Fazm promotes releases between channels after the tag has already been published. Changing a channel should not require re-cutting a release.
What is the crash-loop rollback protection and how do the thresholds work?
UpdateRollbackManager.swift ships three phases. Phase 1 fires inside Sparkle's willInstallUpdate delegate: it runs /usr/bin/ditto to copy the current /Applications/Fazm.app into ~/Library/Application Support/Fazm/UpdateBackup/. Phase 2 runs on every launch: it reads two UserDefaults keys, `rollback_launchCount` and `rollback_launchTimestamp`. If three launches happen with less than 60 seconds between each, we are in a crash loop. Phase 3 restores the backup over the broken app, writes `rollback_blockedVersion = <crashing version>`, and Sparkle's shouldProceedWithUpdate delegate then refuses that version (UpdaterViewModel.swift lines 92-101). The two thresholds are literal values in the source: `crashThreshold = 3` and `rapidCrashWindow = 60`, lines 25-27.
Why does the appcast force `sparkle:criticalUpdate sparkle:version="2.1.0"` on every item?
Because the Fazm team needed to enforce a hard floor for a paywall and auth change that shipped in v2.1.0. Sparkle's criticalUpdate tag tells any client below that version to show a non-skippable prompt on the next check. Every version below 2.1.0 effectively has to update. This is the reason `MIN_SUPPORTED_VERSION` is a const in appcast.rs rather than a config value: changing the floor requires a backend deploy, which is the same blast radius as changing the paywall logic itself.
Is there a way to verify the EdDSA signature that ends up in the appcast?
Yes. The release notes include a line of the form `edSignature: MEUCIQD...` or similar. The backend regex at appcast.rs line 151 extracts any Base64 string of 40 or more characters that follows the literal `edSignature`. Sparkle on the client then verifies that signature against the Fazm EdDSA public key baked into Info.plist before extracting the zip. If the signature is missing, malformed, or does not verify, Sparkle refuses to install. verify-release.sh in the repo root runs this end-to-end: it downloads the appcast, extracts the edSignature and download URL, fetches the zip, and runs the sign_update --verify tool from Sparkle's bin/ directory. No install, just verification.
How does Fazm compare to screenshot-based AI agents on the 'past-day release' angle?
Screenshot-based agents have a very different release surface: they ship model weights and a thin client. Fazm ships a binary that reads the macOS accessibility tree directly via AXUIElementCreateApplication and AXUIElementCopyAttributeValue (AppState.swift line 439 area). The update path has to ship the binary, not just model weights, so the infrastructure described in this guide (Sparkle, EdDSA, ditto backup, crash-loop rollback) is required. A screenshot-based cloud agent can roll out a new model with a Firestore feature flag and no client release. Different shape of past-day release.
Can I build the same thing for my own open-source AI project?
Yes. The three load-bearing pieces are: (1) a small HTTP endpoint that polls api.github.com/repos/OWNER/REPO/releases and emits a Sparkle appcast (150 lines of Rust, or ~200 of Go/Node), (2) Sparkle framework on the client with EdDSA signing (generate_keys once, sign_update per release, store the public key in Info.plist's SUPublicEDKey), (3) a rollback manager on the client that tracks launch timestamps in UserDefaults and keeps a backup of the current .app bundle. Every file in Fazm's repo that implements this is open-source: Backend/src/routes/appcast.rs, Desktop/Sources/UpdateRollbackManager.swift, Desktop/Sources/UpdaterViewModel.swift, release.sh, verify-release.sh.
Try Fazm, then read its release pipeline in the open
Download the Mac app, watch Sparkle pull the latest appcast on first launch, then open Backend/src/routes/appcast.rs in the repo. Every part of the pipeline described on this page is open source at github.com/mediar-ai/fazm.
Download Fazm →
Comments
Public and anonymous. No signup.
Loading…