Commit Graph

6563 Commits

Author SHA1 Message Date
Shijie Rao
05eb867845 ## New Features
- The TUI now offers richer session controls and display: data-driven service-tier commands, blended token usage, permissions/approval mode, effective workspace roots, and responsive Markdown tables. (#21745, #21906, #21991, #21669, #21677, #22052, #22612)
- `@` mentions now search files, directories, plugins, and skills in one picker, backed by app-server plugin metadata. (#19068, #22375)
- Plugin workflows gained marketplace CLI commands, version-aware sharing, share checkout, clearer shared-workspace buckets, and default-enabled plugin hooks. (#21396, #22397, #22425, #22435, #22549)
- Remote workflows now support daemon-managed `codex remote-control`, runtime enable/disable APIs, status reads, and registry-backed/configured remote environments. (#20718, #22218, #22562, #22578, #22877, #20667, #21323)
- The Python SDK moved to `openai-codex` / `openai_codex`, with pinned runtime-generated types, concurrent turn routing, approval modes, and integration coverage. (#21778, #21891, #21893, #21896, #21905, #21910, #22014)
- Added `codex doctor` for support-ready diagnostics across runtime, auth, terminal, network, config, and local state. (#22336)

## Bug Fixes
- Fixed several TUI interaction and rendering issues, including URL wrapping, light-mode selection contrast, Shift+Enter in tmux, `/review` MCP startup status, `/side` Esc handling, and network approval history text. (#21760, #21950, #21943, #21624, #22710, #22229)
- Hardened Windows sandbox behavior around deny-read rules, scoped write roots, ineffective firewall policy, and PowerShell edge cases. (#18202, #21479, #22353, #21400, #22643)
- Preserved managed read restrictions during permission escalation and cleaned up workspace-root permission profile resolution. (#15977, #22624, #22683)
- Made app-server and local state startup safer by preserving SQLite data, failing closed when state cannot open, adding recovery paths, and softening optional metadata sync failures. (#21831, #21847, #22580, #22734, #22899)
- Improved Git and auth reliability by using root worktree hooks consistently, ignoring repo hook/fsmonitor config in helper commands, binding local MCP OAuth callbacks, and revoking superseded login tokens. (#21969, #22843, #22652, #20237, #21747)
- Reduced remote and Windows cleanup friction with longer exec-server transport timeouts, quieter `taskkill` cleanup, and non-queued plugin reads. (#21825, #21759, #22058, #22703)

## Documentation
- Clarified that general Codex product docs should not be added to this repo, while app-server API docs remain in scope. (#21772)
- Updated plugin-creator guidance for the simplified local plugin handoff links. (#22240)
- Documented new app-server/API contracts for remote environments and the desktop-owned config namespace. (#21323, #22584)

## Chores
- Improved CI and release reliability across Rust CI, exact PR-head checkout, Windows Bazel sharding, unsigned macOS artifacts, and signed macOS promotion. (#21604, #21628, #21835, #22408, #22559, #22649, #22737, #22788, #22900)
- Split large TUI ChatWidget, history, and composer code into focused modules without intended behavior changes. (#21866, #22269, #22407, #22433, #22518, #22537, #22704, #22581, #22656)
- Continued extracting extension and tool internals, including shared tool contracts plus guardian and memory extension plumbing. (#21736, #21737, #21738, #22138, #22147, #22216, #22258, #22344, #22476, #22480, #22485, #22498)
- Removed obsolete tool paths, feature flags, config gates, and legacy hooks as defaults stabilized. (#21651, #21805, #22173, #22246, #22565, #22711, #22717, #22724, #22730)

## Changelog

Full Changelog: https://github.com/openai/codex/compare/rust-v0.130.0...rust-v0.131.0

- #21550 [codex] make shutdown pending-touch test deterministic @jif-oai
- #21697 Allow string service tiers in config TOML @aibrahim-oai
- #21687 [codex] Enable apply_patch freeform by default @aibrahim-oai
- #19896 Update models.json @github-actions
- #21669 Display blended token count in status line @etraut-openai
- #21677 Show permissions and approval mode in the TUI status line @etraut-openai
- #21757 api: send hyphenated session and thread headers @jif-oai
- #21763 nit: comment @jif-oai
- #21749 codex-otel: validate provider span attributes consistently @bbrown-oai
- #21767 chore: thread tui @jif-oai
- #21443 [sandboxing] Remove Darwin user cache write from Seatbelt network policy @evawong-oai
- #21604 Fix `rust-ci-full` failures due to missing `bwrap` @zanie-oai
- #21628 Use `CARGO_NET_GIT_FETCH_WITH_CLI` in `rust-ci-full` for more reliable git fetches @zanie-oai
- #21745 [codex] Generalize service tier slash commands @aibrahim-oai
- #21772 Clarify docs folder guidance in AGENTS.md @etraut-openai
- #21622 [codex] Address some more GHA hygiene issues @ww-oai
- #21662 feat: Use installation ID in remote enrollments @ddr-oai
- #20667 Load configured environments from CODEX_HOME @starr-openai
- #21776 Update models.json @github-actions
- #21787 Support resource binaries in Python runtime staging @aibrahim-oai
- #21784 Publish Python runtime wheels on release @aibrahim-oai
- #21601 Emit accepted line fingerprint analytics @alexsong-oai
- #21465 Remove ToolName display helper @pakrym-oai
- #20619 [codex] request desktop attestation from app @jiamingz42
- #21810 Revert "Publish Python runtime wheels on release" @aibrahim-oai
- #21651 [codex] Delete function-style apply_patch @pakrym-oai
- #21805 [codex] Remove legacy after tool use hooks @pakrym-oai
- #21616 Enable `--deny-warnings` for `cargo shear` @charliemarsh-oai
- #21497 Using cached connector directory for discoverable tools list @mzeng-openai
- #21835 ci: check out PR head commits in workflows @bolinfest
- #21794 Make environment provider snapshots path-free @starr-openai
- #21831 app-server: support daemon-safe restart handling @euroelessar
- #20293 Support openai library tool @lt-oai
- #21323 [codex] support executor registry remote environments @miz-openai
- #21825 Increase exec-server environment transport timeouts @starr-openai
- #20718 [daemon] Add app-server daemon lifecycle management @euroelessar
- #21840 feat: add Bedrock Mantle client agent header @celia-oai
- #21847 sqlite: no more destructive version bumps @owenlin0
- #21652 Reapply "Move skills watcher to app-server" @pakrym-oai
- #21290 Move file watcher out of core @pakrym-oai
- #21867 feat: Add role-aware plugin share context APIs @xl-openai
- #21875 [codex] compact network context rendering @sayan-oai
- #21778 Route Python SDK turn notifications by ID @aibrahim-oai
- #21906 [codex] Lowercase TUI service tier commands @aibrahim-oai
- #21819 tests: cover sandbox link write behavior @bolinfest
- #21760 fix(tui): preserve wrapped prose beside URLs @fcoury-oai
- #21950 fix(tui): improve light-mode selection contrast @fcoury-oai
- #21755 Improve hooks trust flow in TUI @abhinav-oai
- #21870 Avoid blocking TUI on agent metadata hydration @etraut-openai
- #21866 Split ChatWidget state into focused modules @etraut-openai
- #21991 Persist 'priority' service tier as fast in config @aibrahim-oai
- #21943 fix(tui): preserve Shift+Enter in tmux csi-u panes @fcoury-oai
- #21759 fix(tui): suppress taskkill output for MCP teardown on Windows @fcoury-oai
- #22039 Deduplicate issue digest interactions by user @etraut-openai
- #22052 feat(tui): render responsive Markdown tables in TUI @fcoury-oai
- #20825 Read cached metadata for installed Git plugins @xli-oai
- #21736 extension: add initial typed extension API @jif-oai
- #21737 extension: wire extension registries into sessions @jif-oai
- #21738 extension: move git attribution into an extension @jif-oai
- #22138 refactor: extract executable tool contracts into codex-tool-api @jif-oai
- #22140 feat: drop `CodexExtension` @jif-oai
- #22143 [codex] default unknown contributed tools to mutating @jif-oai
- #22147 feat: wire extension tool bundles into core @jif-oai
- #22163 feat: move extensions tool @jif-oai
- #22113 Add x-codex-ws-stream-request-start-ms @andmis
- #21860 Persist /goal commands in history @etraut-openai
- #22141 [codex] Harden overflow auto-compaction recovery @aibrahim-oai
- #22170 Revert "[codex] Harden overflow auto-compaction recovery" @aibrahim-oai
- #22106 Fix side conversation config inheritance @etraut-openai
- #22045 Improve goal continuation based on feedback @etraut-openai
- #21981 Use goal preview metadata for goal-first threads @etraut-openai
- #21843 app-server: remove TCP websocket listener @euroelessar
- #22173 chore: drop built-in MCPs @jif-oai
- #21954 Fix goal update and add `/goal edit` command in TUI @etraut-openai
- #22110 Make auto-review denial short-circuit use a rolling review window @won-openai
- #21431 [codex-analytics] add turn tool counts to turn events @rhan-oai
- #22154 Add process-scoped SQLite telemetry @jif-oai
- #19068 Unified mentions in TUI @canvrno-oai
- #20305 fix(exec-policy) use is_known_safe_command less @dylan-hurd-oai
- #22058 fix(exec-server): suppress Windows taskkill output @fcoury-oai
- #22178 fix(app-server): thread history redaction for remote clients @owenlin0
- #15977 fix(permissions): preserve managed deny-read during escalation @viyatb-oai
- #21061 feat(connectors): support managed app tool approval requirements @viyatb-oai
- #22188 [elicitation] Advertise new url elicitation capability when auth_elicitation is enabled. @mzeng-openai
- #22192 config: accept `minus` in TUI keymap config @fcoury-oai
- #21853 daemon: refresh updater after validated binary rollout @euroelessar
- #21747 [login] revoke superseded auth tokens on relogin @cooper-oai
- #20147 feat: add network proxy feature flag @viyatb-oai
- #21891 [1/8] Pin Python SDK runtime dependency @aibrahim-oai
- #21893 [2/8] Generate Python SDK types from pinned runtime @aibrahim-oai
- #21895 [3/8] Run Python SDK tests in CI @aibrahim-oai
- #21896 [4/8] Define Python SDK public API surface @aibrahim-oai
- #21905 [5/8] Rename Python SDK package to openai-codex @aibrahim-oai
- #21910 [6/8] Add high-level Python SDK approval mode @aibrahim-oai
- #22014 [7/8] Add Python SDK app-server integration harness @aibrahim-oai
- #22021 [8/8] Add Python SDK Ruff formatting @aibrahim-oai
- #18748 [codex-analytics] emit terminal review events @rhan-oai
- #22159 Add Windows hook command overrides @abhinav-oai
- #22218 Update codex remote-control to start the daemon @owenlin0
- #22180 Stop uploading accepted line fingerprints @alexsong-oai
- #21617 Support multi-environment apply_patch selection @starr-openai
- #22198 Add production startup and TTFT telemetry @mzeng-openai
- #21963 [exec-server] serve websocket listener via HTTP upgrade @euroelessar
- #21946 fix(tui): handle hidden app git directives @fcoury-oai
- #21595 Simplify MCP tool handler plumbing @pakrym-oai
- #22221 feat(skills): default plugin creator to personal share flow @efrazer-oai
- #21861 Apply sandbox context to local view_image reads @starr-openai
- #20527 Support PreToolUse updatedInput rewrites @abhinav-oai
- #22243 [codex] Filter legacy warning messages during compaction @pakrym-oai
- #22254 [codex] Make handlers own parallel tool support @pakrym-oai
- #18202 feat(sandbox): add Windows deny-read parity @viyatb-oai
- #22265 feat: Normalize remote plugin summary identities. @xl-openai
- #22216 feat: guardian as an extension (contributors part) @jif-oai
- #22311 [rollout-trace] Add x-codex-inference-call-id header to inference calls. @cassirer-openai
- #21206 feat(tui): add ambient terminal pets @fcoury-oai
- #22323 fix: uv lock @jif-oai
- #22207 [codex] Tighten unified exec sandbox setup @bookholt-oai
- #22382 tools: remove is_mutating dispatch gating @pakrym-oai
- #22383 chore(config) include_collaboration_mode_instructions @dylan-hurd-oai
- #22377 code-mode: carry nested tool kind through runtime @pakrym-oai
- #22392 test(tui): relax configured pet load timeout @fcoury-oai
- #22343 feat(exec-server): use protobuf relay frames @apanasenko-oai
- #20509 [codex] Remove workspace owner usage nudge gate @richardopenai
- #22256 Refactor namespaced tool spec registration @pakrym-oai
- #22280 code-mode: Add pending-aware code mode execution @cconger
- #22266 core: box multi-agent handler futures @bolinfest
- #22398 [codex] Add search term coverage for tool_search @pakrym-oai
- #22236 Unify thread metadata updates above store @wiltzius-openai
- #22269 Refactor chatwidget state into modules @etraut-openai
- #22381 [codex] Remove tool search bucket limit override @sayan-oai
- #22386 mark Feature::RemoteControl as removed @owenlin0
- #22240 docs(skills): simplify plugin creator deeplink shape @efrazer-oai
- #22397 feat: Expose plugin versions and gate plugin sharing @xl-openai
- #22404 Restore app-server websocket listener with auth guard @etraut-openai
- #22258 feat: route guardian review model selection through providers @celia-oai
- #22268 hooks: use new session IDs instead of thread IDs for hooks, apply parent's session ID to subagents' hooks @eternal-openai
- #20319 Add allow_managed_hooks_only hook requirement @eternal-openai
- #22413 Remove CODEX_RS_SSE_FIXTURE test hook @pakrym-oai
- #22406 tools: infer code-mode namespace descriptions from specs @pakrym-oai
- #22261 Encapsulate tool search entries in handlers @pakrym-oai
- #22425 feat: Split shared workspace plugins by discoverability @xl-openai
- #22414 Add support for UDS in `codex --remote` @etraut-openai
- #22407 Refactor chatwidget input flow into modules @etraut-openai
- #22439 Remove unavailable MCP placeholder tool backfill @sayan-oai
- #21969 Use root repo hooks in linked worktrees @abhinav-oai
- #21768 add --dangerously-bypass-hook-trust CLI flag @abhinav-oai
- #22435 feat: Add plugin share checkout @xl-openai
- #22355 chore: Keep view_image sandbox test in temp dir @jif-oai
- #22344 extension-api: add approval review contributor flow @jif-oai
- #22359 feat: extract shared tool executor interface @jif-oai
- #22369 Refactor extension tools onto shared ToolExecutor @jif-oai
- #22338 [app-server] Gate login issuer override constant @cassirer-openai
- #22437 [codex] isolate plugin/list from config serialization queue @xli-oai
- #22476 feat: add thread lifecycle contributor hooks @jif-oai
- #22479 nit: codeowners @jif-oai
- #22480 feat: add turn lifecycle contributors @jif-oai
- #22482 fix: emit thread stop lifecycle on implicit shutdown @jif-oai
- #22485 feat: add token usage contributor hook @jif-oai
- #22443 Scope macOS signing secrets to release environment @shijie-oai
- #22490 feat: move extension scope ids into ExtensionData @jif-oai
- #22491 Make context contributors async @jif-oai
- #22214 feat(tui): remove Zellij TUI workarounds @fcoury-oai
- #22139 Add service tier overrides to spawned agents @aibrahim-oai
- #22488 feat: add config-change extension contributor @jif-oai
- #22498 feat: memories ext @jif-oai
- #22503 fix: main @jif-oai
- #22347 feat(tui): standardize picker navigation keys @fcoury-oai
- #22500 refactor: split memories extension crate modules @jif-oai
- #22433 Refactor chatwidget protocol flows into modules (phase 3) @etraut-openai
- #22505 fix: prevent fmt from updating Python SDK lockfile @jif-oai
- #22326 [rollout-trace] Add a trace ID to MCP calls. @cassirer-openai
- #20559 config: add strict config parsing @bolinfest
- #22489 Introduce tool exposure for deferred registration @jif-oai
- #22193 fix: drop underscored id headers @jif-oai
- #22246 [codex] Remove unused legacy shell tools @pakrym-oai
- #22520 revert: mark Feature::RemoteControl as removed @owenlin0
- #22513 Revert "Scope macOS signing secrets to release environment" @shijie-oai
- #22514 feat: expose multi-agent v2 as model-only tools @jif-oai
- #22366 Pass Codex product SKU to ChatGPT backend @ericning-o
- #22519 Deprecate TurnContext cwd and resolve_path @pakrym-oai
- #22518 Refactor chatwidget settings surfaces into modules (phase 4) @etraut-openai
- #21479 [codex] Scope Windows sandbox write-root capability SIDs @adrianbravo-oai
- #22353 windows-sandbox: fail elevated setup when firewall policy is ineffective @iceweasel-oai
- #22527 [codex] Reuse Apps MCP path override for plugin-service rollout @adaley-openai
- #22412 chore(config) rm Feature::CodexGitCommit @dylan-hurd-oai
- #22501 chore(config) rm tools.view_image @dylan-hurd-oai
- #22533 fix: prevent codex-backend from stealing originator @owenlin0
- #22408 Shard Bazel Windows tests across jobs @starr-openai
- #22542 Use selected environment cwd for filesystem helpers @pakrym-oai
- #20237 Add callback ids to local MCP OAuth redirects @stevenlee-oai
- #22549 Enable plugin hooks by default @abhinav-oai
- #22375 Use plugin/list to get list of plugins for mentions @canvrno-oai
- #21235 [codex] Fix TUI wrapping for external borrowed slices @canvrno-oai
- #22336 feat(cli): add codex doctor diagnostics @fcoury-oai
- #22543 clean up instructions @sayan-oai
- #21400 Avoid PowerShell profiles in elevated Windows sandbox @iceweasel-oai
- #22528 Make multi_agent_v2 wait_agent timeouts configurable @andmis
- #22529 Spill oversized PreToolUse additionalContext @abhinav-oai
- #22556 feat: namespace in ext @jif-oai
- #22535 Remove resurrected `/collab` slash command @etraut-openai
- #22537 Refactor chatwidget orchestration into modules (phase 5) @etraut-openai
- #22564 [codex] Canonicalize shared workspace plugin IDs @xl-openai
- #22559 Add unsigned macOS release artifacts @shijie-oai
- #22574 Deprecate issue labeler @maxb-openai
- #22555 Remove connector_openai prefix filtering @ericning-o
- #22580 fix: Block appserver startup if state db can't be opened @ddr-oai
- #22565 chore(config) rm experimental_use_freeform_apply_patch @dylan-hurd-oai
- #22562 Improve remote-control daemon UX @owenlin0
- #22578 enable/disable remote control at runtime, not via features @owenlin0
- #22573 Simplify TUI startup test coverage @etraut-openai
- #22594 Relax remote plugin sync gate @xli-oai
- #22587 Defer startup NUX impressions until startup succeeds @etraut-openai
- #22560 feat: make ToolExecutor an async trait @jif-oai
- #22494 Wire turn item contributors into stream output @jif-oai
- #17141 feat: add layered --profile-v2 config files @jif-oai
- #22643 [codex] treat PowerShell stop-parsing forms as unsupported @bookholt-oai
- #22646 Fix abort-path turn extension data plumbing @jif-oai
- #22624 permissions: canonicalize workspace_roots and danger-full-access names @bolinfest
- #22649 Chore: better published unsigned artifacts @shijie-oai
- #22581 tui: split composer attachment and popup state @etraut-openai
- #21396 [codex] add plugin marketplace CLI commands @caseychow-oai
- #22576 tests: avoid ambient temp sandbox roots @starr-openai
- #22652 [codex] Ignore fsmonitor config in Git metadata reads @bookholt-oai
- #22229 fix(tui): render network approval history by target @fcoury-oai
- #22547 Prefer the model list fetched from the backend for SIWC users @jeevnayak
- #22666 [codex] fix plugin CLI active user layer compile @caseychow-oai
- #22575 Support explicit MCP OAuth client IDs @mzeng-openai
- #22512 test: isolate exec review policy config test @bolinfest
- #22572 Fix remote environment test fixtures @starr-openai
- #22563 tests: isolate codex home for live cli @starr-openai
- #18161 [codex] Support multiple forced ChatGPT workspaces @rreichel3-oai
- #22702 make rust-release-prepare use env secret @sayan-oai
- #22703 Unqueue plugin list and read requests @xli-oai
- #22687 Fix Windows sandbox clippy clones @starr-openai
- #22711 chore(features) rm Feature::ApplyPatchFreeform @dylan-hurd-oai
- #22717 chore(config) rm windows_wsl_setup_acknowledged @dylan-hurd-oai
- #22695 Trim TUI legacy core helper usage @etraut-openai
- #21624 Fix /review mode MCP startup render issue @canvrno-oai
- #22684 Remove SSE fixture loaders @pakrym-oai
- #22730 [codex] Group removed feature flags @dylan-hurd-oai
- #22724 [codex] Remove experimental instructions file config @dylan-hurd-oai
- #22237 Add `user_input_requested_during_turn` to MCP turn metadata @mchen-oai
- #22737 ci: support signed macOS release promotion @bolinfest
- #22303 Stabilize compact rollback follow-up test @dylan-hurd-oai
- #22683 permissions: resolve profile identity with constraints @bolinfest
- #22734 tui: recover local state db startup failures @etraut-openai
- #22584 [codex] Add opaque desktop config namespace @guinness-oai
- #22710 Prevent Esc from dismissing or rewinding `/side` @etraut-openai
- #22704 TUI: split history cells into focused modules @etraut-openai
- #22611 app-server: use permission ids and runtime workspace roots @bolinfest
- #22612 tui/exec: show effective workspace roots in summaries @bolinfest
- #22788 Fix signed macOS release promotion follow-up jobs @shijie-oai
- #22647 Reject legacy [profiles] when using profile-v2 @jif-oai
- #22809 [codex] Use compaction_trigger item for remote compaction v2 @jif-oai
- #22636 Simplify tool executor and registry plumbing @jif-oai
- #22820 Remove zombie tools spec module @jif-oai
- #22828 Run compact hooks for remote compaction v2 @jif-oai
- #22841 Move memory prompt injection to app-server extension @jif-oai
- #22789 guardian: use permission profile for review sandbox @bolinfest
- #22656 tui: split remaining composer draft and footer state @etraut-openai
- #22843 Ignore configured hooks in git helpers @bookholt-oai
- #22790 context: remove legacy permissions instructions helper @bolinfest
- #22791 telemetry: tag sandboxes from permission profiles @bolinfest
- #22872 Forward apps MCP product SKU from Codex config @kumquatexpress
- #22582 Workflow updates @viyatb-oai
- #22792 app-server: stop returning thread permission profiles @bolinfest
- #22795 core: construct test permission profiles directly @bolinfest
- #22900 Disable DMG staging for signed macOS promotion @shijie-oai
- #22877 feat(app-server): update remote control APIs for better UX @owenlin0
- #22899 [codex] Soften SQLite metadata sync failures @wiltzius-openai
rust-v0.131.0
2026-05-18 08:40:25 -07:00
Tom
249d50aafc [codex] Soften SQLite metadata sync failures (#22899)
## Summary
- keep transcript-derived local thread metadata SQLite failures
best-effort
- preserve hard failures for explicit git-only metadata updates that
still require SQLite state
- add regression coverage for the soft-vs-hard metadata update policy

## Root cause
The live thread metadata sync introduced after v0.131.0-alpha.8 moved
append-derived metadata writes above the rollout writer. Those SQLite
writes now propagated through the live thread flush path, so a corrupted
optional state DB could surface as a transcript persistence warning even
when JSONL writes still succeeded.

The hard failures were introduced in #22236
2026-05-15 21:37:27 +00:00
Owen Lin
6a331a66eb feat(app-server): update remote control APIs for better UX (#22877)
## Why
To help improve `codex remote-control` CLI UX which I plan to do in a
followup, this PR adds `server-name` to the various remote control APIs:
- `remoteControl/enable`
- `remoteControl/disable`
- `remoteControl/status/changed`

Also, add a `remoteControl/status/read` API. This will be helpful in the
Codex App.
2026-05-15 14:33:24 -07:00
Shijie Rao
98129fb9c5 Disable DMG staging for signed macOS promotion (#22900)
## Why
`promote_signed` is now used to finish a release from an externally
signed macOS handoff, but this release path (temporarily) no longer
distributes DMGs. Keeping DMG staging enabled made the handoff
unnecessarily require DMG assets and notarization/stapling validation
even though the promoted release only needs the signed macOS binaries.

## What changed
- Set every `stage-signed-macos` matrix entry to `build_dmg: "false"`,
including the primary macOS bundles.
- Kept the existing DMG staging branch in place behind
`matrix.build_dmg` so it can be re-enabled deliberately later.
- Updated the workflow header comment so the signed handoff contract
asks for signed binaries, not signed DMGs.

The regular signed build path that creates, signs, notarizes, and stages
DMGs is unchanged; this only affects the `promote_signed` handoff path.
2026-05-15 14:19:06 -07:00
Michael Bolin
8df2d96860 core: construct test permission profiles directly (#22795)
## Why

The core migration is trying to make `PermissionProfile` the shape tests
and runtime code reason about, leaving `SandboxPolicy` only where legacy
behavior is explicitly under test. The local
`permission_profile_for_sandbox_policy()` test helpers kept new
permission-profile tests mentally tied to the old sandbox model even
when the equivalent profile is straightforward.

## What Changed

- Removed the `permission_profile_for_sandbox_policy()` helper from the
network proxy spec tests and session tests.
- Replaced legacy conversions for read-only, workspace-write, and
full-access cases with `PermissionProfile::read_only()`,
`PermissionProfile::workspace_write()`, and
`PermissionProfile::Disabled`.
- Constructed the external-sandbox session test's
`PermissionProfile::External` directly, while preserving the legacy
`SandboxPolicy` only where the test still exercises legacy config update
behavior.

## How To Review

This PR is intentionally test-only. Review the two touched files and
check that each replacement preserves the old legacy mapping:

- `SandboxPolicy::new_read_only_policy()` ->
`PermissionProfile::read_only()`
- `SandboxPolicy::new_workspace_write_policy()` ->
`PermissionProfile::workspace_write()`
- `SandboxPolicy::DangerFullAccess` -> `PermissionProfile::Disabled`
- `SandboxPolicy::ExternalSandbox { network_access: Restricted }` ->
`PermissionProfile::External { network: Restricted }`

## Verification

- `cargo test -p codex-core
requirements_allowed_domains_are_a_baseline_for_user_allowlist`
- `cargo test -p codex-core
start_managed_network_proxy_applies_execpolicy_network_rules`
- `cargo test -p codex-core
session_configured_reports_permission_profile_for_external_sandbox`
- `cargo test -p codex-core
managed_network_proxy_decider_survives_full_access_start`
- `just fix -p codex-core`








---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22795).
* #22891
* __->__ #22795
2026-05-15 13:09:25 -07:00
Michael Bolin
83bbb4f326 app-server: stop returning thread permission profiles (#22792)
## Why

The app-server thread lifecycle API should no longer expose the full
`PermissionProfile` value. After the permissions-profile migration,
clients should round-trip only the active profile identity through
`activePermissionProfile` and `permissions` when that identity is known.

The full profile is server-side config. Treating a response-derived
legacy sandbox projection as a new local profile can lose named-profile
restrictions and accidentally widen permissions on the next turn. The
legacy `sandbox` response field remains only as the
compatibility/display fallback.

## What Changed

- Removed `permissionProfile` from `ThreadStartResponse`,
`ThreadResumeResponse`, and `ThreadForkResponse`.
- Stopped populating that field in app-server thread start/resume/fork
responses.
- Updated embedded exec/TUI response mapping to derive display
permission state from local config or the legacy sandbox fallback
instead of a response profile value.
- Added a TUI turn override shape that distinguishes preserving server
permissions, selecting an active profile id, and sending a legacy
sandbox for an explicit local override.
- Preserved remote app-server permissions across turns by sending
`permissions` only when an `activePermissionProfile` id is known, and
otherwise sending no sandbox override unless the user selected a local
override.
- Kept embedded `thread/resume` hydration server-authored when
`activePermissionProfile` is absent, which matches the live-thread
attach path where the server ignores requested overrides.
- Updated the app-server README to remove the obsolete lifecycle
response `permissionProfile` reference. The remaining
`permissionProfile` README references are request-side permission
overrides.
- Regenerated app-server JSON schema and TypeScript fixtures.
- Kept the generated typed response enum exempt from
`large_enum_variant`, matching the existing payload enum exemption after
the lifecycle response variants shrank.

## How To Review

Start with `codex-rs/app-server-protocol/src/protocol/v2/thread.rs` to
confirm the response shape, then check the response construction in
`codex-rs/app-server/src/request_processors`. The generated schema and
TypeScript fixture changes are mechanical follow-through from the
protocol removal.

The TUI behavior is the delicate part: review
`codex-rs/tui/src/app_server_session.rs` for response hydration and
turn-start override projection, then
`codex-rs/tui/src/app/thread_routing.rs` for the decision about whether
the next turn should preserve the server snapshot, send an active
profile id, or send a legacy sandbox for an explicit local override.

## Verification

- `just write-app-server-schema`
- `cargo test -p codex-app-server-protocol
thread_lifecycle_responses_default_missing_optional_fields`
- `cargo test -p codex-exec
session_configured_from_thread_response_uses_permission_profile_from_config`
- `cargo test -p codex-tui --lib thread_response`
- `cargo test -p codex-tui turn_permissions_`
- `cargo test -p codex-tui
resume_response_restores_turns_from_thread_items`
- `cargo test -p codex-analytics
track_response_only_enqueues_analytics_relevant_responses`
- `just fix -p codex-analytics`
- `just fix -p codex-app-server-protocol`
- `just fix -p codex-tui`
- `just argument-comment-lint`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22792).
* #22795
* __->__ #22792
2026-05-15 12:45:48 -07:00
viyatb-oai
6afe00efda Workflow updates (#22582) 2026-05-15 12:41:18 -07:00
Boyang Niu
c15613f2b6 Forward apps MCP product SKU from Codex config (#22872)
This adds `apps_mcp_product_sku` as a toplevel config.toml key. We pass
the given value as a header when listing MCPs for the client, allowing
connectors to be filtered per product entry point.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-05-15 11:52:14 -07:00
Michael Bolin
4c80435eba telemetry: tag sandboxes from permission profiles (#22791)
## Why

Sandbox telemetry tags should be derived from the active permission
profile, not from a legacy `SandboxPolicy`, so the tagging code stays
aligned with the permissions migration and does not preserve a
policy-shaped production helper only for tests.

## What Changed

- Removed the production `sandbox_tag(&SandboxPolicy, ...)` helper.
- Updated sandbox tag tests to construct the relevant
`PermissionProfile` values directly.
- Kept the platform-specific sandbox tag behavior under the existing
`permission_profile_sandbox_tag` path.

## How To Review

The production change is in `codex-rs/core/src/sandbox_tags.rs`. Most of
the diff is test cleanup that replaces legacy policy setup with
permission profiles, so review the expected tag assertions rather than
the old helper mechanics.

## Verification

- `cargo test -p codex-core sandbox_tag`









---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22791).
* #22795
* #22792
* __->__ #22791
2026-05-15 10:58:50 -07:00
Michael Bolin
aeca1cba6f context: remove legacy permissions instructions helper (#22790)
## Why

The permissions instruction builder should consume the new permissions
model directly. Keeping a `SandboxPolicy` conversion helper in this path
encourages new code to route through legacy sandbox policy values even
when the caller already has a `PermissionProfile`.

## What Changed

- Removed `PermissionsInstructions::from_policy`.
- Removed the test that exercised that legacy helper.
- Left the existing profile-based instruction coverage in place.

## How To Review

Review `codex-rs/core/src/context/permissions_instructions.rs` first.
This PR is intentionally narrow: the production behavior should be
unchanged for profile callers, and the deleted surface was only a
convenience adapter from `SandboxPolicy`.

## Verification

- `cargo test -p codex-core builds_permissions_from_profile`








---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22790).
* #22795
* #22792
* #22791
* __->__ #22790
2026-05-15 10:11:16 -07:00
Chris Bookholt
9facdccb37 Ignore configured hooks in git helpers (#22843)
## What
- Internal Git helper commands now ignore configured hook directories
during repository bookkeeping.

## Why
- These helper flows should stay consistent even when a repository has
hook-directory configuration of its own.

## How
- Pass a command-local `core.hooksPath` override in the shared helper
path and the Git-info helper path.
- Add regressions for the baseline index rewrite flow and the metadata
status flow.

## Validation
- `cargo fmt --manifest-path
/Users/bookholt/code/codex/codex-rs/Cargo.toml --all --check`
- `cargo test --manifest-path
/Users/bookholt/code/codex/codex-rs/Cargo.toml -p codex-git-utils`
- `cargo test --manifest-path
/Users/bookholt/code/codex/codex-rs/Cargo.toml -p codex-core
test_get_has_changes_`
2026-05-15 10:07:54 -07:00
Eric Traut
7fa0007ea8 tui: split remaining composer draft and footer state (#22656)
## Why

[#22581](https://github.com/openai/codex/pull/22581) started separating
the chat composer’s responsibilities, but `ChatComposer` still owned the
remaining editable draft state alongside footer/status presentation
state. This follow-up makes those ownership lines explicit so future
composer changes have a smaller blast radius and `BottomPane` does not
need to keep exposing scattered draft getters.

This is just a refactor. No functional or behavioral changes are
intended.

## What changed

- Move the remaining editable composer state into
`bottom_pane/chat_composer/draft_state.rs`.
- Move footer and status-row presentation state into
`bottom_pane/chat_composer/footer_state.rs`.
- Add an internal `ComposerDraftSnapshot` for restore flows, replacing
several ad hoc `BottomPane` pass-through reads.
- Rewire the related history-search and thread-input restore paths to
use the extracted state.

## Verification

- `RUST_MIN_STACK=8388608 cargo test -p codex-tui`
- `cargo insta pending-snapshots`
2026-05-15 09:12:52 -07:00
Michael Bolin
68ccfdc905 guardian: use permission profile for review sandbox (#22789)
## Why

`SandboxPolicy` is being pushed back toward legacy config loading and
compatibility boundaries. Guardian review sessions already want the
built-in read-only permission behavior; carrying that as an active
`PermissionProfile` makes the review sandbox follow the new permissions
path instead of configuring the child session through the legacy policy
API.

## What Changed

- Configure the guardian review session with
`PermissionProfile::read_only()`.
- Send the read-only profile through the guardian child `Op::UserTurn`.
- Keep the legacy `sandbox_policy` field populated with
`SandboxPolicy::new_read_only_policy()` declared next to the profile so
the two remain visibly in sync until the compatibility field goes away.

## How To Review

Start in `codex-rs/core/src/guardian/review_session.rs`. The important
check is that both the guardian config and the child turn now use the
read-only permission profile, while the remaining
`SandboxPolicy::ReadOnly` assignment is only the compatibility field
required by the current turn protocol.

## Verification

- `cargo test -p codex-core
guardian_review_session_config_clears_parent_developer_instructions`





---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22789).
* #22795
* #22792
* #22791
* #22790
* __->__ #22789
2026-05-15 08:59:31 -07:00
jif-oai
cccde930ce Move memory prompt injection to app-server extension (#22841)
## Why

Memory prompt injection should be owned by the extension path that
app-server composes at runtime, not by an inlined special case inside
`codex-core`. This keeps `codex-core` focused on session orchestration
while allowing the memories extension to own its app-server prompt
behavior.

## What Changed

- Registers `codex-memories-extension` in the app-server extension
registry.
- Moves the memory developer-instruction injection out of
`core/src/session/mod.rs` and into the memories extension prompt
contributor.
- Adds config-change handling so the extension keeps its per-thread
memory settings in sync after startup.
- Leaves memories read/retrieval tools unregistered for now so this PR
only changes prompt injection.
- Removes the stale `cargo-shear` ignore now that app-server depends on
the extension crate.

## Validation

Not run locally; validation is left to CI.
2026-05-15 16:19:34 +02:00
jif-oai
5d30764fe9 Run compact hooks for remote compaction v2 (#22828)
## Why

Remote compaction v2 is the `/responses` implementation of
session-history compaction, but it still needs to preserve the
observable contract of the legacy `/responses/compact` path. In
particular, users and integrations that rely on `PreCompact` and
`PostCompact` hooks should not see different behavior when
`remote_compaction_v2` is enabled.

## What Changed

- Runs `PreCompact` before issuing the remote compaction v2 request,
including `Interrupted` analytics when a pre-hook stops execution.
- Runs `PostCompact` after a successful v2 compaction and aborts the
turn if the post-hook stops execution.
- Adds `compact_remote_parity` coverage that compares legacy and v2
compaction across manual transcript shapes, automatic pre-turn
compaction, automatic mid-turn compaction, hook payloads, replacement
history, follow-up request payloads, and API-key `service_tier=fast`
behavior.
- Registers the new parity suite under `core/tests/suite`.

Relevant code:

-
[`compact_remote_v2.rs`](af63745cb5/codex-rs/core/src/compact_remote_v2.rs)
-
[`compact_remote_parity.rs`](af63745cb5/codex-rs/core/tests/suite/compact_remote_parity.rs)

## Verification

- Added `core/tests/suite/compact_remote_parity.rs` to assert parity
between legacy remote compaction and remote compaction v2 for the
affected request, hook, rollout-history, and follow-up paths.
- Existing `compact_remote_v2` unit coverage still exercises v2
replacement-history retention and compaction-output collection.
2026-05-15 15:26:21 +02:00
jif-oai
c03cea4ca2 Remove zombie tools spec module (#22820)
## Summary

- move tool_user_shell_type out of the old tools::spec module and call
it from tools directly
- attach the remaining spec planning model tests under spec_plan
- delete core/src/tools/spec.rs

## Tests

- just fmt
- cargo test -p codex-core tools::spec_plan

Note: a broader cargo test -p codex-core run on the earlier PR-head
worktree still hit the pre-existing stack overflow in
agent::control::tests::spawn_agent_fork_last_n_turns_keeps_only_recent_turns.
2026-05-15 13:44:58 +02:00
jif-oai
6f1a01fbdd Simplify tool executor and registry plumbing (#22636)
## Why

The tool runtime path still had a typed output associated type on
`ToolExecutor`, plus a core-only `RegisteredTool` adapter and
extension-only executor aliases. That made every new shared tool runtime
carry extra adapter plumbing before it could participate in core
dispatch, extension tools, hook payloads, telemetry, and model-visible
spec generation.

This PR moves output erasure to the shared executor boundary so core and
extension tools can use the same execution contract directly.

## What Changed

- Changed `codex_tools::ToolExecutor` to return `Box<dyn ToolOutput>`
instead of an associated `Output` type.
- Removed the extension-specific `ExtensionToolExecutor` /
`ExtensionToolOutput` aliases and exposed `ToolExecutor<ToolCall>` plus
`ToolOutput` through `codex-extension-api`.
- Reworked core tool registration around `CoreToolRuntime` and
`ToolRegistry::from_tools`, removing the extra `RegisteredTool` /
`ToolRegistryBuilder` layer.
- Consolidated model-visible spec planning and registry construction in
`core/src/tools/spec_plan.rs`, including deferred tool search and
code-mode-only filtering.
- Added `ToolOutput` helpers for post-tool-use hook ids and inputs so
MCP, unified exec, extension, and other boxed outputs preserve the same
hook payload behavior.
- Updated core handlers, memories tools, and the related
registry/spec/router tests to use the simplified contract.

## Test Coverage

- Updated coverage for tool spec planning, registry lookup, deferred
tool search registration, extension tool routing, post-tool-use hook
payloads, dispatch tracing, guardian output extraction, and memories
extension tool execution.
2026-05-15 11:47:54 +02:00
jif-oai
0322ac3df8 [codex] Use compaction_trigger item for remote compaction v2 (#22809)
## Why

Remote compaction v2 was still using `context_compaction` as both the
request trigger and the compacted output shape. The Responses API now
has the landed contract for this flow: Codex sends a dedicated `{
"type": "compaction_trigger" }` input item, and the backend returns the
standard `compaction` output item with encrypted content.

This aligns the v2 path with that wire contract while preserving the
existing local compacted-history post-processing behavior.

## What changed

- Add `ResponseItem::CompactionTrigger` and regenerate the app-server
protocol schema fixtures.
- Send `compaction_trigger` from `remote_compaction_v2` instead of a
payload-less `context_compaction`.
- Collect exactly one backend `compaction` output item, then reuse the
existing compacted-history rebuilding path.
- Treat the trigger item as a transient request marker rather than model
output or persisted rollout/memory content.

## Verification

- `cargo test -p codex-protocol compaction_trigger`
- `cargo test -p codex-core remote_compact_v2`
- `cargo test -p codex-core compact_remote_v2`
- `cargo test -p codex-core
responses_websocket_sends_response_processed_after_remote_compaction_v2`
- `just write-app-server-schema`
- `cargo test -p codex-app-server-protocol schema_fixtures`
2026-05-15 11:40:35 +02:00
jif-oai
a5e5faf216 Reject legacy [profiles] when using profile-v2 (#22647)
## Why

`profile-v2` layers the selected profile file on top of the base user
`config.toml`, but the legacy `[profiles]` table also stores named
profile overrides in that same base file. Allowing both paths during one
load makes it too easy to get a mixed profile where stale legacy
settings still influence a profile-v2 run.

## What Changed

- Detect a legacy `[profiles]` table in the base user config whenever
`--profile-v2` selects a profile file.
- Fail config loading with an `InvalidData` error that tells the user to
move those settings into the selected profile-v2 file or remove
`[profiles]`.
- Add a loader regression covering `--profile-v2` with legacy
`[profiles]` in `config.toml`.

## Testing

- `cargo test -p codex-config
profile_v2_rejects_legacy_profiles_in_base_user_config`
2026-05-15 11:35:42 +02:00
Shijie Rao
302149d979 Fix signed macOS release promotion follow-up jobs (#22788)
## Why

The `release_mode=promote_signed` path intentionally skips the build
jobs after signed macOS artifacts are staged, then runs the `release`
job from the signed handoff. In the `rust-v0.131.0-alpha.19` promotion
run, `release` succeeded but the npm, PyPI, and `latest-alpha-cli`
follow-up jobs were skipped because their custom job `if:` expressions
let GitHub Actions apply the implicit `success()` status check before
reading `needs.release.outputs.*`.

The unsigned build handoff does not need DotSlash manifests. Publishing
unsigned DotSlash manifests creates release assets that can conflict
with the later signed promotion, especially shared outputs such as
`bwrap`, `codex-command-runner`, and `codex-windows-sandbox-setup`.

## What Changed

- Stop publishing DotSlash manifests when `SIGN_MACOS == 'false'`.
- Delete `.github/dotslash-unsigned-config.json`.
- Gate post-release jobs with the `!cancelled()` status function plus an
explicit `needs.release.result == 'success'` check before consulting
release outputs.
- Keep the existing publish eligibility rules for npm, PyPI, WinGet, and
`latest-alpha-cli`.

## Verification

- `rg -n "dotslash-unsigned-config|SIGN_MACOS ==
'false'.*dotslash|unsigned-config" .github/workflows/rust-release.yml
.github || true`
- `git diff --check -- .github/workflows/rust-release.yml
.github/dotslash-unsigned-config.json`
2026-05-15 00:43:23 -07:00
Michael Bolin
8adb6032cc tui/exec: show effective workspace roots in summaries (#22612)
## Why

This PR builds on [#22611](https://github.com/openai/codex/pull/22611).

After `runtimeWorkspaceRoots` moved onto thread state, the user-facing
summaries were still inconsistent about which roots they showed. In
particular, `/status` and the exec startup summary could under-report
extra workspace roots from `--add-dir` or from profile-defined
`workspace_roots`, which made the new model look incorrect even when the
permissions themselves were right.

## What Changed

- switched the TUI status surfaces to summarize against
`Config::effective_workspace_roots()`
- updated the exec human-output summary to render from the effective
permission profile instead of the raw constrained profile
- added focused regressions for both the TUI and exec code paths so
extra workspace roots stay visible in user-facing summaries

## Verification

Targeted coverage for this follow-up lives in:
- `codex-rs/tui/src/status/tests.rs`
- `codex-rs/exec/src/event_processor_with_human_output_tests.rs`

The added regressions verify that:
- status output includes profile-defined workspace roots in the
effective permissions summary
- exec startup output includes runtime workspace roots instead of
collapsing back to `cwd` only
2026-05-14 23:10:45 -07:00
Michael Bolin
8a5306ff88 app-server: use permission ids and runtime workspace roots (#22611)
## Why

This PR builds on [#22610](https://github.com/openai/codex/pull/22610)
and is the app-server side of the migration from mutable per-turn
`SandboxPolicy` replacement toward selecting immutable permission
profiles by id plus mutable runtime workspace roots.

Once permission profiles can carry their own immutable
`workspace_roots`, app-server no longer needs to mutate the selected
`PermissionProfile` just to represent thread-specific filesystem
context. The mutable part now lives on the thread as explicit
`runtimeWorkspaceRoots`, while `:workspace_roots` remains symbolic until
the sandbox is realized for a turn.

## What Changed

- Replaced the v2 permission-selection wrapper surface with plain
profile ids for `thread/start`, `thread/resume`, `thread/fork`, and
`turn/start`.
- Removed the API surface for profile modifications
(`PermissionProfileSelectionParams`,
`PermissionProfileModificationParams`,
`ActivePermissionProfileModification`).
- Added experimental `runtimeWorkspaceRoots` fields to the thread
lifecycle and turn-start APIs.
- Threaded runtime workspace roots through core session/thread
snapshots, turn overrides, app-server request handling, and command
execution permission resolution.
- Kept session permission state symbolic so later runtime root updates
and cwd-only implicit-root retargeting rebind `:workspace_roots`
correctly.
- Updated the embedded clients just enough to send and restore the new
thread state.
- Refreshed the generated schema/TypeScript artifacts and the app-server
README to match the new contract.

## Verification

Targeted coverage for this layer lives in:

- `codex-rs/app-server-protocol/src/protocol/v2/tests.rs`
- `codex-rs/app-server/tests/suite/v2/thread_start.rs`
- `codex-rs/app-server/tests/suite/v2/thread_resume.rs`
- `codex-rs/app-server/tests/suite/v2/turn_start.rs`
- `codex-rs/core/src/session/tests.rs`

The key regression checks exercise that:

- `runtimeWorkspaceRoots` resolve against the effective cwd on thread
start.
- Profile-declared workspace roots are excluded from the runtime
workspace roots returned by app-server.
- A turn-level runtime workspace-root update persists onto the thread
and is returned by `thread/resume`.
- A named permission profile selected on one turn remains symbolic so a
later runtime-root-only turn update changes the actual sandbox writes.
- A cwd-only turn update retargets the implicit runtime cwd root while
preserving additional runtime roots.
- The protocol fixtures and generated client artifacts stay in sync with
the string-based permission selection contract.











---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22611).
* #22612
* __->__ #22611
2026-05-14 23:00:05 -07:00
Eric Traut
e6a7368810 TUI: split history cells into focused modules (#22704)
## Why

`codex-rs/tui/src/history_cell.rs` had become the dumping ground for
transcript rendering: the shared trait, common helpers, and the concrete
cells for messages, plans, MCP/search, notices, patches, approvals,
session chrome, and separators all lived together. That made small
transcript changes require reopening a very large file and made
ownership less obvious.

## What changed

- Replaced the monolithic `history_cell.rs` with a `history_cell/`
module tree organized by concern.
- Kept the existing `crate::history_cell::*` surface stable through
re-exports in `history_cell/mod.rs`.
- Moved the existing render coverage into `history_cell/tests.rs`.

## Reviewer notes

- This PR is intentionally mechanical in mature — existing code and
tests moving into files that match their concern.
- The snapshot files under `codex-rs/tui/src/history_cell/snapshots/`
moved with the extracted test module. `insta` resolves these unnamed
snapshots relative to the source file that declares them, so this is
path churn only; snapshot contents were not updated.
- The small non-mechanical seam edits are limited to split fallout:
sibling-module visibility for shared cell containers, moving
approval-specific exec-snippet helpers beside approvals, fixing the
separator module path, and keeping a couple of existing test helpers
reachable after extraction.
2026-05-14 21:19:06 -07:00
Eric Traut
d1235a0a78 Prevent Esc from dismissing or rewinding /side (#22710)
Addresses #22599

## Why
`/side` currently lets `Esc` return to the parent thread. Multiple users
reported that this collides with queued-steer UI that also advertises
`Esc`, so a timing-sensitive keypress can dismiss an ephemeral side chat
instead of sending the queued prompt.

After removing that dismissal shortcut, the same `Esc` path could fall
through to main-thread backtrack/edit-previous handling, which is not
valid for ephemeral side conversations. This keeps `/side` out of both
global `Esc` behaviors.

## What changed
- Remove `Esc` from the `/side` return shortcut matcher while keeping
the existing `Ctrl+C` and `Ctrl+D` behavior.
- Update side-conversation hints and blocked-command copy to advertise
`Ctrl+C` as the return shortcut.
- Rename the reserved `Esc` keymap label to describe backtracking only.
- Block backtrack/edit-previous handling while a side conversation is
active and report `Editing previous prompts is unavailable in side
conversations.` when that path would have fired.
- Keep composer-owned `Esc` behavior, such as Vim insert-mode escape,
routed locally.
- Refresh focused shortcut assertions and TUI snapshots for the updated
footer and new side-conversation error message.

## Verification
Manually tested `/side` use cases and `Esc`, `Ctrl+C`, `Ctrl+D`.
2026-05-14 20:51:08 -07:00
guinness-oai
4f2918dd7f [codex] Add opaque desktop config namespace (#22584)
## Summary
- reserve an explicit opaque `desktop` namespace in `ConfigToml`
- expose `desktop` directly in the app-server v2 `config/read` response
- keep `config/value/write` and `config/batchWrite` as the only mutation
seam for paths like `desktop.someKey`
- regenerate the config/app-server schema outputs and document the new
contract

## Why
The desktop settings work wants one durable, user-editable home for
app-owned preferences in `~/.codex/config.toml`, without forcing Rust to
model every individual desktop setting key.

This PR is only the enabling Rust/app-server layer. It gives the
Electron app a first-class config namespace it can read and write
through the existing config APIs, while leaving the actual desktop
migration to the app PR.

## Behavior and design notes
- **Opaque but explicit:** `desktop` is first-class at the typed config
root, while its children remain app-owned and open-ended.
- **Strict validation still works:** arbitrary nested `desktop.*` keys
are accepted instead of being rejected as unknown config.
- **Existing config APIs stay the seam:** `config/read` returns the bag,
and dotted writes such as `desktop.someKey` continue to flow through
`config/value/write` / `config/batchWrite` rather than a bespoke RPC.
- **No new consumer behavior:** Core/TUI do not start depending on
desktop preferences. This only preserves and exposes the namespace for
callers that intentionally use it.
- **Same persistence machinery:** hand-edited `config.toml` keeps using
the existing TOML edit/write path; this PR does not introduce a second
serializer or side channel.
- **TOML-friendly values:** the namespace is intended for ordinary
JSON-shaped setting values that map cleanly into TOML: strings, numbers,
booleans, arrays, and nested object/table values. This PR does not add
special handling for TOML-only edge cases such as datetimes.

## Layering semantics
Reads keep using the ordinary effective config pipeline, so `desktop`
participates in the same layered `config/read` behavior as the rest of
`ConfigToml`. Writes still target user config through the existing
config service.

## Why this is the shape
The alternative would be teaching Rust about each desktop setting as it
is added. That would make ordinary app preferences into a cross-repo
change, which is exactly the coupling we want to avoid.

This keeps the contract small:
1. Rust owns one opaque `desktop` namespace in `config.toml`.
2. The desktop app owns the schema and meaning of individual keys inside
it.
3. The existing config APIs remain the transport and mutation surface.

That is the piece the desktop settings PR needs in order to move forward
cleanly.

## Verification
- `cargo test -p codex-config strict_config_accepts_opaque_desktop_keys`
- `cargo test -p codex-core
desktop_toml_round_trips_opaque_nested_values`
- `cargo test -p codex-core config_schema_matches_fixture`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-app-server --test all desktop_settings`
2026-05-15 02:34:21 +00:00
Eric Traut
3a23e87e20 tui: recover local state db startup failures (#22734)
## Why

#22580 made app-server startup fail when the local SQLite state database
cannot be initialized. Embedded/local TUI startup still continued on the
permissive path, which left the CLI inconsistent and could hide a real
startup problem behind unrelated UI. This brings local TUI startup onto
the same fail-closed behavior while keeping recovery humane for the two
failure modes we are seeing in practice: damaged database files and
startup stalls caused by another process holding the database write
lock.

## What changed

- Embedded TUI startup now uses `state_db::try_init(...)` and returns a
typed `LocalStateDbStartupError` that preserves the affected database
path plus the underlying failure detail.
- CLI startup handles that failure before entering the interactive TUI:
- lock-contention failures tell users to quit other Codex processes and
try again
- failures consistent with a broken local database offer a safe repair
that backs up Codex-owned SQLite files, rebuilds local database files,
and retries startup once
- declined or unsuccessful repairs print concise guidance plus technical
details
- Shared startup error plumbing lives in `tui/src/startup_error.rs`,
while CLI recovery policy and focused recovery tests live in
`cli/src/state_db_recovery.rs`.

## Verification

- `cargo test -p codex-tui
embedded_state_db_failure_is_typed_for_cli_recovery`
- `cargo test -p codex-cli state_db_recovery`
- Manually held an exclusive SQLite lock on `state_5.sqlite` and
confirmed the CLI shows lock-specific guidance without offering repair.
- Manually exercised the repair path with a deliberately invalid
`sqlite_home` and confirmed it backs up the blocking path and resumes
startup.
2026-05-14 18:51:36 -07:00
Michael Bolin
3c6d727810 permissions: resolve profile identity with constraints (#22683)
## Why

This PR is the invariant-cleanup layer that follows the workspace-roots
base merged in [#22610](https://github.com/openai/codex/pull/22610).

#22610 adds `[permissions.<id>.workspace_roots]` and keeps runtime
workspace roots separate from the raw permission profile, but its
in-memory representation is intentionally transitional: `Permissions`
still carries the selected profile identity next to a constrained
`PermissionProfile`. That makes APIs such as
`set_constrained_permission_profile_with_active_profile()` fragile
because the id and value only mean the right thing when every caller
keeps them in sync.

This PR introduces a single resolved profile state so profile identity,
`extends`, the profile value, and profile-declared workspace roots
travel together. The next PR,
[#22611](https://github.com/openai/codex/pull/22611), builds on this by
changing the app-server turn API to select permission profiles by id
plus runtime workspace roots.

## Stack Context

- #22610, now merged: adds profile-declared `workspace_roots`, runtime
workspace roots, and `:workspace_roots` materialization.
- This PR: replaces the parallel active-profile/profile-value fields
with `PermissionProfileState`.
- #22611: switches app-server turn updates toward profile ids plus
runtime workspace roots.
- #22612: updates TUI/exec summaries to show the effective workspace
roots.

Keeping this separate from #22611 is deliberate: reviewers can validate
the internal state invariant before reviewing the app-server protocol
migration.

## What Changed

- Added `ResolvedPermissionProfile::{Legacy, BuiltIn, Named}` and
`PermissionProfileState`.
- Typed built-in profile ids with `BuiltInPermissionProfileId`.
- Moved selected profile identity and profile-declared workspace roots
into the resolved state.
- Replaced `Permissions` parallel profile fields with one
`permission_profile_state`.
- Removed `set_constrained_permission_profile_with_active_profile()`
from session sync paths.
- Kept trusted session replay/`SessionConfigured` compatibility through
explicit session snapshot helpers.
- Updated session configuration, MCP initialization, app-server, exec,
TUI, and guardian call sites to consume `&PermissionProfile` directly.

## Review Guide

Start with `codex-rs/core/src/config/resolved_permission_profile.rs`; it
is the new invariant boundary. Then review
`codex-rs/core/src/config/mod.rs` to see how config loading records
active profile identity and profile workspace roots. The remaining
call-site changes are mostly mechanical fallout from
`Permissions::permission_profile()` returning `&PermissionProfile`
instead of `&Constrained<PermissionProfile>`.

## Verification

The existing config/session coverage now constructs and asserts through
`PermissionProfileState`. The workspace-root config test also asserts
that profile-declared roots are preserved in the resolved state, which
is the behavior #22611 relies on when runtime roots become mutable
through the app-server API.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22683).
* #22612
* #22611
* __->__ #22683
2026-05-14 18:47:44 -07:00
Dylan Hurd
06bb508547 Stabilize compact rollback follow-up test (#22303)
## Summary
- add the missing response.created event to the mocked empty follow-up
response in the compact rollback test
- keep the fix scoped to the flaky mocked stream shape, without
increasing timeouts

## Recent flakes on main
- `snapshot_rollback_followup_turn_trims_context_updates` failed in
`rust-ci-full` on `main` in the Ubuntu remote test job on 2026-05-14:
https://github.com/openai/codex/actions/runs/25891434395/job/76095284830
- The same `compact_resume_fork` suite also failed recently on `main`
with `snapshot_rollback_past_compaction_replays_append_only_history`,
which has the same mocked Responses stream shape sensitivity this PR is
tightening:
https://github.com/openai/codex/actions/runs/25892437363/job/76098329098

## Verification
- env -u CODEX_SANDBOX_NETWORK_DISABLED cargo test -p codex-core --test
all snapshot_rollback_followup_turn_trims_context_updates -- --nocapture
- repeated the same focused test 3 consecutive times locally
- UV_CACHE_DIR=/private/tmp/uv-cache-codex-fmt just fmt
2026-05-14 18:43:18 -07:00
Michael Bolin
db51df0f44 ci: support signed macOS release promotion (#22737)
## Why

`rust-release.yml` can create unsigned macOS artifacts for external
signing, but there was no signed resume path after those artifacts
returned from a secure enclave. Release operators need a way to reuse
the first run artifacts, ingest signed macOS binaries and DMGs, and
continue the normal signed release path without rebuilding every
platform or treating handoff assets as final release assets.

## How this is meant to be used

First, start the release as an unsigned macOS build against the release
tag:

```shell
gh workflow run rust-release.yml \
  --repo openai/codex \
  --ref rust-vX.Y.Z \
  -f release_mode=build_unsigned
```

That run builds the normal Linux/Windows artifacts and publishes
unsigned macOS handoff artifacts. The unsigned macOS binaries are then
copied to the secure enclave, signed and notarized there, packaged as a
signed handoff archive, and uploaded back to the GitHub Release for the
same tag.

The signed handoff asset should contain either target directories such
as `aarch64-apple-darwin/` and `x86_64-apple-darwin/`, or artifact
directories such as `aarch64-apple-darwin-app-server/`. The promote
workflow accepts either layout. The directories should contain the
signed binaries and, for primary macOS bundles, the signed and stapled
DMGs.

For example, after signing, upload the handoff asset to the release:

```shell
gh release upload rust-vX.Y.Z \
  signed-macos-rust-vX.Y.Z.tar.zst \
  --repo openai/codex \
  --clobber
```

Then start the promotion run. `unsigned_run_id` is the workflow run id
from the first `build_unsigned` run, and `signed_macos_asset` is the
exact Release asset name uploaded by the secure enclave:

```shell
gh workflow run rust-release.yml \
  --repo openai/codex \
  --ref rust-vX.Y.Z \
  -f release_mode=promote_signed \
  -f unsigned_run_id=1234567890 \
  -f signed_macos_asset=signed-macos-rust-vX.Y.Z.tar.zst \
  -f signed_macos_sha256=<sha256>
```

The `signed_macos_sha256` input is optional, but when provided the
promotion run verifies the handoff archive before unpacking it. The
promotion run also validates that `unsigned_run_id` points to a
successful manual `rust-release` run for the same tag and commit before
importing artifacts.

## What Changed

- Add explicit manual `release_mode` values for `build_unsigned` and
`promote_signed` while keeping `sign_macos` as a deprecated
compatibility input.
- Add promote inputs for `unsigned_run_id`, `signed_macos_asset`, and
optional `signed_macos_sha256`.
- Add a `stage-signed-macos` job that downloads the signed handoff asset
from the GitHub Release, verifies signed binaries and stapled DMGs,
repacks normal macOS release artifacts, and builds macOS Python runtime
wheels.
- Teach the release job to download Part 1 artifacts from the unsigned
run, discard unsigned macOS staging artifacts, re-upload promoted Linux
and Windows artifacts for npm staging, and then run the signed release
tail.
- Validate that `unsigned_run_id` points to a successful manual
`rust-release` run for the same tag and commit before importing
artifacts.
- Limit unsigned macOS artifact upload to the unsigned build path so
normal signed releases do not publish unsigned handoff binaries.
- Clean up unsigned and signed handoff release assets after successful
promotion.

## Verification

- Parsed `.github/workflows/rust-release.yml` with Ruby YAML loading.

No developers.openai.com documentation update is needed.
2026-05-14 18:36:20 -07:00
mchen-oai
10cf1f79dd Add user_input_requested_during_turn to MCP turn metadata (#22237)
## Why
- Similar change as https://github.com/openai/codex/pull/21219
- Without change: MCP tool calls receive
`_meta["x-codex-turn-metadata"]` with various key values.
- Issue: MCP servers currently do not know if user input was requested
during the turn (Ex: Model decides to prompt the user for approval
mid-turn before making a possibly risky tool call). MCP servers may want
to know this when tracking latency metrics because these instances are
inflated.

## What Changed
- With change: MCP turn metadata now includes
`user_input_requested_during_turn` when a model-visible
`request_user_input` call happened earlier in the turn, propagated in
`_meta["x-codex-turn-metadata"]`.
- `mark_turn_user_input_requested()` is called when user input is
requested through either MCP elicitation (`mcp.rs`) or the
`request_user_input` tool (`mod.rs`).
- MCP tool call `_meta` is now built immediately before execution
(`mcp_tool_call.rs`) so user input requested earlier in the same turn,
including within the same tool call via elicitation, is reflected in the
metadata.
- Normal `/responses` turn metadata headers are unchanged.

## Verification
- `codex-rs/core/src/session/mcp_tests.rs`
- `codex-rs/core/src/tools/handlers/request_user_input_tests.rs`
- `codex-rs/core/src/turn_metadata_tests.rs`
- `codex-rs/core/tests/suite/search_tool.rs`
2026-05-15 01:26:50 +00:00
Michael Bolin
c25d905f61 permissions: support workspace roots in profiles (#22610)
## Why

This is the configuration/model half of the alternative permissions
migration we discussed as a comparison point for
[#22401](https://github.com/openai/codex/pull/22401) and
[#22402](https://github.com/openai/codex/pull/22402).

The old `workspace-write` model mixes three concerns that we want to
keep separate:
- reusable profile rules that should stay immutable once selected
- user/runtime workspace roots from `cwd`, `--add-dir`, and legacy
workspace-write config
- internal Codex writable roots such as memories, which should not be
shown as user workspace roots

This PR gives permission profiles first-class `workspace_roots` so users
can opt multiple repositories into the same `:workspace_roots` rules
without using broad absolute-path write grants. It also starts
separating the raw selected profile from the effective runtime profile
by making `Permissions` expose explicit accessors instead of public
mutable fields.

A representative `config.toml` looks like this:

```toml
default_permissions = "dev"

[permissions.dev.workspace_roots]
"~/code/openai" = true
"~/code/developers-website" = true

[permissions.dev.filesystem.":workspace_roots"]
"." = "write"
".codex" = "read"
".git" = "read"
".vscode" = "read"
```

If Codex starts in `~/code/codex` with that profile selected, the
effective workspace-root set becomes:
- `~/code/codex` from the runtime `cwd`
- `~/code/openai` from the profile
- `~/code/developers-website` from the profile

The `:workspace_roots` rules are materialized across each root, so
`.git`, `.codex`, and `.vscode` stay scoped the same way everywhere.
Runtime additions such as `--add-dir` can still layer on later stack
entries without mutating the selected profile.

## Stack Shape

This PR intentionally stops before the profile-identity cleanup in
[#22683](https://github.com/openai/codex/pull/22683) so the base review
stays focused on config loading, workspace-root materialization, and
compatibility with legacy `workspace-write`.

The representation in this PR is therefore transitional: `Permissions`
carries enough state to distinguish the raw constrained profile from the
effective runtime profile, and there are still call sites that must keep
the active profile identity and constrained profile value in sync. The
follow-up PR replaces that with a single resolved profile state
(`ResolvedPermissionProfile` / `PermissionProfileState`) that keeps the
profile id, immutable `PermissionProfile`, and profile-declared
workspace roots together. That follow-up removes APIs such as
`set_constrained_permission_profile_with_active_profile()` where
separate arguments could drift out of sync.

Downstream PRs then build on this base to switch app-server turn updates
to profile ids plus runtime workspace roots and to finish the
user-visible summary behavior. Reviewers should judge this PR as the
workspace-roots foundation, not as the final in-memory shape of selected
permission profiles.

## Review Guide

Suggested review order:

1. Start with `codex-rs/core/src/config/mod.rs`.
This is the main shape change in the base slice. `Permissions` now
stores a private raw `Constrained<PermissionProfile>` plus runtime
`workspace_roots`. Callers use `permission_profile()` when they need the
raw constrained value and `effective_permission_profile()` when they
need a materialized runtime profile. As noted above,
[#22683](https://github.com/openai/codex/pull/22683) replaces this
transitional shape with a resolved profile state that keeps identity and
profile data together.

2. Review `codex-rs/config/src/permissions_toml.rs` and
`codex-rs/core/src/config/permissions.rs`.
These add `[permissions.<id>.workspace_roots]`, resolve enabled entries
relative to the policy cwd, and keep `:workspace_roots` deny-read glob
patterns symbolic until the actual roots are known.

3. Review `codex-rs/protocol/src/permissions.rs` and
`codex-rs/protocol/src/models.rs`.
These add the policy/profile materialization helpers that expand exact
`:workspace_roots` entries and scoped deny-read globs over every
workspace root. This is also where `ActivePermissionProfileModification`
is removed from the core model.

4. Review the legacy bridge in
`Config::load_from_base_config_with_overrides` and
`Config::set_legacy_sandbox_policy`.
This is where legacy `workspace-write` roots become runtime workspace
roots, while Codex internal writable roots stay internal and do not
appear as user-facing workspace roots.

5. Then skim downstream call sites.
The interesting pattern is raw-vs-effective access: state/proxy/bwrap
paths keep the raw constrained profile, while execution, summaries, and
user-visible status use the effective profile and workspace-root list.

## What Changed

- added `[permissions.<id>.workspace_roots]` to the config model and
schema
- added runtime `workspace_roots` state to `Config`/`Permissions` and
`ConfigOverrides`
- made `Permissions` profile fields private and replaced direct mutation
with accessors/setters
- added `PermissionProfile` and `FileSystemSandboxPolicy` helpers for
materializing `:workspace_roots` exact paths and deny-read globs across
all roots
- moved legacy additional writable roots into runtime workspace-root
state instead of active profile modifications
- removed `ActivePermissionProfileModification` and its app-server
protocol/schema export
- updated sandbox/status summary paths so internal writable roots are
not reported as user workspace roots

## Verification Strategy

The targeted tests cover the behavior at the layers where regressions
are most likely:
- `codex-rs/core/src/config/config_tests.rs` verifies config loading,
legacy workspace-root seeding, effective profile materialization, and
memory-root handling.
- `codex-rs/core/src/config/permissions_tests.rs` verifies profile
`workspace_roots` parsing and `:workspace_roots` scoped/glob
compilation.
- `codex-rs/protocol/src/permissions.rs` unit tests verify exact and
glob materialization over multiple workspace roots.
- `codex-rs/tui/src/status/tests.rs` and
`codex-rs/utils/sandbox-summary/src/sandbox_summary.rs` verify the
user-facing summaries show effective workspace roots and hide internal
writes.

I also ran `cargo check --tests` locally after the latest stack refresh
to catch cross-crate API breakage from the private-field/accessor
changes.







---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/22610).
* #22612
* #22611
* #22683
* __->__ #22610
2026-05-14 18:25:23 -07:00
Dylan Hurd
7dbe1c9498 [codex] Remove experimental instructions file config (#22724)
## Summary

Remove the deprecated `experimental_instructions_file` config setting
from the typed config surface and the remaining deprecation-notice
plumbing. `model_instructions_file` remains the supported setting and
its loading path is unchanged.

The setting was deprecated when it was renamed to
`model_instructions_file` on January 20, 2026 in
https://github.com/openai/codex/pull/9555.

## Changes

- Remove `experimental_instructions_file` from `ConfigToml` and
`ConfigProfile`.
- Delete the custom config-layer scan and session deprecation notice for
the removed setting.
- Stop clearing the removed field from generated session config locks.
- Remove the obsolete deprecation-notice test case while keeping
`model_instructions_file` coverage intact.

## Validation

- `just write-config-schema`
- `just fmt`
- `cargo test -p codex-config`
- `cargo test -p codex-core model_instructions_file`
- `just fix -p codex-core`
- `git diff --check`

Co-authored-by: Codex <noreply@openai.com>
2026-05-14 18:04:26 -07:00
Dylan Hurd
eeabaf74ea [codex] Group removed feature flags (#22730)
## Summary
- move removed feature enum variants under the existing Removed section
- keep active feature variants grouped away from no-op compatibility
flags

## Test plan
- just fmt
- cargo test -p codex-features

Co-authored-by: Codex <noreply@openai.com>
2026-05-15 00:53:13 +00:00
pakrym-oai
4bff020a96 Remove SSE fixture loaders (#22684)
## Why

The Responses API test support already has structured SSE event
builders. Keeping separate JSON fixture loaders made small mock streams
harder to read and left an on-disk fixture for a single event.

## What changed

- Removed `load_sse_fixture` and `load_sse_fixture_with_id_from_str`
from `core_test_support`.
- Deleted the one `tests/fixtures/incomplete_sse.json` Responses API
fixture.
- Replaced the remaining call sites with `responses::sse(...)` and
existing event helpers.

## Validation

- `cargo test -p codex-core --test all
stream_no_completed::retries_on_early_close`
- `cargo test -p codex-core --test all
history_dedupes_streamed_and_final_messages_across_turns`
- `cargo test -p codex-core --test all review::`
2026-05-15 00:40:32 +00:00
canvrno-oai
66af217865 Fix /review mode MCP startup render issue (#21624)
This change fixes the case where the UI can sit on _"Starting MCP
servers"_ even though the review work is already running or has already
completed.

- MCP startup status header is visible when a `/review` turn starts with
enabled MCP server startups
- Restore the underlying _Working..._ status after MCP startup completes
or fails
- Add regression coverage for overlapping startup/turn flows and status
restoration

_De-scoped from a broader thread-scoped MCP status change that would
have made it easier to route MCP startup statuses to the appropriate
thread (parent vs. review). These changes address the UI regression
without requiring more significant changes across app-server & core._

Fixes #18792.
2026-05-14 17:25:32 -07:00
Eric Traut
3dc278b68e Trim TUI legacy core helper usage (#22695)
## Why

The TUI still had a few low-risk dependencies flowing through the
transitional `legacy_core` namespace after the app-server migration.
These helpers either already have clearer non-core owners or are
presentation logic that does not belong in `codex-core`, so moving them
out reduces the compatibility surface without changing product behavior.

## What changed

This is a low-risk change, almost completely mechanical in nature.

- Route TUI Codex-home lookup through `codex-utils-home-dir`, use
`Config::log_dir` directly, and call
`codex-sandboxing::system_bwrap_warning` without going through
`legacy_core`.
- Move shared `codex resume` hint formatting from `codex-core` into
`codex-utils-cli`.
- Update CLI and TUI call sites to use the shared CLI utility, and keep
the resume-command behavior covered by tests in its new home.

## Verification

- `cargo test -p codex-utils-cli`
- `cargo test -p codex-utils-cli resume_command`
2026-05-14 16:54:59 -07:00
Dylan Hurd
85915a2a21 chore(config) rm windows_wsl_setup_acknowledged (#22717)
## Summary
Remove dead code from a notice that no longer exists.

## Testing
- [x] Unit tests pass.
2026-05-14 23:25:15 +00:00
Dylan Hurd
51b0e94105 chore(features) rm Feature::ApplyPatchFreeform (#22711)
## Summary
Removes the feature since this is effectively on by default in all cases
where we should use it, or can be configured via models.json.

## Testing
- [x] unit tests pass
2026-05-14 16:15:56 -07:00
starr-openai
7c11c14efc Fix Windows sandbox clippy clones (#22687)
## Summary
- remove two redundant `PathBuf` clones in Windows sandbox setup tests
- fix current `rust-ci-full` Windows clippy failures on `main`

## Validation
- `just fmt`
- attempted on `dev`: `cargo clippy --target x86_64-pc-windows-msvc
--tests --profile dev --timings -- -D warnings`
- blocked by missing MSVC cross toolchain on the Linux devbox (`lib.exe`
/ MSVC C toolchain unavailable)
- live failure evidence: main `rust-ci-full` runs 25880209898 and
25879137967 failed on `windows-sandbox-rs/src/bin/setup_main/win.rs`
with `clippy::redundant_clone` at the two edited callsites
2026-05-14 15:54:18 -07:00
xli-oai
8c7a176b55 Unqueue plugin list and read requests (#22703)
## Summary
- remove the app-server `plugin-read` serialization queue from
`plugin/list` and `plugin/read`
- allow plugin read/list requests to start immediately instead of
waiting behind other plugin read/list requests

## Test plan
- `just fmt`
- `cargo test -p codex-app-server-protocol`
2026-05-14 15:07:20 -07:00
sayan-oai
d346957288 make rust-release-prepare use env secret (#22702)
made a `rust-release-prepare` environment with the necessary API key as
an environment secret. use this in the workflow rather than the action
secret.

once this merges and i confirm it works as intended, ill rm the action
secret.
2026-05-14 21:45:53 +00:00
rreichel3-oai
02a7205250 [codex] Support multiple forced ChatGPT workspaces (#18161)
## Summary

This change lets `forced_chatgpt_workspace_id` accept multiple workspace
IDs instead of a single value.

It keeps the existing config key name, adds backward-compatible parsing
for a single string in `config.toml`, and normalizes the setting into an
allowed workspace list across login enforcement, app-server config
surfaces, and local ChatGPT auth helpers.

## Why

Workspace-restricted deployments may need to allow more than one ChatGPT
workspace without dropping the guardrail entirely.

## Server-side impact

Codex's local server and app-server protocol needed changes because they
previously assumed a single workspace ID. The local login flow now
matches the auth backend interface by sending the allowed workspace list
as a single comma-separated `allowed_workspace_id` query parameter.

## Validation

This was tested with:

- A single workspace config
- With multi-workspace configs
- With multiple workspaces in the config
- The user only being a part of a subset of them

All were successful.

Automated coverage:

- `cargo test -p codex-login`
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-tui local_chatgpt_auth`
- `cargo test --locked -p codex-app-server
login_account_chatgpt_includes_forced_workspace_allowlist_query_param`
2026-05-14 17:11:36 -04:00
starr-openai
32b45a43e2 tests: isolate codex home for live cli (#22563)
## Why

Some core integration-test paths were creating Codex state under ambient
`~/.codex`. In environments where `HOME=/tmp`, that showed up as
`/tmp/.codex`, which is host-level shared state and makes these tests
environment/order sensitive.

The affected paths were:

- `core/tests/suite/live_cli.rs`: `run_live()` spawned the real CLI with
a temp cwd, but without an isolated home, so the child resolved Codex
home from ambient `HOME`.
- core / exec-server integration test binaries using
`configure_test_binary_dispatch(...)`: their startup ctor installs arg0
helper aliases like `apply_patch` and `codex-linux-sandbox`. Full
`arg0_dispatch()` also installs aliases from ambient Codex-home
resolution, so test-binary startup could create `CODEX_HOME/tmp/arg0`;
with `HOME=/tmp`, that became `/tmp/.codex/tmp/arg0/...`.

## What changed

- `live_cli` now gives the spawned CLI a temp `HOME` and temp
`CODEX_HOME`.
- arg0 alias setup now has an explicit-home form,
`prepend_path_entry_for_codex_aliases_in(...)`, so test helpers can
place alias state under a temp directory without relying on ambient
`CODEX_HOME`.
- helper re-entry behavior is preserved with
`dispatch_arg0_if_needed()`, so aliases like `apply_patch` and
`codex-linux-sandbox` still dispatch correctly before test alias
installation.
- core test support keeps the temp Codex home alive for the lifetime of
the test binary, matching the alias lifetime.

## Verification

Verified on `dev2` with `HOME=/tmp` that the focused core test-binary
startup path no longer recreates `/tmp/.codex`.

Also checked the exact `live_cli` test path under `HOME=/tmp`; on `dev2`
it still hits the existing remote-only `cargo_bin("codex-rs")`
resolution failure before spawning the child, but `/tmp/.codex` remains
absent after the run.
2026-05-14 12:59:56 -07:00
starr-openai
255748638c Fix remote environment test fixtures (#22572)
## Why
The Docker remote-env coverage was failing before it reached the
behavior those tests are meant to exercise. The remote-aware test
fixture only registered the remote environment, so tests that
intentionally select both `local` and `remote` could not start a turn.
After that was fixed, two tests exposed stale fixtures: the approval
test was auto-approving under workspace-write, and the remote
`view_image` test was writing invalid PNG bytes.

## What Changed
- Added `EnvironmentManager::create_for_tests_with_local(...)` so tests
can keep the provider default while also selecting `local` explicitly.
- Updated `build_remote_aware()` to use that test-only manager when a
remote exec-server URL is present.
- Changed the remote apply-patch approval helper to use
`SandboxPolicy::new_read_only_policy()` so the test actually exercises
approval caching per environment.
- Replaced the hardcoded remote `view_image` PNG blob with the existing
`png_bytes(...)` helper so the test uses a valid image fixture.

## Validation
Ran these isolated Docker remote-env tests on the devbox with
`$remote-tests` setup:
-
`suite::remote_env::apply_patch_freeform_routes_to_selected_remote_environment`
-
`suite::remote_env::apply_patch_approvals_are_remembered_per_environment`
-
`suite::remote_env::apply_patch_intercepted_exec_command_routes_to_selected_remote_environment`
-
`suite::remote_env::exec_command_routes_to_selected_remote_environment`
- `suite::view_image::view_image_routes_to_selected_remote_environment`

All five pass.
2026-05-14 12:40:01 -07:00
Michael Bolin
e8969d940d test: isolate exec review policy config test (#22512)
## Why


`thread_start_params_include_review_policy_when_review_policy_is_manual_only`
builds a `Config` with a temporary `CODEX_HOME`, but
`ConfigBuilder::default()` can still load host-managed configuration. On
local macOS machines with enterprise-managed Codex config, that host
state can leak into the test and change the resulting config, even
though CI does not have the same managed config source.

This makes the test environment-dependent: it can pass in CI while
failing locally for developers who have managed configuration installed.

## What Changed

- Updated `codex-rs/exec/src/lib_tests.rs` so the test calls
`LoaderOverrides::without_managed_config_for_tests()` through
`ConfigBuilder::loader_overrides(...)`.
- Left the rest of the test setup intact, including the temporary
`CODEX_HOME`, temporary cwd, and explicit `approvals_reviewer` harness
override.

## Verification

```shell
cargo test -p codex-exec thread_start_params_include_review_policy_when_review_policy_is_manual_only
```
2026-05-14 12:14:20 -07:00
Matthew Zeng
d8ddeb6869 Support explicit MCP OAuth client IDs (#22575)
## Why
Some MCP OAuth providers require a pre-registered public client ID and
cannot rely on dynamic client registration. Codex already supports MCP
OAuth, but it had no way to supply that client ID from config into the
PKCE flow.

## What changed
- add `oauth.client_id` under `[mcp_servers.<server>]` config, including
config editing and schema generation
- thread the configured client ID through CLI, app-server, plugin login,
and MCP skill dependency OAuth entrypoints
- configure RMCP authorization with the explicit client when present,
while preserving the existing dynamic-registration path when it is
absent
- add focused coverage for config parsing/serialization and OAuth URL
generation

## Verification
- `cargo test -p codex-config -p codex-rmcp-client -p codex-mcp -p
codex-core-plugins`
- `cargo test -p codex-core blocking_replace_mcp_servers_round_trips
--lib`
- `cargo test -p codex-core
replace_mcp_servers_streamable_http_serializes_oauth_resource --lib`
- `cargo test -p codex-core config_schema_matches_fixture --lib`

## Notes
Broader local package runs still hit unrelated pre-existing stack
overflows in:
- `codex-app-server::in_process_start_clamps_zero_channel_capacity`
-
`codex-core::resume_agent_from_rollout_uses_edge_data_when_descendant_metadata_source_is_stale`
2026-05-14 11:52:43 -07:00
Casey Chow
4a1f1df8ce [codex] fix plugin CLI active user layer compile (#22666)
## Why

PR #21396 merged after #17141 removed the old
`ConfigLayerStack::get_user_layer()` API. The new plugin CLI call sites
still used that stale API, which caused `main` to fail compilation.

## What Changed

- update `codex plugin marketplace list` to read configured marketplaces
through `get_active_user_layer()`
- update the plugin snapshot validation helper to use
`get_active_user_layer()`

This preserves the intended active writable user-layer behavior from the
profile-aware config API while fixing the stale call sites.

## Validation

- `cargo check -p codex-cli`
- `cargo test -p codex-cli --test plugin_cli`
- `git diff --check`
2026-05-14 18:41:04 +00:00
Rajeev Nayak
f13e21ef43 Prefer the model list fetched from the backend for SIWC users (#22547)
## Summary
- For SIWC users, update the model list merging logic to prefer the
model list fetched from the backend over the bundled model list (this is
needed for special cases where users have a more limited set of models
they're allowed to use)
- Add or update tests covering the revised cache behavior

## Testing
- Added/updated unit tests in
`codex-rs/models-manager/src/manager_tests.rs`
- Not run (not requested)
2026-05-14 13:45:49 -04:00
Felipe Coury
5a02962519 fix(tui): render network approval history by target (#22229)
## Why

Network approval prompts are rendered without a command string on the
app-server path. After the user approves one of those prompts, the TUI
history cell previously fell back to command-oriented copy and produced
malformed lines such as:

```text
You approved codex to run  every time this session
```

That hid the network target the user actually approved and left a
visibly broken transcript entry.

## What changed

- Preserve the approval subject as either a command or a network target
when recording TUI approval decisions.
- Render target-aware history copy for network approval outcomes:
  - approve once
  - approve for the current session
  - cancel
- Include the approval protocol and preserve the managed-proxy
`network-access` target when present, including non-default ports such
as `https://example.com:8443`.
- Fall back to formatting the network approval context as
`protocol://host` when no generated target command is available.
- Keep ordinary command approval history, Guardian approval history, and
persisted network-rule history behavior unchanged.
- Add focused regression coverage and snapshots for the three
network-history cases.

## How to Test

1. Start Codex in a flow that triggers a network approval prompt.
2. Approve network access only for the current conversation.
3. Confirm the transcript records the approved network target, for
example:
- `You approved codex network access to https://example.com:8443 every
time this session`
4. Trigger the prompt again and verify the one-time approval and cancel
paths also record target-specific history text instead of an empty
command gap.

Targeted automated coverage:
- `cargo test -p codex-tui network_exec_approval_history`

## Additional verification

- `cargo insta pending-snapshots`
- `git diff --check`
- `just fix -p codex-tui`
- `just argument-comment-lint`

## Known unrelated local test noise

A full `cargo test -p codex-tui` run still hits a pre-existing stack
overflow outside this change:
- `tests::fork_last_filters_latest_session_by_cwd_unless_show_all`
aborts with a stack overflow
2026-05-14 14:33:54 -03:00
Chris Bookholt
6ec8c4a6ec [codex] Ignore fsmonitor config in Git metadata reads (#22652)
## Summary
- keep Git metadata/status subprocesses independent of repository
`core.fsmonitor` configuration
- preserve existing working-tree state reporting while making the helper
behavior more predictable
- add regression coverage for `get_has_changes` when a repository
defines an fsmonitor command

## Validation
- `cargo fmt --all`
- `cargo test -p codex-core test_get_has_changes_`
- `cargo test -p codex-git-utils`
2026-05-14 10:07:43 -07:00