github code-yeongyu/oh-my-openagent v5.0.0-beta.54

latest release: v5.0.0-beta.55
3 hours ago

OMO 5.0.0-beta.54

Devin is a first-class provider now — OAuth login, the native Cascade transport, and SWE-2 running on the prompt it was tuned for. Goals stop blocking themselves on bookkeeping they cannot satisfy, Windows sessions stop losing their RPC host to a race, and every saved account can finally carry a name you recognize. The engine underneath is senpi 2026.9.11.

Devin (Cognition) is a provider you can log into

Sign in to Devin the same way you sign in to anything else. The login runs Devin's own CLI authorization flow — PKCE S256, a loopback callback on 127.0.0.1:59653, and the state validated before the code is ever spent — and the issued CLI token is stored with the expiry read out of its own JWT rather than an assumed lifetime, so the session knows when it actually goes stale (#1601).

Devin models stream through the native Cascade protocol, not a translation layer. The devin-agent Connect/protobuf transport maps text, thinking, tool calls, usage, and stop reasons straight onto the shared stream contract. A failed or content-filtered stop surfaces as a real error instead of a turn that quietly ends, and a truncated turn keeps its length stop reason so retry logic can tell "the model stopped" from "the model was cut off". Model discovery is authenticated with your stored credential and falls back to the bundled SWE seed when the discovery endpoint is unreachable, so a rate-limited or offline discovery never leaves you with an empty model list (#1604).

SWE-2 runs on the Kimi K3 prompt. OMO routes devin/swe-2-low|high|max and bare swe-2 to the bundled Kimi K3 atlas system prompt — the one this model family was actually tuned against — instead of the generic atlas instructions. The match is on a name boundary, so swe-1-7 and swe-20 are untouched, and SWE-1.x keeps its existing prompt (#8130).

The changelog you see after an update is OMO's own

omo now ships and renders an OMO-owned changelog instead of the engine's. Until now the post-update notice rendered senpi's changelog, so an OMO release announced engine entries and said nothing about OMO's own work. The changelog source is now part of every launcher payload - the npm package, the compiled binary and its contract pins, and the local plugin launcher - and the renderer reads it with source-isolated seen-version tracking, so the engine's notice and OMO's notice never overwrite each other's "already seen" state. The senpi side of the same pairing landed as branded changelog support (#1583), which is what lets a fork point the renderer at its own file and authored version.

Goals block when they are genuinely blocked, and not before

A goal no longer refuses to move because of its own audit. The rule that a goal may not be marked blocked while a live resumption channel (a monitor, a background session, a detached eval cell, a child task, or a pending question) can still deliver — and not until the same blocker has survived three goal turns — now lives where it belongs: in the goal continuation prompt and the update_goal tool description. The transition itself is model-controlled again; update_goal enforces only that a blocked call carries a reason. create_goal likewise carries a decision rule for work that outlives the turn rather than "only when explicitly requested".

A provider policy rejection ends the turn instead of looping. A terminal policy refusal now blocks the active goal rather than queuing automatic recoveries that cannot succeed. The unstructured Codex diagnostic (This request was blocked by our safety systems) is trusted only when the message carries the Codex responses api id, so another provider or gateway emitting the same sentence keeps its ordinary provider and system recovery — and the api id is pinned against the shipped model catalog, so renaming it there cannot silently disarm the guard (#1520, thanks @rlaope).

ulw-loop's Codex goal is a driver, not a gate. Completing a ulw-loop story used to throw ulw_loop_codex_snapshot_mismatch and refuse the checkpoint whenever get_goal disagreed with the plan's objective, reported a paused or limited status, or was missing entirely. All of those are now warnings with a concrete next action — call get_goal, resume the goal, or call create_goal with the plan's objective pasted in verbatim — and the checkpoint goes through. checkpoint --status complete no longer requires --codex-goal-json, and a value that is neither JSON nor a readable path fails with the stable ULW_LOOP_CODEX_GOAL_JSON_INVALID instead of a raw ENOENT (#8122).

Windows sessions stop losing their RPC host

Four separate ways a Windows session could fail to start are gone. A reuse probe now registers its socket error listener before writing the named-pipe handshake, so a pipe an idle host removed while the probe was in flight reads as "no existing host" and the caller starts a fresh one instead of the ENOENT escaping and failing the session (#1593). Ownership checks no longer treat a temporarily empty process-identity observation for a live PID as evidence that the shared host is dead, so a transient Windows CIM gap can no longer make one caller terminate another caller's healthy host. The supervisor creates its internal socket directory recursively and provisions a missing public socket secret while reusing a valid one, so launching --internal-rpc-host-supervisor on a fresh profile reaches its listener instead of crashing twice on ENOENT (#1370).

And a busy machine no longer kills the host it just started. Every Windows identity probe spawns powershell.exe with Get-CimInstance under a one-second timeout; under load every attempt times out, and the host that was already alive and answering its pipe was refused with started but its process identity stayed unreadable and then terminated. Such a host is now registered with a pidfile that explicitly carries no ownership guard: the record can never claim the host or authorize a signal, so the worst case is a fresh host on the next start instead of a healthy one being killed (#1609).

When a child really does fail to start, the breadcrumb says what happened. The durable task_start_failed record now carries rejected_while: alive | exited: alive means the prompt write failed while the child was still running and no exit cause is invented from the cleanup kill that follows, exited means the child had genuinely exited and its real exit code and signal are preserved. The old record blamed the cleanup SIGKILL for the failure, which read as a crash that never happened (#8114).

Accounts you can tell apart

Name your saved accounts. /gpt-account rename <id> <display name...>, /claude-account rename <id> <display name...>, and /account <provider> rename <id> <display name...> attach a human label to any saved OAuth account, and clear-name <id> removes it. Labels render as displayName (id) in the status surfaces and in the footer, while pins, removal, refresh, and session affinity keep using the immutable id. Labels are NFC-normalized with collapsed whitespace, capped at 32 terminal columns, and rejected when two of them would render identically — the comparison folds case, compatibility forms, invisible code points, and Cyrillic lookalikes, so Work and Wоrk cannot both exist in one provider.

Multi-account pools stopped eating each other. A provider-owned login pool is merged onto the stored pool at commit time instead of overwriting it with the snapshot taken before the browser flow, so a sibling account's rotated refresh token or fresh rate-limit block survives another account's login. A slot still holding the managed sentinel is healed the moment auth.json is read and the repair written back once, so a second login can no longer leave a dead login-N entry that hard-errors every request whose affinity lands on it, and an unconfigured-slot auth miss is classified per credential so one bad slot cannot dead-end a healthy pool (#1304, thanks @eddieparc).

Claude SDK sessions recover instead of re-sending everything. A persisted binding whose prompt or toolset drifted after a stream-start timeout now forks the stored session at its last assistant UUID rather than flattening megabytes of transcript into a fresh request, and both the timeout and a bare invalid_request remint on the same model instead of hard-hopping onto an unauthenticated gateway route. Lock file is already being held is classified as transient and retryable rather than an unknown terminal failure.

Smaller things that bite less often but bite hard

$ skill autocomplete behaves like a completion, not a hijack. Skill hints complete at valid prompt boundaries while literal shell variables such as $HOME and $1 stay untouched (#1575), and the completion stays alive on multiline drafts and on follow-up input typed while a turn is streaming (#1590).

The ask-user overlay answers with plain Enter. Enter confirms and advances through question tabs, multi-select choices survive confirmation, an explicit Submit tab carries optional comments and partial answers, editor focus traps are gone, and a partial answer no longer demands a comment before it can be reported (#1573).

Clipped eval output keeps a full copy. Output truncated by a narrow terminal column cap now preserves a recoverable full-output artifact, and the eval instructions tell callers to emit large text in bounded chunks or through offset-based reads and to treat a truncation notice as incomplete data rather than the whole result (#1600).

A remote catalog refresh cannot downgrade the shipped one. Remote pi.dev refreshes no longer lower or replace capabilities declared by the static model catalog: existing rows and -fast variants stay authoritative, conflicting provider or model fields are exposed through the remote-catalog diagnostics API, and malformed remote rows are rejected outright.

Credential reloads are observed even inside one filesystem tick. Auth and cached provider-settings reload detection keys off file content revisions instead of mtimes, so two rewrites landing in the same timestamp granularity are both seen and the session picks up the newer credentials deterministically.

DeepSeek V4.1 Flash has its own preset. Every published id shape resolves to it — deepseek-flash, deepseek-v4.1-flash, deepseek/deepseek-v4.1-flash, deepseek-ai/DeepSeek-V4.1-Flash, fireworks' deepseek-v4p1-flash, venice's deepseek-v4-1-flash — along with the official provider's retired deepseek-v4-flash aliases, which now serve V4.1 Flash. The preset deliberately carries only the shared core and the eval-routing stance: the V4-Flash repair rules were written against transcripts from a model that no longer exists (#1574).

Repeated reflection failures back off instead of retrying on every step. An automatic reflection that fails now records the consecutive-failure count on the journal and pushes its next eligibility out exponentially - five seconds, then ten, then twenty, capped at five minutes - so a machine whose reflection child cannot start stops burning a retry on every completed step and recovers on its own once the cause clears (#8128).

The recall sidecar is configurable. memory.recall gains category (default quick), per-event character caps (tool_args 400, result_head 600, assistant 1500, prompt 4000), sidecar_max_tokens (48000), max_concurrent_wakes (2), and tool_budget (8), settable at the shared root, the harness or profile layer, or per agent (#8126), with a dedicated recall-wake lease domain underneath so concurrent wakes serialize on their own lock rather than contending with reflection (#8127).

Image-heavy /resume stops reparsing the transcript. A resumed session used to reparse the complete JSONL once per evicted resident string; one ordered materialization pass now performs a single authoritative history load while preserving transcript contents and branch state (#1407).

Engine: senpi 2026.9.11

The engine release folded into this build carries everything above that is not OMO-side, plus:

  • The GPT-6 Astra preset drops its three-attempt failure cap for an unbounded-retry rule that widens the source on an empty lookup, ends a turn only when a pending handle will wake the session, requires a named next step to be taken in the same turn, and defaults its question tool to the non-blocking mode.
  • Branded builds can ship their own changelog, with an absolute changelog path and authored version, source-isolated seen-version tracking, and interactive rendering; engine changelog notifications keep their existing link rewriting and install telemetry (#1583).
  • OAuth login stops painting two live prompts when the browser callback finishes before the paste-code field is submitted, and an interleaved waiting or info step replaces the live hint row instead of duplicating it.

npm i -g omo-ai@beta

After updating, restart running sessions: a process cannot adopt a new payload in place, and omo doctor names sessions still running from an older payload.

Don't miss a new oh-my-openagent release

NewReleases is sending notifications on new releases.