MAY 28 2026 / 54 COMMITS / 5 PATCH RELEASES

New AI projects on Hugging Face or GitHub, May 28 2026. One repo changed a single model ID and broke every long chat, then fixed it the same evening.

The interesting shipment on May 28 was not a new model on a leaderboard. It was a one-line default-model bump, from claude-opus-4-7 to claude-opus-4-8, inside the open-source macOS agent Fazm. The new default is an extended-thinking model, and within hours it surfaced a bug that returned HTTP 400 on the next message of any interrupted conversation. This is that day, read in the commits: the line that broke things, the failure that cascaded, and the 55-line fix that saved the chats.

M
Matthew Diakonov
9 min read

Direct answer, verified 2026-05-30

No platform publishes an official "May 28, 2026" list of new AI projects. Both Hugging Face and GitHub order discovery by a rolling trending score, not by calendar date. New work surfaces continuously across three live feeds:

The records that genuinely carry that exact date are tagged releases and commit logs. Two of them: huggingface_hub v1.17.0 (cross-repo file copies, ssh-to-Spaces, and token files written at 0o600 instead of world-readable defaults), and the open-source macOS agent Fazm, which pushed 54 commits and cut five patch releases (v2.9.48 through v2.9.52), recorded in CHANGELOG.json. Fazm's standout was the Opus 4.8 default-model bump and the fix it forced. The rest of this page opens that fix.

The line that started it

Commit ac5b4f81, 19:08 PDT, changes one default in Desktop/Sources/FloatingControlBar/ShortcutSettings.swift. The Smart picker's model id moves from claude-opus-4-7 to claude-opus-4-8. The same commit updates the normalizeModelId function so the legacy "default" alias and any prior-pinned Opus version (claude-opus-4-5, claude-opus-4-7) all resolve to the new canonical id. That part is careful: the bridge no longer advertises the bare "default" alias, so without the mapping an old pinned id would silently fall back to whatever the SDK treats as default, not necessarily Opus.

The careful part was not the problem. The problem was that claude-opus-4-8 is an extended-thinking model, and Fazm runs it over the Agent Client Protocol bridge at 0.37.0, which forwards signed thinking blocks. A model that thinks out loud has state that a model that does not think out loud never had. That state is what broke.

How a single unsigned block cascaded

Extended-thinking models emit thinking blocks that the API signs. When a turn is cancelled or stalls mid-thinking, the SDK leaves an assistant message whose thinking block was never finalized with a signature. That unsigned block sits in the session history, both in memory and on disk. Here is what happened on the next message.

The 400 cascade, before the fix

Chat UIACP bridgeAnthropic APIsend next promptsession/resume + replay history400: thinking blocks cannot be modifiedretry: resume same session again400 again (poison replayed)conversation broken

The plain session-resume retry, which exists to recover from a dead ACP process, made it worse here. Resuming the session reloaded the same poisoned history and 400'd again. The author noted the cascade in the source: it was observed going from depth 0 to depth 1 in production, which is exactly what "it destroyed the whole conversation" looked like from the user's side. The retry meant to save the turn was replaying the poison that killed it.

The fix, in commit e4cb4f09

19:09 PDT, one minute after the model bump. The change is +55 lines, -5 lines, all in acp-bridge/src/index.ts. It detects the specific 400 by matching the error text, then reroutes the retry through a fresh session instead of resuming the poisoned one.

acp-bridge/src/index.ts · commit e4cb4f09 · +55 / -5

Two details carry the fix.

  • Setting msg.resume to undefined. This is the whole trick. With resume unset, the next handleQuery goes through session/new and replays priorContext, which is plain user and assistant text with no signed thinking blocks. There is nothing left for the API to reject.
  • Matching the message, not a status code. A bare 400 could mean many things. The regex pins the reroute to the one failure mode it is safe for: thinking or redacted_thinking blocks that cannot be modified. Every other 400 falls through to the normal retry path below it.

The trade-off the author accepts is real: the fresh session loses the model's private reasoning from earlier turns. But it keeps every visible message. To the user the conversation continues; to the model it is a clean session seeded with what was said, not what was thought.

Resume versus rebuild, side by side

The fix is one branch in a retry path, but the difference between the two branches is the difference between a broken chat and a working one.

Old: session/resume
  • Reloads full history, signed thinking blocks included.
  • The unsigned mid-cancel block rides along.
  • API rejects the request: 400, blocks cannot be modified.
  • Retry resumes again, replays the same poison, 400 again.
  • Conversation is unrecoverable.
New: session/new + priorContext
  • Cached poisoned session is unregistered.
  • msg.resume is set to undefined.
  • priorContext replays as plain user and assistant text.
  • No thinking blocks, so nothing to reject.
  • Conversation continues from the next message.

