Added
oh-my-openagent install --platform=native now installs OmO Native for you, so you no longer have to know the package name or the recommended runtime. native is a public platform now, listed in install --help and in the interactive picker beside OpenCode, Codex and Both. Choosing it performs the real install - bun add -g omo-ai@beta when bun is on PATH, npm i -g omo-ai@beta when it is not, with bun named as the recommended runtime - and then points you at omo setup. When the global install fails, the exact command to run by hand and the reason it failed are printed instead of a raw error. The in-repo development adapter keeps today's behaviour under --platform=native-dev, still gated by an environment flag (OMO_ENABLE_NATIVE_DEV_PLATFORM, and the old OMO_ENABLE_SENPI_PLATFORM is still accepted). (#8618)
An OpenCode session can point you at OmO Native from inside the TUI. The only pointer used to print at install time, which npm hides by default and which scrolls away for everyone else. A throttled toast on session start now names OmO Native and the install command, and /native in the command palette opens a dialog: install prints the command for you to run, or you can open the guide, be reminded in a week, or stop asking. The toast stays off when Native is already installed, when native-edition-nudge is in disabled_hooks, in a child session, and when the toast cannot record itself - a showing that cannot be remembered is skipped, so it cannot nag every session. Automatic showings stop after four, with widening gaps, and at most once per process. (#8619)
Changed
The unspecified-low category now runs on MiMo V2.6 Pro first, and its Grok rung moves to Grok 4.7. (#8652)
unspecified-low is where delegated work lands when no specialist category fits and the job is contained. The chain led with Grok 4.6 at xhigh; it now leads with MiMo V2.6 Pro at max, served by Xiaomi or opencode-go, with Grok 4.7 at xhigh right behind it. Grok 4.7 is not served by the opencode provider, so that lane left the rung and opencode-go joined it. The rest of the chain - GPT-5.6 Terra, Claude Sonnet 5, Qwen 3.8 Max Preview, DeepSeek V4 Pro - is unchanged, and MiMo V2.5 Pro stays as the last rung.
Write your harness block as [native] in omo.json, and delegate to the omo-native-* reviewers. (#8620)
The standalone edition is branded OmO Native, but the block you write in omo.json to override settings for it was spelled [senpi], and the reviewer agents you delegate to by name were omo-senpi-code-reviewer, omo-senpi-qa-executor and omo-senpi-gate-reviewer. Both spellings came from the engine's package name.
[senpi] keeps working. It is canonicalized when the config is read, so a config nothing can rewrite still applies every value it sets, and first launch rewrites the key in the file once and names it in a startup notice. A file carrying both blocks resolves [native] and reports the ignored one. A config that never mentioned [senpi] is not touched at all.
The reviewer agents now answer to omo-native-code-reviewer, omo-native-qa-executor and omo-native-gate-reviewer. The old names still resolve for one release line, so existing skills and AGENTS.md files keep working while you rename them.
The engine underneath OmO Native is still senpi and still called senpi. The senpi command, @code-yeongyu/senpi, SENPI_CODING_AGENT_DIR and the telemetry identifiers are unchanged.
The catch-all unspecified-high category no longer runs on GPT-6 Astra. (#8616)
Work lands in unspecified-high when no specialist category fits and the job is big, so that lane absorbs a large share of delegated turns. Its chain led with Astra at high, which put the most expensive reasoning model on the most generic lane.
The chain now starts at the rung that already sat behind Astra: Claude Opus 5 at xhigh, then GLM 5.3 at max, then Kimi K3 at max. The default written in the category config moves to Opus 5 with it, so the primary rung and the model a user reads in their config agree.
Astra stays where it was chosen on purpose: ultrabrain, deep-high, and the plan reviewer. Point the category back at a GPT-6 model in your own config and the child still gets the Astra-tuned prompt append.
quick drops Kimi HighSpeed from its model chain, and the two search agents (explore, librarian) pick it up with thinking off. (#8616)
Kimi HighSpeed led the quick chain and no other lane used it. The quick chain now starts at GPT-5.6 Luna Fast at low, followed by DeepSeek V4 Flash at off.
explore and librarian now lead with Kimi HighSpeed at variant off. The Kimi endpoint rejects an explicit disabled-thinking block, so senpi sends the request with no thinking parameter and the lowest adaptive effort, which is what a grep-and-report agent needs. A machine with no Kimi Code subscription falls through to Luna Fast, the model those two agents ran on before this change.
The standalone edition is called OmO Native everywhere. The installer hint, the package postinstall notice, the installation guide, the README and its four translations, and the omo-ai package description called it the "Senpi edition" - a name the product itself never used, having said OmO Native in the TUI footer and Edition: Native in omo doctor all along. The telemetry, model-profile and config-startup notices on that same screen opened with omo-senpi. They all say OmO Native now, and the hint names what you get: the same omo as one omo command, with no OpenCode host required, while the install you already have keeps working. senpi still names the engine, in omo doctor, in this file's engine headings, and in its own environment variables and paths. Telemetry identifiers are unchanged. A regression test fails if the old edition wording comes back. (#8618, #8629)
Engine: senpi 2026.9.22-2
A shared RPC host compiles one extension module generation per source version, not one per session. Opening a session used to compile a fresh copy of every extension and leave it in the module registry for the life of the host, so a long-lived daemon retained another full graph each time. Sources are compiled once and reused until a source file changes; each session still gets its own extension instance. Measured on one machine, retained size per session fell from 74.6 MiB to 3.1 MiB. (senpi #1952)
Grok 4.7 is a supported model family. Every grok-4.7 id shape - including aggregator ids like openrouter/x-ai/grok-4.7 and Venice's dashed grok-4-7 - reuses the Grok 4.6 system prompt, grok-4.7 is a promptPreset value, and the xAI provider default moves from grok-4.5 to grok-4.7. (senpi #1990)
A hard OpenAI usage-limit 429 is terminal on the first failure. usage_limit_reached / "The usage limit has been reached" used to classify as a transient rate limit, so a turn spent five retries over about a minute on an account that cannot serve another request until the quota resets. The same wording now pins a billing fallback for the rest of the session. Warnings that only approach the limit still retry. (senpi #1969)
Normalizing a tool call's arguments no longer rewrites the assistant message the model produced. Two argument normalizers — the 80-character clamp on an eval cell's summary and the edit tool's rewrite of its edits list — used to change that message in place. On the claude-sdk-oauth lane that was the usual cause of Session continuity lost - resent the full conversation (assistant_rewritten). They now run on a detached copy. The 80-character eval summary limit is unchanged: it is enforced on the rendered line. (senpi #1472)
A supervised RPC host whose supervisor loses its observer keeps reconnecting, and a host whose socket file is deleted drains and exits. The supervisor retried a lost observer once and then gave up, which kept an idle window from ever elapsing because an unhealthy observer counts as busy; reconnects now continue until they succeed, and an observer that stays unhealthy for a whole idle window no longer counts as busy. Removing the workspace or deleting the socket used to leave the pair running until reboot; attached sessions finish, then the host exits. A host started as persistent still never exits for idleness. (senpi #1979, #1961)
Opening a second terminal on a live Claude SDK session no longer throws away the resumable binding (the saved link that lets the next turn continue the conversation instead of resending it). The startup notice it appends used to retire the binding, so the next turn re-sent the entire conversation as registry_miss. Append-only entries after the committed assistant keep the binding; a later assistant message, a compaction, a branch summary and an explicit invalidation still discard it. A fork point (the message the conversation branched from) that Claude Code reports missing is dropped instead of being requested again every turn. (senpi #1964, #1958, #1973)
A session whose worker dies while it is being opened now reports open_failed carrying the worker's reason, instead of session_closing, which means a session somebody else is tearing down. (senpi #1953)
Fixed
A DAG snapshot now carries what each node actually returned, and shows when a running node's child last did anything. (#8674)
workflow tells you to detach and peek with action=snapshot, but the snapshot never carried a node's output. The text was being saved - it just was not reachable except through the blocking wait, so a run you were supervising showed six nodes with nothing to read, and the only way to learn what a child had done was to look at the files it wrote.
A settled node now carries output (the child's final message, up to 2000 characters) and outputBytes (its full size, so you can tell a truncated preview from the whole thing, and a node that returned nothing reads as 0 rather than as nothing recorded). A running node carries lastActivityAt, the last time its child wrote anything at all, and snapshot names any running node that has been silent for more than ten minutes. Silence is reported, never judged - one long tool call looks the same as a stalled child - but a node quiet for fifty minutes is now something you can see instead of something you have to guess.
The end time was already recorded, under the name completed_at. A node stuck in running because its child finished but was never reaped is a separate defect, tracked in #8659.
A git that dies mid-command no longer hangs isolation work until its helpers exit. runGit settled on the child close event, which fires only after every stdio pipe closes — but git's ! alias shells inherit those pipes. On Windows, killing git alone (TerminateProcess has no tree semantics) left those shells holding every handle, so a run whose git had already failed stayed pending until the last survivor exited; in CI that raced the 30-second test budget and intermittently lost, with the survivor's locked working directory surfacing as an EBUSY on fixture teardown. A git that exits to a signal death or a disallowed exit code now settles at once: what remains of the tree is killed immediately, and pipes still held a second later are force-closed so the typed GitCommandError surfaces with the output kept so far. Normal commands are unaffected — their pipes close in milliseconds anyway. (#8663)
A resumed DAG no longer shows nodes as running when nothing is running them. (#8657)
Resuming a session re-adopted every DAG node whose child task record still said running, without asking whether anything in the resuming process still held that child. A child whose host went away is kept as running on purpose, so it can be reopened from its transcript later - but a DAG node waiting on one waits forever, because the run folds a node only when its child settles here. The node therefore stayed running in the run's saved state through restart after restart, with the work behind it blocked, and the widget kept counting hours on children that had died hours ago.
Such a node now fails at resume with a reason naming the task and why it cannot be reached, the nodes behind it skip as they would for any failure, and retry or send still revives it. A node whose child this session really does hold is reattached as before.
Resuming a session that has DAG history no longer freezes the TUI. Listing DAG runs parsed every checkpoint in the runs directory on each call, and the status widget asked for that list about once a second, so a resume - a burst of checkpoint writes - starved the screen while the process stayed alive and still answered prompts. The list now keeps a per-run summary cache. On a directory of 710 checkpoints, one call fell from 473 ms median to 3.4 ms. (#8649)
DAG run history is pruned on the advertised 7-day retention. The prune existed, was tested, and was called from nowhere, so checkpoints, event logs, results and keys accumulated forever. A long-lived project directory held 711 checkpoints, the oldest 25 days old against a 7-day policy. The sweep now runs once per DAG runtime after session start, off the start path so a stale file cannot fail the session, and indexes the keys and locks directories once per sweep. A paused run whose lease holder is still alive is kept. Against a copy of a 170 MB state directory the sweep cut 10,623 files to 1,779 and 170 MB to 38 MB. (#8651)
Migrating a leftover config.jsonc writes [native], and a [native] block gets the same reasoning cleanup as the old name. First launch used to copy the retired harness key into the new file, so a later pass had to rename it. The leftover-file transform now emits [native]. Reasoning-key unification walks [native] as well as the old spelling, because that cleanup runs before the rename pass and a file already written with the documented name was being skipped. (#8631)
A failed turn in a delegated task is no longer counted as a turn. When a provider error ends an assistant turn, that turn now lands in a new failed_turns stat instead of inflating turns, and its usage - typically an all-zero block the provider sends alongside the error - contributes no tokens, no cost and no generation time. A run that never produced a successful turn reports token and cost coverage as unavailable and omits the cost field entirely, instead of claiming turns: 6 for six consecutive failures. A successful turn that cost $0 keeps reporting a cost of 0, and a failure re-anchors the generation window so the next successful turn's throughput is measured from the failure, not from spawn. The live task row now tells the same story: it reads starting until the first successful turn lands - no phantom turn 0, no cost token - shows failed N with the verb retrying while provider attempts keep failing, and returns to running only after a real turn. Both the TUI status line and the background task row draw their stats tokens from one shared builder, so the two grammars cannot drift apart again. (#8627)
The ulw-loop gate reviewer is enforced again on the Codex surface. (#8630)
Renaming the reviewer agents to omo-native-* left the Codex-side ulw-loop guard (which checks that a gate reviewer only starts after a manual-QA artifact exists) matching only the retired omo-senpi-* spellings. Because the resolver (which maps a reviewer's old name to its new one before any check runs) canonicalizes a name before the guard sees it, the guard received a name it did not recognize and treated the spawn as ordinary work: the gate reviewer could start without a manual-QA artifact, and the per-reviewer no-progress cap stopped counting. Both checks apply again, and either spelling is recognized, so nothing that named the old reviewer breaks. The denial message and the spawn counter now name the reviewer that actually ran.
Known issues
One Windows-only test flake is not fixed in this release. On a slow Windows CI runner, the DAG lock test in senpi-task (store.test.ts) can still fail with Timed out acquiring DAG lock when an earlier run crashed while it was clearing a lock. The fix (#8672) ships in 5.0.0-beta.84. It changes only how that leftover lock file is cleared on Windows; nothing in this build behaves differently for users.
- 6b5e2ab Merge pull request #8681 from code-yeongyu/release/v5.0.0-beta.83-source-state
- d862a09 Merge pull request #8680 from code-yeongyu/fix/release-stamp-codex-install-bundle
- 376b1a7 ci(publish): rebuild and stage the Codex installer bundle in the release commit (#8679)
- 0fc93b3 test(publish): RED the release stamp must rebuild the Codex installer bundle (#8679)
- 5abfaba Merge pull request #8677 from code-yeongyu/fix/8674-dag-node-output-ended
- 3147cb2 fix(dag): never let the node activity clock throw out of a snapshot projection
- b9e5f88 fix(dag): project a node's own output and its child's activity clock into the snapshot
- c5228ce Merge pull request #8675 from code-yeongyu/docs/beta83-known-issue
- 2c28a48 docs(changelog): note the win32 DAG-lock flake fix ships in beta.84, not beta.83
- 15ec5e1 Merge pull request #8665 from code-yeongyu/fix/win-command-test-stdin-dead-child
- bf006d5 Merge pull request #8669 from code-yeongyu/feat/8668-browser-skill
- 06bcc1e docs(evidence): record the CI rounds and the shipped-set drift they exposed
- a007602 fix(telemetry,skills): allow browser in the skill_loaded enum and the remaining shipped-set lists
- 70cecbc fix(skills): register the browser skill in every shipped-set list CI checks
- 7112a2a feat(skills): ship a browser skill that drives the user's own browser
- cb8d8c1 feat(shared-skills): deny share links, token urls, mail addresses and credential env paths
- 5ae21b9 Merge pull request #8661 from code-yeongyu/docs/changelog-beta83
- 935d8b3 docs(changelog): five clarifying clauses on the twice-flagged sentences
- bea5e27 docs(changelog): one so-what sentence for Native install, two glosses for ulw-loop
- 895548b docs(changelog): gloss the ulw-loop guard and the Native install so-what
- 990906a fix(isolation-core): settle runGit at child exit when pipe-holding survivors pin close
- 9bcde5d Merge pull request #8666 from code-yeongyu/fix/nudge-state-windows-unwritable
- 679371f test(omo-opencode): build the unwritable nudge-state fixture from a file parent
- 2153e2d docs(changelog): complete [Unreleased] for 5.0.0-beta.83
- fae5622 Merge pull request #8660 from code-yeongyu/docs/8657-live-verification
- 2ca9dc0 docs(evidence): record the post-merge live verification for #8657
- 7dd8ad4 Merge pull request #8658 from code-yeongyu/fix/dag-recovery-orphaned-running-node
- ec99948 Merge pull request #8656 from code-yeongyu/fix/8651-dag-retention-call-site
- f6fa6a8 Merge pull request #8653 from code-yeongyu/feat/8652-unspecified-low-mimo-v2.6-grok-4.7
- 01ae51b fix(model-core): snapshot-back mimo-v2.6-pro so the capability guardrail passes
- 0d8bfc1 docs: track the mimo-v2.6-pro unspecified-low default and the grok-4.7 rung
- 49e4bc5 feat(model-core): lead unspecified-low with mimo-v2.6-pro and move grok to 4.7
- 7f6be0c Merge pull request #8650 from code-yeongyu/fix/dag-resume-tui-repaint
- 5bac023 test(dag): record the real-surface resume proof for the list() summary cache
- eb04a9a fix(dag): stop re-parsing every checkpoint when listing DAG runs
- 2a80b83 Merge pull request #8647 from code-yeongyu/feat/8619-native-edition-nudge
- e325caf test(omo-opencode): drive the command registration instead of assuming it
- b811dc1 test(omo-opencode): capture the live session.created frame with corrected assertions
- 32cab18 Merge pull request #8648 from code-yeongyu/test/8632-widen-wording-guard
- b0f882a test(omo-opencode): make the widened wording guard actually enforce rule 2
- 20b635e test(omo-opencode): correct the live-capture assertions and state their scope
- 409262f feat(omo-opencode): add the OmO Native command-palette dialog
- d9bfd6b test(omo-opencode): record the native-edition nudge QA evidence
- 729b5a8 feat(omo-opencode): register the native-edition nudge hook
- c7251be feat(omo-opencode): wire the native-edition nudge to the toast surface
- e504f68 feat(omo-opencode): add the native-edition nudge decision core
- 032dbbf Merge pull request #8641 from code-yeongyu/docs/8628-native-wording-sweep
- 1d69ece docs: name the standalone edition OmO Native and recommend bun
- aa436cb Merge pull request #8642 from code-yeongyu/fix/8631-migration-native-key
- 0925e75 fix(config-migration): emit [native] from leftover config.jsonc transform
- af7c5f6 Merge pull request #8639 from code-yeongyu/fix/8629-native-notice-wording
- 1bc4541 docs: keep the notice-rename entry out of the human-command audit
- 76c2612 docs: record the OmO Native notice rename
- 11763e5 Merge pull request #8635 from code-yeongyu/fix/8630-ulw-loop-reviewer-alias
- c775ef0 Merge pull request #8638 from code-yeongyu/fix/8633-untrack-install-local
- e79024a test(codex-install): record the post-rebase gate and acceptance capture
- 41e6e05 fix(codex-install): digest the bundle's real inputs, not just the installer directory
- 1f506d9 docs: record the reviewer-guard repair in changes.md
- a844b2f docs: record the ulw-loop reviewer-name guard repair
- e217be3 fix(omo-codex): recognize the renamed ulw-loop reviewer agents in the spawn guard
- 9c43c5a Merge pull request #8637 from code-yeongyu/fix/8636-wording-guard-red-on-dev
- 329998c docs: name the retired reviewer ids literally so the wording guard passes
- f66850f Merge pull request #8634 from code-yeongyu/fix/8627-failed-turn-is-not-a-turn
- b1f8622 fix(task): live rows read "starting" until a real turn lands
- e4dd14f Merge pull request #8623 from code-yeongyu/feat/8620-native-config-contract
- 8773a5a Merge pull request #8624 from code-yeongyu/fix/8618-omo-native-wording
- 9eb97f8 docs(qa): attribute every test failure seen while landing the rename
- 66b65b3 docs(qa): record the repo-audit gate results for the OmO Native rename
- 62b548b test(qa): record the bundle freshness verification
- 5f816fa fix(omo-opencode): keep the legacy-command and shim audits green after the rename
- 5e5c60b docs(evidence): redact the sandbox temp paths
- 81e4958 test(qa): record the root typecheck evidence
- 722290d test(qa): record the disabled_skills harness-scope red/green evidence
- 0a13841 docs(evidence): redact the capture paths to a repo-relative prefix
- ca68564 build: regenerate the omo JSON schema for the [native] harness block
- 7ee8243 fix(omo-config-core): honor a legacy harness-scoped disabled_skills entry
- a68561a docs(changelog): describe the OmO Native rename and the public native platform
- e1c9398 test(omo-opencode): guard the OmO Native wording on every user-facing surface
- f006837 docs: call the standalone edition OmO Native
- a2cb290 fix(postinstall): name OmO Native in the package notice
- befb0d9 refactor(omo-opencode)!: rename the standalone edition surfaces to OmO Native
- a8e4e7a feat(omo-opencode): add install-native, the real OmO Native installer
- b65a071 test(qa): record the [native] harness contract and reviewer alias evidence
- 1fc3961 docs: describe [native] as the harness block and omo-native-* as the reviewers
- 9b6029e Merge pull request #8622 from code-yeongyu/fix/example-presets-routing
- e5170c8 docs: stop recommending Astra for unspecified-high in the shipped examples
- cd00c00 Merge pull request #8617 from code-yeongyu/fix/8616-unspecified-high-drop-astra
- e74b8f8 feat(categories): drop Astra from unspecified-high, move Kimi HighSpeed from quick to the search agents
npm i -g omo-ai@beta