OMO 5.0.0-beta.13 — Recoverable Graphs, Side Conversations, and a Faster Senpi 2026.8.20-2
The center of gravity: a failed DAG run is no longer a total loss, /btw gives you a second conversation without burning your main context, and the bundled Senpi 2026.8.20-2 engine ships a large performance + Cursor-correctness wave.
🕸️ mass-ulw: retry, steer, and amend a live graph
A graph that lost one node to a flaky tool call used to mean re-running the whole thing and paying for every child again. Not anymore:
dag retryreturns failed, cancelled, and skip-cascaded nodes to a fresh attempt while every completed node keeps its cached result. Prompt-corrected retries (retry+prompt) are supported for exactly one node.dag sendroutes a message to one node's child with real delivery semantics —steerinto a running child,revivea finished-but-resident child with its context intact,queuedwith a durable queue position when the child cannot take it yet. Non-continuable children get typed refusals (node_not_continuable,node_has_no_task; an unknown node getsnode_not_found) that name the remedy.dag amendaccepts an edited definition against the same run, SHA-256-fingerprint-diffs every node, and re-runs only changed + added nodes plus their transitive dependents.load_skillsis deliberately outside the fingerprint, so a skills-only edit re-runs nothing.- Per-node result artifacts are written atomically (temp file + fsync + rename), so a crash mid-retry can no longer leave a truncated result a reader would trust.
- Three new journaled event types —
dag.node.retried,dag.node.steered,dag.definition.amended— record every deliberate re-run and amendment explicitly in the journal. All strictly additive:schemaVersionstays 1, documented indocs/reference/mass-ulw-protocol.mdwith an explicit no-break guarantee. - The status widget shows an
x<attempt>badge on re-run nodes;/dagshowsamended x<n>and prefixes node errors with the error code. A lost amend race is now a cleanrun_still_activerefusal instead of a run wedged on journal replay. - The JS SDK gains
retry,send, andamendwrappers, and the mass-ulw skill documents the full refusal matrix.
💬 /btw — ask a side question without polluting the main thread
/btw <question> (alias /side) opens a temporary session on the same model and agent. Ctrl+/ toggles between main and side; Ctrl+C on an empty side composer closes it. The side thread sees your recent main context as read-only background (capped at 64 messages / 64 KiB behind a boundary that tells the side model to keep its hands off files and subagents unless you explicitly ask), and its Q&A never enters the main transcript. Parent deletion, crash re-adoption, BTW-in-BTW nesting, and cancellation ordering are all explicitly handled, so side sessions don't leak. Guide: docs/guide/btw.md.
🔁 Model fallback stops going quiet (#6579)
Community fix by @MoerAI (#6611):
The repeated-error stall is fixed at its root: the retry-dedupe key didn't include the failing model, so the same error on a different model looked like a duplicate and was dropped — the session just went silent. Now:
- Dedupe keys are scoped per model; a skipped retry returns its key instead of burning it forever.
- Internal fallback retries carry an explicit marker so they stop being discarded as synthetic traffic.
- Model identity travels as provider/model plus variant through the whole fallback path — your reasoning-effort selection survives a fallback and a recovery.
- Watchdog timers are generation-scoped, so a timer from an abandoned attempt can never hijack a later turn.
- A manual model change resets the fallback watchdog, in-flight retry flag, and the retry-key set.
🖼️ One notice language across the transcript
Fallback-architect notices, tips, task-completion cards, team-member liveness warnings, and every memory notice (reflection, health, soul-update, write receipts, nudges) now render through one shared padded notice box. Completion cards lead with a tone glyph (●/✗/⚠/◐) and the task name, keep id · target/model · duration · tokens · tools · tps on a dim second row, and hold continuation hints behind expansion.
🩺 /doctor reflection health is deterministic
Reflection-health severity was a function of the wall clock — [warn] decayed to [ok] by pure passage of time. The check now reads an injectable clock, so the verdict is a pure function of your reflection data.
🧪 CI and tests stop lying
The Senpi adapter is now a first-class mandatory-QA surface with a machine-enforced evidence-path contract. Two DAG wait-hang classes (resident-cap saturation, terminalization during subscription setup) are pinned by bounded regression tests. Memory-test teardown retries narrowly on EFAULT only, and three Windows-slow suites got honest ceilings with waits left event-driven.
🧰 Bun 1.4.0 stable, everywhere
Bun 1.4 went stable today, and this release train rides it end to end:
- omo: every CI, publish, and platform-build workflow moved from Bun 1.3.14 to 1.4.0 (cache keys included), and the committed omo-senpi extension bundles were regenerated under stable 1.4.0 so the CI freshness gate and your installed extension agree byte-for-byte.
- senpi 2026.8.20-2 (same-day re-release on top of 2026.8.20): the compiled
senpibinary is now built with Bun 1.4.0 stable (was 1.3.14), and npm publishing graduated from the Bun canary channel to stable 1.4. - Safe dependency refresh riding along — omo: posthog-node 5.49, puppeteer-core 25.8, @clack/prompts 1.7, MCP SDK 1.30, js-yaml 4.3.1, picomatch 4.0.5, bun-types 1.4.0; senpi: Biome 2.5.9, @types/node 26.2.0, vitest + coverage 4.1.11, AWS Bedrock/Smithy patches, protobuf 2.14.0. Deliberately excluded: anything major, the Anthropic SDKs (OAuth-lane sensitivity), @google/genai, @mistralai.
⚙️ Bundled Senpi 2026.8.20-2 — the engine wave
Faster everywhere
/resumeno longer stalls on big sessions: exact byte-bounded streaming summaries are reused for unchanged files, and the visible transcript tail paints first while older messages warm progressively.- Startup sheds 680 modules: the 1.2 MB Claude Agent SDK bundle and the jsdom/Readability/turndown HTML stack now load on first use, not at boot (14,203 → 13,523 modules).
- One process lighter per launch:
cli.tsruns the agent in-process unless an Inspector option or custom exec args genuinely require a child (measured -75 ms, -6.2% on--help). - On-disk compile cache: Node's
enableCompileCache()is on for both CLI entries and published to children, so second launches skip recompiling the engine graph. - Hot reload off the critical path: recursive config watchers run in a worker thread on macOS too, watcher teardown leaves the reload path (1.5–62 s of shutdown stall eliminated), and MCP reconnect no longer blocks a reload.
- Watch scope fixed: recursive watch targets now open one non-recursive subscription per in-scope directory — an extensions dir containing
node_modulesno longer drivesfseventsdto 123% CPU and multi-GB RSS. - Retry spinners throttle on sessions with 1,000+ persisted entries; the countdown stays.
The TUI stops freezing
- Goal footer tickers retire themselves on a stale extension context instead of ticking dead forever — the "Pursuing goal" label and continuation countdown no longer freeze the session after a reload.
- TUI mode switches detach live components instead of disposing them; spinners and widget intervals survive the switch.
- A vetoed or failed
/reloadno longer destroys live extension footers and task widgets. - Assistant text that arrives after the last tool call renders below the tool cards, so approval questions stay visible.
claude-sdk-oauth: the $1,084 retry-storm fix (#723)
Stream-start-timeout retries now fork the SDK conversation at the last assistant boundary instead of re-sending the whole conversation — each retry re-bills only its own turn on a prefix-cache read. Before: cache writes grew ~8K/attempt, $25/6min, $1,084/3days on worker dispatch.
Cursor, seriously corrected (community wave — thanks @leeseunguk and @HeiTuz)
- 0-token
resource_exhaustedis treated as overflow: surface on first failure → compact before any rotation; rotation persists under the agent dir and survives TUI restarts; a rotation skip at the 3-rotation cap remints a fresh wire id instead of poisoning the session. - Same-model retry after remint/compact instead of falling back to another provider; too-small overflow compacts drop to the last user turn; implausible billed
cacheRead(3×/8× the live window) can no longer force useless compacts. - Mid-turn compaction refuses while a native Run is live, so
conversationIdcan't get poisoned mid-flight. - Turns that end
stopwith pending toolCalls continue astoolUse; turns idle after completed tools end normally instead of hanging to the idle timeout. - ANTML invoke recovery is skipped on
cursor-agent, so Claude-named Cursor models stop rejecting parallel tool starts. - Native
todocalls persist even when the server resolves them without a local op; latetool_execution_endevents draw their card instead of orphaning results; streamed task args survive an empty{}completion. - Explicit thinking levels resolve to catalog suffix variant ids (
claude-fable-5-thinking-low) on both the native and CLI lanes — no moreConnect error not_found. - Exec-bridge ownership is airtight: handlers bind to the owning run's abort signal, fail closed without a captured run, re-check ownership after approval prompts, and emit
tool_execution_enderrors so nothing dangles. - Session titles use the session model's own summarization auth — no more
unauthenticatedtitle calls under an explicit compaction model.
Long-running sessions stop burning money
- Goal continuations are append-only: per-request history rewriting invalidated the provider's cache prefix, so long team-mode sessions paid a full uncached re-read every turn and drove themselves into 429 storms.
- Same-model 429 retries floor every wait with the exponential schedule — a provider answering with the same tiny
retry-afterhint can't pin the cadence at milliseconds anymore.
Config reload behaves in shared-agent-dir setups (thanks @Indosaram, #1006)
Routine-preference saves (like defaultModel) from another session no longer cascade a reload; the handoff snapshot is cleared unconditionally after requestReload() settles, so a stale plaintext settings snapshot can't survive.
For extension authors
The notice-box primitives are public API now: buildNoticeBox, noticeMessageRenderer, noticeEntryRenderer, and the NoticeSpec/NoticeLine/NoticeTone types — render your transcript notices in the shared visual family instead of re-implementing it.
Full engine changelog: senpi v2026.8.20 (+ v2026.8.20-2, the same-day Bun 1.4 re-release)
- 5d2742b Merge pull request #7075 from code-yeongyu/fix/omo-ci-bun-1314-until-windows-tail
- b4d52a8 fix(test): build the absent-store fixture absent instead of deleting it back out
- 3d91936 fix(test): give the Windows setup fixtures a real absent store and a real home
- 3809286 fix(test): let win32 teardown leak an OS-owned temp root instead of failing
- 8cff720 fix(test): widen the Windows EBUSY teardown budget with escalating backoff
- f92deb8 fix(test): make the Windows suites correct under bun 1.4
- 3a6fa0f test(omo-opencode): pin ResolveMessage identity instead of its prototype for bun 1.4
- 8d6a66f Merge pull request #7074 from code-yeongyu/fix/btw-parent-remote-revalidation
- 8aee394 test(qa): check in BTW revalidation evidence
- fc2c5aa fix(opencode): require remote BTW parent confirmation
- aff84c7 fix(qa): keep resolver imports side-effect free
- d92429e Merge pull request #7071 from code-yeongyu/feat/dag-node-resume-steer
- 37c5d6e Merge pull request #7068 from code-yeongyu/test/dag-happy-timeout-contract
- 5a6f21d docs(omo): state the additive compatibility stance for dag node-control events
- 1bbc2aa docs(omo): mass-ulw protocol additions for per-node retry/steer/amend
- 26b2506 Merge pull request #7067 from code-yeongyu/fix/tui-notice-block-style
- 56df6d7 Merge pull request #7066 from code-yeongyu/fix/dag-wait-residency-regression
- 8134492 Merge pull request #6611 from MoerAI/fix/6579-runtime-fallback-dedup
- 3932c9c fix(runtime-fallback): mark reused internal retry parts
- b401eb4 fix(runtime-fallback): clear first skipped retry key
- 51573a1 fix(runtime-fallback): scope retry marker to fallback generation
- 2305720 fix(runtime-fallback): recover skipped retry status keys
- d5c5918 test(qa): verify PR 6611 after dev rebase
- 2ad216f test(qa): record pre-push fork head
- 4868449 test(qa): record PR 6611 fallback evidence
- fc1c631 fix(opencode): route only marked fallback retries
- b7ee41a fix(runtime-fallback): preserve explicit retry effort
- 62491bd fix(runtime-fallback): restore effective primary variants
- 3aba9d1 fix(runtime-fallback): index registered category models
- 891937e fix(runtime-fallback): bind timeouts to state generations
- f603b5b fix(runtime-fallback): own queued retry generations
- 0b097b7 fix(runtime-fallback): reject stale timeout generations
- f4517c4 fix(runtime-fallback): acknowledge synthetic retries
- 0616cd6 fix(runtime-fallback): align created fallback identity
- 8bcfcc6 fix(runtime-fallback): retain queued fallback state
- 88d7cb4 test(lsp): isolate Windows compatibility checks
- 671f69b fix(runtime-fallback): honor explicit retry variants
- 895b9d4 fix(runtime-fallback): align retry reasoning state
- 06eab0f fix(runtime-fallback): isolate retry generations
- 3e24b39 fix(runtime-fallback): preserve effective retry state
- c09d258 test(runtime-fallback): wire generation acknowledgment
- c42be3e fix(runtime-fallback): align fallback generations
- 9af2747 fix(runtime-fallback): scope model-less retry dedupe
- 8c465e4 fix(runtime-fallback): preserve variant lifecycle state
- a5f5fee fix(runtime-fallback): persist effective fallback variant
- 8310d91 fix(runtime-fallback): preserve fallback variants
- f015363 fix(runtime-fallback): read variant from chat output
- 5f7b005 test(runtime-fallback): prove source-current OpenCode QA
- bee9021 test(runtime-fallback): record variant reset QA
- e6fa807 fix(runtime-fallback): reset retry keys on variant change
- b586cef fix(runtime-fallback): reset retry keys on manual model change
- 26a2a8f fix(runtime-fallback): retain active retry keys
- 5e3a12e fix(runtime-fallback): distinguish retry variants
- 11798f8 fix(runtime-fallback): dedupe model-less retry statuses
- 6174009 fix(runtime-fallback): prevent repeated-error stalls (fixes #6579)
- e676fef Merge pull request #7062 from code-yeongyu/refactor/doctor-health-clock-thread
- b8b7b09 Merge pull request #7060 from code-yeongyu/test/memory-teardown-efault-retry
- 9dc8116 Merge pull request #7058 from code-yeongyu/feat/btw-codex-side-ui
- 6eb7e8c fix(opencode): revalidate BTW parents
- 198a196 docs(opencode): update BTW hook inventory
- 1280716 fix(opencode): preserve BTW cancellation semantics
- 28284f2 fix(opencode): reject deleted pending BTW
- e4ce3f6 docs(opencode): index BTW feature module
- bc2f496 fix(opencode): preserve BTW route ownership
- 1be1102 fix(opencode): own every BTW cleanup
- 786d195 fix(opencode): await pending BTW creation
- b174d98 fix(opencode): await BTW cleanup on dispose
- cdc1061 fix(opencode): close final BTW boundary gaps
- ed86828 fix(opencode): propagate BTW classification failures
- 369be36 fix(opencode): retry BTW session classification
- f3a3c0b fix(opencode): restrict unverified BTW sessions
- 399ddb8 fix(opencode): retry persisted BTW adoption
- e015f8e fix(opencode): validate persisted BTW parents
- 8b423d9 fix(opencode): enforce BTW execution bounds
- 113b493 fix(opencode): bound BTW prompt inheritance
- 6809736 fix(opencode): block orphaned BTW nesting
- baf7d92 fix(opencode): reject deleted BTW parents
- b3f4f0b fix(opencode): re-adopt persisted BTW sessions
- 3cbeeeb fix(opencode): cancel BTW on parent deletion
- a3981b9 fix(opencode): discard stale BTW adoption
- 4586d13 fix(opencode): cancel pending BTW navigation
- 960947c fix(opencode): harden BTW deletion lifecycles
- 559b3e2 fix(opencode): address BTW review feedback
- b5eb048 feat(opencode): align BTW side conversation with Codex
- ec3d5af Merge pull request #7057 from code-yeongyu/fix/beta12-lockfile-sync
- 23db3d9 fix(deps): sync bun.lock with the v5.0.0-beta.12 version bump
- 65f8540 Merge pull request #7056 from code-yeongyu/fix/windows-team-idle-wake-budget
Thank you to 1 community contributor:
- @MoerAI:
- feat(opencode): align BTW side conversation with Codex
- fix(opencode): address BTW review feedback
- fix(opencode): harden BTW deletion lifecycles
- fix(opencode): cancel pending BTW navigation
- fix(opencode): discard stale BTW adoption
- fix(opencode): cancel BTW on parent deletion
- fix(opencode): re-adopt persisted BTW sessions
- fix(opencode): reject deleted BTW parents
- fix(opencode): block orphaned BTW nesting
- fix(opencode): bound BTW prompt inheritance
- fix(opencode): enforce BTW execution bounds
- fix(opencode): validate persisted BTW parents
- fix(opencode): retry persisted BTW adoption
- fix(opencode): restrict unverified BTW sessions
- fix(opencode): retry BTW session classification
- fix(opencode): propagate BTW classification failures
- fix(opencode): close final BTW boundary gaps
- fix(opencode): await BTW cleanup on dispose
- fix(opencode): await pending BTW creation
- fix(opencode): own every BTW cleanup
- fix(opencode): preserve BTW route ownership
- docs(opencode): index BTW feature module
- fix(opencode): reject deleted pending BTW
- fix(opencode): preserve BTW cancellation semantics
- docs(opencode): update BTW hook inventory
- fix(opencode): revalidate BTW parents
- Merge pull request #7058 from code-yeongyu/feat/btw-codex-side-ui
- fix(runtime-fallback): prevent repeated-error stalls (fixes #6579)
- fix(runtime-fallback): dedupe model-less retry statuses
- fix(runtime-fallback): distinguish retry variants
- fix(runtime-fallback): retain active retry keys
- fix(runtime-fallback): reset retry keys on manual model change
- fix(runtime-fallback): reset retry keys on variant change
- test(runtime-fallback): record variant reset QA
- test(runtime-fallback): prove source-current OpenCode QA
- fix(runtime-fallback): read variant from chat output
- fix(runtime-fallback): preserve fallback variants
- fix(runtime-fallback): persist effective fallback variant
- fix(runtime-fallback): preserve variant lifecycle state
- fix(runtime-fallback): scope model-less retry dedupe
- fix(runtime-fallback): align fallback generations
- test(runtime-fallback): wire generation acknowledgment
- fix(runtime-fallback): preserve effective retry state
- fix(runtime-fallback): isolate retry generations
- fix(runtime-fallback): align retry reasoning state
- fix(runtime-fallback): honor explicit retry variants
- test(lsp): isolate Windows compatibility checks
- fix(runtime-fallback): retain queued fallback state
- fix(runtime-fallback): align created fallback identity
- fix(runtime-fallback): acknowledge synthetic retries
- fix(runtime-fallback): reject stale timeout generations
- fix(runtime-fallback): own queued retry generations
- fix(runtime-fallback): bind timeouts to state generations
- fix(runtime-fallback): index registered category models
- fix(runtime-fallback): restore effective primary variants
- fix(runtime-fallback): preserve explicit retry effort
- fix(opencode): route only marked fallback retries
- test(qa): record PR 6611 fallback evidence
- test(qa): record pre-push fork head
- test(qa): verify PR 6611 after dev rebase
- fix(runtime-fallback): recover skipped retry status keys
- fix(runtime-fallback): scope retry marker to fallback generation
- fix(runtime-fallback): clear first skipped retry key
- fix(runtime-fallback): mark reused internal retry parts
- Merge pull request #6611 from MoerAI/fix/6579-runtime-fallback-dedup
- fix(opencode): require remote BTW parent confirmation
- test(qa): check in BTW revalidation evidence
- Merge pull request #7074 from code-yeongyu/fix/btw-parent-remote-revalidation