The version flip-flop is the debugging session

One artifact of the day reads like a maintainer narrowing down a suspect in real time. The bridge dependency @agentclientprotocol/claude-agent-acp moved three times.

  • 11:59 went to 0.37.0 (commit b92b19b0).
  • 18:48 downgraded to 0.29.2 (commit 1b0f9086), when the thinking-block rejections started showing up.
  • 19:08-19:10 back to 0.37.0 (commits 931775c0, b860a170), one minute after the poison handler landed in e4cb4f09 at 19:09.

The downgrade-then-re-upgrade is the visible shape of testing a hypothesis: was the failure the protocol version, or the session state the new version exposed? It was the session state. Once the handler caught the poison, 0.37.0 was safe to keep, and it stayed.

Five releases, one day

The model migration was the headline, but most of the day was performance work, shipped as small named releases rather than one rolled-up note. A release is the unit of one fix.

v2.9.4808:09Started reporting Fazm-paid LLM usage from chat with the bridge now stamping the real model id and real Gemini token counts on every turn.
v2.9.4910:05Cut idle CPU and layout churn in home, history, and detached windows by truncating long previews, capping history loads, and disabling background animations. Session recording and screen observation now off by default.
v2.9.5010:40Routine performance landing cut as part of the same idle-CPU sweep.
v2.9.5116:25Stopped the Settings sidebar Update Available indicator pulsing forever (the same always-on animation pattern behind the v2.9.47 main-thread storm). Fixed the optional sign-in experiment.
v2.9.5219:30Fixed chat getting stuck loading, returning empty, or erroring on the next message after a long or complex response. This is the release that carried the poisoned thinking-block fix and the Opus 4.8 default.

v2.9.52, the release that carried the Opus 4.8 default and the poisoned thinking-block fix, is highlighted. Cut times are Pacific, sourced from the corresponding release-changelog commits in the public log.

Why this beats a trending list for May 28

A trending page tells you what existed at the end of the day. It cannot tell you that a one-line model bump is the riskiest kind of change, because the line is small and the consequences are not. The commit log can. On May 28 it showed a maintainer changing a default, watching long chats break, downgrading a dependency to isolate the cause, writing 55 lines to detect the exact failure, and re-upgrading once it was caught, all inside one evening.

The lesson generalizes past Fazm. Anyone moving to an extended-thinking model inherits signed thinking blocks in their session history, and any cancel or stall mid-thinking can leave one unsigned. If your retry path resumes the session, it will replay the poison. The shape of the fix is portable: detect the specific 400, drop the cached session, and rebuild from plain-text context rather than resuming. The model id was one line. The handler is the part worth copying.

Migrating to an extended-thinking model?

In twenty-five minutes we open the commit, the session-history path, and your own retry logic together, and decide whether your stack has the same poisoned-block hole.

Frequently asked questions

What new AI projects appeared on Hugging Face or GitHub on May 28, 2026?

Neither platform publishes a dated release list. Models, datasets, papers, and repositories surface continuously, ordered by a rolling trending score rather than by calendar date. The closest thing to a true daily record is a tagged release or a commit log, where each change carries an author, a message, and a timestamp. Two records that genuinely carry 2026-05-28: huggingface_hub v1.17.0 was uploaded that day with cross-repo file copies, ssh-to-Spaces, and a security fix that writes token files at 0o600 instead of world-readable defaults; and the open-source macOS agent Fazm pushed 54 commits and cut five patch releases (v2.9.48 through v2.9.52). Fazm's standout change was a one-line default-model bump from claude-opus-4-7 to claude-opus-4-8 in ShortcutSettings.swift, plus the bug fix that bump forced: commit e4cb4f09, which stops poisoned thinking-block history from returning HTTP 400 on the next message.

Why would changing one model ID break existing conversations?

Because the new default, claude-opus-4-8, is an extended-thinking model, and Fazm runs it over the Agent Client Protocol bridge at version 0.37.0. Extended-thinking models emit signed thinking blocks. If a turn is cancelled or stalls mid-thinking, the SDK leaves an assistant message whose thinking block was never finalized with a signature. That unsigned block lives in the session history, in memory and on disk. The very next prompt replays it, and the Anthropic API rejects the entire request with `400 ... thinking ... blocks ... cannot be modified`. The plain session-resume retry just replays the same poison and 400s again, which is what 'it destroyed the whole conversation' looked like to a user. The model ID was one line; the blast radius was every long chat that had ever been interrupted.

What is the actual detector in commit e4cb4f09?

