Open-source AI projects with GitHub release updates in the past day, and the three Swift functions that decide whether the update reaches your Mac
Lists for this query rank projects by stars and tag dates. None of them mention the part that matters to a user: on macOS 26 the install fails with SUInstallationError 4005 unless the developer shipped a launchctl kickstart loop, an App Management permission probe, and a blocked-version refusal. This guide walks the three short Swift functions Fazm ships in its public repo to make a same-day GitHub release actually land in /Applications/.
What every list for this query misses
A tag is not an update. An update is what lands in /Applications/.
Search results for "open source ai projects github releases updates past day" almost always return the same shape: a table of repos with a star count, a tag name, and a publication date. The unstated assumption is that publishing a tag and shipping an update to a user are the same event.
On macOS 26 they are very much not the same event. Between the tag and the user's /Applications/ folder there is a Sparkle installer call, an SMJobSubmit invocation, an AuthorizationCreate check, a launchd service that may refuse to start, and an App Management permission gate that did not exist a year ago. Any one of these can quietly fail. When they do, the user sees no update, no error, no nothing. Sparkle logs SUSparkleErrorDomain code 4005 and exits.
The interesting question is not which projects published a release in the past 24 hours. The interesting question is which projects wrote the workaround code that makes that release reach the user on the current macOS. Fazm did. The functions are short. They live in three contiguous places in one Swift file.
The same GitHub release on macOS 26
Project ships a Sparkle-based update with no macOS 26 workarounds. User clicks Install. The update appears to start. The app silently never updates because SMJobSubmit returned 4005 and the Sparkle dialog closed without surfacing the error.
- User has no idea the update failed
- Tag exists on GitHub, but no install on disk
- Repeats every 10 minutes; user eventually disables auto-update
- Project ships a 'past-day release' that nobody on macOS 26 actually has
The anchor fact
Three Swift functions, one file, all in the public repo
The Sparkle docs say none of this. Apple's release notes say none of this. Every workaround below is in one file at Desktop/Sources/UpdaterViewModel.swift, MIT-licensed, readable in the open.
kickstartSparkleServices()
Lines 209-238. Schedules three Process calls to /bin/launchctl with arguments 'kickstart', '-p', 'gui/<uid>/<bundleID>-sparkle-updater', delayed 0.5s, 2.0s, and 5.0s after Sparkle's didExtractUpdate. Three retries because timing variance under macOS 26 on-demand-only launchd mode can drop a single retry. Best effort: ignores all errors.
probeAndUnlockAppManagement()
Lines 414-439. Tries to create a one-byte file at Bundle.main.bundlePath + '/Contents/.fazm-permission-test'. If the create succeeds, App Management permission is granted; the file is removed, hasSuccessfullyInstalledSparkleUpdate is set, and the 'done' guide window appears with a button that auto-triggers checkForUpdates().
shouldProceedWithUpdate() blocklist
Lines 88-101. Reads UpdateRollbackManager.blockedVersion from UserDefaults. If the offered version matches, throws an NSError with domain com.fazm.rollback. Sparkle treats the throw as 'do not present the update.' The block clears automatically when GitHub publishes a newer tag.
didAbortWithError 4005 branch
Lines 173-193. When Sparkle returns SUInstallationError, sets hasSeenAppManagementError flag, resets hasSuccessfullyInstalledSparkleUpdate to false (so the proactive guide shows next time), and surfaces AppManagementSetupWindowController with explicit Quit & Reopen instructions.
Function 1 of 3: kickstartSparkleServices()
macOS 26's "on-demand-only mode" for user-agent launchd services means a service submitted by Sparkle's installer with RunAtLoad=YES does not actually start. Sparkle 2.9.0 added a built-in probe via PR #2852, but timing variance can still drop the wake-up. Three calls to launchctl kickstart at staggered delays beat the variance.
Function 2 of 3: probeAndUnlockAppManagement()
macOS does not expose a clean API to ask "is App Management permission granted right now." The probe asks the only way that works: try to write a one-byte file inside the app bundle. A successful write is the permission grant. The probe runs on every launch when there is a pending guide.
Function 3 of 3: blocked-version refusal in shouldProceedWithUpdate
High release cadence is only safe when bad versions die quickly. The crash-loop detector writes the bad version to UserDefaults at rollback_blockedVersion. Sparkle's shouldProceedWithUpdate delegate then throws when the version it wants to install matches the blocked version, until a NEWER tag ships and clears the block.
Log file when the workarounds work
Log file when permission is missing (and how the probe rescues it)
How the three functions slot into the install path
Sparkle drives the install. The three Fazm functions hook in at the three points where macOS 26 can break it.
GitHub release -> Sparkle install -> /Applications/Fazm.app
What happens between a same-day GitHub release and your Mac
- 1
Tag pushed to GitHub
release.sh runs Codemagic build + sign + notarize
- 2
/appcast.xml polls in 60s
Backend fetches GitHub releases live, caches 60s
- 3
Sparkle discovers in <11 min
updateCheckInterval = 600 seconds
- 4
Workaround functions fire
Probe + kickstart + blockedVersion gate
- 5
Install lands in /Applications/
ditto backup, then Sparkle replaces the app
The timing constants that absorb the variance
Why three retries at [0.5, 2.0, 5.0] seconds
A single launchctl kickstart at 1 second after didExtractUpdate works most of the time but loses to about 1 in 30 installs under macOS 26's on-demand-only launchd mode. The three staggered retries cover three failure modes: the launchd service has not been registered yet (0.5s catches the fast case), the registration completed but the daemon is debouncing wake-ups (2.0s catches the typical case), the system is under heavy load right after Sparkle relaunched its installer process (5.0s catches the slow case).
Errors from each Process invocation are intentionally swallowed. If the service was already running, kickstart returns nonzero and that is fine. If it does not exist yet, kickstart returns nonzero and the next retry tries again. The only goal is "at least one of these three runs the service."
The release pressure that forced these workarounds
Five same-day-eligible releases, each with a specific fix
Every fix below was driven by a real install failure on a real user's Mac. The CHANGELOG entries are public on github.com/mediar-ai/fazm/releases.
“"All detection/restore code uses only Foundation + logSync — no Firebase, Sentry, or PostHog (those frameworks might be what is crashing)."”
Desktop/Sources/UpdateRollbackManager.swift, line 11
Standard listicles vs. this guide
Same query, two very different answers.
| Feature | Standard listicles | This guide (Fazm) |
|---|---|---|
| Names projects with same-day releases | Yes, usually a table of tag names | Yes, five tagged versions in 9 days |
| Explains why the install can fail on macOS 26 | Not mentioned | SMJobSubmit + on-demand launchd + permission gate |
| Quotes the exact Swift function that fixes it | None | kickstartSparkleServices() in full |
| Documents the App Management permission probe | Not mentioned | 23-line probe with the temp-file path |
| Explains how a bad release dies quickly | Not mentioned | blockedVersion refusal in shouldProceedWithUpdate |
| Links to a single OSI-licensed repo with everything | Links to many repos, no install-side detail | github.com/mediar-ai/fazm |
Why this lives in the binary, not in a server flag
Real accessibility APIs mean the agent ships in the .app
Fazm reads the macOS accessibility tree directly via AXUIElementCreateApplication, not via screenshots routed through a cloud model. The agent code that orchestrates a Mac action lives inside the .app bundle. Improving the agent means shipping a binary update, which means going through the macOS 26 installer constraints described above.
A screenshot-based cloud agent ships its "updates" as Firestore feature flags. No installer involved, no permission gate, no launchd service to kickstart. Their answer to "updates in the past day" is a server-side toggle that flips for every user instantly.
Fazm's answer is a real release on github.com/mediar-ai/fazm, verified end-to-end by an EdDSA signature, installed by Sparkle, backed up by ditto, refused if it crash-loops. That is a heavier update path. It is also the only way to get an AI agent that reads any app on your Mac via real accessibility APIs onto a Mac running macOS 26.
Frequently asked questions
Frequently asked questions
What does 'updates in the past day' actually mean for the user of an open-source AI Mac project?
It means the developer pushed a tag, GitHub built the release, and your machine has to install it. On macOS 26 the install side is the part that breaks. Sparkle, the standard Mac auto-updater, calls SMJobSubmit to launch a privileged installer service. macOS 26 introduced an 'on-demand-only' launchd mode and stricter code signature validation that together cause SUInstallationError code 4005 unless the app has App Management permission and the developer manually kickstarts the launchd service. Almost no listicle for this query mentions any of that.
What is the anchor fact for this guide and where can I verify it?
Three Swift functions in github.com/mediar-ai/fazm. (1) kickstartSparkleServices() at Desktop/Sources/UpdaterViewModel.swift lines 209-238 retries `launchctl kickstart -p gui/<uid>/<bundleID>-sparkle-updater` at 0.5s, 2s, and 5s. (2) probeAndUnlockAppManagement() at lines 414-439 writes a temp file to `Bundle.main.bundlePath + "/Contents/.fazm-permission-test"` to detect when the user has granted App Management permission, then auto-resumes the install. (3) shouldProceedWithUpdate() at lines 88-101 throws when the new version equals UpdateRollbackManager.blockedVersion, refusing to install a tag that just crash-looped. All three are MIT-licensed source code, readable in the public repo.
Why does macOS 26 break Sparkle's normal install flow?
Two changes. First, launchd on macOS 26 can run in 'on-demand-only mode' for user agents, which means a service submitted via SMJobSubmit with RunAtLoad=YES does not actually start at load time, only when something pings it. Sparkle 2.9.0 added a built-in probe via PR #2852, but the probe still does not always succeed under timing variance, which is why Fazm runs `launchctl kickstart` three times at 0.5s, 2.0s, and 5.0s after Sparkle's didExtractUpdate fires. Second, the system enforces App Management permission for any tool that wants to overwrite an app inside /Applications/. If the user has not granted it, AuthorizationCreate inside Sparkle's installer fails with NSOSStatusErrorDomain -60005, which Sparkle surfaces as SUSparkleErrorDomain code 4005.
How does the App Management permission probe actually work?
macOS does not expose a clean 'is App Management granted' API for sandboxed processes. Fazm probes by trying to write a one-byte temp file at Bundle.main.bundlePath + '/Contents/.fazm-permission-test'. If the create succeeds, the file is deleted immediately and the app sets `hasSuccessfullyInstalledSparkleUpdate = true` in UserDefaults so the next update goes through Sparkle's normal UI without a guide. The probe runs on every launch but only when there is a pending guide for the previously-blocked version. The whole function is 23 lines of Swift in UpdaterViewModel.swift.
How fast does an update from a same-day GitHub release actually reach the user?
The cap is around 11 minutes. The backend appcast at fazm-backend caches GitHub's releases response for 60 seconds, so a new tag is reflected in /appcast.xml within a minute. Sparkle on the client polls every 600 seconds (UpdaterViewModel.swift line 361 sets `updateCheckInterval = 600`), and that timer fires uniformly distributed in [0, 600], so the median wait from tag-push to client-discovers-update is around 5 minutes 30 seconds, with a worst case at 11 minutes plus the cache TTL. After discovery, a successful install with the kickstart workaround typically completes in 4-8 seconds. If the user has not granted App Management permission yet, the App Management guide window appears instead of Sparkle's dialog, and the install pauses until they grant it.
How does the rollback interact with 'updates past day'?
If the new release crash-loops, three launches in 60 seconds triggers a rollback. The rolled-back version is stored in UserDefaults at `rollback_blockedVersion`. On the next Sparkle check, shouldProceedWithUpdate sees the available version equals blockedVersion and throws an NSError with domain `com.fazm.rollback`. That throw blocks the install and tells PostHog the version was blocked. The block clears automatically when GitHub publishes a NEWER version, which is exactly what makes a high cadence of past-day updates safe: a bad release is dead within minutes and the next tag fixes it without manual intervention.
Which Fazm releases shipped these specific workarounds?
v2.1.2 (Apr 7) added the 4005 detection branch in didAbortWithError that sets the `hasSeenAppManagementError` UserDefaults flag and resets the success flag so the App Management guide shows again. v2.1.3 (Apr 9) wired the guide ahead of Sparkle's UI in shouldProceedWithUpdate. v2.2.0 (Apr 11) added probeAndUnlockAppManagement() to the launch path so granting the permission and reopening would auto-resume. v2.2.1 (Apr 12) added the third retry of launchctl kickstart at the 5.0-second delay after FAZM-9K. v2.3.2 (Apr 16) is the first release after macOS 26.1 brought even stricter SMJobSubmit checks. Every one of these is a public tag at github.com/mediar-ai/fazm/releases.
Why log synchronously instead of using PostHog or Firebase here?
Because the logger is the only thing you can trust during a Sparkle install. The comment at UpdaterViewModel.swift line 45 spells it out: 'Sparkle may terminate the app immediately after willInstallUpdate / didAbortWithError, so async logging would be lost.' UpdateRollbackManager goes further at line 11: 'All detection/restore code uses only Foundation + logSync — no Firebase, Sentry, or PostHog (those frameworks might be what is crashing).' If the update is bad, the analytics SDK might be the bug. The crash-loop detector cannot depend on it.
Can I copy this pattern for my own open-source AI project?
Yes. The minimum is three short Swift functions and one Sparkle delegate. (1) Implement kickstartSparkleServices(): at the end of didExtractUpdate, schedule three Process invocations of `/bin/launchctl kickstart -p gui/<uid>/<bundleID>-sparkle-updater` at 0.5s, 2.0s, 5.0s. (2) Implement probeAndUnlockAppManagement(): on every launch, if you have a pending guide, try to write a temp file inside Bundle.main.bundlePath + '/Contents/'; success means permission is granted. (3) Implement shouldProceedWithUpdate to throw when the version matches a stored blockedVersion key in UserDefaults. The total is around 80 lines, mostly defensive logging. Copy from Desktop/Sources/UpdaterViewModel.swift.
How is this different from screenshot-based AI agents that update?
Screenshot-based cloud agents push model updates server-side. Their 'release' is a Firestore feature flag, not a binary install. Fazm reads the macOS accessibility tree directly via AXUIElementCreateApplication, which means the agent code lives inside the .app bundle, which means a model improvement OR an agent improvement requires a real binary update through Sparkle. That puts macOS 26's installer constraints squarely on the critical path. A consumer-friendly desktop AI app on the latest macOS has to ship its own Sparkle workarounds. There is no other option.
How do I find other open-source AI projects that handle this correctly?
Look for three signals in the repo. First, a Swift file named UpdaterViewModel, UpdaterDelegate, or anything subclassing SPUUpdaterDelegate. Second, the substring 'launchctl kickstart' anywhere in the Swift sources (without it, the app will hit 4005 on macOS 26 and most users will give up). Third, the substring 'shouldProceedWithUpdate' implementing a version blocklist. If a repo has an SPUUpdaterDelegate but none of those three things, the project's same-day GitHub releases are not actually reaching users on macOS 26.
See the workarounds run on your own Mac
Download Fazm. The first auto-update will exercise every function on this page. If you are on macOS 26 and have not granted App Management permission, the probe-driven guide is what you will see.
Download Fazm →
Comments (••)
Leave a comment to see what others are saying.Public and anonymous. No signup.