* fix(codex): reclaim binding ownership when sessions are deleted
Prepare harness deletion outside the SQLite writer and compare-delete exact companion ownership at the session removal edge, with compensation before commit and native subscription release afterward. Preserve live siblings and upstream native history. Repair proven orphan bindings through the existing Doctor planner under maintenance ownership.
* fix(codex): reuse prepared auth for resumed thread ownership
* docs(plugins): clarify shared migration and auth contracts
* test(codex): use the canonical config type facade
* fix(codex): preserve native threads during manual resume
Record pending attachment intent and validate the immutable native tool catalog
before applying configuration to the selected thread. Require uninterrupted
physical-client ownership through native unsubscribe, resume, and binding commit.
Keep the thread intact on unsupported policy, competing work, or failed proof.
Reuse canonical retained-owner cleanup and preserve unsafe-client retirement.
Cover the real command producer, cold and loaded resumes, competing leases,
lazy-store commit fencing, and the Gateway competing-owner path.
* test: isolate Codex auth and session completion fixtures
The detached Skill Workshop experience review rebuilt its system prompt and tool catalog from a different context than the foreground turn, so every review missed the prompt cache. Native harnesses (embedded, Codex, Copilot) now hand the review the same foreground prompt context via buildEmbeddedForegroundPromptContext; the review reuses the foreground prefix and gates execution to skill_workshop while keeping the catalog identical. Reviews without a foreground prompt (CLI hook contexts) are skipped.
* fix(gateway): permission modes work on rootless sessions via workspace default root
Session permission modes hard-required a recorded sessionRoot, which only the
sessions.create RPC ever records. Channel sessions, pre-#124909 rows, and
exec-node sessions are rootless, so runs failed closed with 'session permission
mode requires a recorded session root' (rows poisoned before the #128149 guards
were permanently bricked) and operators could not set a mode on channel
sessions at all.
The mode semantics are root-free; every containment consumer already falls
back to the workspace, and the remote worker launcher already derives its
containment root from placement.remoteWorkspaceDir. Make that the canonical
rule: a recorded sessionRoot pins worktree/explicit-cwd boundaries, and a
rootless session's boundary is the agent's canonical workspace resolved where
the run is prepared.
- embedded runner + compaction: default policy root to realpath(workspace)
instead of throwing/dropping the mode; bricked rows self-heal
- gateway: delete the patch/create/reset rejection guards and
session-permission-policy.ts entirely
- codex plugin: helpers take a required defaultRoot (agent workspace fact,
never a requested thread cwd); delete the four root throws; sandbox context
for conversation bindings now derives from the agent workspace
- ui: drop the rootless-rejection surface from the permission picker
- docs: permission-modes boundary contract updated
* fix(agents): split workspace path identity out of the kysely state store
Heals main: #116650 made memory-host-sdk/dreaming.ts import
resolveWorkspaceStateIdentity from workspace-state-store, statically pulling
kysely into the memory-core doctor-contract closure and failing the
doctor-contract-closure-guard lane on origin/main. The identity helpers are
pure path/crypto code; move them to workspace-state-identity.ts and repoint
all importers (dreaming, event-store, onboarding recommendations, workspace
migrations, legacy state).
* fix(ui): drop the unused permission picker sessionRoot prop and dead i18n keys
check-prod-types caught the New Session dialog still passing the removed
sessionRoot picker prop; the prop and the permissionControls.rootLabel /
sessionRoot strings have had no consumers since #124301.
* fix(codex): resolve rootless permission boundaries from agent config, not bind cwd
ClawSweeper P1: /codex bind --cwd stores the requested path as the binding
workspaceDir, which the previous commit then trusted as defaultRoot — letting
a bound thread's requested cwd become (and widen) the rootless permission
boundary. resolveConversationAppServerRuntime now owns the fact: it resolves
the selected agent's canonical workspace from config (falling back to the
plugin's configured default workspace), and the caller-supplied
agentWorkspaceDir parameter chain is deleted so no call site can pass a
tainted value. Recovery of recorded roots is unchanged (pinned roots stay
pinned); the moved-history test now proves the bind-cwd clamp lands on the
agent workspace.
* fix(codex): keep /codex model scoped to the native binding
/codex model wrote the outer OpenClaw session model override (and marked
a pending live model switch) any time a session context was present,
even for a thread bound through /codex bind. In a dual-runtime setup
that let a Codex-scoped model change silently redirect the next turn
to a different configured runtime. The binding store is now the sole
owner of this selection; only /model may change the outer session
override.
* fix(codex): make /codex model status binding-owned
The no-argument /codex model status read still preferred the outer
SessionEntry override over the native binding, so it could report a
stale model that diverged from what /codex model just wrote to the
binding. Read the binding first and fall back to the outer session
model only when no binding exists yet.
* fix(codex): preserve authoritative model selection ownership
Co-authored-by: chelsealong <chelsealong@126.com>
* fix(codex): retain session identity narrowing
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Codex 0.149 emits a session-configure warning whenever UnderDevelopment-stage
features are enabled, and OpenClaw always enables features.code_mode and
features.apply_patch_streaming_events for native code mode threads. The
warning relays into chat as a SYSTEM card telling operators to edit the
managed codex-home config.toml they should never touch.
Send suppress_unstable_features_warning: true in the same thread-config
block that enables those features. When native code mode is off, OpenClaw
does not send the flag, so warnings for user-enabled under-development
features still surface. The general warning relay is untouched.
Verified live against the pinned @openai/codex 0.149.1 app-server binary:
thread/start without the flag emits the exact warning; with it, none.
* fix(codex): back off between app-server startup retries
A transient Codex app-server startup exit could burn all three startup
attempts inside one contention window: codex 0.149.1 hard-fails
StateRuntime::init after its five-second SQLite busy timeout when another
Codex instance (e.g. Codex Desktop) is actively using the same codex home,
and the startup loop restarted immediately, so attempts 1-3 raced the same
held lock roughly six seconds apart and onboarding's Codex candidate died
with 'initialize transport failed after request write'. The same
activation retried later succeeds in one attempt.
Keep the canonical three-attempt owner but wait 1s before attempt 2 and 2s
before attempt 3 (zero for executable-selection changes), abortable via
the existing startup abandonment signal. Non-transport errors still fail
immediately. Production LOC net-neutral.
Upstream contract verified in ../codex at rust-v0.149.1:
app-server/src/lib.rs:613 (fatal init), rollout/src/state_db.rs:45 (CLI
warns instead), state/src/sqlite.rs:285 (5s busy_timeout).
Four hermetic child-process regressions: first-spawn exit recovers;
contention outlasting immediate retries recovers only with backoff (fails
pre-fix); persistent exits stop at three attempts; unsupported version
fails after one.
* chore: drop worker scratch file
* fix(channels): preserve gateway context for inbound turns
* fix(plugin-sdk): type bound channel reply dispatcher
* fix(channels): carry bound reply dispatchers
* fix(channels): keep reply carrier internal
* fix(auto-reply): consolidate dispatcher type imports
* fix(channels): keep reply dispatch typing internal
* fix(channels): derive inbound reply dispatcher types from turn plan
Keep ChannelRuntimeSurface identical to main: adapters read the bound
dispatchReplyFromConfig through the existing PluginRuntime["channel"]
wiring type and derive its type from the public ChannelInboundTurnPlan
contract, so the compatibility surface no longer grows a Gateway-bound
reply member.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(channels): hoist bound channel runtime casts for assertion ratchet
The assertion-safety ratchet collects SAFETY comments with a plain
ts.Scanner pass, which desyncs at the first template literal with a
substitution — comments after that point in a file are invisible, so
deep casts in monitor files cannot be SAFETY-covered. Hoist one shared
cast per call-site scope (absorbing the pre-existing buildContext
casts) and retype Discord's internal channelRuntime chain as
PluginRuntime["channel"] so dispatch reads need no assertion.
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(channels): verify gateway dispatcher ownership
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* test(codex): assert sequenced node process notifications
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* docs(changelog): preserve release-owned root changelog
Channel Gateway tools preserve the owning dispatcher for Telegram, Discord, iMessage, Signal, and WhatsApp so terminal tools remain available. Thanks @VACInc.
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
* test(codex): avoid shadowing process notification bindings
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
---------
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Allow exact upstream prompt provenance to use the existing 512 KiB settled-projection budget while preserving ordinary text bounds and aggregate accounting.
Co-authored-by: Marvinthebored <marvin.assistant@lindsey.jp>
* Let Codex run newly available account models without host credentials
* Keep authored provider routes ahead of native account authentication
* Keep native Codex account discovery consistent with model availability
* Preserve advanced reasoning for newly discovered Codex models
Doctor migrations and auth-profile writes open per-agent and shared state
databases under the fixture's temporary directory. Clearing the plugin
state store or the runtime auth snapshots does not release those handles,
so Windows fails the directory removal with EBUSY while Linux unlinks the
open files and stays green.
Close the cached databases before each removal, matching the ordering the
zalouser and zalo fixtures already use.