The v2.4.0 release where a consumer Mac agent stopped hardcoding Claude model IDs.
Every roundup for the April 20-21, 2026 window covers the household names: Claude Opus 4.7, OpenAI Agents SDK, Ollama, vLLM, llama-stack, Continue. Useful if you want headline repos. Not useful if you want to see what actually shipped in the quiet corner of the MIT-licensed consumer AI tooling world. This guide zooms into one release: fazm v2.4.0 on April 20 at 10:41 PT, and the one architectural change inside it that answers a real question every downstream Claude consumer eventually asks. Three short aliases replaced three pinned model IDs. New Claude versions now light up on next session, not next DMG.
WHAT EVERY OTHER GUIDE COVERS
The household names for this window
Open the question, read the first ten pages of coverage, and the same repos show up in every list. OpenAI and Anthropic, Meta and Ollama, a couple of lock-step awesome-lists. Coverage overlap is north of eighty percent. You walk away with a good read on what the big labs announced and zero read on what actually shipped in the long tail of consumer-facing MIT-licensed work.
Every one of those is real and worth reading about somewhere. What is missing in that coverage: one level below the press releases, there are MIT-licensed consumer AI tools shipping daily work that answers questions the frameworks keep dodging. This page picks exactly one, zooms into one release, and stays there long enough to show the architecture.
THE ANCHOR FACT
Three full Claude IDs collapsed to three aliases
The center of this page is one file: Desktop/Sources/FloatingControlBar/ShortcutSettings.swift. Before April 18, it held three ModelOption entries with ids like claude-sonnet-4-6. After commit 8b4ad3bf on April 18, 2026 at 14:04 PT, the same entries hold the ids haiku, sonnet, opus. The normalizer below it flipped direction too: it used to map aliases up to full IDs, now it maps any full ID down to one of three aliases. That change shipped to users in v2.4.0 on April 20 at 10:41 PT.
The model-ID decoupling in ShortcutSettings.swift
// Desktop/Sources/FloatingControlBar/ShortcutSettings.swift
// Before commit 8b4ad3bf (pre-April 18, 2026)
static let defaultModels: [ModelOption] = [
ModelOption(id: "claude-haiku-4-5-20251001",
label: "Scary (Haiku)",
shortLabel: "Scary"),
ModelOption(id: "claude-sonnet-4-6",
label: "Fast (Sonnet)",
shortLabel: "Fast"),
ModelOption(id: "claude-opus-4-6",
label: "Smart (Opus)",
shortLabel: "Smart"),
]
static func normalizeModelId(_ modelId: String) -> String {
if modelId.hasPrefix("claude-") { return modelId }
switch modelId {
case "haiku": return "claude-haiku-4-5-20251001"
case "sonnet": return "claude-sonnet-4-6"
case "opus": return "claude-opus-4-6"
default: return modelId
}
}The delta is small. The meaning is not. The app is no longer making a claim about which Claude models exist. It is saying I know there are three families, ask the agent which specific version is current. When Anthropic releases a new Sonnet or a new Opus, the next agent response will carry the new full ID, the UI will show it, and nobody has to cut a signed DMG.
THE 50-SECOND RELEASE BURST
How a 21-day trial became a 1-day trial, in one commit per ten seconds
The other headline change in v2.4.0 is the free trial. The interesting part is how fast it shipped. Four commits, two languages, four files, fifty seconds of wall-clock commit time on the morning of April 20. One hour and three minutes later, v2.4.0 went out.
09:37:57 PT, commit 5b812cbb
Backend/src/config.rs, Rust, one line. STRIPE_TRIAL_DAYS default drops from 21 to 1 for every new checkout session the backend mints.
09:38:09 PT, commit 42e42e76
Desktop/Sources/Chat/PaywallSheet.swift, Swift, two strings. The SwiftUI paywall copy flips from 21 days free, then $49/mo to 1 day free, then $49/mo, including the referral-credit variant.
09:38:36 PT, commit 5f0e997d
Desktop/Sources/Providers/ChatProvider.swift, Swift, four lines removed. The bridgeMode != builtin excuse disappears from the pre-query paywall check. Built-in mode is no longer exempt.
09:38:47 PT, commit a6c5a416
Desktop/Sources/Providers/SubscriptionService.swift, Swift, one line. The in-memory trial-days constant matches the backend and the paywall. Sequence closed.
Rust backend, Swift SwiftUI, Swift provider, Swift service. Four files kept in lockstep because a mismatch between any two of them would have meant a UI saying 21 days while the Stripe session said 1, or a local counter running on the old trial length. The release at 10:41 PT bundled all four. Nothing was left half-shipped for later.
REPRODUCE IT
One shell pane, every claim on this page
The repo is public. None of the numbers above come from a marketing doc. Clone it and run:
THE PATTERN
Pinned IDs versus agent-reported aliases, by what the choice actually costs you
Most client apps that wrap Claude have to pick one of two strategies. You can pin a specific model ID in your code, or you can delegate model resolution to an agent protocol that reports the current list at runtime. The two sides look like this in practice.
| Feature | Pinned model IDs | Fazm v2.4.0 (agent-reported) |
|---|---|---|
| How a new Claude model reaches users | Next signed DMG, notarized, auto-updated | Next session after Anthropic publishes it |
| What the app stores in user preferences | Full dot-version (claude-sonnet-4-6) | Short alias (haiku, sonnet, opus) |
| Stale-model risk if release cadence slows | Users can drift a full model version behind | None, the agent resolves to current |
| Fallback if the agent reports nothing | Hardcoded list the app was shipped with | Three defaultModels aliases in Swift |
| Migration for users upgrading from v2.3.x | Usually a one-time store-and-forget upgrade | normalizeModelId substring-matches legacy IDs |
| Can a user pin an exact dot-version? | Yes, that is the only option | Yes, full IDs still pass through unchanged |
The v2.4.0 choice is the left column, with a deliberate escape hatch in the normalizer so any user who wants to keep their old full ID still can. The substring match in normalizeModelId is the forgiving part. Pass in claude-sonnet-4-6 and you get sonnet. Pass in some other string, you get it back unchanged. The agent decides what to do next.
THE NORMALIZER, ANNOTATED
Nine lines of Swift that quietly answer the pin question
The most commented-on decision in the release is compact enough to read in one glance. Here is the whole normalizer as it stands after April 18, with the one-line comment the commit left in place.
The function is called on every app launch against the user's stored model preference before it is handed to the Claude agent. Anything containing one of the three substrings collapses. Anything else passes through. The agent, not the app, decides which specific Sonnet or Opus the user gets. That is the entire v2.4.0 architectural story in nine lines.
THE TAKEAWAY IN ONE NUMBER
0 days
Time between Anthropic publishing a new Claude model and a v2.4.0-or-later Fazm user seeing it in their model picker, assuming the agent protocol side already supports the family. Before April 18, that number was however long it took to cut, sign, notarize, and auto-update a DMG. After April 18, it is one new chat session.
THE REST OF THE RELEASE
Everything in v2.4.0, end to end
The full v2.4.0 entry in CHANGELOG.json has ten line items. The model-ID decoupling and the trial cut are the two that matter architecturally and commercially. Here is the rest, verbatim from the shipped changelog.
shipped in v2.4.0 on 2026-04-20
- Added custom MCP server support via ~/.fazm/mcp-servers.json with a Settings UI to add, edit, and toggle servers
- Available AI models now populate dynamically from the agent, so newly released Claude models appear without an app update
- Added Referrals section to Settings with a $49 credit banner on the paywall
- Upgraded Claude agent protocol to v0.29.2
- Fixed follow-up messages not appearing when sent during a streaming response
- Fixed AI responses occasionally splitting mid-word into separate bubbles
- Updated default model selection and simplified model labels
- Enlarged the chevron button hit area in AI response view
- Paywall now triggers after 3 messages for all users, including built-in mode
- Shortened free trial from 21 days to 1 day
WHY THIS BELONGS IN AN APRIL 20-21 ROUNDUP
What MIT-licensed consumer AI tooling actually did this weekend
The reason this release is worth a page: consumer AI tooling is a different operating environment from developer frameworks. A developer framework pinning a model ID costs its users a pip install --upgrade. A consumer DMG pinning the same ID costs its users a sign, notarize, staple, auto-update cycle that can drag out for days. The right answer, if you are a consumer app, is to stop pinning. v2.4.0 is what that looks like when it ships.
The other angle: Fazm reads the focused app's content through the macOS Accessibility tree rather than screenshots. That architectural choice pairs well with this release. Accessibility gives typed fields, hierarchies, and roles, so the app can work against any Mac app and not only the browser. Decoupling the model from the shipping app is the runtime side of the same idea: stop pinning anything you do not need to pin, read what is actually there, react to it.
Want the real v2.4.0 walkthrough on a call?
Fifteen minutes with the team behind this release. We will share screen, open the diffs, and show the model-ID migration live on a Mac.
Book a call →Frequently asked questions
What were the big open source AI updates on April 20-21, 2026?
The headline-grabbing work that every roundup for this window covers: Claude Opus 4.7 continuing its rollout, OpenAI Agents SDK momentum, Ollama and vLLM engine tweaks, and the usual stars on llama-stack and Continue. What no roundup covers: v2.4.0 of Fazm (github.com/mediar-ai/fazm), an MIT-licensed consumer Mac AI agent. It shipped on April 20, 2026 at 10:41 PT. The single architecturally interesting change in the release is that the app stopped pinning Claude model IDs. The default model list is now three short aliases (haiku, sonnet, opus), and the real ID comes from the agent protocol at runtime. When Anthropic releases a new Claude, Fazm picks it up on the next session, no app update needed.
How can I verify the v2.4.0 release date and the model-ID change myself?
Clone github.com/mediar-ai/fazm and run: git show dfe79ee5 to see the CHANGELOG.json entry for v2.4.0 dated 2026-04-20. Then run git show 8b4ad3bf to see the diff on Desktop/Sources/FloatingControlBar/ShortcutSettings.swift where the defaultModels array flipped from ids like claude-sonnet-4-6 to the short alias sonnet. Commit 8b4ad3bf landed on April 18, 2026 at 14:04 PT and shipped to users as part of the April 20 v2.4.0 release. Every claim on this page falls out of the repo.
Why is decoupling the model ID from the app a non-obvious engineering decision?
Because every downstream Claude API consumer eventually hits the pin-versus-track problem. If you pin a full model ID like claude-sonnet-4-6 in your Swift, your users are stuck on that version until you cut a new build and push it through Mac signing, notarization, and auto-update. If you pass the user's preference to the agent as a short family alias (haiku, sonnet, opus) and let the agent resolve it server-side, the freshest model for that family lights up the same day Anthropic publishes it. The trade-off: users lose the ability to pin a specific dot-version. The April 18 commit 8b4ad3bf made the explicit choice, keeping a tiny normalizeModelId helper to collapse any legacy full ID in a user's saved preferences back to the three aliases.
What other changes shipped in Fazm v2.4.0 on April 20, 2026?
Ten line items in CHANGELOG.json. The most visible to end users: custom MCP server support via ~/.fazm/mcp-servers.json (from the April 16 burst), a Referrals section in Settings with a $49 credit banner on the paywall, upgrade to Claude agent protocol 0.29.2, a fix for follow-up messages not appearing during streaming, a fix for AI responses splitting mid-word, and a paywall change that now triggers after three messages for all users including built-in mode. The least visible and most business-critical: the free trial was shortened from 21 days to 1 day.
How fast did the 21-day to 1-day trial cut actually ship?
Fifty seconds of wall-clock commit time across two languages and four files. Starting commit: 5b812cbb at 09:37:57 PT on Backend/src/config.rs (Rust, one line, STRIPE_TRIAL_DAYS default 21 to 1). Then 42e42e76 at 09:38:09 PT on Desktop/Sources/Chat/PaywallSheet.swift (Swift, two strings in the SwiftUI paywall copy). Then 5f0e997d at 09:38:36 PT on Desktop/Sources/Providers/ChatProvider.swift (removed the built-in mode bypass from the paywall check, four lines). Closing at 09:38:47 PT: a6c5a416 on SubscriptionService.swift (one line). Whole sequence: fifty seconds. Release followed at 10:41 PT, sixty-three minutes later.
Why does the Fazm paywall check now apply to built-in mode too?
Because commit 5f0e997d on April 20 removed a two-condition guard from ChatProvider.swift that previously excused built-in mode from the daily free message count. The old comment read builtin mode uses the bundled Anthropic key and is always allowed. That comment and the branch bridgeMode != builtin were both deleted. The effect: everyone hits the same daily free limit, regardless of whether they are using their own key or the bundled one. The cost of honesty is visible in a four-line diff.
Is the architectural shift to short model aliases unique to Fazm, or is it a pattern across agent-protocol clients?
It is a direct consequence of how the Agent Client Protocol (ACP) evolved in the 0.28 to 0.29 line. ACP agents expose a dynamic model list through a server-reported Initialize response. Clients that embraced that contract get to delegate model resolution to the agent. Clients that did not keep pinning. Fazm picked the delegated path: as of April 18, the app ships three fallback aliases in ShortcutSettings.swift and then overwrites its availableModels array whenever the ACP SDK reports fresh data. Other clients in the ecosystem are still mid-migration. Fazm's v2.4.0 is one of the cleanest public examples of the pattern in a shipping consumer app.
Where exactly in the source can I read the new model list and the normalizer?
File: Desktop/Sources/FloatingControlBar/ShortcutSettings.swift. The defaultModels array starts at line 150 and contains three ModelOption entries with ids haiku, sonnet, opus. The modelFamilyMap tuple at line 156 maps those substrings to user-friendly short labels (Scary, Fast, Smart) and the family display name (Haiku, Sonnet, Opus). The normalizeModelId function below that collapses any incoming model ID containing one of the substrings to the corresponding alias. The availableModels published property starts as defaultModels and is overwritten by update logic that merges the ACP SDK's model report while preserving user-friendly labels for known families.
Does this change break users who had pinned a full Claude model ID in earlier versions?
No. Commit 28f94d0d on April 18 added a migration in the same file that normalizes legacy full IDs on load. If a user's stored preference is claude-sonnet-4-6 from v2.3.x, the app maps it to sonnet before sending to the agent. The agent resolves sonnet to the freshest Sonnet, so an old preference actually upgrades the user to the latest version, not the one they had saved. For most users this is what they want. Users who truly need to pin a specific dot-version can still pass a full ID; the normalizer is substring-based and forgiving.
How does this relate to Fazm's broader positioning compared to other open source AI agents shipping this week?
Fazm is a consumer DMG, not a developer framework, and it reads the focused app's content through the macOS Accessibility tree rather than screenshots. Both choices matter for this release. Because the app is a consumer product, the cost of pinning a stale model is higher: users cannot pip install --upgrade their way to the latest; they have to wait for a signed, notarized DMG. Decoupling from full IDs is a direct consequence of that shipping constraint. Because the app uses Accessibility APIs rather than screenshots, it also reads structured content from any Mac app, not just the browser. Put together, v2.4.0 is what it looks like when a non-developer-framework, real-APIs-not-OCR consumer AI tool matures past its first year of versioning.