mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
bb72e151e50cfd4f6282ab86418188af3c83b5df
893 Commits
-
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 -
Remove async-trait from extension contributors (#27383)
## Why Extension contributors are registered behind `dyn Trait` objects, so native `async fn`/RPITIT methods would make these traits non-object-safe. Spell out the boxed, `Send` future contract directly so `extension-api` no longer needs `async-trait` while retaining the existing runtime model. ## What changed - add a shared `ExtensionFuture` alias and use it for asynchronous contributor methods - migrate production and test implementations to return `Box::pin(async move { ... })` - remove `async-trait` dependencies where they are no longer used, keeping it dev-only where unrelated test executors still require it ## Behavior No behavior change is intended. Contributor futures remain boxed, `Send`, dynamically dispatched, and lazily executed; cancellation and callback ordering stay unchanged. ## Testing - `just test -p codex-extension-api` (11 passed) - affected extension crates (64 passed) - targeted `codex-core` contributor tests (14 passed) - `just fmt` - `just bazel-lock-update` - `just bazel-lock-check` A broad local `codex-core` run compiled successfully but encountered unrelated sandbox and missing test-binary fixture failures; CI will run the full checks.jif ·
2026-06-10 14:31:09 +02:00 -
[codex-analytics] emit goal lifecycle analytics (#27078)
## Why - Currently, there is no analytics event for `/goal` behavior - Existing events cannot identify goal execution or its resulting outcome - The original update in [#26182](https://github.com/openai/codex/pull/26182) was implemented before `/goal` moved into `codex-goal-extension`. ## What Changed - Adds `codex_goal_event` serialization and enrichment to `codex-analytics` - Emits goal events from the canonical `codex-goal-extension` mutation and accounting paths: - `created` when a new logical goal is persisted - `usage_accounted` when cumulative goal usage is persisted - `status_changed` when the stored goal status changes - `cleared` when the goal is deleted - Preserves causal `turn_id` for turn driven events and uses null attribution for external or idle lifecycle events - Changes goal deletion to return the deleted row so `cleared` retains the stable goal ID ## Event Details Includes standard analytics metadata along with goal specific fields: - `goal_id`: Stable ID stored in the local SQLite goal row and shared across the goal's events - `event_kind`: Observed operation (see the 4 lifecycle events cited in the above bullet) - `goal_status`: Resulting or last stored status: `active`, `paused`, `blocked`, `usage_limited`, etc. - `has_token_budget`: Indicates whether a token budget is configured - `turn_id`: Causal turn ID, or null when no causal turn exists - `cumulative_tokens_accounted`: Cumulative tokens on `usage_accounted` events; null otherwise - `cumulative_time_accounted_seconds`: Cumulative active time on `usage_accounted` events; null otherwise ## Validation - `just test -p codex-analytics -p codex-state -p codex-goal-extension` - `just test -p codex-core -E 'test(/goal/)'` - `just test -p codex-app-server` - `cargo build -p codex-analytics -p codex-core -p codex-state -p codex-app-server`
marksteinbrick-oai ·
2026-06-09 18:45:54 -07:00 -
feat: use provider defaults for memory models (#27129)
## Why Memory startup used hardcoded OpenAI model slugs for extraction and consolidation. That works for the default OpenAI-compatible path, but provider-specific backends can require different model identifiers. In particular, Amazon Bedrock should use its Bedrock model ID for these background memory requests instead of the OpenAI `gpt-5.4-mini` / `gpt-5.4` slugs. ## What Changed - Added provider-owned preferred memory model methods alongside `approval_review_preferred_model`. - Updated memory extraction and consolidation to resolve their default model through the active `ModelProvider`. - Added Amazon Bedrock overrides so both memory stages use `openai.gpt-5.4` through Bedrock’s provider-specific model ID. - Kept explicit `memories.extract_model` and `memories.consolidation_model` config overrides taking precedence. - Added startup coverage for default OpenAI and Bedrock memory model selection. #closes #26288
Celia Chen ·
2026-06-09 23:49:09 +00:00 -
Route hosted Apps MCP through extensions (#27191)
## Stack - Base: #27184 - This PR is the second vertical and should be reviewed against `jif/external-plugins-1`, not `main`. ## Why CCA is moving toward a split runtime where the orchestrator may have no filesystem or executor, but it still needs to activate remotely hosted plugin components. HTTP MCP servers are the simplest complete example: they need configuration and host authentication, but they do not need an executor process. The Apps MCP endpoint is currently synthesized by a special-purpose loader inside the MCP runtime. That works locally, but it leaves hosted MCP activation outside the extension model being established in #27184. It also makes the Apps path a poor foundation for plugins whose skills, MCP servers, connectors, and hooks may come from different sources or execute in different places. This PR moves that one behavior behind an extension-owned contribution while preserving the existing local fallback. It deliberately does not introduce a generic plugin activation framework. ## What changed ### MCP extension contribution `codex-extension-api` gains an ordered `McpServerContributor` contract. A contributor returns typed `Set` or `Remove` overlays for MCP server configuration; later contributors win for the names they own. The contract stays at the existing MCP configuration boundary. Extensions do not create a second connection manager or transport abstraction. ### Hosted Apps MCP extension A new `codex-mcp-extension` contributes the reserved `codex_apps` server from the existing Apps feature, ChatGPT base URL, path override, and product SKU configuration. When `apps_mcp_path_override` is enabled for `https://chatgpt.com`, the resulting streamable HTTP endpoint is `https://chatgpt.com/backend-api/ps/mcp`. The existing ChatGPT-auth gate remains authoritative, so this server can run in an orchestrator-only process without being exposed for API-key sessions. ### One resolved runtime view `McpManager` now distinguishes three views: - **configured:** config- and plugin-backed servers before extension overlays; - **runtime:** configured servers plus host-installed extension contributions; - **effective:** runtime servers after auth gating and compatibility built-ins. App-server installs the hosted MCP extension and uses the runtime view for thread startup, refresh, status, threadless resource reads, connector discovery, and MCP OAuth lookup. This keeps `mcpServer/oauth/login` consistent with the servers exposed by the other MCP APIs. The hosted Apps server itself continues to use existing ChatGPT host authentication rather than MCP OAuth. ## Compatibility Hosts that do not install the MCP extension retain the existing Apps MCP synthesis path. This preserves current local-only, CLI, and standalone-host behavior while app-server exercises the extension path. Disabling Apps removes the reserved `codex_apps` entry, and losing ChatGPT auth removes it from the effective runtime view. Executor availability is not consulted for this HTTP transport. ## Follow-ups The next vertical will resolve a manifest-declared stdio MCP server from an executor-selected plugin root and execute it in the environment that owns that root. Later verticals can add backend-owned skills, connector metadata, hooks, durable selection semantics, and incremental local convergence without changing the component-specific runtime boundaries introduced here. ## Verification Focused coverage was added for: - contributing the hosted Apps MCP at `/backend-api/ps/mcp` without an executor; - requiring ChatGPT auth in the effective runtime view; - removing a reserved configured Apps server when the Apps feature is disabled. `cargo check -p codex-app-server -p codex-mcp-extension -p codex-extension-api -p codex-mcp` passed. Tests and Clippy were not run locally under the current development instruction; CI provides the full validation pass.
jif ·
2026-06-09 22:44:16 +02:00 -
[codex] Test extension API contracts (#26835)
## Why `codex-extension-api` defines contracts shared by extension crates and their hosts, but it had no direct test suite. Host and feature tests cover downstream behavior, while regressions in the API crate's own typed state, registry ordering, and capability adapters could go unnoticed. ## What - Add public-surface integration tests for `ExtensionData`, including concurrent initialization and poison recovery. - Cover contributor registration order, approval short-circuiting, event sink retention, no-op response injection, and closure-based agent spawning. - Add the test-only dependencies used by the suite. ## Validation - `just test -p codex-extension-api` - `just argument-comment-lint -p codex-extension-api` - `just bazel-lock-check`
Adam Perry @ OpenAI ·
2026-06-09 18:30:24 +00:00 -
Load selected executor skills through extensions (#27184)
## Why CCA is moving toward a split runtime where the orchestrator may not have a filesystem, while executors can expose preinstalled plugins and skills. A thread therefore needs to select capabilities without asking app-server or core to interpret executor-owned paths through the orchestrator's filesystem. The longer-term model is broader than executor skills: - A plugin is a bundle of skills, MCP servers, connectors/apps, and hooks. - A plugin root can be local, executor-owned, or hosted by a backend. - Components inside one plugin can use different access and execution mechanisms. A skill may be read from a filesystem or through backend tools; an HTTP MCP server can run without an executor; a stdio MCP server or hook needs an execution environment. - Core should carry generic extension initialization data. The extension that owns a component should discover it, expose it to the model, and invoke it through the appropriate runtime. This PR establishes that architecture through one complete vertical: selecting a root on an executor, discovering the skills beneath it, exposing those skills to the model, and reading an explicitly invoked `SKILL.md` through the same executor. ## Contract `thread/start` gains an experimental `selectedCapabilityRoots` field: ```json { "selectedCapabilityRoots": [ { "id": "deploy-plugin@1", "location": { "type": "environment", "environmentId": "workspace", "path": "/opt/codex/plugins/deploy" } } ] } ``` The root is intentionally not classified as a "plugin" or "skill" in the API. It can point at a standalone skill, a directory containing several skills, or a plugin containing skills and other components. This PR only teaches the skills extension how to consume it; later extensions can resolve MCP, connector, and hook components from the same selection. The platform-supplied `id` is stable selection identity. The location says which runtime owns the root and gives that runtime an opaque path. App-server does not inspect or canonicalize the path. ## What changed ### Generic thread extension initialization App-server converts selected roots into `ExtensionDataInit`. Core carries that generic initialization value until the final thread ID is known, then creates thread-scoped `ExtensionData` before lifecycle contributors run. This keeps `Session` and core independent of the capability-selection contract. The initialization value is consumed during construction; it is not retained as another long-lived `Session` field. ### Executor-backed skills The skills extension now owns an `ExecutorSkillProvider` that: - resolves the selected environment through `EnvironmentManager` - discovers, canonicalizes, and reads skills through that environment's `ExecutorFileSystem` - contributes the bounded selected-skill catalog as stable developer context - reads an explicitly invoked skill body through the authority that listed it - warns when an environment or root is unavailable - never falls back to the orchestrator filesystem for an executor-owned root Skill catalog and instruction fragments have hard byte bounds, which also bound them below the 10K-token per-item context limit. If a selected executor skill has the same name as a legacy local skill, the executor selection owns that invocation and the local body is not injected a second time. Existing local and bundled skill loading remains in place. Omitting `selectedCapabilityRoots` therefore preserves current local-only behavior. ## Current semantics - Only environment-owned locations are represented in this first contract. - Roots are resolved by the destination extension, not by app-server or core. - An unavailable executor or invalid root produces a warning and no capabilities from that root; it does not trigger a local-filesystem fallback. - Selection applies to a newly started active thread. - MCP servers, connectors, and hooks beneath a selected plugin root are not activated yet. - Selection is not yet persisted or inherited across resume, fork, or subagent creation. Existing local capabilities continue to behave as they do today in those flows. ## Planned vertical follow-ups 1. **Hosted HTTP MCP:** add an extension-backed HTTP MCP source that works without an executor, then replace the special-purpose MCP plugins loader with that implementation. 2. **Executor MCP:** register and execute stdio MCP servers through the environment that owns the selected plugin root. 3. **Backend skills:** add a hosted skill source whose catalog and bodies are accessed through extension tools rather than a filesystem. 4. **Connectors and hooks:** activate those components through their owning extensions, using the same selected-root boundary and component-specific runtime. 5. **Durable selection:** define the desired-selection lifecycle, persist it, and make resume, fork, and subagent inheritance explicit rather than accidental. 6. **Local convergence:** incrementally route existing local plugin, skill, and MCP loading through the same extension model while preserving current local behavior. Each follow-up remains reviewable as an end-to-end capability. The platform selects roots, generic thread extension data carries the selection, and the owning extension resolves and operates its component. ## Verification Coverage added for: - app-server end-to-end discovery and explicit invocation of a skill inside an executor-selected plugin root - exclusive invocation when a selected executor skill collides with a local skill name - executor filesystem authority for discovery, canonicalization, and reads - thread extension initialization before lifecycle contributors run - stable executor catalog context, explicit invocation, context rebuilding, hidden skills, and preserved host/remote catalog behavior Targeted protocol, core-skills, skills-extension, core lifecycle, and app-server executor-skill tests were run during development.jif ·
2026-06-09 19:51:54 +02:00 -
Add typed file URIs (#26840)
## Why Codex needs stable `file:` URI identifiers that can cross process and operating-system boundaries without eagerly interpreting them as native paths. Existing fields also need to keep accepting absolute path strings during migration. ## What changed - Add `codex-utils-path-uri` with a validated, immutable `PathUri` wrapper that currently accepts only `file:` URLs. - Expose URI-level `basename`, `parent`, and `join` operations that preserve authorities and percent encoding without guessing the source operating system. - Keep native conversion explicit through `AbsolutePathBuf` and the current host rules. - Serialize as canonical URI text while accepting both URI text and legacy absolute native paths during deserialization. - Add adversarial coverage for Windows-looking and POSIX paths, UNC authorities, encoded metadata characters, non-UTF-8 POSIX paths, URI hierarchy operations, and legacy serde round trips.
Adam Perry @ OpenAI ·
2026-06-08 16:33:41 -07:00 -
Route image edits through referenced file paths (#26486)
## Why Image edits should use the exact images selected by the model instead of inferring edit inputs from conversation history. ## What changed - Replaced the image tool's `action` argument with optional `referenced_image_paths`. - Treats omitted or empty references as generation and populated references as editing. - Reads referenced absolute image paths and packages them as image data URLs for the edit request. - Removed the previous history-selection and image-count heuristics. - Updated direct and code-mode tool instructions and calls. - Added an app-server integration test covering an attached image routed to the image edit endpoint. ## Validation - Tested end-to-end on local `just codex` with copy pasted image, attached image, etc. - `just test -p codex-image-generation-extension` - `just test -p codex-app-server standalone_image_edit_uses_attached_model_visible_image` - `just fix -p codex-image-generation-extension` - `just bazel-lock-check`
Won Park ·
2026-06-08 14:23:55 -07:00 -
Michael Bolin ·
2026-06-07 17:35:33 -07:00 -
Channing Conger ·
2026-06-06 14:27:23 -07:00 -
[codex] Use standalone tools for Responses Lite (#26490)
## Summary Responses Lite does not execute hosted Responses tools, so models using it must route web search and image generation through Codex-owned executors & standalone Response's API endpoints. This PR is stacked on #26487. ## Validation - `cargo test -p codex-core responses_lite_ --lib` - `cargo test -p codex-core standalone_executors_remain_hidden_without_flags_or_responses_lite --lib` - `cargo test -p codex-core hosted_tools_follow_provider_auth_model_and_config_gates --lib` - `cargo test -p codex-web-search-extension -p codex-image-generation-extension` - `cargo test -p codex-app-server --test all standalone_` - `cargo fmt --all -- --check`
rka-oai ·
2026-06-06 00:23:40 +00:00 -
[2 of 2] Finish moving goal runtime to extension (#26548)
## Stack 1. [#26547](https://github.com/openai/codex/pull/26547) - [1 of 2] Align goal extension with core behavior 2. [#26548](https://github.com/openai/codex/pull/26548) - [2 of 2] Move goal runtime to extension ## Why This PR completes the switch of the goal behavior to the extension-backed runtime and removes the old core goal implementation. ## What Changed - Installs the goal extension for app-server `ThreadManager` sessions. - Routes app-server thread goal `get`, `set`, and `clear` through `GoalService`. - Uses thread-idle lifecycle emission after goal resume and snapshot ordering so the extension can decide whether to continue the goal. - Forwards extension goal updates through a FIFO async app-server notification path so backpressure does not drop them or reorder updates. - Keeps review turns from enabling goal runtime behavior. - Plans extension tools before dynamic tools so built-in goal tool names keep their old precedence when goals are enabled. - Removes the old core goal runtime, core goal tool handlers, and core goal tool specs. - Updates tests that were coupled to the core-owned goal runtime while leaving the legacy `<goal_context>` compatibility path in core for old threads. - Removes the stale cargo-shear ignore now that `codex-goal-extension` is used by the workspace. - Keeps realtime event matching exhaustive after removing the old goal-specific realtime text path. ## Validation - Ran manual `/goal` runs in TUI. Validated time accounting matched wall-clock time and goal lifecycle state transitions.
Eric Traut ·
2026-06-05 14:17:30 -07:00