mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
2cf2a6a844f1fc2ddd489c8a67fa8bc2f59a6f3d
905 Commits
-
Prepare managed network sandbox context (#29456)
## Why Managed network configures commands to use local HTTP and SOCKS proxies. For commands delegated to the exec server, the proxy environment and the sandbox policy were prepared separately. On macOS, that meant a command could receive `HTTPS_PROXY=http://127.0.0.1:43123` while Seatbelt still denied access to port `43123`. ## What changed `NetworkProxy` now prepares the command environment and sandbox context together from the same runtime snapshot: ```text Prepared managed network ├── command environment: HTTPS_PROXY=http://127.0.0.1:43123 └── sandbox context: allow outbound to 127.0.0.1:43123 ``` That context travels with remote exec requests. The exec server preserves the managed proxy and CA environment, and macOS Seatbelt allows only the prepared loopback proxy ports without enabling broad network access or local binding. The protocol field is optional and the existing enforcement flag remains in place, preserving compatibility with callers that do not send the new context.
jif ·
2026-06-23 20:07:09 +01:00 -
[codex] Instrument rollout persistence bytes (#29498)
- Add 1%-sampled rollout persistence metrics that report per-item and per-thread JSON byte totals before and after filtering when metrics export is enabled. - Tag each item with its exact response or event variant, including nested turn-item kinds for conditionally persisted completion events, so aggregate cloud-storage impact can be estimated by policy choice.
Tom ·
2026-06-23 09:26:30 -07:00 -
Update rmcp to 1.8.0 (#29634)
## Summary - Update `rmcp` and `rmcp-macros` from 1.7.0 to 1.8.0. - Adapt to the new shared `peer_info` return type. - Box OAuth status discovery at the MCP boundary to keep the expanded future type from overflowing Rust's trait recursion limit. This brings in custom OAuth HTTP client support from [modelcontextprotocol/rust-sdk#908](https://github.com/modelcontextprotocol/rust-sdk/pull/908).
jif ·
2026-06-23 15:25:28 +01:00 -
PAC 4 - Add macOS system proxy resolver (#26709)
## Summary Stacked on #26708. Adds the macOS implementation of the shared system-proxy contract. This allows Codex-owned auth clients to use the route macOS selects for each auth URL through SystemConfiguration and CFNetwork, including PAC and WPAD results. The `respect_system_proxy` feature is disabled by default, so existing client behavior remains unchanged unless explicitly enabled. ## Implementation - Adds the macOS-only `system-configuration` dependency to `codex-client`. - Dispatches system-proxy resolution to `outbound_proxy/macos.rs` on macOS. - Reads system proxy settings from `SCDynamicStore` and resolves the target URL with `CFNetworkCopyProxiesForURL`. - Executes PAC URLs and inline PAC JavaScript through a bounded run loop with a five-second timeout. - Handles `DIRECT`, HTTP proxies, and CFNetwork HTTPS entries using HTTP CONNECT; unsupported SOCKS entries map to `UnsupportedProxyScheme`. - Builds concrete proxy URLs from host and port entries, including IPv6 host bracketing. - Maps results into the shared `SystemProxyDecision::{Direct, Proxy, Unavailable}` contract. - Hashes URL-specific cache keys so PAC decisions remain distinct without retaining raw request URLs or query strings. ## End-user behavior - Disabled/default: existing client behavior is unchanged. - Enabled with `[features.respect_system_proxy]`: - macOS auth clients honor system proxy configuration, PAC, and WPAD; - valid OS/PAC `DIRECT` decisions use a direct connection; - unavailable system resolution falls back to explicit environment proxy variables, then `DIRECT`, through the shared contract from #26707. - Unsupported proxy schemes are not silently translated into another route. - Custom CA handling remains separate from proxy selection. - Known limitation: only the first supported system/PAC candidate is used. Subsequent proxy or `DIRECT` candidates are not attempted after a connection failure. This matches the current Windows behavior and leaves room for future ordered-fallback support. ## Tests - `just test -p codex-client` — 34 tests passed. - `just clippy -p codex-client` - `just fmt` - `just bazel-lock-check`
canvrno-oai ·
2026-06-22 17:56:04 -07:00 -
Upgrade bundled OpenSSL to 3.6.3 (#29487)
## Summary - upgrade the bundled OpenSSL source from 3.5.5 to 3.6.3 - update the Bazel `openssl-sys` build dependency to use the upgraded source crate - refresh the Bazel module lockfile ## Why OpenSSL 3.5.5 is within the affected ranges for security issues fixed in later releases. The Rust `openssl-src` wrapper does not currently publish OpenSSL 3.5.7, so this moves the vendored Linux musl build to the available patched 3.6.3 release.
jif ·
2026-06-23 00:19:54 +02:00 -
PAC 3 - Add Windows system proxy resolver (#26708)
## Summary Stacked on #26707. Adds the Windows implementation of the shared system-proxy contract. This allows Codex-owned auth clients to use the route Windows selects for each auth URL, including explicit PAC configuration, WPAD auto-detection, static proxies, and bypass rules. The `respect_system_proxy` feature is disabled by default, so existing client behavior remains unchanged unless explicitly enabled. ## Implementation - Adds Windows-only `codex-client` dependencies: - `windows-sys` with `Win32_Foundation` and `Win32_Networking_WinHttp`; - `sha2` for redacted cache keys. - Dispatches system-proxy resolution to `outbound_proxy/windows.rs` on Windows. - Reads the current-user WinHTTP/IE proxy configuration via `WinHttpGetIEProxyConfigForCurrentUser`. - Resolves explicit PAC URLs first, then OS-enabled WPAD auto-detection, then static proxy and bypass settings. - Uses `WinHttpGetProxyForUrl` for PAC/WPAD and maps results into the shared `SystemProxyDecision::{Direct, Proxy, Unavailable}` contract. - Parses `DIRECT`, `PROXY`, `HTTPS`, and keyed static proxy entries. - Treats unsupported schemes such as SOCKS as unavailable so the shared resolver can apply its environment-proxy fallback. - Handles Windows bypass entries, including `<local>` and host, suffix, wildcard, and port matching. - Releases WinHTTP-owned strings with `GlobalFree` and closes sessions with `WinHttpCloseHandle`. - Hashes URL-specific cache keys with SHA-256 so PAC decisions remain URL-specific without retaining raw request URLs or query strings. ## End-user behavior - Disabled/default: existing client behavior is unchanged. - Enabled with `[features.respect_system_proxy]`: - Windows auth clients honor explicit PAC configuration, OS-enabled WPAD, static proxies, and bypass rules; - valid OS/PAC `DIRECT` decisions use a direct connection; - unavailable system resolution falls back to explicit environment proxy variables, then `DIRECT`, through the shared contract from #26707. - Unsupported proxy schemes are not silently translated into a different route. - Custom CA handling remains separate from proxy selection. ## Tests Adds coverage for: - PAC-style proxy tokens such as `PROXY proxy.internal:8080` and `HTTPS proxy.internal:8443`; - static WinHTTP proxy entries keyed by target scheme; - `DIRECT` and unsupported proxy-token behavior; - Windows bypass matching, including `<local>`, wildcard, suffix, and port-qualified entries; - preserving URL-specific PAC cache decisions without retaining the raw URL on Windows.
canvrno-oai ·
2026-06-22 14:38:33 -07:00 -
chore: advance tungstenite fork pins (#29480)
## Why `openai-oss-forks/tokio-tungstenite` now includes the updated `tungstenite` fork revision from [openai-oss-forks/tokio-tungstenite#3](https://github.com/openai-oss-forks/tokio-tungstenite/pull/3). Codex should consume the merged fork commit and resolve its direct and transitive `tungstenite` dependencies to the same revision instead of retaining the older pins. ## What Changed - Advanced the `tokio-tungstenite` git pin to `0e5b2d73aa18dd9f0a50ee9ff199d5aef7594186`. - Advanced the `tungstenite` fork pin to `4fffad30fe373adbdcffab9545e9e9bf4f2fc19f` and adjusted the patch source so the transitive dependency resolves to that revision. - Updated `Cargo.lock` and `MODULE.bazel.lock` to match the dependency graph.
Anton Panasenko ·
2026-06-22 14:24:02 -07:00 -
Honor startup custom CA bundles with managed MITM (#29014)
## Why When Codex starts with a custom CA override such as `SSL_CERT_FILE=/path/to/corp-ca.pem codex`, `rustls-native-certs` treats that override as a replacement for the platform trust store. The managed proxy then rewrites child CA variables to its generated bundle, so the custom root or the ordinary platform roots can be lost. The proxy's upstream TLS connector must trust the same roots or private and corporate upstream certificates still fail after interception. ## What - load platform-native roots without consulting inherited CA override variables - append certificates from the existing curated startup CA file variables and `SSL_CERT_DIR` - share those platform and startup roots with the MITM upstream rustls connector - exclude the Codex managed MITM CA from upstream trust - normalize OpenSSL `TRUSTED CERTIFICATE` blocks while dropping trailing trust metadata - skip an inherited current Codex-managed bundle so nested launches do not duplicate it - append the Codex managed MITM CA to the child-facing bundle - copy certificate material only, so a private key or unrelated text colocated in a startup file is never exposed through the public bundle This is intentionally limited to CA paths present when Codex starts. It does not parse inline shell assignments or add per-command bundle materialization. This changes only `codex-network-proxy` and dependency metadata; it does not touch `codex-core` or sandbox orchestration. ## Validation - `just test -p codex-network-proxy` - includes an end-to-end upstream TLS test using a server trusted only by the startup custom CA - `just fix -p codex-network-proxy` - `just bazel-lock-check`
Winston Howes ·
2026-06-22 14:16:48 -07:00 -
[codex] handle request_user_input in app-server test client (#29476)
## Why `codex-app-server-test-client` previously treated `item/tool/requestUserInput` as an unsupported server request and terminated the connection. That made it impossible to use the client for end-to-end testing of interactive turns: an operator could observe the request, but could not answer it and confirm that the same turn resumed. ## What changed - Handle `ToolRequestUserInput` server requests in the test client's central request dispatcher. - Render numbered terminal choices, accept exact option labels, support free-form `Other` and text-only questions, and collect multiple answers. - Send a protocol-native `ToolRequestUserInputResponse` and continue streaming the active turn. - Fail clearly when interactive input is requested without a terminal. - Document the interactive behavior and add focused tests for option selection, free-form answers, multiple questions, and invalid-selection retries. ## Testing - `just test -p codex-app-server-test-client` - `just bazel-lock-check` - Manually exercised the app-server flow, selected `TUI`, observed `serverRequest/resolved`, and verified that the same turn completed with the selected answer.
Celia Chen ·
2026-06-22 13:55:32 -07:00 -
Allow ChatGPT accounts without email (#28991)
# Summary Codex required every ChatGPT account to have an email address. A service-account personal access token can return valid account metadata without one, so PAT login failed while decoding the metadata response. This change makes email optional in the account metadata type that owns it and preserves that absence through authentication, provider account state, the app-server API, generated clients, and TUI bootstrap. Existing accounts with email addresses keep the same behavior. ## Behavior-changing call sites | Call site | Behavior after this change | | --- | --- | | `login/src/auth/personal_access_token.rs` | PAT metadata accepts a missing or null email and retains `None`. | | `agent-identity/src/lib.rs` | Agent Identity JWT claims accept an omitted email. | | `login/src/auth/storage.rs` and `login/src/auth/agent_identity.rs` | Stored and managed Agent Identity records carry `Option<String>`. Deserialization maps the legacy empty-string sentinel to `None`. | | `login/src/auth/manager.rs` | `get_account_email` returns the stored option, and managed identity bootstrap no longer converts `None` to an empty string. | | `model-provider/src/provider.rs` and `protocol/src/account.rs` | A ChatGPT provider account requires a plan type but may carry no email. | | `app-server-protocol/src/protocol/v2/account.rs` | `account/read` keeps the `email` field on the wire and returns `null` when the account has no email. Generated TypeScript and JSON schemas describe a required, nullable field. | | `sdk/python/src/openai_codex/generated/v2_all.py` | The generated Python `ChatgptAccount` model accepts `None` for email. | | `tui/src/app_server_session.rs` | Email-less ChatGPT accounts bootstrap normally, keep external feedback routing, omit account-email telemetry, and display the plan in account status. | ## Design decisions - Missing email remains `None` at every layer. The code never uses an empty string as a substitute. - The app-server response includes `"email": null` instead of omitting the field. Clients retain a stable response shape. - Plan type remains required for provider account state. This change relaxes only the email assumption. ## Testing Tests: affected test targets compile, scoped Clippy and formatting pass, a focused TUI snapshot covers plan-only account status, real before/after PAT login smoke covers metadata without email, app-server smoke covers `account/read` with `email: null`, and a regression smoke covers an existing email-bearing PAT. Unit tests run in CI. ## Evidence Visual smoke evidence will be attached here.
efrazer-oai ·
2026-06-22 13:19:40 -07:00 -
Parallelize skill metadata stats (#29326)
## Summary This switches skill discovery to the simpler same-connection scalar request shape. After reading a skills directory, discovery now starts the existing `fs/getMetadata` calls for all visible entries in that directory before awaiting the results. There is no JSON-RPC batch frame and no new filesystem API; remote filesystems use the existing request-id multiplexing on the same exec-server connection. This is the scoped alternative to the batch-frame approach in #29074 / #29075. ## What changed - Collect visible directory entries before processing them. - Run their existing `fs.get_metadata(...)` calls with `join_all`. - Process the results in the original directory order, so skill discovery behavior stays the same. ## Benchmarks Fresh local benchmark against generated skill trees over a real exec-server remote filesystem. The benchmark calls the actual `load_skills_from_roots` path, so this includes directory reads, metadata stats, `SKILL.md` reads, and parsing. Times are p50 milliseconds from 5 samples after 1 warmup, using warmed runs. | Scenario | Legacy `main` | Batch frame stack (#29074 / #29075) | Same-connection scalar stack | | --- | ---: | ---: | ---: | | 100 flat skills | 377.4 | 389.0 | 378.6 | | 500 flat skills | 1983.2 | 1856.6 | 1757.5 | Takeaway: for the actual skill discovery path, same-connection scalar is tied with legacy at 100 skills and best at 500 skills. The batch-frame stack does not show enough win here to justify the extra protocol/API surface. Benchmark command: - `just test -p codex-exec-server benchmark_remote_skill_discovery --run-ignored ignored-only --no-capture` Checked locally with: - `just test -p codex-core-skills` - `just bazel-lock-update` - `just bazel-lock-check`
jif ·
2026-06-21 14:04:18 +02:00 -
chore(deps): advance tokio-tungstenite (#29132)
## Why Responses websocket connections use `tokio-tungstenite`. When DNS returns an unusable native IPv6 address before a working IPv4 address, sequential dialing can consume Codex's outer websocket timeout before reaching IPv4. The merged fork change adds Happy Eyeballs-style alternate-family racing so websocket dialing matches the recovery behavior already present in the HTTP path. ## What Changed Advance the workspace `tokio-tungstenite` patch from `132f5b39` to merged commit `e5e64b86`, and update the matching lockfile source. The new revision comes from [openai-oss-forks/tokio-tungstenite#1](https://github.com/openai-oss-forks/tokio-tungstenite/pull/1).
Anton Panasenko ·
2026-06-19 12:02:12 -07:00 -
feat: opt ChatGPT auth into agent identity (#19049)
## Stack This is PR 2 of the simplified HAI single-run-task stack: - [#19047](https://github.com/openai/codex/pull/19047) Agent Identity assertion and task-registration primitives, including the shared run-task helper used by existing Agent Identity JWT auth. - [#19049](https://github.com/openai/codex/pull/19049) Disabled-by-default ChatGPT auth opt-in that provisions/reuses persisted Agent Identity runtime auth and its single run task. - [#19051](https://github.com/openai/codex/pull/19051) Run-scoped provider auth that uses one backend-owned task id for first-party inference and compaction requests. [#19054](https://github.com/openai/codex/pull/19054) collapsed out of the active stack because the simplified design no longer needs a separate background/control-plane task helper. ## Summary This PR adds the disabled-by-default path for normal ChatGPT-login Codex sessions to obtain Agent Identity runtime auth through the Codex backend. Existing Agent Identity JWT startup mode remains a separate path and does not require the feature flag. What changed: - adds the experimental `use_agent_identity` feature flag and config schema entry - adds an explicit `AgentIdentityAuthPolicy` so call sites choose `JwtOnly` or `ChatGptAuth` instead of passing a bare boolean - stores standalone Agent Identity JWT credentials separately from backend-registered Agent Identity records - persists the registered Agent Identity record, private key, and single run task id in `auth.json` so process restarts reuse the same identity - derives the agent/task registration base URL from ChatGPT/Codex auth config while keeping JWT JWKS lookup separate - provisions and caches ChatGPT-derived Agent Identity runtime auth when `use_agent_identity` is enabled - reuses the shared run-task registration helper from PR1 rather than adding a second task-registration path This PR intentionally does not switch model inference over to `AgentAssertion` auth. The provider-auth integration lands in the next PR. ## Testing - `just test -p codex-login`
Adrian ·
2026-06-18 14:05:27 -07:00 -
[codex] Remove hardcoded app ID filters (#28947)
## Summary - remove the duplicated originator-specific connector ID denylists - stop filtering connector directory/accessibility results and live/cached Codex Apps MCP tools by hardcoded connector ID - remove the now-unused `codex-login` dependency from `codex-utils-plugins` - update regression coverage so formerly blocked connector IDs are preserved ## Why The client-side policy was duplicated across crates, used opaque IDs without ownership or expiry information, and could drift between app listing and MCP tool behavior. Server-provided visibility, authorization, plugin discoverability, accessibility, enabled-state handling, and consequential-tool approval templates remain unchanged. ## Validation - `just fmt` - `just bazel-lock-update` - `just bazel-lock-check` - `git diff --check` - confirmed the final diff contains no hardcoded denylist symbols A targeted `codex-mcp` test build spent an unusually long time in local compilation/linking. Its first attempt exposed a test-only `PartialEq` assertion issue, which was corrected. A follow-up non-linking `cargo check -p codex-mcp --tests` was still running when this draft was opened; CI should provide the complete Rust validation.
Eric Ning ·
2026-06-18 20:29:01 +00:00 -
Scope MCP sandbox metadata to server environment (#28914)
Scope MCP sandbox metadata to the MCP server's owning environment. Previously, `codex/sandbox-state-meta` always used the turn's primary cwd and rebuilt a legacy sandbox policy from that cwd. That can be wrong for MCP servers owned by a different execution environment. This now sends the owning environment cwd as a `file:` URI in `sandboxCwd`, keeps `permissionProfile` as the permission source of truth, and omits sandbox-state metadata when a non-default server environment is not selected for the turn. Local/default MCP servers keep the existing fallback cwd behavior. Tests: - `just fmt` - `just bazel-lock-update` - `just bazel-lock-check` - `just test -p codex-mcp` - `just test -p codex-core mcp_sandbox_cwd` - `cargo build -p codex-rmcp-client --bin test_stdio_server` - `just test -p codex-core stdio_mcp_tool_call_includes_sandbox_state_meta`
jif ·
2026-06-18 19:31:07 +02:00 -
Run fs helper through Windows sandbox wrapper (#28359)
## Why This is the final PR in the Windows fs-helper sandbox stack and contains the actual bug fix. The exec-server filesystem helper is a direct-spawn path: it asks `SandboxManager` for a `SandboxExecRequest`, then launches the returned argv itself. That works on macOS and Linux because the transformed argv is already a self-contained sandbox wrapper. On Windows, the transformed request carried `WindowsRestrictedToken` metadata, but the direct-spawn fs-helper runner still launched the helper argv directly. That means Windows filesystem built-ins backed by the fs-helper could run with the parent Codex process permissions instead of the configured Windows sandbox. This PR makes the direct-spawn transform produce a self-contained Windows wrapper argv before fs-helper launches it. ## What Changed - Added `SandboxManager::transform_for_direct_spawn()` for callers that launch the returned argv themselves. - Wrapped Windows restricted-token direct-spawn requests with `codex.exe --run-as-windows-sandbox` and then marked the outer request as unsandboxed, matching the macOS/Linux wrapper argv shape. - Updated `exec-server/src/fs_sandbox.rs` to use the direct-spawn transform for fs-helper launches. - Materialized the inner `codex.exe --codex-run-as-fs-helper` executable into `.sandbox-bin` so the sandboxed user can run it. - Carried runtime workspace roots through `FileSystemSandboxContext` as `PathUri` values so `:workspace_roots` policies resolve correctly without sending native client paths over exec-server JSON. - Preserved wrapper setup identity environment needed by Windows sandbox setup without changing the serialized inner helper environment. ## Verification - `just bazel-lock-update` - `just bazel-lock-check` - `just test -p codex-sandboxing transform_for_direct_spawn_windows` - `just test -p codex-exec-server fs_sandbox::tests` - `just fix -p codex-windows-sandbox -p codex-sandboxing -p codex-exec-server -p codex-core -p codex-file-system` Local note: `just fmt` completed Rust formatting, but this workstation still fails the non-Rust formatter phases because uv cannot open its cache and the local buildifier/dotslash path is missing.
iceweasel-oai ·
2026-06-17 10:00:42 -07:00 -
[codex] [3/4] Activate endpoint plugin recommendations (#27704)
Summary\n- Await endpoint recommendation selection while constructing each authenticated turn, removing the first-turn cache race.\n- Snapshot and filter endpoint candidates once per turn, then use that same set for the bounded contextual user fragment, tool exposure, and exact install validation.\n- Keep recommendation selection ephemeral: do not persist recommendation state in or gate resumed threads on prior context.\n- Hide the legacy list tool in endpoint mode and preserve legacy discovery unchanged when the endpoint is disabled or unavailable.\n- Keep remote plugin and connector app identities out of model-visible context and attach them only to Codex-owned elicitation metadata.\n\nStack\n- 3/4, based on #28400.\n- Endpoint client and cache: #28399.\n- Generalized suggestion presentation: #28400.\n- Install-schema follow-up: #28403.\n\nValidation\n- \n- \n- \n- \n- Full : 2,649 passed and 88 environment-dependent tests failed because this sandbox cannot write , nest Seatbelt, or locate auxiliary test binaries.
Alex Daley ·
2026-06-16 23:04:07 +00:00 -
[codex] Route MCP file uploads through environment filesystem (#27923)
## Why Codex Apps tools can mark arguments with `openai/fileParams`, but the execution path resolved and opened those files directly on the host. That bypassed the selected turn environment and prevented annotated file arguments from working with remote environments. ## What changed - resolve annotated file arguments against the primary turn environment - read file metadata and contents through that environment's sandboxed `ExecutorFileSystem` - reject files over the 512 MiB limit from metadata before reading or transferring them - retain the buffered upload-size check as defense in depth - make the OpenAI upload API accept a filename and buffered contents instead of owning local filesystem access - describe the model-visible argument as a path in the primary environment This builds on #27927, which added `size` to internal filesystem metadata. ## Testing - `just test -p codex-api upload_openai_file_returns_canonical_uri` - `just test -p codex-mcp tool_with_model_visible_input_schema_masks_file_params` - `just test -p codex-core mcp_openai_file` - `just test -p codex-core codex_apps_file_params_upload_environment_files_before_mcp_tool_call`
pakrym-oai ·
2026-06-16 11:27:46 -07:00 -
[codex] exec-server: stream files in chunks (#28354)
## Why `fs/readFile` buffers the entire file in one response, which makes large remote reads expensive and prevents callers from applying backpressure. We need an opt-in streaming path with bounded block sizes while preserving the existing single-call API for small and sandboxed reads. ## What changed - Add `ExecServerClient::stream`, returning a named `FileReadStream` that implements `futures::Stream` and yields immutable 1 MiB byte blocks. - Add internal `fs/open`, `fs/readBlock`, and `fs/close` RPCs. `fs/readBlock` accepts an explicit offset and length. - Keep unsandboxed files open between block reads, cap open handles per connection, and clean them up on EOF, error, stream drop, explicit close, or connection shutdown. - Reject platform-sandboxed streaming opens instead of turning the one-shot sandbox helper into a persistent server. Existing `fs/readFile` behavior is unchanged. ## Testing - `just test -p codex-exec-server` - Integration coverage for 1 MiB chunking, exact block-boundary EOF, sandbox rejection, and continued reads from the opened file after path replacement. - Handle-manager coverage for non-sequential offsets, variable block lengths, the 128-handle limit, and capacity release after close.
pakrym-oai ·
2026-06-16 09:50:55 -07:00 -
Use ApiPathString in app-server filesystem permission paths (#28367)
## Why Clients running an app-server on one OS and an exec-server on another OS need to be able to pass sandbox config to app-server that refers to resources on the executor's foreign OS. ## What `AbsolutePathBuf` can't represent these paths and we don't want users to be exposed to `PathUri` yet, so this moves the public app-server API to be expressed in terms of `ApiPathString`. Stacked on #28165. - change app-server v2 filesystem permission paths, including legacy read/write roots, to `ApiPathString` - localize API paths through `PathUri` when converting into the current native core permission types - make path-bearing permission conversions fallible and surface localization failures instead of silently treating malformed grants as ordinary denials - propagate conversion failures through app-server and TUI approval handling - regenerate the app-server JSON and TypeScript schemas - leave migration TODOs on native-path conversions so they can be removed once core permission paths use `PathUri`
Adam Perry @ OpenAI ·
2026-06-15 19:25:54 -07:00 -
Use PathUri in filesystem permission paths for exec-server (#28165)
## Why Progress towards letting app-server and exec-server run on different platforms, specifically for sandbox configuration. ## What - Make the filesystem path containment hierarchy generic, defaulting to `AbsolutePathBuf` for now. - Have clients specify `AbsolutePathBuf` or `PathUri` directly where needed. - Use `PathUri` throughout exec-server filesystem protocol and trait boundaries. - Implement `From` for conversion to path URIs and `TryFrom` for fallible conversion to absolute paths through the generic type hierarchy.
Adam Perry @ OpenAI ·
2026-06-15 23:55:23 +00:00 -
exec-server: add Noise relay transport (#26242)
## Why Rendezvous forwards traffic between the orchestrator and exec-server. The endpoints need to authenticate each other and encrypt that traffic without trusting Rendezvous with plaintext or endpoint keys. ## Changes - Adds a hybrid Noise IK channel through Clatter using X25519, ML-KEM-768, AES-256-GCM, and SHA-256. - Binds each handshake to `environment_id`, `executor_registration_id`, and `stream_id`. - Pins the registry-provided executor key and carries the harness authorization inside the encrypted handshake. - Orders relay frames before consuming Noise nonces and fragments large JSON-RPC messages into bounded records. - Bounds handshake payloads, frames, streams, and message reassembly. Runtime activation is in [openai/codex#26245](https://github.com/openai/codex/pull/26245). ## Stack 1. **[openai/codex#26242](https://github.com/openai/codex/pull/26242)**: Noise channel and relay transport 2. [openai/codex#26245](https://github.com/openai/codex/pull/26245): remote registration and runtime activation ## Verification - `just test -p codex-exec-server` - Oversized initiator payload regression coverage - `just fix -p codex-exec-server` - `just bazel-lock-check` - `cargo shear` --------- Co-authored-by: Codex <noreply@openai.com>
viyatb-oai ·
2026-06-15 16:39:41 -07:00 -
[codex] Reuse Apps policy evaluation across MCP tool exposure (#27813)
## Summary - move `AppToolPolicyEvaluator` and the Apps config/requirements policy logic from `codex-core` into `codex-connectors` - resolve one immutable policy snapshot per exposure build and reuse it across every Codex Apps MCP tool - keep core as a thin adapter from MCP metadata to connector-owned policy input while preserving the call-time defense-in-depth check ## Why `build_mcp_tool_exposure` evaluates every Codex Apps tool on each sampling request. The old path rebuilt effective Apps configuration for every tool, and the policy implementation lived in the already-large core crate even though it is connector-specific. The connector-owned evaluator keeps the expensive config merge/decode out of the loop and gives core only the effective policy result it needs. ## Performance With the real 557-tool Apps corpus, `build_mcp_tool_exposure` measured 3.74 ms and 3.33 ms after the extraction (3.54 ms mean). The original path measured 807 ms mean, so the final result retains the 99.6% reduction. ## Validation - `cargo check -p codex-connectors -p codex-core` - `just test -p codex-connectors` — 15 passed - `just test -p codex-core --lib connectors` — 35 passed - `just test -p codex-core --lib mcp_tool_exposure` — 5 passed - `just test -p codex-core --lib mcp_tool_call` — 72 passed - `just bazel-lock-update` - `just bazel-lock-check` - `just fix -p codex-connectors` - `just fix -p codex-core` - `just fmt`
Matthew Zeng ·
2026-06-15 15:24:33 -07:00 -
Add hidden Windows sandbox wrapper entrypoint (#28358)
## Why This is the second PR in the Windows fs-helper sandbox stack. The fs-helper path needs a Windows sandbox launcher that has the same argv-shaped contract as macOS `sandbox-exec` and `codex-linux-sandbox`, but this PR only introduces that hidden launcher. It does not route fs-helper through it yet. The hidden launcher still needs to be policy-complete before later direct-spawn callers use it. In particular, it has to carry the same Windows sandbox policy details that the existing spawn paths already understand: proxy enforcement, read/write root overrides, and deny-read/deny-write overrides. ## What Changed - Added the hidden `codex.exe --run-as-windows-sandbox` arg1 dispatch path. - Added `windows-sandbox-rs/src/wrapper.rs`, which parses the wrapper argv, launches the requested command through the shared Windows sandbox session runner from PR1, and forwards stdio. - Added `create_windows_sandbox_command_args_for_permission_profile()` so later direct-spawn callers can build the wrapper argv consistently. - Made the wrapper argv round-trip the full Windows sandbox policy surface it needs later: workspace roots, environment, permission profile, sandbox level, private desktop, proxy enforcement, read/write root overrides, and deny-read/deny-write overrides. - Carried `proxy_enforced` through the shared Windows session request so proxy-managed executions continue to use the offline/elevated sandbox identity. - Added wrapper argument round-trip coverage for the full policy fields. ## Verification - `just test -p codex-windows-sandbox windows_wrapper_args_round_trip` - `just test -p codex-arg0` - `just test -p codex-core exec::tests::windows_` - `just fix -p codex-windows-sandbox -p codex-core -p codex-cli` Local note: the full `just fmt` command still fails on this workstation in non-Rust formatter setup (`uv` cache access denied and missing `dotslash`/buildifier), but the Rust formatter phase completed.
iceweasel-oai ·
2026-06-15 21:30:32 +00:00 -
[codex] Preserve plugin apps in connector listings (#27602)
## Context This is PR4 in the plugin auth-routing stack. The earlier PRs make plugin surface projection auth-aware and narrow App/MCP conflicts by App declaration name. This PR keeps connector listing paths aligned with that projected plugin App set. This means ChatGPT/SIWC users will still see plugin-provided Apps in connector listing surfaces like the Apps/connector picker, while API-key users will not see Apps they cannot use. ## Stack - PR1: #27652 seed plugin manager auth at construction. - PR2: #27459 route plugin surfaces by auth mode. - PR3: #27607 dedupe plugin MCP servers by App declaration name. - PR4: #27602 preserve plugin Apps in connector listings. - PR5: #27461 skip install-time plugin MCP OAuth for matching App routes. ## Summary - Have app-server compute effective plugin Apps from the existing PluginsManager and pass them into connector listing. - Keep plugin Apps visible in Apps/connector listing for ChatGPT/SIWC users. - Keep API-key-style auth from surfacing plugin Apps in connector listings. ## Validation ```bash cargo test -p codex-chatgpt connectors::tests cargo test -p codex-app-server list_apps_includes_plugin_apps_for_chatgpt_auth git diff --check ```
felixxia-oai ·
2026-06-15 13:50:08 +01:00 -
Discover stdio MCP servers from selected executor plugins (#27870)
## Why **In short:** this PR discovers MCP registrations by reading a selected plugin's `.mcp.json` on its executor. #27884 then resolves those registrations in the shared catalog. `thread/start.selectedCapabilityRoots` can select a plugin root owned by an executor, and Codex can resolve that package through the executor filesystem. MCP declarations inside the selected plugin are still ignored. This PR adds the source-specific discovery layer on top of the selected-plugin catalog boundary in #27884: ```text selected capability root | v resolve the plugin through its executor filesystem | v read and normalize its MCP config through the same filesystem | v contribute stdio registrations bound to that environment ID ``` The existing MCP launcher and connection manager remain unchanged. MCP config parsing is shared with local plugins through #27863. ## What changed - Added an executor plugin MCP provider in the MCP extension. - Retained only the exact filesystem capability used for package resolution and reused it for the selected plugin's MCP config, with no host-filesystem fallback or unrelated process/HTTP authority. - Read either the manifest-declared MCP config or the default `.mcp.json`; a missing default file means the plugin has no MCP servers. - Accepted stdio servers only for this first vertical. Executor-owned HTTP declarations are skipped with a warning until their placement semantics are defined. - Normalized stdio registrations with the owning environment's stable logical ID and plugin-root working directory. - Resolved environment-variable names on the owning executor and rejected explicit local forwarding for non-local plugins. - Froze discovered declarations once per active thread runtime, then applied current managed plugin and MCP requirements when contributing them. - Carried the selected root ID, display name, and selection order into the catalog contribution defined by #27884. ## Behavior and scope There is intentionally no production behavior change yet. This PR provides the executor provider and contribution boundary, but app-server does not install it in this change. Existing local plugin MCP loading is unchanged, and no MCP process is launched by this PR alone. ## Assumptions - The selected root ID is the plugin policy identity; the manifest display name is presentation metadata. - An environment ID is a stable logical authority. Reconnection or replacement under the same ID does not change ownership. - Selected plugin packages and their manifests are trusted inputs. - The selected package and MCP discovery snapshot remain frozen for the active thread runtime. ## Follow-up The next PR installs this contributor in app-server and adds an end-to-end test proving that a selected plugin MCP tool launches on its owning executor, can be called by the model, survives an explicit MCP refresh, and is invisible when its root was not selected. Resume, fork, environment removal or ID changes, dynamic catalog reload, and executor-owned HTTP MCP placement remain separate lifecycle decisions. ## Verification Focused tests cover executor-only filesystem reads, missing and malformed config, stdio filtering and normalization, managed requirements, package attribution, and selection order. CI owns execution of the test suite.
jif ·
2026-06-15 11:52:05 +02:00 -
[codex] exec-server honors remote environment cwd and shell (#28122)
## Why Next slice needed to make progress on the `remote_env_windows` test is to support passing a Windows cwd for the remote environment and using that environment's native shell. This lets the test run a real Windows process instead of only recording an early path or shell mismatch. ## What - change `TurnEnvironmentSelection.cwd` from `AbsolutePathBuf` to `PathUri` - convert local cwd values to URIs when constructing selections - preserve a remote primary cwd instead of replacing it with the local legacy fallback - prefer the selected environment's discovered shell for unified exec, falling back to the session shell when unavailable - convert back to a host-native absolute path at current native-only consumer boundaries - reject or deny unsupported foreign cwd values at the existing request-permissions boundary, with TODOs for its future migration - extend the hermetic Wine test to execute Windows PowerShell in `C:\windows` and verify successful process completion - record the current app-server rejection against the same Wine-backed remote Windows fixture when its cwd is supplied as a native Windows path
Adam Perry @ OpenAI ·
2026-06-14 06:07:46 +00:00 -
[codex] Pin bundled SQLite to fixed WAL-reset version (#27992)
## Summary Prevent dependency refreshes from silently downgrading Codex's bundled SQLite to a release affected by the WAL-reset corruption bug. SQLx 0.9 accepts a broad `libsqlite3-sys` range. An unrelated lock refresh therefore moved Codex from `libsqlite3-sys 0.37.0` back to `0.35.0`, changing the bundled SQLite runtime from 3.51.3 to 3.50.2. SQLite documents the affected versions and fix in [The WAL Reset Bug](https://www.sqlite.org/wal.html#the_wal_reset_bug) and the [SQLite 3.51.3 changelog](https://www.sqlite.org/changes.html#version_3_51_3).
Gabriel Peal ·
2026-06-13 21:28:31 -07:00 -
[codex] Carry exec-server cwd as PathUri (#28032)
## Why This is the second-to-last place in the exec-server protocol that needs to migrate to URIs to support cross-OS operation. ## What - Change `ExecParams.cwd` to `PathUri`. - Keep the cwd URI-shaped through core and rmcp producers, converting it to `AbsolutePathBuf` only in `LocalProcess::start_process`. - Reject non-native cwd URIs before launch and update the affected protocol documentation and call sites.
Adam Perry @ OpenAI ·
2026-06-13 20:56:42 +00:00 -
[codex] Limit app-based plugin suggestions to remote catalogs (#27988)
## Summary - Keep local plugin suggestions bounded to fallback and explicitly configured plugins. - Preserve app-overlap recommendations for remote plugins using cached catalog metadata. - Remove the WSL-specific local discovery exception and move manager-owned discovery tests into `codex-core-plugins`. ## Why Local curated marketplaces were allowlisted before plugin detail loading, so every uninstalled candidate could be deep-read before its app IDs were checked. That caused per-turn reads of candidate plugin manifests, skills, app configs, hooks, and MCP configs, which is especially expensive on slow disks. Remote discovery does not need those local candidate reads because app IDs are already available in the cached remote catalog. Installed local plugins are still loaded when needed to determine the user's installed app IDs. ## Validation - `just fmt` - `just test -p codex-core-plugins discoverable::tests` (13 passed) - `just test -p codex-core plugins::discoverable::tests` (4 passed) - `just bazel-lock-update` - `just bazel-lock-check` - `git diff --check`
xl-openai ·
2026-06-12 17:51:09 -07:00 -
[codex] make PathUri::from_abs_path infallible (#27976)
## Why `PathUri::from_abs_path` can fail for absolute paths that do not have a normal `file:` URI representation, forcing filesystem call sites to handle a conversion error even though the original path can be preserved losslessly. ## What Make `from_abs_path` infallible and migrate its callers. Unrepresentable paths use `file:///%00/bad/path/<base64>`, encoding Unix bytes or Windows UTF-16LE; `to_abs_path` validates and decodes that fallback. The leading encoded null reserves a namespace that cannot collide with a real Unix or Windows path, and fallback URIs remain opaque to lexical path operations. ## Validation Added path-URI coverage for Unix null and non-UTF-8 paths, Windows device/verbatim and non-Unicode paths, serialization, malformed fallbacks, opaque lexical operations, invalid native payloads, and literal `/bad/path` collision resistance.
Adam Perry @ OpenAI ·
2026-06-12 16:58:42 -07:00 -
feat: use encrypted local secrets for MCP OAuth (#27541)
## Summary - store MCP OAuth credentials in the configured auth credential backend - support encrypted-local OAuth storage, including legacy keyring migration - propagate the credential backend through MCP refresh, session, CLI, and app-server paths ## Stack 1. #27504 — config and feature flag 2. #27535 — auth-specific secret namespaces 3. #27539 — encrypted CLI auth storage 4. this PR — encrypted MCP OAuth storage This is a parallel review stack; the original #17931 remains unchanged. ## Tests - `just test -p codex-rmcp-client` (the transport round-trip test passed after building the required `codex` binary and retrying) - `just test -p codex-mcp` - `just test -p codex-app-server refresh_config_uses_latest_auth_keyring_backend` - `just test -p codex-core refresh_mcp_servers_is_deferred_until_next_turn` - `just test -p codex-cli mcp` - `just fix -p codex-rmcp-client -p codex-mcp -p codex-core -p codex-cli -p codex-app-server -p codex-protocol` - `just bazel-lock-check`
Celia Chen ·
2026-06-12 22:03:51 +00:00 -
feat: use encrypted local secrets for CLI auth (#27539)
## Why Windows Credential Manager limits generic credential blobs to 2,560 bytes. Large serialized ChatGPT auth payloads can exceed that limit, so keyring-mode CLI auth needs a backend that keeps only the encryption key in the OS keyring and stores the payload in Codex's encrypted local-secrets file. This is the third PR in the encrypted-auth stack: 1. #27504 — feature and config selection 2. #27535 — auth-specific local-secrets namespaces 3. This PR — CLI auth implementation and activation 4. MCP OAuth implementation and activation ## What Changed - Added encrypted CLI-auth storage using the `CliAuth` secrets namespace. - Preserved direct keyring storage for platforms/configurations where it remains selected. - Selected the backend consistently for login, logout, refresh, device-code login, auth loading, and login restrictions. - Threaded resolved bootstrap/full config through CLI, exec, TUI, app-server account handling, cloud config, and cloud tasks. - Removed stale `auth.json` fallback data after successful encrypted saves and removed encrypted, direct-keyring, and fallback data during logout. - Added storage and integration coverage for both direct and encrypted keyring modes. MCP OAuth persistence is intentionally left to the next PR. ## Validation - `just test -p codex-login` — 131 passed - `just test -p codex-cli` — 280 passed - `just test -p codex-app-server v2::account` — 25 passed - `just test -p codex-cloud-config service` — 21 passed, 7 skipped - `just fix -p codex-login` - `just fix -p codex-cli` - `just fmt`
Celia Chen ·
2026-06-12 21:23:50 +00:00 -
Remove TUI realtime voice support (#27801)
## Why Removes the realtime audio support from TUI. ## What Changed - Removed the TUI `/realtime` and realtime `/settings` command paths. - Deleted TUI voice capture/playback, WebRTC session handling, audio-device selection UI, and recording-meter code. - Removed TUI realtime tests and snapshots that covered the deleted surfaces. - Dropped the TUI-only `cpal` and `codex-realtime-webrtc` dependencies and refreshed the Rust/Bazel locks.
Eric Traut ·
2026-06-12 14:20:55 -07:00 -
[codex] Align implicit skill reads with parser (#27926)
## Summary - reuse the shared shell read parser for implicit skill doc invocation detection - add regression coverage for `nl -ba .../SKILL.md` ## Why Desktop could render `Read User Context skill` for reads recognized by the shared command parser, while implicit `skill_invocation` analytics used a separate reader allowlist and missed cases such as `nl`. ## Validation - `HOME=/private/tmp/codex-core-skills-home-pr PATH=/Users/alexsong/.cache/cargo-home/bin:$PATH CARGO_HOME=/Users/alexsong/.cache/cargo-home just test -p codex-core-skills` - `git diff --cached --check` - `just fmt` attempted; Rust formatting completed, but the Python formatters could not download uncached Ruff wheels because `files.pythonhosted.org` is blocked in this sandbox. - `bazel mod deps --lockfile_mode=update/error --repo_env=ASPECT_TOOLS_TELEMETRY= --repo_env=DO_NOT_TRACK=1` evaluated the module graph and produced no `MODULE.bazel.lock` diff, but Bazel crashed on sandboxed `sysctl` during exit.
alexsong-oai ·
2026-06-12 13:23:22 -07:00 -
[login] revoke existing auth before starting login (#27674)
## Why `codex login` previously persisted newly issued OAuth credentials and only then attempted to revoke the superseded refresh token. The old credential must be revoked before a replacement browser or device-code flow starts, and successful login must not perform any post-login revocation attempt. ## What changed - Revoke and clear existing stored auth before browser or device-code CLI login begins. - Remove superseded-token detection and revocation from the shared token persistence path; successful login now only saves the new credentials. - Read the raw configured auth store during CLI cleanup so environment-provided auth cannot mask the stored refresh token. - Preserve `auto` storage fallback semantics when keyring deletion fails by clearing the fallback auth file. - Add a process-level CLI regression test that requires the revoke request to precede every device-login request and occur exactly once. If replacement login is canceled or fails, the previous local credentials have already been cleared. Remote revocation remains best effort, matching explicit logout behavior. ## Validation ### Process-level before/after reproduction I compiled the real `codex` CLI from the pre-fix parent (`14df0e8833`) and from the PR implementation (`25c002f23b`; the login behavior is unchanged at the current head), then ran the same device-code flow against a local HTTP mock OAuth authority. Each run: 1. Used a fresh temporary `CODEX_HOME` configured with `cli_auth_credentials_store = "file"`. 2. Seeded that temporary home with managed ChatGPT auth containing `old-access` and `old-refresh` tokens. 3. Pointed `CODEX_REVOKE_TOKEN_URL_OVERRIDE` at the mock `/oauth/revoke` endpoint. 4. Ran the compiled CLI as: ```shell CODEX_HOME=<temporary-home> \ CODEX_REVOKE_TOKEN_URL_OVERRIDE=<mock-issuer>/oauth/revoke \ <compiled-codex> login --device-auth --experimental_issuer <mock-issuer> ``` 5. Recorded every request received by the mock authority. The mock marked `new-access` valid when `/oauth/token` issued it and invalidated it if `/oauth/revoke` arrived afterward, reproducing the observed session-invalidating failure mode. After login exited, the harness also verified the persisted refresh token and probed a protected endpoint with `new-access`. | Build | Observed request order | CLI/persistence result | `new-access` probe | | --- | --- | --- | --- | | Pre-fix | `usercode → device token → OAuth token → revoke(old-refresh)` | Exit `0`; `new-refresh` persisted | `401` | | PR | `revoke(old-refresh) → usercode → device token → OAuth token` | Exit `0`; `new-refresh` persisted | `200` | The PR run therefore issued exactly one revocation request, before any request that initiated the replacement login, and issued no revocation after token exchange. ### Regression coverage `codex-rs/cli/tests/login.rs::device_login_revokes_existing_auth_before_requesting_new_tokens` runs the real first-party `codex` binary against a `wiremock` OAuth server with an isolated temporary `CODEX_HOME`. It asserts: - the exact request sequence is `/oauth/revoke`, `/api/accounts/deviceauth/usercode`, `/api/accounts/deviceauth/token`, then `/oauth/token`; - there is exactly one revoke request and its body contains `old-refresh` with the `refresh_token` hint; - the completed login persists `new-refresh`. Local validation: - `just test -p codex-login` — 130 passed - `just test -p codex-cli` — 280 passed, including the new process-level regression test - `just bazel-lock-check`cooper-oai ·
2026-06-12 12:38:30 -07:00 -
sandboxing: migrate cwd inputs to PathUri (#27816)
## Why Sandbox cwd values can cross app-server and exec-server host boundaries. They should retain URI semantics until the receiving host validates them instead of being interpreted early as native paths. ## What - Carry `PathUri` through filesystem sandbox contexts, sandbox commands, and transform inputs. - Convert command and policy cwd once in `SandboxManager::transform`, then keep launch requests native. - Preserve sandbox cwd over remote filesystem transport and reject non-native URIs without fallback. - Cache paired native/URI turn-environment cwd values during migration, with immutable access to keep them synchronized. - Extend existing protocol, forwarding, transform, and core runtime tests.
Adam Perry @ OpenAI ·
2026-06-12 11:38:01 -07:00 -
Extract shared plugin MCP config parsing (#27863)
## Why We want a thread-selected plugin to eventually expose stdio MCP servers that run on the executor owning that plugin. The existing plugin MCP parser lived inside `core-plugins` and was coupled to the host filesystem loader. Reusing it from an executor provider would either duplicate MCP normalization or make the plugin package layer own MCP runtime semantics. This PR creates the shared MCP-owned boundary first. In simple terms: ```text plugin .mcp.json | v shared parser in codex-mcp | +-- Declared placement: preserve current local-plugin behavior | +-- Environment placement: produce config bound to one executor ``` This builds on the authority-bound plugin descriptors from #27692. It intentionally does not discover, register, or launch executor MCP servers yet. ## What changed - Moved plugin MCP file parsing and normalization from `core-plugins` into `codex-mcp`. - Kept support for both existing file shapes: a top-level server map and an object containing `mcpServers`. - Kept per-server failure isolation: one invalid server does not discard valid siblings, while malformed top-level JSON still fails the whole file. - Updated the existing local plugin loader to use `Declared` placement, preserving its current transport, OAuth, relative `cwd`, and error behavior. - Added `Environment` placement for the next stacked PR: - the selected environment ID overrides anything declared by the plugin; - missing stdio `cwd` defaults to the plugin root; - relative `cwd` is resolved beneath the plugin root and cannot traverse outside it; - bare or source-less environment-variable references resolve on a non-local executor; - explicit orchestrator environment-variable forwarding is rejected for executor-owned plugins. ## User impact None in this PR. Existing local plugin MCP loading follows the same behavior through the shared parser. The executor placement mode is not connected to thread startup until the follow-up registration PR. ## Assumptions - A selected capability root's environment is authoritative. A plugin cannot redirect its stdio process to the orchestrator or another executor. - Relative working directories belong under the plugin package root. Explicit absolute working directories remain valid within the owning environment. - For a non-local executor, unqualified environment-variable names refer to that executor. Reading an orchestrator variable requires an explicit contract and is rejected for now. - Parsing only produces normalized `McpServerConfig` values. Process startup remains owned by the existing MCP runtime and connection manager. ## Follow-ups 1. Add the executor MCP provider and catalog registration: read the selected plugin's MCP config through the same executor filesystem, support stdio only, freeze the result per active thread, apply managed policy, and resolve name collisions as discovered plugin < selected plugin < explicit config. 2. Install that provider in app-server and add an end-to-end test proving `thread/start.selectedCapabilityRoots` launches and calls the MCP tool on the selected executor, preserves the frozen registration across refresh, and does not expose it to an unselected thread. 3. After the initial executor-stdio vertical, define resume/fork/environment-replacement semantics, executor HTTP placement, warning delivery, common MCP tool-context bounds, and move remaining MCP source composition above core. ## Verification - `cargo check -p codex-mcp -p codex-core-plugins --tests` - `just bazel-lock-check` - Added focused parser coverage for legacy local normalization, executor authority, working-directory handling, and environment-variable sourcing.jif ·
2026-06-12 15:10:05 +02:00 -
Add executor-owned plugin resolution (#27692)
## Why CCA can select a capability root that lives in an executor environment, but Codex only had a host-filesystem plugin loader. Before selected executor plugins can contribute MCP servers, we need a small package boundary that can answer: > Does this selected root contain a plugin, and if so, what does its manifest > declare? The answer must come from the selected environment's filesystem. A failed executor lookup must never fall back to the orchestrator filesystem. ## What this changes This PR introduces: ```rust PluginProvider::resolve(root) -> Result<Option<ResolvedPlugin>, Error> ``` `ExecutorPluginProvider` resolves one `SelectedCapabilityRoot` through its exact `environment_id`. It checks the recognized manifest locations, reads the manifest through that environment's `ExecutorFileSystem`, and returns an inert `ResolvedPlugin` containing: - the opaque selected-root ID; - the environment-bound plugin root; - the authority-bound manifest resource; - parsed metadata and authority-bound component locators. Descriptor construction rejects manifest or component paths outside the selected package root, so consumers cannot accidentally lose the package boundary when they receive a resolved plugin. If the root has no plugin manifest, resolution returns `None`, allowing the caller to treat it as a standalone capability such as a skill. ```text selected root: repo -> env-1:/workspace/repo | | env-1 filesystem only v .codex-plugin/plugin.json | v ResolvedPlugin { authority, root, manifest } ``` The existing host loader and the new executor provider now share the same manifest parser. Existing `codex-core-plugins::manifest` type paths remain available through re-exports, so host behavior and callers are unchanged. ## Scope This is intentionally a non-user-visible package-resolution PR. It does not: - parse or register plugin MCP server configurations; - activate skills, connectors, hooks, or MCP servers; - change app-server wiring; - introduce host fallback, caching, or lifecycle behavior. #27670 has merged, and this PR is now based directly on `main`. Together with the resolved MCP catalog from #27634, it establishes the inputs needed for the executor stdio MCP vertical without changing the existing MCP runtime. ## Follow-up The next PR will consume `ResolvedPlugin`, read its declared/default MCP config through the same executor filesystem, bind supported stdio servers to that environment, and feed those registrations into the resolved MCP catalog. An app-server E2E will prove that selecting an executor plugin exposes and invokes its tool on the owning executor. Resume/fork semantics, dynamic environment replacement, and non-stdio placement remain separate lifecycle decisions. ## Validation - `just fmt` - `cargo check --tests -p codex-plugin -p codex-core-plugins` - `just bazel-lock-check` - `git diff --check` Test targets were compiled but not executed locally; CI will run the test and Clippy suites.jif ·
2026-06-12 13:37:33 +02:00 -
code-mode standalone: extract protocol and add host crate (#27724)
This is phase 1 of a 4 phase stack: 1. **Add protocol and host crates for new IPC code mode implementation** 2. Create the new standalone binary 3. Create a new IPC `CodeModeSessionProvider` to use new binary 4. Remove v8 from core and only use IPC provider ## Add protocol and host crates for new IPC code mode implementation Establish a clean process boundary without changing the existing in-process behavior. - Add the codex-code-mode-protocol crate for shared session, runtime, response, and tool-definition types. - Move protocol-facing code out of the V8-backed implementation. - Add a buildable codex-code-mode-host crate as the foundation for the standalone process. - Keep the existing in-process runtime as the active implementation.
Channing Conger ·
2026-06-11 22:37:26 -07:00 -
[codex] Remove async_trait from first-party code (#27475)
## Why First-party async traits should expose their `Send` contracts explicitly without requiring `async_trait`. This completes the migration pattern established in #27303 and #27304. ## What changed - Replaced the remaining first-party `async_trait` traits with native return-position `impl Future + Send` where statically dispatched and explicit boxed `Send` futures where object safety is required. - Kept implementations behavior-preserving, outlining existing async bodies into inherent methods where that keeps the diff reviewable. - Removed all direct first-party `async-trait` dependencies and the workspace dependency declaration. - Added a cargo-deny policy that permits `async-trait` only through the remaining transitive wrapper crates. - Updated `rand` from 0.8.5 to 0.8.6 to resolve RUSTSEC-2026-0097 and keep the full cargo-deny check passing. ## Validation - `just test -p codex-exec-server`: 216 passed, 2 skipped. - `just test -p codex-model-provider`: 39 passed. - `just test -p codex-core` and `just test`: changed tests passed; remaining failures are environment-sensitive suites unrelated to this migration. - `cargo deny check` - `just fix` - `just fmt` - `cargo shear` - `just bazel-lock-check`
Adam Perry @ OpenAI ·
2026-06-11 18:16:39 -07:00 -
Fix image extension PathUri conversion (#27711)
## Why `main` stopped compiling when #27498 passed an `AbsolutePathBuf` to the `ExecutorFileSystem` API migrated to `PathUri` by #27653. ## What Convert referenced image paths to `PathUri` before filesystem reads, declare the internal path-URI dependency, and refresh `Cargo.lock`.
Adam Perry @ OpenAI ·
2026-06-12 00:15:19 +00:00 -
Route image extension reads through turn environments v2 (#27498)
## Why Image generation used `std::fs::read` for referenced image paths, which did not support environment-backed filesystems or their sandbox context. ## What changed - Expose optional turn environments to extension tool calls. - Include each environment’s ID, working directory, filesystem, and sandbox context. - Read referenced images through the selected environment filesystem. - Keep sandbox usage at the extension call site so extensions can choose the appropriate access mode. - Consolidate image request construction into one async function. - Add coverage for successful environment reads and read failures. ## Validation - `cargo check -p codex-image-generation-extension --tests` - `just fmt` - `just bazel-lock-update` - `just bazel-lock-check` `just test -p codex-image-generation-extension` could not complete because the build exhausted available disk space.
Won Park ·
2026-06-11 16:32:52 -07:00 -
[codex] Load user instructions through an injected provider (#27101)
## Why We want to remove implicit use of `$CODEX_HOME` from `codex-core` and make embedders responsible for supplying user-level instructions. This also ensures user instructions load when no primary environment is selected. ## What changed Stacked on #27415, which makes `codex exec` surface thread-scoped runtime warnings. - Added `UserInstructionsProvider` to `codex-extension-api`, with absolute source attribution and recoverable loading warnings. - Added `codex-home` with the filesystem-backed provider for `AGENTS.override.md` and `AGENTS.md`, preserving precedence, fallback, trimming, lossy UTF-8 handling, and the existing uncapped global instruction size. - Removed global instruction loading from `Config` and require `ThreadManager` callers to inject a provider. - Load provider instructions once for each fresh root runtime, including runtimes without a primary environment. Running sessions retain their snapshot, while child agents inherit the parent snapshot without invoking the provider. - Keep provider instructions separate while loading project `AGENTS.md`, then assemble the model-visible instructions with the existing ordering, source attribution, warning, and turn-context behavior. - Wired the Codex home provider through the CLI, app server, MCP server, core facade, and thread-manager sample. ## Validation - `just test -p codex-home -p codex-extension-api` - `just test -p codex-core agents_md` - `just test -p codex-core guardian` - `just test -p codex-app-server thread_start_without_selected_environment_includes_only_global_instruction_source` - `just test -p codex-exec warning` - `just bazel-lock-check`
Adam Perry @ OpenAI ·
2026-06-11 19:28:47 +00:00 -
[codex] migrate ExecutorFileSystem paths to PathUri (#27424)
## Why We're moving exec-server to use PathUri for its internal path representations. ## What Move `ExecutorFileSystem` APIs to use `PathUri` instead of `AbsolutePathBuf`. Future changes will convert higher-level parts of exec-server.
Adam Perry @ OpenAI ·
2026-06-11 18:44:18 +00:00 -
skills: decouple the skills extension from core (#27413)
## Why `ext/skills` currently depends on `codex-core` for two host concerns: reading the concrete `Config` type and borrowing core-owned model-context fragment types. That coupling prevents the extension from being assembled independently above core and leaves context that belongs to the skills feature owned by core. This stacked PR introduces the host boundary needed for the broader extension migration while intentionally preserving existing skills behavior. It is stacked on #27404. ## What changed - Adds a small public `SkillsExtensionConfig` view and makes skills installation generic over the host config type. - Requires the host to map its config into that view; app-server supplies the current `Config` values. - Moves the available-skills and selected-skill context fragment implementations into `ext/skills`, preserving their roles, markers, and rendered bytes. - Removes the direct `codex-core` dependency from `codex-skills-extension`. - Keeps local discovery, invocation, side effects, and the `codex-core-skills` compatibility types unchanged for later staged PRs. ## Behavior This adds no capability and is intended to have no user-visible or model-visible behavior change. The install API and ownership boundary change internally; emitted skills context remains byte-for-byte compatible. ## Validation - Updates the skills extension integration coverage to use a host-owned test config. - Asserts the complete rendered catalog and selected-skill fragments, including their roles and markers. - `just bazel-lock-check` - Rust tests and Clippy were not run locally per request; CI will run them.
jif ·
2026-06-11 14:03:53 +02:00 -
nit: cap error (#27585)
Just cap an error that could end up in the model context
jif ·
2026-06-11 12:52:46 +02:00 -
skills: expose remote skill resource tools (#27388)
## Why PR #27387 makes backend plugin skills discoverable and invocable without an executor, but resources referenced by those skills still sit behind the generic MCP resource surface. The model needs a skills-owned API that preserves the provider authority and package boundary instead of treating remote resources like local files. This is stacked on #27387. ## What - Adds one `skills` namespace with bounded `list` and `read` tools for remote skill providers. - Revalidates `authority + package` against the live remote catalog on every read, then routes the opaque resource ID back through that provider. - Allows the backend provider to read canonical child `skill://` resources while rejecting cross-package, non-canonical, query, fragment, and traversal-shaped URIs. - Caps each serialized tool result at 8 KB. Lists are paginated; reads return an opaque continuation cursor. - Marks the JSON output as external context so memory generation can apply its normal suppression policy. - Deliberately does not add `skills.search`; that waits for a bounded plugin-service search contract. ## Tool contract Pseudo-Python matching the wire shape: ```python from typing import Literal, NotRequired, TypedDict class RemoteSkillAuthority(TypedDict): kind: Literal["remote"] id: str # e.g. "codex_apps" class RemoteSkill(TypedDict): authority: RemoteSkillAuthority package: str # opaque provider-owned package ID name: str description: str main_resource: str # opaque provider-owned SKILL.md ID class SkillsListParams(TypedDict): cursor: NotRequired[str] class SkillsListResult(TypedDict): skills: list[RemoteSkill] next_cursor: str | None warnings: list[str] truncated: bool class SkillsReadParams(TypedDict): authority: RemoteSkillAuthority # copied from skills.list package: str # copied from skills.list resource: str # provider-owned child resource ID cursor: NotRequired[str] # copy next_cursor to continue class SkillsReadResult(TypedDict): resource: str contents: str next_cursor: str | None truncated: bool class Skills: def list(self, params: SkillsListParams) -> SkillsListResult: ... def read(self, params: SkillsReadParams) -> SkillsReadResult: ... ``` There is one namespace for all remote skills, not one tool or MCP server per skill. No resource ID is converted into a filesystem path. ## Backend dependency `/ps/mcp` must support direct reads of child resources such as `skill://plugin_demo/deploy/references/deploy.md`. This PR implements and tests the Codex side of that contract; production child reads remain dependent on the corresponding plugin-service support. Search remains out of scope until that service exposes a bounded search/resource API. ## Validation - Added an app-server integration test covering `skills.list` followed by `skills.read` with no executor. - Ran `just fmt`. - Ran `just bazel-lock-update` and `just bazel-lock-check`. - Did not run Rust tests or Clippy locally, per request; CI will run them.
jif ·
2026-06-11 12:38:04 +02:00 -
skills: make backend plugin skills invocable without an executor (#27387)
## Why #27198 made the extension-owned `codex_apps` MCP connection the hosted plugin runtime, but its `mcp/skill` resources still bypassed the skills extension. App-server could list and read those resources through generic MCP APIs, but a thread with no selected environment did not expose them in the model's skills catalog or load their `SKILL.md` through `$skill`. Hosted skills should stay remote while using the same typed catalog, source authority, deduplication, bounded contextual catalog, and selected-skill prompt injection as host and executor skills. They should not be downloaded or exposed as ambient filesystem paths. ## What changed - Add a session-scoped `McpResourceClient` over the replaceable MCP connection manager so resource list/read calls follow startup and refresh replacements. - Add a `BackendSkillProvider` that pages `codex_apps` resources, accepts bounded and validated `mcp/skill` entries, and reads a selected skill's `SKILL.md` through the same MCP connection. - Register the remote provider in app-server and include it in the skills catalog even when a thread has no selected capability roots or executor. - Contribute hosted skill metadata through the bounded `AvailableSkillsInstructions` developer-context path, exclude remote entries from per-turn catalog injection, and classify `<skills>` messages as contextual developer content so rollback can trim and rebuild them correctly. ## Testing - Extend the app-server MCP resource integration test with `environments: []` to exercise two-page discovery, filter a non-`mcp/skill` resource, verify the escaped developer catalog entry and user-role `<skill>` fragment containing the fetched `SKILL.md`, and preserve generic MCP resource reads. - Add core event-mapping coverage that classifies `<skills>` developer messages as contextual history.
jif ·
2026-06-11 11:28:16 +02:00 -
[codex] Remove async_trait from ToolExecutor (#27304)
## Why We're now [discouraging use of `async_trait`](https://github.com/openai/codex/pull/20242). Removing use of `async_trait` from `ToolExecutor` yields a `codex_core` debug test build speedup of ~78% (from 227.5s to 50.3s) on my machine. Stacked on #27299, this PR applies the trait change after the handler bodies have been outlined. ## What Changed `ToolExecutor::handle` to return an explicit boxed `ToolExecutorFuture` instead of using `async_trait`. Updated ToolExecutor implementors to return `Box::pin(...)`, reexported the future alias through `codex-tools` and `codex-extension-api`, and removed `codex-tools` direct `async-trait` dependency.
Adam Perry @ OpenAI ·
2026-06-10 10:26:53 -07:00