A regex test against the error message and a reroute. The detector is `isThinkingBlockPoison`, which matches either /thinking[\s\S]{0,40}blocks[\s\S]{0,80}cannot be modified/i or /blocks in the latest assistant message cannot be modified/i. When that matches and a sessionId exists and retry depth is under MAX_QUERY_RETRIES, the bridge unregisters the cached session, clears the pending tools and timers, sets msg.resume to undefined, records the stuck session id, and calls handleQuery again at depth + 1. Because msg.resume is now undefined, the retry goes through session/new and replays priorContext (plain user and assistant text, no signed thinking blocks) instead of resuming the poisoned session. The fix is +55 lines, -5 lines, all in acp-bridge/src/index.ts.

Why does session/new + priorContext sidestep the 400 when session-resume does not?

Because priorContext is plain text. A session resume reloads the full message history including the signed thinking blocks, and the unsigned, mid-cancel block among them is what the API refuses to accept. priorContext is the conversation re-expressed as ordinary user and assistant turns with no thinking blocks at all, so there is nothing for the API to reject. The trade-off is that the freshly started session loses the model's private reasoning trace from earlier turns, but it keeps every visible message. To the user the conversation continues; to the model it is a clean session seeded with what was said, not what was thought.

What was the ACP version flip-flop on the same day?

The bridge dependency @agentclientprotocol/claude-agent-acp moved three times on May 28. It went to 0.37.0 at 11:59 PDT (commit b92b19b0), was downgraded to 0.29.2 at 18:48 (commit 1b0f9086) when the new version started surfacing the thinking-block rejections, then went back to 0.37.0 at 19:08 to 19:10 (commits 931775c0 and b860a170) once the poison handler in e4cb4f09 landed at 19:09. The downgrade-then-re-upgrade is the visible shape of a maintainer isolating whether the failure was the protocol version or the session state. It was the session state; with the handler in place, 0.37.0 was safe to keep.

What else shipped that day besides the model migration?

Most of the other 54 commits were performance work. v2.9.47 and v2.9.49 chased an idle CPU storm: four withAnimation(.repeatForever) patterns (an update-available pulse, an update-button pulse, an upgrade-Claude pulse, and a hang-flash) were keeping a SwiftUI animation transaction open forever, recomputing the chat scroll view every display cycle and pegging the main thread. The fix disabled those animations and added automatic stack-sampling: when the top thread sustains over 85 percent CPU for a minute, the app shells out to /usr/bin/sample and writes the hot-stack trace to the log. v2.9.49 also turned session recording and screen observation off by default. v2.9.48 started reporting Fazm-paid LLM usage with the real model id and real Gemini token counts. v2.9.51 fixed a forever-pulsing Update Available indicator and the optional-sign-in experiment. v2.9.52 closed the day with the chat-stuck-loading fix and the referral Copy Link button.

Is claude-opus-4-8 a real model, and did Fazm just rename a label?

It is a real model id, and the change was more than a label. The diff in ShortcutSettings.swift swaps the Smart picker's default id from claude-opus-4-7 to claude-opus-4-8 and updates the normalizeModelId function so the legacy 'default' alias and any prior-pinned Opus version (claude-opus-4-5, claude-opus-4-7) all resolve to the new canonical id. That normalization matters because the bridge no longer advertises the bare 'default' alias; without the mapping, an old pinned id would silently fall back to whatever the SDK treats as default, which is not guaranteed to be Opus. So the one-line default change is backed by a migration path for every previously stored model preference.

How do I read any project's real May 28 myself?

Three artifacts, in order. Open the project's CHANGELOG.json or CHANGELOG.md at the root and read the entries dated 2026-05-28. Open the commit log with `git log --since=2026-05-28 --until=2026-05-29 --no-merges` and read the messages, ignoring the release-changelog commits. Then pick one commit whose subject sounds load-bearing (here, 'Fix 400 errors from poisoned thinking-block session history') and run `git show <hash>` to read the diff and, more importantly, the comment the author left for future readers. The README is marketing; the diff is the truth. A model-version bump that looks like a one-line change is often the most dangerous kind, because the line is small and the consequences are not.

Where do I find the actual files this page cites?

github.com/mediar-ai/fazm is the public repo. The poison handler lives in acp-bridge/src/index.ts inside handleQuery, in the block that defines isThinkingBlockPoison (commit e4cb4f09). The default-model change is in Desktop/Sources/FloatingControlBar/ShortcutSettings.swift, in defaultModels and normalizeModelId (commit ac5b4f81). The ACP version moves are in acp-bridge/package.json. Release notes are in CHANGELOG.json at the repo root. For the Hugging Face side, the v1.17.0 notes are at github.com/huggingface/huggingface_hub/releases.

How did this page land for you?

React to reveal totals

Comments ()

Leave a comment to see what others are saying.

Public and anonymous. No signup.