mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
2d385e166c2dff131ca21294216ce61eb62fd3c2
6179 Commits
-
feat: add skills extension scaffold (#25953)
## Disclaimer This is only here for iteration purpose! Do not make any code rely on this ## Why Skills still live behind `codex-core` discovery and injection paths, but the extension system needs an authority-aware home before that logic can move. This adds that boundary without changing current skills behavior, and keeps host, executor, and remote skills distinct so future list/read/search flows do not collapse back to ambient local paths. ## What changed - Add the `codex-skills-extension` workspace/Bazel crate under `ext/skills`. - Define the initial catalog, authority, provider, and turn-state types for authority-bound skill packages and resources. - Register placeholder thread/config/prompt/turn lifecycle contributors plus host, executor, and remote provider aggregation points. - Capture the remaining extraction work as TODOs, including the missing extension API hooks needed for per-turn catalog construction and typed skill injection. - Keep plugins outside the runtime skills model: plugin-installed skills are treated as materialized host-owned skill sources once available. ## Verification - Not run locally.
jif ·
2026-06-03 01:10:26 +02:00 -
Expose standalone image generation in code mode (#25923)
## Why Standalone image generation remained top-level-only in code-mode sessions. ## What changed - Change imagegen exposure from `DirectModelOnly` to `Direct`. - Keep direct-mode access while enabling nested code-mode access. - Add a focused regression test for the exposure contract. ## Validation - `just test -p codex-image-generation-extension`
Won Park ·
2026-06-02 22:27:52 +00:00 -
config: remove dead profile sandbox fallback (#25943)
## Why `profile_sandbox_mode` was left over from the old selected legacy profile path. Production now always derives permissions without that value, and legacy profile contents are ignored, so keeping a parameter that is always `None` makes `derive_permission_profile` look like it still supports a fallback that no longer exists. ## What Changed - Removed the `profile_sandbox_mode` argument from `ConfigToml::derive_permission_profile`. - Updated the production caller and legacy sandbox-policy test helper to match. - Dropped the stale unselected legacy-profile sandbox test that only protected the removed fallback shape. ## Verification - `just test -p codex-config` - `just test -p codex-core 'config::'` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/25943). * #25926 * __->__ #25943
Michael Bolin ·
2026-06-02 22:05:04 +00:00 -
Add remote request permissions integration coverage (#25867)
## Stack 1. #25850 - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. #25858 - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. #25862 - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. This PR (#25867) - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. This PR is stacked on #25862 and should be reviewed after #25850, #25858, and #25862. ## Why The environment-scoped permission stack needs one end-to-end check that exercises the CCA-shaped path, not only unit-level parsing. This verifies that a model-sent `environmentId` on `request_permissions` reaches the approval event, stores the grant under the selected environment, and is reused by a later tool call in that same environment. ## What Changed - Adds a remote executor integration test for `request_permissions` with `environmentId: remote` and a relative write root. - Asserts the permission event reports the remote environment and cwd, and that the normalized grant resolves under the remote cwd. - Approves the grant, then runs a remote `exec_command` without explicit per-call permissions and verifies it completes without another exec approval and writes only in the remote filesystem. ## Verification - Not run locally per instruction. - `git diff --check`
jif ·
2026-06-02 23:55:08 +02:00 -
[codex] Keep hosted tools visible in code-only mode (#25890)
## Why `code_mode_only` moved ordinary runtime tools behind `exec`, but it also hid hosted Responses tools. Hosted `web_search` and `image_generation` do not have a nested `exec` runtime path, so code-only sessions lost those capabilities entirely even when their existing provider, auth, model, and configuration gates passed. ## What changed - Keep hosted Responses tools top-level in `code_mode_only` sessions after their existing gates pass. - Preserve the existing nested-tool behavior for ordinary runtimes and the direct-only behavior for multi-agent v2 tools. - Add planner coverage for `code_mode_only` with default multi-agent v2 settings, hosted live web search, and hosted image generation. ## Verification - Added focused regression coverage in `codex-rs/core/src/tools/spec_plan_tests.rs`. - Left execution to CI per repository workflow.
Ahmed Ibrahim ·
2026-06-02 14:50:16 -07:00 -
Split cloud config bundle service modules (#25668)
## Summary - Splits the monolithic `codex-cloud-config` implementation into focused modules. - Keeps behavior unchanged from the preceding config bundle runtime switch. ## Details This is the reviewability follow-up after the lineage-preserving migration PRs. The split separates backend transport, loader construction, cache handling, metrics, validation, service orchestration, and focused tests into named files. Verification: `just fmt`; `just test -p codex-cloud-config`.
joeflorencio-openai ·
2026-06-02 14:30:12 -07:00 -
core: stop passing legacy SandboxPolicy to guardian reviews (#25911)
## Why Guardian review turns already submit a read-only `PermissionProfile`, which is the permissions model the runtime should honor. Passing the equivalent legacy `SandboxPolicy` through `ThreadSettingsOverrides` keeps two representations of the same read-only constraint alive on this path and makes the guardian flow depend on compatibility plumbing that is being phased out. ## What Changed - Set `sandbox_policy` to `None` when the guardian review session submits its child `Op::UserInput`. - Keep `permission_profile: Some(PermissionProfile::read_only())` and `approval_policy: Some(AskForApproval::Never)`, so the guardian review remains read-only and cannot request approvals. - Remove the now-unused `SandboxPolicy` import and redundant comment from `codex-rs/core/src/guardian/review_session.rs`. ## Verification Not run locally; this is a narrow cleanup of redundant thread-settings override state.
Michael Bolin ·
2026-06-02 14:16:12 -07:00 -
fix: update image generation test helper rename (#25938)
## Summary - update the app-server image generation integration test to use `TestAppServer` - completes the test helper rename from #25701 for this newer test file ## Validation - `cargo fmt -- --config imports_granularity=Item` - `cargo check -p codex-app-server --test all` Note: `just fmt` ran Rust formatting but failed on Python/SDK formatting because the sandbox could not access the local `uv` cache.
joeflorencio-openai ·
2026-06-02 14:11:20 -07:00 -
Switch runtime to cloud config bundle (#24622)
## Summary - Adapts the moved `codex-cloud-config` crate from the legacy cloud requirements endpoint to the new config bundle endpoint. - Switches runtime consumers from `CloudRequirementsLoader` to `CloudConfigBundleLoader` so one shared bundle supplies cloud-delivered config and requirements. - Removes the legacy cloud requirements domain loader path. ## Details This intentionally keeps `codex-cloud-config` monolithic for review lineage: the previous PR establishes the crate move, and this PR shows the behavior change against that moved implementation. A follow-up PR splits the module back into focused files. The new bundle path preserves the important cloud requirements loader semantics where intended: account-scoped signed cache, 30 minute TTL, 5 minute refresh cadence, retry/backoff, auth recovery, and fail-closed startup loading. The cached payload changes from a single requirements TOML string to the backend-delivered bundle, and validation rejects malformed config or requirements fragments before cache write/use.
joeflorencio-openai ·
2026-06-02 13:18:59 -07:00 -
Populate workspace kind on Codex turn events (#25135)
## Summary - carry `workspace_kind` from Responses API client metadata into the turn resolved analytics fact - serialize the optional value on `codex_turn_event` - cover both the turn metadata source and turn event serialization The `workspace_kind` tells us whether a thread had a project attached vs projectless. this is an indicator for who is adopting Codex for knowledge work outside of coding ## Testing - `env UV_CACHE_DIR=/private/tmp/uv-cache /private/tmp/cargo-tools/bin/just fmt` - `env PATH=/private/tmp/cargo-tools/bin:$PATH CARGO_HOME=/private/tmp/cargo-home UV_CACHE_DIR=/private/tmp/uv-cache /private/tmp/cargo-tools/bin/just test -p codex-analytics` - `env PATH=/private/tmp/cargo-tools/bin:$PATH CARGO_HOME=/private/tmp/cargo-home UV_CACHE_DIR=/private/tmp/uv-cache /private/tmp/cargo-tools/bin/just test -p codex-core turn_metadata` Paired with openai/openai#970661, which keeps forwarding the same metadata key through Responses API headers.
knittel-openai ·
2026-06-02 12:46:14 -07:00 -
Fix Windows running thread resume path normalization (#25509)
## Why Fixes #24944. On Windows, app-server resume could reject an active running thread when the requested session path used normal `C:\...` form and the already-running path used verbatim `\\?\C:\...` form. The paths point at the same JSONL file, but the resume stale-path guard compared raw `PathBuf`s, so desktop resume and heartbeat flows could fail with a mismatched-path error. ## What Changed - Compare requested and active rollout paths with `path_utils::paths_match_after_normalization`. - Extend the existing running-thread mismatched-path test with a Windows-only same-file resume case before the stale-path rejection. ## Verification - `just test -p codex-app-server thread_resume_rejects_mismatched_path_for_running_thread_id`
Eric Traut ·
2026-06-02 12:42:42 -07:00 -
Propagate permission approval environment id (#25862)
## Stack 1. #25850 - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. #25858 - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. This PR (#25862) - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. #25867 - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. This PR is stacked on #25858, and #25867 is stacked on this PR. ## Why PR2 lets the model bind a `request_permissions` call to a selected environment, but the approval event and client-facing request still needed to carry that binding. For CCA, the user-facing prompt and delegated approval path should know which environment the grant applies to instead of relying on cwd alone. ## What Changed - Added optional `environmentId` to `RequestPermissionsEvent`. - Emit the selected environment id from core permission approval events. - Preserve the environment id through delegate forwarding, including cwd-based delegated requests. - Added `environmentId` to app-server permission approval params, generated schema/TypeScript artifacts, and README examples. - Preserve and display the environment id in TUI permission approval prompts. - Updated focused core, app-server protocol, and TUI conversion coverage. ## Testing Not run locally per instruction. Performed read-only `git diff --check`.
jif ·
2026-06-02 21:09:34 +02:00 -
Route standalone image generation through host finalization md (#25176)
## Why Standalone image-generation extensions emitted turn items through the low-level event path, bypassing host-owned finalization such as image persistence and contributor processing. At the same time, the generated-image save-path hint must remain visible to the model through the extension tool's `FunctionCallOutput`, rather than the legacy built-in developer-message path. ## What changed - Extended `ExtensionTurnItem` to support image-generation items while keeping the extension-facing emitter API limited to `emit_started` and `emit_completed`. - Routed extension completion through core `finalize_turn_item`, so standalone image-generation items receive host-owned processing and persisted `saved_path` values before publication. - Kept legacy built-in image generation on its existing developer-message hint path, while standalone image generation returns its deterministic saved-path hint in `FunctionCallOutput`. - Shared the image artifact path and output-hint formatting used by core and the image-generation extension. - Passed thread identity through extension tool calls so standalone image generation can construct the same intended artifact path as core. - Added an app-server integration test covering real standalone image generation, saved artifact publication, model-visible output hint wiring, and absence of the legacy developer-message hint. ## Validation - `just fmt` - `just test -p codex-image-generation-extension` - `just test -p codex-web-search-extension` - `just test -p codex-goal-extension` - `just test -p codex-memories-extension` - Targeted `codex-core` tests for image save history, extension completion finalization, and contributor execution - `just test -p codex-app-server standalone_image_generation_returns_saved_path_hint_to_model` - `just fix -p codex-core` - `just fix -p codex-image-generation-extension` - `just bazel-lock-update` - `just bazel-lock-check`
Won Park ·
2026-06-02 12:00:04 -07:00 -
Add environmentId to request_permissions (#25858)
## Stack 1. #25850 - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. This PR (#25858) - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. #25862 - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. #25867 - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. This PR is stacked on #25850; #25862 and #25867 are stacked on this PR. ## Why PR1 made request-permission grants internally environment-keyed, but the model-facing `request_permissions` tool could still only target the primary environment. For CCA and multi-environment turns, the tool needs an explicit way to bind a permission request to a selected attached environment before resolving relative paths. ## What Changed - Added optional `environmentId` to `RequestPermissionsArgs`, with `environment_id` accepted as an alias. - Exposed `environmentId` in the `request_permissions` tool schema and description. - Resolve the selected environment before parsing filesystem permission paths, so relative paths bind to the selected environment cwd. - Route validated tool calls through `request_permissions_for_environment` directly instead of duplicating environment lookup in `Session::request_permissions`. - Reject unknown environment ids with a model-facing error. - Updated focused request-permissions and Guardian call sites for the new optional field. ## Testing Not run locally per instruction.
jif ·
2026-06-02 20:51:25 +02:00 -
[codex-analytics] Track CodexErr details in turn analytics (#25707)
## Summary - add analytics-only `CodexErr` telemetry to `codex_turn_event` while leaving existing `turn_error` unchanged - record terminal `CodexErr` facts from core immediately before the existing turn error event is sent - emit source-truth `codex_error_*` fields for downstream analytics, including the raw `CodexErr::InvalidRequest(String)` message as `codex_error_subreason` ## Validation - `just test -p codex-analytics` - attempted `just test -p codex-core`, but the local run timed out across unrelated integration suites in this environment and is not being used as validation
rhan-oai ·
2026-06-02 11:40:35 -07:00 -
Key request-permission grants by environment (#25850)
## Stack 1. This PR (#25850) - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. #25858 - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. #25862 - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. #25867 - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. #25858, #25862, and #25867 are stacked on this PR and should be reviewed after it. ## Why Multi-environment CCA turns can attach both local and remote executors, but request-permission grants were still effectively cwd-only. Pending permission requests tracked a cwd, while stored turn/session grants had no environment identity, so sticky grants could be reused through the wrong executor context. This makes the first permission-grant step environment-aware without changing the external `request_permissions` payload shape: omitted environment targeting remains bound to the primary turn environment. ## What Changed - Store turn- and session-scoped request-permission grants by `environment_id`. - Keep the selected `TurnEnvironmentSelection` with pending `request_permissions` calls so approval responses normalize and record grants against the same environment. - Resolve relative `request_permissions` file paths against the primary turn environment cwd instead of deprecated `turn.cwd`. - Apply sticky grants in `shell`, `exec_command`, and `apply_patch` by selected environment id while still using the actual tool cwd for cwd-relative permission materialization. - Update Guardian and request-permissions coverage for the environment-keyed grant behavior. ## Testing Not run locally. Added or updated focused coverage for: - `request_permission_grants_are_environment_keyed` - `request_permissions_tool_resolves_relative_paths_against_primary_environment` - related Guardian/request-permissions sticky grant tests
jif ·
2026-06-02 20:16:57 +02:00 -
[codex] Revert shared BuildBuddy Bazel wrapper (#25909)
## Why PR #25905 intentionally adds a failing `codex-core` unit test, but its [Bazel test on Windows check](https://github.com/openai/codex/actions/runs/26837526950/job/79135369259) passed. That shows the Bazel configuration introduced by #25156 is not behaving as expected, so revert it while the configuration can be investigated separately. ## What changed Revert #25156 in full, restoring the previous Bazel remote configuration, CI scripts, workflows, `rusty_v8` handling, and documentation. This removes the shared BuildBuddy wrapper and its tests. ## Validation Not run locally; this exact revert was prioritized for a fast rollback.
Adam Perry @ OpenAI ·
2026-06-02 11:06:01 -07:00 -
core: derive built-in permission profiles from raw policies (#25739)
## Why Permission profiles that extend a built-in profile should behave like other TOML inheritance: parent entries provide defaults, and child keys override matching fields before the profile is compiled. That was not true for `:workspace`. Previously, a profile with `extends = ":workspace"` seeded the compiled runtime `PermissionProfile::workspace_write()` policy and then appended child filesystem entries. A child override such as `":tmpdir" = "read"` therefore left the inherited `":tmpdir" = "write"` entry in the final policy. Since same-target `write` wins over `read` during runtime resolution, the child override was ineffective. This also needs a clear source of truth for the built-in profiles. The protocol-level sandbox policy constructors now define the raw built-in filesystem entries, and both `PermissionProfile` presets and config-profile inheritance derive from those same values. ## What Changed - Add a canonical `FileSystemSandboxPolicy::read_only()` constructor while keeping the read-only and workspace-write raw filesystem entries explicit and independent. - Derive `PermissionProfile::read_only()` from `FileSystemSandboxPolicy::read_only()`; `PermissionProfile::workspace_write()` continues to derive from `FileSystemSandboxPolicy::workspace_write()`. - Build extensible `:read-only` and `:workspace` parent profiles by projecting those canonical sandbox policies into `PermissionProfileToml`, then merge user overrides at the TOML layer before compilation. - Add config parsing support for `:slash_tmp` so the built-in `:workspace` parent can be expressed in the same TOML-shaped filesystem table as user profiles. - Document that `PermissionsToml::resolve_profile()` returns an already-merged `PermissionProfileToml`, and return that profile directly after removing the resolved-profile wrapper. - Extend the config test for `extends = ":workspace"` to assert that inherited `":slash_tmp" = "write"` is preserved and that a child `":tmpdir" = "read"` entry replaces the inherited `write` entry. ## Verification - `just test -p codex-config` - `just test -p codex-protocol` - `just test -p codex-core permissions_profiles_resolve_extends_parent_first_with_child_overrides` - `just test -p codex-core default_permissions_profile_can_extend_builtin_workspace` - `just test -p codex-core` - Result: 2596 passed, 4 failed, 1 timed out. - The failures were existing sandbox/environment-sensitive tests unrelated to this permissions change: `suite::user_shell_cmd::user_shell_command_does_not_set_network_sandbox_env_var`, `suite::user_shell_cmd::user_shell_command_history_is_persisted_and_shared_with_model`, `suite::abort_tasks::interrupt_persists_turn_aborted_marker_in_next_request`, `suite::abort_tasks::interrupt_tool_records_history_entries`, and `thread_manager::tests::start_thread_uses_all_default_environments_from_codex_home`.Michael Bolin ·
2026-06-02 10:57:35 -07:00 -
Route Bazel CI through shared BuildBuddy remote config wrapper (#25156)
## Why Bazel remote configuration was selected in several CI scripts and workflow steps. That made the BuildBuddy tenant policy easy to duplicate and harder to audit, especially for fork pull requests that must not use the OpenAI tenant. This builds on [sluongng/buildbuddy-ci-host-routing](https://github.com/openai/codex/compare/main...sluongng:codex:sluongng/buildbuddy-ci-host-routing) and consolidates the policy in one place. ## What to do if this breaks you See `codex-rs/docs/bazel.md` for details. TLDR: 1. make a BuildBuddy API key and put it in `~/.bazelrc` 2. if you're an OpenAI employee, add `common --config=buildbuddy-openai-rbe` to `user.bazelrc` in the repo root Run `just bazel-test` to ensure it works. Note that `just bazel-remote-test` no longer exists, you need to select a remote configuration as documented to use RBE. ## What changed - Add `.github/scripts/run_bazel_with_buildbuddy.py` as the shared Bazel wrapper and Python library. It selects the OpenAI host only for trusted upstream GitHub Actions runs, routes keyed fork runs to the generic host, and falls back to local Bazel execution when no key is available. - Move endpoint selection into explicit `.bazelrc` configurations and update Bazel CI, query helpers, and `rusty_v8` staging to use the shared policy. Loading-phase target-discovery queries remain local. - Add wrapper and `rusty_v8` unit coverage, plus `just test-scripts` for the `.github/scripts` Python tests. - Document local Bazel usage, `user.bazelrc` setup, BuildBuddy configurations, and CI behavior in `codex-rs/docs/bazel.md`. ## Validation - `just test-scripts` - `bash -n .github/scripts/run-bazel-ci.sh .github/scripts/run-bazel-query-ci.sh .github/scripts/run-argument-comment-lint-bazel.sh scripts/list-bazel-clippy-targets.sh` - `python3 -m py_compile .github/scripts/run_bazel_with_buildbuddy.py .github/scripts/test_run_bazel_with_buildbuddy.py .github/scripts/test_rusty_v8_bazel.py .github/scripts/rusty_v8_bazel.py` - `ruff check .github/scripts/run_bazel_with_buildbuddy.py .github/scripts/test_run_bazel_with_buildbuddy.py .github/scripts/test_rusty_v8_bazel.py .github/scripts/rusty_v8_bazel.py`
Adam Perry @ OpenAI ·
2026-06-02 09:56:20 -07:00 -
Skip startup prewarm when websockets are disabled (#25868)
## Summary - skip startup websocket prewarm setup when the model client has Responses-over-WebSocket disabled - avoid making HTTP-only sessions build prewarm prompt/tool state that cannot produce a reusable websocket session ## Why Recent macOS timing flakes were timing out while waiting for first-turn events in HTTP-only core tests. Startup prewarm is only useful for websocket-capable providers, but it was scheduled for every session. For HTTP-only test providers this added unnecessary async startup work before the regular turn could reach the mocked response flow. ## Testing - bazel test //codex-rs/core:core-all-test --test_filter=suite::auto_review::remote_model_override_uses_catalog_model_for_strict_auto_review --test_output=errors - bazel test //codex-rs/core:core-all-test --test_filter=suite::request_permissions_tool::approved_folder_write_request_permissions_unblocks_later_apply_patch --test_output=errors
jif ·
2026-06-02 17:27:30 +02:00 -
[app-server][core] Add connector-level Guardian reviewer overrides (#25167)
Context: https://openai.slack.com/archives/C0B4JAF0Q2C/p1779912328647229 ``` approvals_reviewer = "auto_review" [apps.connector_5f3c8c41a1e54ad7a76272c89e2554fa] enabled = true approvals_reviewer = "user" default_tools_approval_mode = "prompt" ``` <img width="230" height="84" alt="Screenshot 2026-05-31 at 11 56 34 AM" src="https://github.com/user-attachments/assets/e319f8f7-0983-42a7-98cd-3302732fa406" /> <img width="841" height="233" alt="Screenshot 2026-05-31 at 11 52 42 AM" src="https://github.com/user-attachments/assets/7ac76645-4e90-4d00-8242-f031146a22a5" /> ------- ``` approvals_reviewer = "user" [apps.connector_5f3c8c41a1e54ad7a76272c89e2554fa] enabled = true approvals_reviewer = "auto_review" default_tools_approval_mode = "prompt" ``` <img width="195" height="83" alt="Screenshot 2026-05-31 at 12 02 27 PM" src="https://github.com/user-attachments/assets/3d374dc8-8aa2-466f-a13f-e4ed8567aa2e" /> <img width="771" height="207" alt="Screenshot 2026-05-31 at 12 05 42 PM" src="https://github.com/user-attachments/assets/105c2575-68d6-4ca6-8e69-dc8c82da36a2" /> ## Summary - add `apps.<connector_id>.approvals_reviewer` to override Guardian or user review routing per connected app - apply overrides across direct app MCP calls, delegated MCP prompts, and app-server MCP elicitation review while preserving global behavior for non-app MCP servers - expose and document the config through app-server v2 and generated schemas, while honoring global managed reviewer requirements --------- Co-authored-by: jif-oai <jif@openai.com>
Alex Zamoshchin ·
2026-06-02 17:04:11 +02:00 -
Run Codex async main on a sized stack (#25847)
## Why `Runtime::block_on` executes the top-level future on the caller's OS thread, not on one of Tokio's worker threads. That matters for the interactive CLI because the Tokio runtime already configures larger worker stacks, while the process main thread can still have a smaller platform default stack. This showed up as a `/clear` crash on macOS: starting a fresh TUI thread reloads config, and the stack-heavy TOML deserialization path can overflow before the new session is actually started. ## What Changed - Run the regular `arg0_dispatch_or_else` async entrypoint on a named `codex-main` thread. - Give that thread the same `TOKIO_WORKER_STACK_SIZE_BYTES` stack budget already used for Tokio worker threads. - Keep `Arg0DispatchPaths` and the arg0 alias guard lifetime behavior the same. - Resume panics from the spawned main thread so panic behavior is preserved. ## Verification - `cargo check -p codex-cli` currently fails because the top-level CLI/TUI future is not `Send` under the new thread boundary.
jif ·
2026-06-02 16:34:48 +02:00 -
flake: Keep plugin test homes alive (#25857)
## Summary Keep the full `TestCodex` harness alive in plugin integration tests instead of returning only the `CodexThread`. ## Why The helper was moving a temporary `codex_home` into `TestCodex`, then immediately dropping the harness and returning only the thread. For plugin MCP tests, the MCP server cwd is inside that temporary home. If the temp directory is removed while MCP startup is still racing, the server launch can fail with `No such file or directory`. Keeping the harness in scope keeps the temp home alive for the test duration and removes the lifetime race behind the recent `explicit_plugin_mentions_inject_plugin_guidance` flake. ## Validation - `just fmt` - `just test -p codex-core explicit_plugin_mentions_inject_plugin_guidance`
jif ·
2026-06-02 16:21:22 +02:00 -
Reduce stack pressure in session startup and config rebuilds (#25844)
## Why `/clear` starts a fresh thread with `InitialHistory::Cleared`, which re-enters the thread/session startup path. That path now builds large async futures through `ThreadManagerState::spawn_thread_with_source`, `Codex::spawn`, and `Session::new`. Separately, TUI config rebuilds for cwd and permission-profile changes build a similarly heavy `ConfigBuilder::build()` future inside the app task. In debug and Bazel runs, those call chains can put enough state on the caller stack to abort before startup or config refresh completes. This change keeps the behavior the same while moving the heaviest future frames off the caller stack. ## What changed - Box `Codex::spawn(...)` in `codex-rs/core/src/thread_manager.rs` before awaiting it from `spawn_thread_with_source`. - Box `Session::new(...)` in `codex-rs/core/src/session/mod.rs` before awaiting it from `Codex::spawn_internal`. - Route `ConfigBuilder::build()` through a small `tokio::spawn` helper in `codex-rs/tui/src/app/config_persistence.rs` so cwd and permission-profile config rebuilds run on a runtime worker stack while preserving error context. ## Verification CI is running on the PR. No new targeted tests were added. This is a mechanical stack-pressure reduction that keeps the existing behavior and error propagation intact.
jif-oai ·
2026-06-02 15:42:47 +02:00 -
Test runtime selector before first turn (#25724)
Stack split from #25708. Original PR intentionally left open. This fifth PR adds coverage that a remotely selected multi-agent runtime is applied when the model is selected before the first turn.
jif-oai ·
2026-06-02 15:01:10 +02:00 -
Test remote multi-agent runtime selector override (#25723)
Stack split from #25708. Original PR intentionally left open. This fourth PR adds coverage that remote model multi-agent runtime selectors override local feature flag defaults.
jif-oai ·
2026-06-02 14:48:13 +02:00 -
fix: main oops (#25840)
Fix main, comment is self-explainatory
jif-oai ·
2026-06-02 14:48:04 +02:00 -
session: keep startup prewarm aligned with resolved multi-agent runtime (#25841)
## Why Follow-up to #25722. Startup prewarm builds a preview `TurnContext` before the first real turn so it can precompute the initial prompt and tool surface. After the per-thread runtime work landed, that preview path still recomputed multi-agent mode from `model_info` and feature defaults instead of reusing the runtime the session had already resolved from persisted metadata or inheritance. That could leave the prewarmed session primed for a different multi-agent mode than the first real turn, which is especially risky because collaboration tool exposure depends on `turn_context.multi_agent_version`. ## What changed - In the `TurnMultiAgentRuntime::Preview` path, prefer `Session::multi_agent_version()` when it is already known. - Only fall back to `model_info.multi_agent_version` and feature defaults when the session has not resolved a runtime yet. - Keep preview mode read-only: this still avoids storing a runtime during startup prewarm. ## Testing - Not run (small runtime-selection follow-up)
jif-oai ·
2026-06-02 14:35:26 +02:00 -
Resolve per-thread multi-agent runtime (#25722)
Stack split from #25708. Original PR intentionally left open. This third PR resolves the effective per-thread multi-agent runtime from persisted metadata, inherited runtime, and current model selection.
jif-oai ·
2026-06-02 14:31:00 +02:00 -
Persist multi-agent runtime metadata (#25721)
Stack split from #25708. Original PR intentionally left open. This second PR persists multi-agent runtime metadata through thread creation, rollout recording, and thread storage.
jif-oai ·
2026-06-02 13:05:20 +02:00 -
Add multi-agent runtime metadata types (#25720)
Stack split from #25708. Original PR intentionally left open. This first PR adds the multi-agent runtime metadata types and catalog plumbing used by the rest of the stack.
jif-oai ·
2026-06-02 12:10:14 +02:00 -
feat: reuse compressed rollout search snippets (#25814)
## Summary - teach rollout search to return precomputed snippets for compressed rollouts - reuse those snippets in local thread search instead of reopening matching compressed files - keep the no-`rg` fallback single-pass and add regression coverage for the compressed path ## Why `thread/search` currently decodes matching compressed rollouts twice: once to discover the matching path and again to extract the snippet shown in results. That defeats a meaningful part of the compressed-read optimization work. ## Impact Compressed rollout hits now pay one decode pass on the search path while plain `.jsonl` hits keep the existing ripgrep-driven flow. ## Validation - `just test -p codex-rollout` - `just test -p codex-thread-store` - `just fix -p codex-rollout` - `just fix -p codex-thread-store` - `just fmt`
jif-oai ·
2026-06-02 11:32:36 +02:00 -
[codex] Validate plugin skill base names (#25782)
## Summary - Validate skill base name length before plugin namespacing. - Bound the composed `plugin:skill` qualified name to 128 characters. - Keep plugin skill runtime names in the existing `plugin:skill` form. - Add regression tests for the max qualified-name boundary and rejection path. ## Root Cause Plugin skills are represented as `plugin_name:skill_name`, but the loader previously applied the 64-character skill name limit after adding the plugin namespace. Moving that check to the base name fixes valid plugin skills with longer namespaces, and the separate 128-character qualified-name limit keeps model-visible skill names bounded. ## Validation - `just fmt` - `just test -p codex-core-skills plugin_skill_name_length_limit` - `git diff --check`
xl-openai ·
2026-06-02 06:33:02 +00:00 -
[codex] Move plugin discoverable logic into core-plugins (#25783)
## Summary - Move plugin discoverable recommendation filtering from `codex-core` into `codex-core-plugins` behind `ToolSuggestPluginDiscoveryInput`. - Keep `codex-core` as a thin adapter from `Config` to the core-plugins API and back to `DiscoverablePluginInfo`. - Keep the existing discoverable allowlist private to the core-plugins implementation. ## Validation - `just fmt` - `just test -p codex-core list_tool_suggest_discoverable_plugins` - `git diff --check` - Read-only subagent review: no findings
xl-openai ·
2026-06-01 23:25:37 -07:00 -
[codex] Cache remote plugin catalog for suggestions (#25457)
## Summary - cache the global remote plugin catalog when remote plugin listing runs and warm it during startup - use the cached remote catalog in plugin install recommendations with canonical `plugin@openai-curated-remote` ids - reuse the session `PluginsManager` for plugin recommendations so remote cache state is visible on the recommend path - skip core installed-state verification for remote plugin install suggestions while leaving local plugin and connector verification unchanged ## Testing - `just fmt` - `git diff --check` - `cargo test -p codex-core list_tool_suggest_discoverable_plugins_includes_cached_remote_global_plugins` - `cargo test -p codex-core remote_plugin_install_suggestions_skip_core_installed_verification` - `cargo test -p codex-app-server plugin_list_includes_remote_marketplaces_when_remote_plugin_enabled` Earlier focused checks during the same branch: codex-tools TUI filter test, request_plugin_install tests, and codex-app-server build.
xl-openai ·
2026-06-01 22:10:52 -07:00 -
[codex] Add plugin list JSON output (#25330)
## Summary - add `--json` output to `codex plugin list` with `installed` and `available` arrays - add `--available` for JSON output only; using it without `--json` is rejected - keep the existing non-JSON table output unchanged - add CLI coverage for JSON installed/available output and the `--available`/`--json` requirement ## Validation - `just test -p codex-cli plugin_list` - `just fix -p codex-cli` - `git diff --check` Note: `just fmt` ran Rust formatting first, then failed in the Python ruff step because `openai-codex-cli-bin==0.132.0` has no wheel for this Linux platform.
xl-openai ·
2026-06-01 21:27:06 -07:00 -
feat: show enterprise monthly credit limits in status (#24812)
## Summary Enterprise users can have an effective monthly credit limit, but Codex `/status` currently drops that metadata from the account-usage response. This change adds the optional `spend_control.individual_limit` projection to the existing rate-limit snapshot flow. The backend client reads the monthly limit, app-server exposes it as `individualLimit`, and the TUI renders a `Monthly credit limit` row through the existing progress-bar renderer. When the backend does not return an effective monthly limit, existing rate-limit behavior is unchanged. ## Existing backend state The account-usage backend already returns the effective monthly limit and current usage together: ```json { "spend_control": { "reached": false, "individual_limit": { "limit": "25000", "used": "8000", "remaining": "17000", "used_percent": 32, "remaining_percent": 68, "reset_after_seconds": 86400, "reset_at": 1778137680 } } } ``` Before this change, Codex projected rolling `primary` and `secondary` windows plus `credits`. It ignored `spend_control.individual_limit`, so app-server clients and `/status` could not render the monthly cap. The updated flow is: ```text account usage backend -> backend-client reads spend_control.individual_limit -> existing rate-limit snapshot carries optional individual_limit -> app-server exposes optional individualLimit -> TUI renders Monthly credit limit ``` ## App-server contract `account/rateLimits/read` and sparse `account/rateLimits/updated` notifications now include an additive nullable `rateLimits.individualLimit` field: ```json { "individualLimit": { "limit": "25000", "used": "8000", "remainingPercent": 68, "resetsAt": 1778137680 } } ``` In an `account/rateLimits/read` response, `null` means no monthly limit is available. `account/rateLimits/updated` remains a sparse rolling notification: clients merge available values into their most recent `account/rateLimits/read` snapshot or refetch. Nullable account metadata in a rolling notification does not clear a previously observed value. ## Design decisions - Extend the existing rate-limit snapshot instead of introducing a separate request or wire-level update protocol. - Keep the Codex projection narrow: `/status` needs the effective limit, current usage, remaining percentage, and reset timestamp. - Render the monthly row through the existing progress-bar renderer, with one optional detail line for `8,000 of 25,000 credits used`. - Keep the backend response optional so existing accounts and older usage states preserve their current behavior. - Preserve cached monthly metadata when sparse rolling notifications omit it. Live account-usage reads remain authoritative and can clear a removed limit. ## Visual evidence ```text Monthly credit limit: [██████████████░░░░░░] 68% left (resets 07:08 on 7 May) 8,000 of 25,000 credits used ``` Snapshot: `codex-rs/tui/src/status/snapshots/codex_tui__status__tests__status_snapshot_includes_enterprise_monthly_credit_limit.snap` ## Testing Tests: generated app-server schema verification, protocol tests, backend-client tests, app-server integration coverage, TUI snapshot coverage, formatting, and workspace lint cleanup.efrazer-oai ·
2026-06-01 21:25:42 -07:00 -
feat(remote-control): add pairing start (#25675)
## Why Remote control enrollment authorizes a desktop server, but app-server v2 did not expose the follow-up pairing operation needed to mint a short-lived controller pairing artifact from that enrolled server. Clients need a narrow RPC that starts pairing without exposing the backend `serverId` or conflating pairing with websocket connection state. Issue: N/A; internal remote-control pairing API change. ## What Changed Added experimental app-server v2 `remoteControl/pairing/start` with `manualCode` input and `pairingCode`, nullable `manualPairingCode`, `environmentId`, and Unix-seconds `expiresAt` output. The method serializes under its own `global("remote-control-pairing")` scope and is documented in `app-server/README.md`. Extended the remote-control transport with private `/server/pair` request/response types and normalized `pair_url` handling. Pairing uses the current enrolled server bearer, refreshes that bearer when needed, keeps backend `server_id` private, validates returned `server_id` and `environment_id` against the current enrollment, and preserves backend status/header/body context for failures and malformed responses. Wired the request through `RemoteControlRequestProcessor` and `MessageProcessor`, mapping unavailable/disabled pairing to `invalid_request` and backend failures to internal errors. ## Verification - `just test -p codex-app-server-transport` - `just test -p codex-app-server remote_control_pairing_start_returns_pairing_artifacts`Anton Panasenko ·
2026-06-02 01:05:50 +00:00 -
Handle invalid plugin skills manifest field (#25717)
## Summary - Treat invalid `plugin.json` `skills` shapes as a field-level warning instead of rejecting the whole manifest - Keep valid string path behavior unchanged and continue falling back to the default `skills/` root - Add regression coverage for array-shaped `skills` ## Tests - `just fmt` - `cargo test -p codex-core-plugins`
xli-oai ·
2026-06-01 17:19:34 -07:00 -
Move cloud requirements crate to cloud config (#24621)
## Summary - Moves the existing `codex-cloud-requirements` crate to `codex-cloud-config`. - Updates workspace dependencies and imports to the new crate name. - Intentionally keeps runtime behavior unchanged: this still fetches the legacy cloud requirements endpoint. ## Details This PR exists to make the lineage obvious before the bundle migration. GitHub should show the old `codex-rs/cloud-requirements/src/lib.rs` implementation as moved to `codex-rs/cloud-config/src/lib.rs`, rather than as unrelated new code. The follow-up PR adapts this moved crate to the new config bundle API and switches runtime consumers over.
joeflorencio-openai ·
2026-06-01 16:43:52 -07:00 -
app-server: remove experimental persist_extended_history bool flag (#25712)
## Summary Remove the dead experimental `persistExtendedHistory` app-server flag and collapse rollout persistence to the single policy app-server already used. ## What Changed - Removed `persistExtendedHistory` from v2 thread start/resume/fork params and deleted its deprecation notice path. - Removed the persistence-mode enums and plumbing through core, rollout, and thread-store. - Made rollout filtering mode-free, keeping the existing limited persisted-history behavior. ## Test Plan - `just write-app-server-schema` - `cargo nextest run --no-fail-fast -p codex-app-server-protocol schema_fixtures` - `cargo nextest run --no-fail-fast -p codex-app-server thread_shell_command_history_responses_exclude_persisted_command_executions` - `cargo nextest run --no-fail-fast -p codex-rollout -p codex-thread-store` - final `rg` for removed flag/type names
Owen Lin ·
2026-06-01 23:33:42 +00:00 -
Wire managed MITM CA trust into child env (#22668)
## Stack 1. Parent PR: #18240 uses named MITM permissions config. 2. This PR wires managed MITM CA trust into spawned child processes. ## Why When Codex terminates HTTPS for limited mode or MITM hooks, child HTTPS clients need to trust Codex's managed MITM CA. Exporting proxy URLs alone is not enough, but blindly replacing user CA settings would be wrong: it can break custom enterprise/test roots, leak unreadable CA files into generated bundles, or make the child env disagree with its sandbox policy. ## Summary 1. Build immutable managed CA bundles under `$CODEX_HOME/proxy` that include native roots, the managed MITM CA, and only inherited or command-scoped CA bundles the child is allowed to read. 2. Export curated CA env vars alongside managed proxy env vars while preserving user CA override semantics, including nested Codex `SSL_CERT_FILE` precedence. 3. Thread generated CA bundle paths into child sandbox readable roots, including debug sandbox execution, so the exported env vars work inside sandboxed commands. 4. Remove only Codex-generated MITM CA bundle env when a child intentionally drops managed proxying for escalation or no-proxy retry. 5. Document the managed CA bundle behavior and cover env injection, per-child bundle generation, sandbox readable roots, and no-proxy cleanup in tests. ## Validation 1. Ran `just test -p codex-network-proxy`. 2. Ran `just test -p codex-protocol`. 3. Ran `just fix -p codex-network-proxy -p codex-protocol`. 4. Tried focused `codex-core` validation, but the crate currently fails to compile in `core/tests/suite/guardian_review.rs` because an existing `Op::UserInput` initializer is missing `additional_context`. --------- Co-authored-by: Eva Wong <evawong@openai.com>
Winston Howes ·
2026-06-01 23:23:59 +00:00 -
Reject directory rollout paths for pathless side chats (#25661)
## Why Fixes openai/codex#20944. Desktop side chats are intentionally ephemeral and pathless. They can still accept live turns while loaded, but after a reload there is no persisted rollout to resume. In the reported failure mode, Desktop could send `$CODEX_HOME` as the resume/fork path for one of these pathless side chats. `thread/resume` and `thread/fork` prefer an explicit `path` over `threadId`, and rollout path lookup only checked that a candidate existed. That let `$CODEX_HOME` pass as a rollout path, so the later rollout reader tried to open a directory and surfaced the low-level `Is a directory` error. ## What Changed - Reject explicit rollout paths that resolve to a directory or other non-file before attempting to read rollout history. - Make `codex_rollout::existing_rollout_path` return only plain or compressed rollout candidates that are actual files. - Add an app-server regression test that creates an ephemeral fork, runs a turn while the side thread is loaded, simulates reload, then verifies both `thread/resume` and `thread/fork` reject `$CODEX_HOME` with `path is a directory` instead of the OS-level directory-read error. - Rebase over the `TestAppServer` rename and update the remaining stale test harness call sites to use `TestAppServer` with `app_server` local variables. Relevant code: - `thread-store/src/local/read_thread.rs` validates explicit rollout paths before rollout reading: https://github.com/openai/codex/blob/25b47c8f425d351aaba4baa955a8092064a1707b/codex-rs/thread-store/src/local/read_thread.rs#L146-L165 - `rollout/src/compression.rs` now requires file metadata for plain and compressed rollout candidates: https://github.com/openai/codex/blob/25b47c8f425d351aaba4baa955a8092064a1707b/codex-rs/rollout/src/compression.rs#L940-L950 - The repro test covers the pathless ephemeral side-chat reload case: https://github.com/openai/codex/blob/25b47c8f425d351aaba4baa955a8092064a1707b/codex-rs/app-server/tests/suite/v2/thread_fork.rs#L774-L886 ## Verification - `just test -p codex-app-server pathless_ephemeral_thread_rejects_codex_home_path_after_reload`
Michael Bolin ·
2026-06-01 16:02:06 -07:00 -
fix(tui): clarify footer shortcut overlay hints (#25625)
## Why The TUI shortcut overlay used static labels for `Tab` and `Ctrl+C`, even though both keys change behavior while a task is running. That made the visible help misleading: idle `Tab` submits rather than queues, and active-turn `Ctrl+C` interrupts rather than exits. Closes #25531. Closes #25564. ## What Changed - Pass task-running state into the shortcut overlay renderer. - Render `Tab` as `submit message` while idle and `queue message` while work is running. - Render `Ctrl+C` as `exit` while idle and `interrupt` while work is running. - Add snapshot coverage for the active-work shortcut overlay and update idle overlay snapshots. ## How to Test 1. Start Codex and open the shortcut overlay with `?` while no task is running. 2. Confirm the overlay shows `tab to submit message` and `ctrl + c to exit`. 3. Start a task, then open or keep the shortcut overlay visible while work is running. 4. Confirm the overlay shows `tab to queue message` and `ctrl + c to interrupt`. 5. Type a follow-up prompt during active work and press `Tab`; confirm it queues rather than submitting immediately. Targeted tests: - `just test -p codex-tui footer_snapshots` - `just test -p codex-tui footer_mode_snapshots` ## Validation Notes `just test -p codex-tui` currently has two unrelated guardian feature-flag test failures on this base: - `app::tests::update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history` - `app::tests::update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default` `just argument-comment-lint codex-rs/tui/src/bottom_pane/footer.rs` could not run locally because the prebuilt wrapper requires `dotslash`; the touched Rust diff was manually inspected for opaque positional literals.
Felipe Coury ·
2026-06-01 19:41:22 -03:00 -
Move tool search metadata onto ToolExecutor (#25684)
Deferred tools need to be searchable even when they are not implemented inside `codex-core`. Extension-provided tools can be registered for later discovery, but the search metadata path was still owned by core-specific runtime hooks, which meant the shared `ToolExecutor` abstraction could not describe how a deferred extension tool should appear in `tool_search`. ## Changes - Move `ToolSearchEntry` and `ToolSearchInfo` into `codex-tools` and re-export them from the shared tools crate. - Add a default `ToolExecutor::search_info` implementation that derives loadable tool-search metadata from function and namespace specs. - Forward search metadata through extension adapters and exposure overrides while keeping custom search text/source metadata for dynamic, MCP, and multi-agent tools. - Remove the old core-local `tool_search_entry` module now that search metadata lives with the shared executor APIs. ## Testing - Added `deferred_extension_tools_are_discoverable_with_tool_search` coverage in `core/src/tools/spec_plan_tests.rs`.
jif-oai ·
2026-06-02 00:24:41 +02:00 -
Fix stale TestAppServer rename in plugin_list test (#25705)
## Why #25701 renamed the app-server test harness to `TestAppServer`, but it raced with #25681, which added a new `plugin_list` test call site still using the old `McpProcess` name. Once both changes met on `main`, app-server test builds failed before running the suite because `McpProcess` no longer exists in that scope. This PR fixes that CI break by updating the remaining stale call site to the renamed helper. ## What Changed - Replaced the `McpProcess::new(...)` use in `codex-rs/app-server/tests/suite/v2/plugin_list.rs` with `TestAppServer::new(...)`. - Renamed the local variable from `mcp` to `app_server` at the same call site to match the helper rename. Relevant code: https://github.com/openai/codex/blob/aadd9c999b4e0789f7afb2b9b8cc43000bb47e86/codex-rs/app-server/tests/suite/v2/plugin_list.rs#L234-L246 ## Verification Not run locally; this is a compile fix for the app-server test harness rename.
Michael Bolin ·
2026-06-01 15:14:03 -07:00 -
[codex] enable parallel standalone web search calls (#25702)
## Summary - opt the extension-backed standalone `web.run` tool into parallel tool execution - update the existing extension registration test to assert that the tool advertises parallel-call support ## Why The standalone web-search API endpoint now supports parallel requests. The extension executor still inherited the shared serial default, causing multiple `web.run` calls to acquire the exclusive runtime lock. ## Impact Models that emit multiple standalone web-search calls can now execute them concurrently when model-level parallel tool calls are enabled. ## Validation - `just fmt` - `just test -p codex-web-search-extension` - `git diff --check origin/main...HEAD`
sayan-oai ·
2026-06-01 15:04:11 -07:00 -
fix: rename McpServer to TestAppServer (#25701)
This PR brought to you via VS Code rather than Codex... - opened `codex-rs/app-server/tests/common/mcp_process.rs` - put the cursor on `McpServer` - hit `F2` and renamed the symbol to `TestAppServer` - went to the file tree - hit enter and renamed `mcp_process.rs` to `test_app_server.rs` - ran **Save All Files** from the Command Palette - ran `just fmt` The End (Admittedly, most of the local variables for `TestAppServer` are still named `mcp`, though.)
Michael Bolin ·
2026-06-01 21:49:38 +00:00 -
fix: Deduplicate installed local and remote curated plugins (#25681)
## Summary - Deduplicate installed `openai-curated` and `openai-curated-remote` plugin conflicts by feature flag. - Prefer remote when remote plugins are enabled; otherwise prefer local, while preserving one-sided installs. ## Testing - `just fmt` - `git diff --check` - Targeted `just test` was blocked locally because `cargo-nextest` is not installed.
xl-openai ·
2026-06-01 14:27:18 -07:00 -
[codex] Generalize deferred nested tool guidance (#25689)
## Summary - describe omitted code-mode tools as deferred nested tools instead of MCP/app tools - update the prompt-description assertion to match ## Why Deferred dynamic tools are also callable through `tools` and discoverable in `ALL_TOOLS`, so the previous MCP/app-specific wording was too narrow. ## Validation - `just fmt` - `just test -p codex-code-mode` - `git diff --check`
sayan-oai ·
2026-06-01 21:01:30 +00:00