mirror of
https://github.com/openai/codex.git
synced 2026-09-06 15:29:32 +00:00
rust-v0.131.0
6563 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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-openairust-v0.131.0 |
||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
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
|
||
|
|
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 |
||
|
|
6afe00efda | Workflow updates (#22582) | ||
|
|
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> |
||
|
|
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 |
||
|
|
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 |
||
|
|
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_` |
||
|
|
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` |
||
|
|
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 |
||
|
|
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. |
||
|
|
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`]( |
||
|
|
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. |
||
|
|
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. |
||
|
|
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`
|
||
|
|
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` |
||
|
|
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` |
||
|
|
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 |
||
|
|
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 |
||
|
|
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. |
||
|
|
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`. |
||
|
|
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` |
||
|
|
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. |
||
|
|
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 |
||
|
|
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 |
||
|
|
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. |
||
|
|
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` |
||
|
|
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 |
||
|
|
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> |
||
|
|
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> |
||
|
|
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::` |
||
|
|
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. |
||
|
|
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` |
||
|
|
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. |
||
|
|
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 |
||
|
|
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 |
||
|
|
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` |
||
|
|
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. |
||
|
|
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` |
||
|
|
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.
|
||
|
|
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. |
||
|
|
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 ``` |
||
|
|
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` |
||
|
|
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` |
||
|
|
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) |
||
|
|
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 |
||
|
|
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` |