The Opus 4.7 release, from inside the desktop app that had to render it
Opus 4.7's release note says "more reliable long-running agent work" in one line. The client-side cost of that one line is five new ACP update types, a per-turn Set<string>, and a stale-task detector so a late notification from the last prompt does not contaminate the next one. This page walks through the exact plumbing, by file and by line, inside a consumer Mac app that already shipped it.
THE GAP BETWEEN THE RELEASE NOTE AND THE UI
Longer runs break clients that only listen to text_delta
Opus 4.6 turns were short enough that a naive chat client could survive on three events: start of stream, text_delta chunks, and end of stream. A tool call here or there. Anthropic's April 2026 release shifts the distribution. Opus 4.7's stronger instruction following and longer leash mean a single turn can decompose into named subtasks, spawn several tools in sequence, stream progress while each one is running, and emit a final tool-use summary that covers all of them at once.
A chat client that only listens for text_delta sees that turn as intermittent text punctuated by long quiet gaps. The user sees it as an app that hangs.
The real work of absorbing an April 2026 model release in a desktop app is not about the model at all. It is about making the UI faithful to the shape of a turn the model is now allowed to produce.
WHAT FAZM PICKED UP
Five forwarded event types the April 2026 turn actually uses
Below is the subset of Agent Client Protocolsession/updatetypes the Fazm bridge has to translate for Opus 4.7 turns to look right in the chat. The full switch is atacp-bridge/src/index.ts:2071-2489.
task_started (bridge line 2402)
The model has decomposed the turn into a named subtask. The bridge pulls taskId and description, adds taskId to the per-turn Set<string>, and sends task_started up to Swift. The UI calls addToolActivity with toolName 'Subtask' at ChatProvider.swift:2600, and a live activity row appears inside the assistant bubble.
task_notification (bridge line 2411)
A subtask finished or changed status. Before forwarding, the handler at line 2416 checks whether taskId is still in currentTurnTaskIds. If not, it calls onStaleNotification, bumps staleTaskNotificationCount, and tags the log 'STALE'. The forwarded event still arrives on Swift so the UI can decide, but the label is now honest.
tool_progress (bridge line 2427)
Periodic heartbeat while a single tool call is running. Carries toolUseId, toolName, elapsedTimeSeconds. On Opus 4.6 this was nice-to-have. On Opus 4.7 it is the reason an activity row can show '12s' next to a long WebSearch instead of just a static spinner.
tool_use_summary (bridge line 2435)
A short synthetic summary of several tool calls at once, with precedingToolUseIds. The bridge forwards it up and the Swift side logs the first 100 chars. On long turns, Opus 4.7 emits this in place of a verbose text block summarizing what each tool did, which keeps the message body clean.
compact_boundary (bridge line 2376)
The underlying Claude Code SDK just compacted the context. Carries trigger ('auto' or 'manual') and preTokens. Opus 4.7's longer runs make this fire more often, and the UI renders a subtle boundary so the user understands why the model suddenly forgot something.
How a single Opus 4.7 turn reaches the chat bubble
THE ANCHOR FACT
The thirteen lines that make stale-task detection work
The whole mechanism fits in three places in the bridge and two lines in the Swift UI. First, the declaration, inside the per-query handler at line 1531:
Next, the wire-in where the bridge passes that set down into the shared session-update handler, at line 1577:
Then the two cases in handleSessionUpdate that read and mutate the set. task_started adds the id, task_notification checks it and flags stale:
The set is cleared at the end of every turn at line 1728, so a fresh prompt starts from zero and late notifications from the previous prompt are correctly flagged. Finally, the Swift side turns task_started into a visible subtask row:
That is the whole story. A Set<string> created when a turn starts, populated when the model names a subtask, checked when a notification arrives, and cleared when the turn ends. Late or cancelled notifications can still arrive, and now they are labeled honestly instead of contaminating the next prompt.
“To keep a late task notification from a previous turn from lighting up the next one.”
acp-bridge/src/index.ts:1531, 1577, 2402-2425
WHAT A TURN ACTUALLY LOOKS LIKE
A typical Opus 4.7 long turn on the wire
Below is the abbreviated bridge log for a real long-running Opus 4.7 turn, with the events that did and did not exist in the Opus 4.6 era. The stale task notification at the bottom is what prompted the detector.
Seven of the event types in that transcript did not exist as first-class Fazm events before the ACP update surface expanded. The last line is the reason stale-task detection shipped in the same patch.
Opus 4.6 turn shape vs Opus 4.7 turn shape
Same $5 / $25 per MTok pricing, same ACP protocol, very different event distribution at the client.
| Feature | Opus 4.6 turn | Opus 4.7 turn |
|---|---|---|
| Average notifications per turn (long prompt) | 10 to 25, mostly agent_message_chunk and tool_call. | 50 to 200, including several task_started, frequent tool_progress, and at least one tool_use_summary. |
| Named subtasks emitted | Rare. Most multi-step work stayed inside one logical turn without task decomposition. | Common on planning or cross-app work. Shows up as addToolActivity(toolName: 'Subtask', ...). |
| Late notifications after the turn ends | Rare enough to ignore. | Frequent enough that a stale detector is now load-bearing. |
| Compact boundaries per session | Once or twice on very long sessions. | Multiple times per long turn. compact_boundary now has UI meaning. |
| Client-side code needed to absorb the release | n/a (this was the baseline). | 5 new forwarded event types, 1 per-turn Set<string>, 1 stale detector, 0 new desktop build. |
| Pricing per MTok input / output | $5 / $25. | $5 / $25, unchanged. |
The ACP surface, as one sequence diagram
one Opus 4.7 long turn, four actors
What you should actually do with this on your own client
Stop assuming one turn equals one list of tool calls
Opus 4.7 turns can be nested: a top-level plan, a subtask per step, tool calls inside each subtask. Your UI needs a container that maps naturally to that tree, not a flat list of tools in the order they arrived.
Forward tool_progress, even if you do not render it yet
Long tool calls now account for most of the perceived latency. tool_progress is cheap to route and costs almost nothing to ignore. If you do not forward it, you cannot retroactively render a progress badge later.
Keep a per-turn set of live taskIds
Not a global set, not a per-session set. Per-turn. Clear it when the turn ends. Any notification for a taskId outside the set is a stale event by construction, and you want to know that before the user does.
Leave every unknown update type as a logged default
handleSessionUpdate's default case should log 'Unknown session update type' and keep going. Anthropic will ship new ones. A crash on an unknown type is worse than ignoring something the UI does not render yet.
Do not rebuild session state because the model changed
Opus 4.7 reuses the same ACP surface as 4.6. No field changed, no header changed. If the client is event-driven end to end, a model switch is a one-line constant change and a session restart, not a migration.
The honest framing of an Anthropic new-model release is less glamorous than the benchmark charts. Opus 4.7 is better. The release note is right. But the client-side work that lets "better at long-running agent work" reach a user is unglamorous plumbing: a set, a check, five new case branches, and a discipline about clearing state at turn boundaries. Fazm has a 0 percent new-build cost for Opus 4.7 because that plumbing was in the codebase before the model dropped, waiting for a model that emits enough events to make it visible.
Want to watch a real Opus 4.7 long turn hit a Mac app, not a browser?
Fifteen minutes. We open Fazm, flip the model to Opus, and run a long cross-app task while you watch task_started, tool_progress, and a stale notification show up in the log, live.
Book a call →Frequently asked questions
What is Anthropic's new model release for April 2026?
Claude Opus 4.7 went generally available in April 2026 at the same $5 / $25 per million tokens pricing as Opus 4.6. Anthropic frames the upgrade as stronger software engineering, higher-resolution vision, sharper instruction following, and more reliable long-running agent work. The same month, Anthropic unveiled a second model, Claude Mythos (internal codename Capybara), through Project Glasswing, a gated early-access program limited to roughly 50 partner organizations with no public release date. A third surface, Claude Design, launched as a Labs product for creating designs, prototypes, slides, and one-pagers, but it is a product on top of the existing models rather than a new model.
Why does 'more reliable long-running agent work' require new client code?
Because a long-running agent emits more events. A short turn might be one text block plus one tool call. A long turn on Opus 4.7 can spawn nested subtasks, stream tool progress while a task is running, post a final tool-use summary when several calls finish, and split its output across multiple text blocks separated by tool use. If a client only listens for text_delta and tool_call, those richer turns arrive as silence punctuated by jumps in the text. Fazm had to forward five additional Agent Client Protocol update types to the Swift app so the UI can represent what Opus 4.7 is actually doing: task_started, task_notification, tool_progress, tool_use_summary, and compact_boundary.
Where in the Fazm source does a task_started event become a visible row?
Two hops. First, the ACP bridge, a long-lived Node.js subprocess, handles the raw ACP update at acp-bridge/src/index.ts:2402. It pulls taskId and description out of the update, adds taskId to a per-turn Set<string> at line 2405, and sends a typed task_started event to the Swift app. Second, the Swift side, ChatProvider.swift:2600-2607, receives the event and calls addToolActivity with toolName 'Subtask', status .running, and the taskId as toolUseId. The chat view already knows how to render a tool activity row, so the subtask inherits the existing animation, status pill, and completion behavior.
What is the stale-task detector for, and why did Opus 4.7 force us to build one?
On a long turn it is possible for a task_notification to arrive after the turn has ended, because the underlying Claude Code SDK can deliver late updates for a task that was logically finished or cancelled. Without guarding for that, you see yesterday's subtasks blink into today's chat. The bridge keeps a per-turn Set<string> called currentTurnTaskIds, declared at acp-bridge/src/index.ts:1531 and cleared at line 1728 when the turn ends. When a task_notification arrives, the handler at line 2416 checks whether the task's taskId is still in the set. If it is not, the handler calls onStaleNotification (wired at line 1577 to increment staleTaskNotificationCount) and tags the log line with 'STALE'. The client still forwards the event so the Swift side can decide whether to suppress it, but it is now labeled.
Does every Opus 4.7 turn produce task_started events?
No. Short turns look the same as they did on Opus 4.6: agent_message_chunk for text, tool_call for tool use, a closing stop reason. task_started appears when the model decomposes the work into named subtasks, typically on multi-step requests that involve planning across files or apps. Fazm's rate-limit behaviour, streaming throttle, and session pre-warming did not need to change for Opus 4.7, which is exactly the kind of release note that does not ship: 'we changed nothing and users still saw every new feature.'
Where is the per-turn cleanup that resets currentTurnTaskIds?
The set is cleared at acp-bridge/src/index.ts:1728 inside the per-turn cleanup block, right after the prompt resolves and before the handler runs its post-turn bookkeeping. Clearing on turn end, instead of on session end, is what makes the detector correct: if the user sends a new prompt in the same session a few seconds later, a late task_notification from the previous prompt gets flagged as stale instead of being attributed to the new prompt's taskIds.
How is tool_progress different from task_started, and why does Opus 4.7 need it?
task_started marks the beginning of a named subtask (a logical unit of work the model has planned). tool_progress is a periodic heartbeat emitted while a single tool call is running, carrying toolUseId, toolName, and elapsed time in seconds. On Opus 4.6 with shorter turns, tool_progress was nice-to-have. On Opus 4.7, where a single tool call can run long enough that the UI would look frozen without feedback, tool_progress is the thing that lets the activity row show '[WebSearch] running 12s' instead of a spinner that just keeps spinning. It is handled by Fazm's bridge at acp-bridge/src/index.ts:2427-2433 and logged on the Swift side at ChatProvider.swift:2616-2617.
Did Fazm ship a new Mac build for Opus 4.7?
No. Fazm does not hardcode a model list. On each session start, the ACP SDK reports the models the user's auth has access to via an availableModels array, the bridge forwards it as a models_available event, and the Swift picker rebuilds from scratch. When Anthropic flipped Opus 4.7 on, it appeared in the picker the next time the floating bar opened, relabeled 'Smart (Opus, latest)' by the substring family map in ShortcutSettings.swift. Zero signed-and-notarized desktop release, zero Sparkle auto-update, zero user action. The task-tracking event handlers described above were already there from a previous release, waiting for a model that emits them frequently enough to matter.
How does this compare to a Computer Use style agent on Opus 4.7?
A Computer Use style agent screenshots the screen each turn and asks the model to OCR it. Opus 4.7's higher-resolution vision is a clear win for that class of agent because the bottleneck is reading the picture. But on long-running work, that agent still has to figure out how to render progress to the user, which means wiring up task_started, task_notification, and tool_progress the same way. The client-side plumbing problem is orthogonal to the vision-vs-structure tradeoff. Every Opus 4.7 host has to solve it.
Is Claude Mythos part of this same April 2026 release bundle?
Chronologically yes, practically no. Mythos is distributed only to the small set of partner orgs inside Project Glasswing and is not available through any public API, plan, or console. Anthropic has described Mythos as capable of identifying and exploiting software vulnerabilities with high accuracy, which is why the rollout is gated. If you are building on Claude today, the GA ceiling is Opus 4.7 and that is what you should plan your next six months around. If Anthropic ever opens Mythos GA, Fazm's substring family map and availableModels forwarding will pick it up the same way they picked up Opus 4.7, with no new build.
Where is the full list of forwarded event types from the bridge to the Swift app?
The handleSessionUpdate function in acp-bridge/src/index.ts (roughly lines 2071 through 2489) is the canonical switch. The cases relevant to the April 2026 new-model release are: agent_message_chunk (text), agent_thought_chunk (thinking delta on a separate channel), tool_call and tool_call_update (tool lifecycle), plan, compact_boundary, status_change, compaction_start, compaction_delta, task_started, task_notification, tool_progress, tool_use_summary, rate_limit, api_retry, and usage_update. Anything not in that switch logs an 'Unknown session update type' line and is ignored, which is the right behavior when the ACP surface adds something new in the future.