* fix(doctor): detect Codex bwrap loopback denials that unshare misses
The Codex bwrap network-namespace probe ran `unshare --user --map-root-user
--net true`, which never configures loopback. It passed on hosts where Codex's
Bubblewrap sandbox then fails before any shell command with
`bwrap: loopback: Failed RTM_NEWADDR`, the exact symptom doctor documents.
Doctor now asks the Codex plugin to run the configured Codex runtime's own
`codex sandbox` in workspace-write mode with network access disabled, using a
throwaway CODEX_HOME and a bounded timeout. Only Codex's own namespace-denial
lines are diagnosed; other failures are reported as unverified. The plugin
owns binary selection (shared with the managed app-server check); core reaches
it through the existing Codex owner-selection and trust path. The user
namespace probe and its messages are unchanged.
* fix(codex): use the OpenClaw temp root for the sandbox probe
Extension runtime code must not use host tmp defaults; the boundary check requires resolvePreferredOpenClawTmpDir from the plugin SDK, matching the Codex plugin's other temp users.
* fix(doctor): keep Codex bwrap diagnostics out of update Doctor passes
The Codex bwrap namespace diagnostic is advisory and has no update
migration or readiness dependency, but it ran inside doctor:sandbox,
which update Doctor passes execute for registry migration. It now lives
in its own doctor:codex-bwrap contribution with standalone update scope,
so `openclaw update` never spawns the Codex probe or loads a retained
Codex plugin's probe API, and lists it under "Omitted during update".
Probe commands, gating, and messages are unchanged; image repair keeps
its engine validation through a shared enabled-backend helper.
* feat(ui): select Ultrafast for supported accounts
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(gateway): preserve Ultrafast compatibility and account authority
Negotiate speed decoding per connection and keep canonical session state intact. Fence personal-account catalog requests at final guarded HTTP dispatch. Refresh the measured UI boot manifest without changing performance limits.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* refactor(openai): keep account catalog outcomes together
Move the existing account-scoped result projection into the already imported catalog helper without changing its behavior. Keep the provider owner below its existing line-count ratchet.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test: refresh Ultrafast tool prompt fixtures
Regenerate the canonical Codex dynamic-tool fixtures for the authorized Ultrafast speed value. Update only that enum value and its derived size/hash metadata; keep snapshot checks enabled.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix: stop account catalog requests after default unlink
Bind automatic account selections to the canonical profile writer's committed link authority and carry the real request scope through final guarded dispatch. Keep explicit retained account selections usable after unlink and evict failed discovery custody. Preserve the existing active Auto Ultrafast opt-in while explicit Fast stays priority.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* refactor(codex): use narrowed Auto activation flag
Keep the reviewed Auto tier predicate while satisfying the typed boolean lint contract.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(ui): share speed applicability for optional Ultrafast
Respect the selected request mapping before offering an optional entitled tier. Preserve all three choices on eligible routes and clearable stored preferences on unsupported routes. Reproduced the contradictory catalog regression and passed 59 unit/Chromium cases; scoped independent review found no actionable P0/P1.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(ci): export manifest in same-revision preflight harness
Restore the trusted file omitted when the inline manifest moved out of ci.yml in 9d75a8fe87. Actual preflight job109720001696 failed before tests with MODULE_NOT_FOUND; real Git push and PR materialization fixtures reproduce the same omission. Keep the canonical index export owner, regenerate its workflow projection, and preserve all source/credential guards. Fifteen materialization variants, five import/size checks, root test types, and focused independent review pass.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(ci): satisfy extracted manifest static contracts
Repair inherited check-lint failures from the manifest extraction without changing CI routing: avoid namespace shadowing, retain error cause and the diagnostic callback string contract, preserve nonmutating shard copies, and apply required branch syntax. All1259 scripts lint clean;45 planner/import/size cases, formatting, UI i18n, styles, ratchet and independent review pass.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(ci): centralize dependency-free workflow flag parsing
Remove the extracted manifest local coercion helper and preserve its exact narrow Boolean grammar under the existing script argument owner. Register the canonical declaration rather than weakening the guard, and carry its runtime through trusted preflight materialization and fixtures.77 argument cases,11 declaration-guard cases,71 scoped integration cases, types, lint, export scans and remaining guard commands pass; independent review has no actionable P0/P1.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(gateway): separate model publication authority from selection scope
Keep the actual request lifetime in selected-account HTTP assertions without treating every anonymous unscoped catalog read as a personal account projection. Restore the established models.list response shape; no assertions weakened.177 model/catalog/session cases and10physical HTTP authority cases pass, together with types, lint, ratchet and independent review.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix: preserve session response argument tuples
Forward the original response tuple while projecting successful legacy payloads, without appending optional undefined arguments.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(codex): preserve existing Ultrafast opt-ins
Keep the v2026.9.7 Fast and active Auto opt-in semantics while adding explicit per-session Ultrafast. Standard still clears the tier. Cover cold and warm native turn requests without requiring a migration.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(ui): distinguish speed labels from model names
Match the complete Effort and Speed section labels rather than the Speed only fixture model. Retain the independent absence assertions for reasoning and speed controls. All four failures reproduced before the repair; the complete 13-case bundled browser file passes afterward.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(openai): intercept the shared transcription socket
Update the two stale socket mock registrations after the upstream transport consolidation. Keep the actual provider/session code, fake peers, assertions, timeouts, and Bun transport guard unchanged. All 86 OpenAI shard files pass: 1263 passed and one existing skip.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(gateway): construct complete session reset callers
Replace partial caller objects cast as never with the existing typed session mutation client fixture. Preserve provenance and required-sandbox assertions and the production client capability contract. Both CI failures reproduce before the repair; all 15 reset-model cases pass afterward.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix: confirm the selected Ultrafast command mode
Share the direct command, directive reply, and system-event confirmation formatter so the saved Ultrafast tier is named accurately. Include the accepted manual value in help and docs without advertising an unverified optional native-menu choice. Preserve boolean Fast, Auto, reset, authorization and persistence behavior. Three regressions fail before repair; 274 focused cases pass afterward.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
---------
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(tool-search): run tool_search_code in the QuickJS sandbox
Tool Search code mode spawned a Node --permission child with a node:vm
guest. Under Bun it needed an installed Node, and without one an explicit
code config silently downgraded to structured tools mode.
Run the guest through the Code Mode executor contract with the bundled
quickjs executor on every runtime. openclaw.tools.search/describe/call use
the shared namespace bridge with lazy thenables; the host admits only those
three operations through ToolSearchRuntime. codeTimeoutMs still bounds the
whole invocation, now including executor preparation. A denied or disabled
code-mode-quickjs plugin fails explicitly with next-step guidance instead of
falling back.
Remove the child source, IPC types, stderr-tail handling, and the Node and
Electron capability probe.
* refactor(tool-search): retire the tool_search_code bridge
Keep structured Tool Search and generic Code Mode as the two large-catalog surfaces. Remove the superseded JavaScript bridge and its runtime, display, and QA paths.
Doctor migrates legacy code mode to tools and removes codeTimeoutMs while preserving activation. toolSearch: true now selects structured search; JavaScript orchestration uses Code Mode exec/wait.
* test(tool-search): cover runtime behavior through structured controls
Exercise retained catalog, policy, hook, cancellation, terminal, MCP and client behavior through structured controls and their runtime owner. Delete bridge-only sandbox and JavaScript envelope cases while preserving nested call-id compatibility.
* test(tool-search): drop retired code mode prompt case
* test: repair fixtures exposed by Tool Search retirement checks
Remove the remaining retired Tool Search mode row. Preserve the session reader owner through the media retention mock and remove an unreachable queued-only branch from the ACP controls/submission fixture.
* test(upgrade-survivor): seed retired Tool Search code mode config
Author the legacy mode and timeout through every supported representative baseline CLI recipe, then require structured search and timeout removal after candidate update and Doctor. Existing config validation proves the resulting effective config.
Include the diagnostics native assignment summary in frozen target staging; the required assertion suite exposed its missing import. Node recipe and assertion tests: 238 passed, 157.87s wall. Docker validation remains with the coordinator.
* refactor(tool-search): drop the retired code-mode recovery surface
* chore: shrink assertion baseline after Tool Search retirement
* test(tool-search): drop the unused Tool Search test API
* chore: drop the retired Tool Search test API assertion baseline
* fix(e2e): drop duplicate native assignment staging line
Main now stages native-assignment-summary.mjs for frozen upgrades itself; the branch copy from the Tool Search upgrade proof became a duplicate after merging.
* build(pr): list Tool Search migration in wrapper inventory
The scripts/pr wrapper loads the Doctor config migrations at runtime, so the new Tool Search retirement migration belongs in its extracted component inventory.
* test(e2e): ship the Tool Search recipe to prepared tooling workers
Prepared tooling workers copy only listed source-relative assets, while the
upgrade survivor config recipe reads every section file by name at import.
The new tools-tool-search.json was missing, so the Docker scheduler parent
signal test's runner died with ENOENT and its polling wait reported a generic
5 s timeout that looked like a flake.
List the asset, guard the recipe directory against the preserved list, and
make the scheduler readiness wait fail with the runner's stderr once it exits.
Pass admitted tools to memory prompt providers and enable the parent-local relay for managed Desktop stdio children. Keep native history and child isolation, external-client exclusions, and subscription-sharing restrictions. Local tracking: oc-874.
* fix(codex): restore installed skills with catalog-backed models
* fix(codex): keep skill catalog refreshable on live incognito threads
Moving the installed-skill catalog into thread developer instructions made
every catalog refresh look like a generic policy change. On a live incognito
thread the warm-reuse guard compared the whole creation string, so editing a
skill description and sending another message threw
CodexIncognitoPolicyChangeError before turn/start.
The catalog is now a separate lifecycle input (`skillsInstructions`). The
request builder joins it onto the wire developer carrier after the generic
policy, so catalog-backed models still receive it and persistent threads keep
cold-resuming through the existing policy handoff. The retained ephemeral
record splits the immutable generic policy from the catalog last delivered;
incognito warm reuse compares only the generic policy (unchanged guard, still
fail-closed) and delivers a changed catalog with a `thread/inject_items`
developer message, tracked so an unchanged catalog is not re-sent.
Docs: the runtime guide, system-prompt concept, and token-use reference still
said the catalog rode turn-scoped collaboration instructions; they now match
the thread carrier and the incognito refresh.
Codex protocol behavior checked in sibling ../codex (main 459a79e):
core/src/context/world_state/collaboration_mode.rs:30-42 (catalog messages
replace caller collaboration instructions), app-server-protocol v2 thread.rs
(thread/settings/update has no developerInstructions), turn_processor.rs
thread_inject_items, context-fragments/src/additional_context.rs (1,000-token
cap rules out additionalContext as the catalog carrier).
* test(codex): cover catalog refresh on reused persistent threads
Adds the missing half of the reused-thread coverage. The incognito case
already proved an edited catalog reaches a live ephemeral thread through
thread/inject_items. This covers the persistent case: the catalog rides the
thread developer carrier, so it participates in the thread-config
fingerprint (thread-fingerprints.ts:121). An edited skill therefore
invalidates warm reuse and cold-resumes the SAME thread with the new
catalog, instead of either losing the conversation or answering from the
stale catalog.
Mutation-checked: dropping options.skillsInstructions from the join in
buildCodexThreadConfiguration fails both this test and the incognito
two-turn test, so neither assertion is vacuous.
Also adapts the native skills test to upstream's changed shutdown contract.
closeAndWait() returns CodexAppServerCloseResult rather than boolean since
bcef3b3526 (#139657); the assertion now uses the same
toMatchObject({ exited: true }) form as the other native tests
(thread-lifecycle.native.test.ts:142, settled-turn-finalizer.native.test.ts:57).
* fix(codex): break app-server import cycle and register skills test lanes
Extract joinPresentSections into a zero-import leaf module so
thread-requests.ts no longer imports run-attempt-state.ts, which closed a
10-file strongly connected component in extensions/codex/src/app-server.
The merge base is clean, so the cycle was introduced by this branch.
Register the two new skills test files in the vitest project that already
owns the comparable run-attempt.native-hook-relay test, so full-suite file
ownership is exactly one project per file.
* fix(codex): keep refreshed incognito skill catalogs across compaction
An incognito thread carries its skill catalog in creation-time native
developer instructions. A mid-session catalog change is delivered as a
client-authored developer message, but Codex remote compaction drops those
messages unless retain_client_developer_messages is enabled (off by default)
and rebuilds initial context from the unchanged native instructions. The host
had already recorded the refreshed catalog as delivered, so later turns
skipped reinjection and the conversation silently reverted to the catalog it
started with: edited skills kept stale descriptions and removed skills
stayed visible.
Track the creation-time catalog separately from the current one and
re-deliver the current catalog after every compaction, including compaction
inside a turn, via the existing onContextCompacted hook. An unchanged catalog
still sends nothing, because compaction rebuilds it natively.
* test(codex): cover catalog restoration across native compaction
Drive the packaged Codex app-server binary through a real compaction on a
live incognito thread: turn two refreshes the catalog, turn three exceeds the
resolved auto-compact limit, and turn four must still show the model the
current catalog.
The continuation request after summarization is asserted to carry the
creation-time catalog and not the refresh, which reproduces the reversion
natively. The creation-time catalog stays in the ephemeral thread's immutable
developer instructions and is re-emitted on every request, so restoration is
pinned by catalog ordering rather than absence.
Pin nativeSkillsInstructions in the ephemeral policy binding assertions so a
refresh is shown never to rewrite what compaction will restore.
* fix(codex): re-deliver the catalog after a failed post-compaction restore
A failed or aborted restore was logged and dropped while the retained record
still named the refreshed catalog as delivered. Warm reuse compares that
record, so every later turn skipped the refresh and the conversation stayed
stranded on the creation-time catalog for the rest of its life.
Record what compaction actually restored when the injection fails, so the
next turn delivers the current catalog again.
* docs(codex): state catalog restore timing precisely
The restore is issued as soon as a compaction completes, but that turn's own
continuation request may already have been built, so the guaranteed floor is
the following request rather than the remainder of the compacting turn.
* fix(codex): keep incognito creation policy across standalone compaction
Standalone compaction re-retained the live thread without its ephemeral
policy, so the record lost the creation-time generic policy and the catalog
it had delivered. The next turn then read the live incognito thread as policy
drift, and the discarded catalog refresh was never re-sent.
Carry the ephemeral policy back through the re-retain and record the catalog
compaction actually restored, so an edited or withdrawn skill is delivered
again on the next turn instead of reverting for the rest of the conversation.
* fix(codex): revert the catalog on the incognito compaction path
Standalone compaction only claims and re-retains a thread for non-incognito
session keys, so the previous reversion never ran for the conversations it was
written for. An incognito thread keeps its own live subscription, leaving the
retained record still naming the discarded refresh as delivered.
Correct the retained record in place after a completed compaction, and cover
both session kinds so an incognito key can no longer be masked by an ordinary
one in the regression.
* fix(codex): preserve trajectory helper import after rebase
* test(codex): budget the compaction history read in skill catalog tests
The three post-compaction catalog re-delivery tests never observed
`thread/inject_items`, which read as the repair being broken. It was not.
Compaction runs the real `before_compaction` hook, which performs an actual
mirrored-session history read; its first worker start costs several seconds.
`createParams` defaults `timeoutMs` to 5s, so the attempt execution budget
expired inside that read, aborted projection, and the `onContextCompacted`
restore never ran -- reproducing precisely the symptom these tests assert
against.
Give these turns the same budget the sibling compaction tests already use in
`run-attempt.skills.native.test.ts` and `run-attempt.hooks.test.ts`. Every
assertion is unchanged.
* fix(codex): preserve parent-only skills on managed connections
* test(codex): validate managed instructions before collection
---------
Co-authored-by: Rook <rook@openclaw.invalid>
Co-authored-by: Colton Harris <287090614+Colton-Harris@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
* fix(codex): discover GPT-6 models with runtime 0.155.1
Keep the managed runtime, ACP adapter, and subscription catalog client version on the same exact release. Refresh the native model discovery snapshot from an authenticated 0.154.0 to 0.155.1 cache reuse probe. Related: #155937; follow-up to #155967.
* test(codex): sync runtime fixtures with 0.155.1
Explain missing native-only Codex profiles after upgrades through shared Codex-plugin Doctor and Gateway startup warnings. Keep recovery explicit with provider device-code login and per-agent guidance; warnings do not import credentials or block updates.
Preserve local selected-profile lookup failures across rotation, fallback, and tracing without manufacturing HTTP 401 or misleading reauthentication advice. Keep real provider HTTP failures and credential ownership unchanged. Document the verified shared-store preparation command for upgrades from 2026.9.4.
Thanks @msobrosa for the upgrade report and native-credential ownership confirmation, and @kpwillis for the separate shared-store diagnostics.
Validation: 44 focused assertion-cutover tests passed; changed-file checks passed with the documented nested-checkout extension-lint substitute and failing canary. Published 2026.9.4-to-2026.9.5 proof used isolated synthetic credentials; live OAuth was not exercised. Exact-head CI and independent review passed.
Fixes#152968. Shared-store routing report #148557 remains separate.
Preserve native Codex configuration, tools, and model ownership when continuing supervised conversations through a shared local daemon.
Return valid retained subscriptions after passive preflight and pre-turn startup failures without weakening cancellation, revocation, replacement, or ambiguous-write safeguards. Preserve established native search policy when daemon defaults change, and document credential handoff, refresh ownership, and shared-account limits.
Validation: 291 fresh focused tests passed; exact-head hosted CI passed. Additional live startup-failure/retry capture was not performed; the PR records that limitation and the earlier native proof at its original revision.
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: galiniliev <5711535+galiniliev@users.noreply.github.com>
Back off repeatedly failing catalog sources so newly admitted callers do not
restart the same timeout on every page. Keep retry health in a typed sibling
module while the control owner retains page sharing and stale delivery.
Preserve one immediate retry, bound recovery delays to 60 seconds, and keep
older overlapping failures from undoing a successful recovery.
Isolate the native hook relay build graph while preserving readonly state lookup, explicit policy decisions, and the lazy authenticated Gateway fallback.
Cancel disconnected request waits through the existing approval authority. Keep duplicate callers independently cancellable, retain unbound durable approval deduplication, and detach exact relay-owned entries before callbacks so old cleanup cannot remove a successor. Observe already-started promises when synchronous cancellation wins.
Update managed Codex to the official 0.154.0 release and align its version fixtures and current documentation. This improves lifecycle ownership and reduces the relay import closure; it does not cap hook concurrency, prove faster bursts, or establish resolution of the historical constrained-host timeout.
Related: https://github.com/openclaw/openclaw/issues/91009
Thanks to @nvtoroy for the constrained-host captures and guarded opt-out evidence in https://github.com/openclaw/openclaw/pull/121668 and https://github.com/openclaw/openclaw/pull/111205. The opt-out proposal remains distinct and unimplemented by this change.
Closes the open `accuracy` audit findings scoped to `docs/plugins/`, each
verified against source before editing.
Corrections where the docs understated or misstated the code:
- Telephony support listed 2 of 9 bundled providers that implement
`synthesizeTelephony`.
- `allowInvalidConfigRecovery` named 2 of the 5 recovery cases in
`isAllowedPluginRecoveryIssue`.
- The `activation-command-hint` row omitted the live
`manifest-cli-command-owner` reason.
- A `js`/`export default` config example was neither a real config surface nor
checked by `check-docs-config-examples` (that fence language is skipped);
converted to `json5`, now validated.
- `npm:@openclaw/google-meet` skips the official-catalog install plan; the
package is in the catalog, so the bare spec is correct.
Version scope added only where a release or dated compat record exists:
`2026.4.22` (guardian env removal), `2026.5.2` (Meet access-type control),
`2026.8.1` (Teams/Zoom live validation), `2026.8.2` (Beam named links),
`2026.9.2` (legacy doctor selector), and the dated `removeAfter` records in
`src/plugins/compat/`. Elsewhere the time-relative wording is dropped and
present behaviour stated, rather than a version guessed.
`docs/plugins/plugin-inventory.md` is generated: the fix is in
`scripts/generate-plugin-inventory-doc.mts`, regenerated, `plugins:inventory:check` rc=0.
docs/plugins/codex-harness-reference.md was 68,643 characters. It is now a
short index plus nine child pages, one per reader job:
- codex-harness-reference/supervision
- codex-harness-reference/app-server-transport
- codex-harness-reference/approval-and-sandbox
- codex-harness-reference/auth
- codex-harness-reference/dynamic-tools
- codex-harness-reference/timeouts
- codex-harness-reference/model-discovery
- codex-harness-reference/restricted-turns
- codex-harness-reference/workspace-bootstrap-files
The index keeps the frontmatter, the intro, "Plugin config surface", and
"Related", and adds a "Where each section moved" map. Child naming, index
shape, and the "Where each section moved" wording follow the earlier
docs/plugins/codex-harness split.
Anchors: all 14 ids published by the single-page version still resolve on the
index. "plugin-config-surface" and "related" stay real headings there; the
other 12 are authored <a id="..."> stubs beside the link that now owns the
section. Ids were enumerated with parseDocsDocument before and after: 14/14
resolve, with 0 duplicate authored/canonical ID collisions.
Losslessness: 974 non-blank source lines, 0 missing after the move. Fences
17 to 17 with an identical fence-by-fence digest over info string and body.
Table rows 54 to 54, identical row for row. All 18 original links retained,
39 navigation links added. Words 7,528 to 8,032, the delta being new
frontmatter, lead sentences, and the section map. No prose was rewritten.
Nav and zh-CN glossary entries were added for the nine children.
Closes audit findings: r3-0561