Commit Graph
7508 Commits
Author SHA1 Message Date
cooper-oaiandGitHub d1aaf789ad [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`
2026-06-12 12:38:30 -07:00
Celia ChenandGitHub b724f5966e feat: add secret auth storage configuration (#27504)
## Why

Windows Credential Manager limits generic credential blobs to 2,560
bytes. The encrypted local secrets backend avoids storing large
serialized auth payloads directly in the OS keyring, but selecting that
backend needs an independently reviewable feature/config layer before
the auth and secrets implementation is wired in.

## What Changed

- Added the stable `secret_auth_storage` feature, enabled by default on
Windows and disabled by default elsewhere.
- Added `AuthKeyringBackendKind` and config resolution for full and
bootstrap config loading.
- Applied managed feature requirements when resolving the bootstrap auth
backend.
- Updated the generated config schema and added focused tests.

This is the base PR for #17931. The auth, secrets, MCP, CLI, TUI, and
app-server implementation remains in that follow-up PR.

## Validation

- `just test -p codex-features`
- `just test -p codex-config`
- `just test -p codex-core
resolve_bootstrap_auth_keyring_backend_kind_uses_secret_auth_storage_feature`
- `just write-config-schema`
- `just fix -p codex-core`

The full `just test -p codex-core` run compiled successfully and ran
2,690 tests; 2,589 passed, one was flaky, and 101 environment-sensitive
tests failed because this shell injects a `pyenv` rehash warning into
command output or because sandboxed subprocesses timed out.
2026-06-12 19:15:21 +00:00
pakrym-oaiandGitHub 76d8f20241 [codex] Add size to internal filesystem metadata (#27927)
## Why

`ExecutorFileSystem::get_metadata` reports file kind and timestamps but
not size. Internal callers that need to enforce a size limit therefore
have to read the complete file first, which is especially wasteful for
remote filesystems.

This adds the missing internal metadata so consumers can reject
oversized files before transferring or buffering them. The field is
named `size`, matching VS Code's `FileStat.size` filesystem convention.

## What changed

- add `size: u64` to internal `FileMetadata`
- populate it from the underlying filesystem metadata
- carry it through sandbox-helper and remote exec-server responses
- cover files, directories, symlink targets, and sandboxed reads across
local and remote filesystem implementations

The new field is intentionally not exposed through the app-server API.

## Testing

- `just test -p codex-exec-server get_metadata`
- `just test -p codex-exec-server
file_system_sandboxed_metadata_and_read_allow_readable_root`
- `just test -p codex-core-plugins`
- `just test -p codex-skills-extension`
2026-06-12 12:12:08 -07:00
Won ParkandGitHub b6baa77eec Handle standalone image generation failures as terminal items (#27920)
## Why

Standalone image generation emitted a started item but no terminal item
when the backend failed. Clients could leave the operation unresolved or
render it as successful.

## What changed

- Emit a terminal image-generation item with `status: "failed"` when
generation or editing fails.
- Skip image persistence for failed terminal items.
- Render failed image generation distinctly in TUI history.
- Preserve the status when handling live and replayed terminal items.

## Looks for TUI, App-Side change needed 

<img width="867" height="89" alt="image"
src="https://github.com/user-attachments/assets/9e32342f-a982-411e-8498-456639fc468a"
/>

## Validation

- `just test -p codex-image-generation-extension`
- App-server image-generation tests
- Core stream-event tests
- TUI image-generation lifecycle and snapshot tests
- Scoped Clippy and formatting
2026-06-12 11:57:22 -07:00
pakrym-oaiandGitHub e26f734f91 [codex] unify apply patch parsing (#27913)
## Why

`apply_patch` maintained separate batch and streaming parsers for the
same patch grammar. That duplicated the parsing rules and allowed final
execution to disagree with the live streamed preview.

## What changed

- Make `StreamingPatchParser` the single owner of hunk and environment
ID parsing.
- Keep heredoc and outer patch-boundary normalization in the existing
`parse_patch` wrapper, preserving its public API.
- Reject non-whitespace content after `*** End Patch` and preserve
separator handling after `*** End of File`.
- Reject duplicate environment ID preambles explicitly.
- Remove the duplicate batch hunk parser and its implementation-specific
tests.

The change removes 201 net lines while retaining focused coverage for
the unified parser's boundary behavior.

## Validation

- `just test -p codex-apply-patch`
- Compared a 24-hour corpus of 2,788,059 observed `apply_patch` payloads
against the previous batch parser. All 2,779,502 accepted payloads
produced identical hunks, canonical patch text, and environment IDs; the
remaining 8,557 payloads were rejected by both parsers, with zero
acceptance or payload mismatches.
2026-06-12 11:54:28 -07:00
Eric NingandGitHub 9600afb1a1 [codex] expose remote plugin share URL (#27890)
## Summary

- expose the remote plugin detail endpoint's `share_url` as nullable
`PluginDetail.shareUrl`
- preserve existing `PluginSummary.shareContext` behavior for local and
workspace sharing flows
- regenerate the app-server TypeScript and JSON schema fixtures

## Why

The remote plugin detail response already includes a canonical
`share_url`, but that value was not surfaced by `plugin/read` for global
plugins. Global plugins intentionally have no `shareContext`, so using
that model for the URL would change the semantics consumed by the
existing share modal.

## User impact

Codex clients can use `PluginDetail.shareUrl` for a remote plugin's
copy-link action, including when the plugin is disabled by an
administrator, without changing existing share-modal or ownership
behavior.

## Validation

- `cargo test -p codex-app-server
plugin_read_includes_share_url_for_admin_disabled_remote_plugin`
- `cargo test -p codex-app-server-protocol
typescript_schema_fixtures_match_generated`
- `cargo test -p codex-app-server-protocol
json_schema_fixtures_match_generated`
- `cargo fmt --all`
2026-06-12 11:53:55 -07:00
Adam Perry @ OpenAIandGitHub 52a50aec70 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.
2026-06-12 11:38:01 -07:00
jifandGitHub 84520225b9 chore: prompt MAv2 (#27919)
Prompt update of MAv2
2026-06-12 20:17:12 +02:00
Peter BakkumandGitHub 6652e82dd0 realtime: add AVAS architecture override (#27720)
## Summary

Adds a `RealtimeConversationArchitecture` option for realtime
conversation startup, with `realtimeapi` as the default and `avas` as an
opt-in architecture.

The AVAS path is limited to realtime v1 conversational WebRTC starts,
and WebRTC call creation appends `intent=quicksilver&architecture=avas`
to `/v1/realtime/calls`. The existing sideband websocket still joins by
`call_id`.

This also exposes the per-session architecture override through
app-server v2 `thread/realtime/start` params and updates the config
schema for `[realtime].architecture`.

## Validation

- `just fmt`
- `just write-config-schema`
- `just test -p codex-api sends_avas_session_call_query_params`
- `just test -p codex-core -E
'test(~conversation_webrtc_start_uses_avas_architecture_query)'`
- `just test -p codex-core -E 'test(realtime_loads_from_config_toml)'`
- `just test -p codex-app-server-protocol -E
'test(~serialize_thread_realtime_start) |
test(generated_ts_optional_nullable_fields_only_in_params)'`
- `just test -p codex-app-server -E
'test(realtime_webrtc_start_emits_sdp_notification)'`
2026-06-12 18:11:13 +00:00
Charlie MarshandGitHub 94427aaf46 Use uv as Python SDK build backend (#27901)
## Summary

Replace Hatchling with uv's build backend for the Python SDK. The
backend infers the `src/openai_codex` module from the normalized project
name and standard source layout, so no uv-specific package configuration
is required.

This keeps Python packaging within the uv toolchain already used for
dependency management and release builds. A controlled before-and-after
PEP 517 comparison produced identical wheel package paths, bytes,
permissions, and semantic metadata. The sdist retains the SDK package
tree, root README, and project metadata while dropping the unrelated
examples README that Hatch included through its broad include matching.
2026-06-12 17:21:00 +00:00
Brent TrautandGitHub d735ef162f tui: Allow extra o's in /goal command (#27814)
## Why

The TUI rejected playful `/goal` spellings such as `/goooooooooooal`,
even though Codex Apps accepts them for the World Cup promotion. This
keeps the TUI behavior consistent without changing how the canonical
command is presented.

## How it works

Built-in command lookup recognizes lowercase `go+al` as the existing
`goal` command after normal exact-name parsing fails. The command
catalog remains unchanged, so autocomplete continues to advertise
`/goal` normally.

## Verification

Added lookup-level and end-to-end TUI coverage for the flexible
spelling. The focused tests, scoped Clippy checks, and formatting pass.
The full `codex-tui` suite passed 2,833 of 2,835 tests; the two failing
guardian feature-flag tests reproduce unchanged on fresh `origin/main`.
2026-06-12 09:30:25 -07:00
Eric TrautandGitHub 096e5e76a2 Persist update dismissal without cache (#27783)
## Summary

Choosing “Don’t remind me” can silently fail when `version.json`
disappears before dismissal because `dismiss_version` returns success
without writing anything. The same update can then reappear on the next
launch.

Initialize a minimal `VersionInfo` from the selected version when the
cache cannot be read, then persist the dismissal through the existing
write path.

Fixes #27147
2026-06-12 09:26:08 -07:00
Charlie MarshandGitHub c375deaf66 Use dependency groups for Python SDK tooling (#27538)
## Summary

`just fmt` previously used `uv run --with ruff` to make Ruff available.
Because `--with` creates an ephemeral overlay outside the project
lockfile, uv periodically re-resolved Ruff (by default every 10 minutes)
instead of using the version recorded in `uv.lock`.

Move the Python SDK tooling dependencies from the published `dev` extra
into `format`, `test`, and composed `dev` dependency groups. The
formatter now selects only the locked `format` group, contributor and CI
setup explicitly sync the `dev` group, and CI and release commands reuse
that environment with `--frozen --no-sync`. The scripts formatter also
uses its project's locked Ruff dependency instead of an ephemeral
overlay.

Validated the Python 3.12 SDK suite (119 passed, 38 skipped) and the
repository formatter.
2026-06-12 16:10:07 +00:00
Alex ZamoshchinandGitHub 3cac2e0d3f [ez][codex-rs] Support approvals reviewer in app defaults (#27075)
[from codex]

## Summary

- add `approvals_reviewer` support to `[apps._default]`
- resolve connected-app reviewers in per-app, app-default, then global
order
- expose the setting through the v2 config API and regenerate schema
fixtures

## Context

PR #25167 added `apps.<connector_id>.approvals_reviewer`, but the shared
app defaults table could not specify the reviewer. This extends the same
behavior to `[apps._default]` while preserving per-app overrides.

Managed `allowed_approvals_reviewers` requirements still constrain both
default and per-app values. A disallowed app value falls back to the
global reviewer, and non-app MCP servers continue using the global
reviewer.

## Testing

- `just write-config-schema`
- `just write-app-server-schema`
- `just fmt`
- `just test -p codex-config`
- `just test -p codex-core app_approvals_reviewer`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server config_read_includes_apps`
2026-06-12 09:06:58 -07:00
Eric TrautandGitHub 5b8e3c6d40 Reject transcript backtrack in side conversations (#27791)
## Why

Fixes #27735.

Side conversations are ephemeral forks, and thread rollback currently
requires persisted thread history. The normal backtrack path already
rejected editing previous prompts in side conversations, but
transcript-mode backtrack could still call the rollback path and surface
the core `thread/rollback` failure as a TUI error.

## What changed

- Moved the existing side-conversation edit rejection message into
`app_backtrack.rs` so backtrack rollback code can reuse it.
- Added a side-conversation guard in `apply_backtrack_rollback` so
transcript-mode confirmation is rejected before submitting
`thread/rollback`.

## Verification

- `just test -p codex-tui
app::tests::side_backtrack_rejection_reports_unavailable_message_snapshot`
2026-06-12 08:58:08 -07:00
jifandGitHub b65fe3d897 fix: serialize auth environment tests (#27879)
## Summary
- serialize the remaining login tests that mutate or read the
process-global auth environment
- include Bedrock auth-manager tests in the existing `codex_auth_env`
serial group

## Root cause
The login unit-test binary runs tests concurrently. One test removed
`CODEX_ACCESS_TOKEN` without joining the existing serial group, while
several Bedrock tests constructed `AuthManager` and read that same
process-global environment outside the group. An interleaving could
restore a stale personal access token while another test was loading
file-backed auth, causing the observed mismatched `/whoami` request
count and related auth-state flakes.

## Verification
- `just fmt`
- `git diff --check`
- `bazel test //codex-rs/login:login-unit-tests --nocache_test_results
--runs_per_test=20 --test_output=errors` (20/20 passed)
- `just test -p codex-login` (135/135 passed)
2026-06-12 16:24:08 +02:00
stefanstokic-oaiandGitHub 743a4147d9 [codex] restore source-specific import copy (#27703)
## Summary

- restore source-specific wording across the `/import` picker, lifecycle
messages, diagnostics, and help text
- update the matching Unix and Windows snapshots
- leave import behavior unchanged

## Why

The import path currently supports one source, so the UI should identify
that source directly instead of presenting the flow as
provider-agnostic.

## Validation

- `just test -p codex-tui external_agent_config_migration` (12 passed)
- `just fix -p codex-tui`
- `just fmt`
2026-06-12 10:19:17 -04:00
jifandGitHub 17b9f4843e 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.
2026-06-12 15:10:05 +02:00
jifandGitHub 267eacfca2 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.
2026-06-12 13:37:33 +02:00
rka-oaiandGitHub c09df9e353 [code-mode] Reject remote image URLs from output helpers (#27732)
## Summary

- reject HTTP(S) image URLs from the shared code-mode output-image
normalization path
- return a concise model-visible tool error so the model can recover on
its next turn
- apply the targeted rejection to both `image()` and `generatedImage()`
- leave other non-empty image URL values to existing downstream handling

The returned error is:

> Tool call failed: remote image URLs are not supported in tool outputs.
Pass a base64 data URI instead

## Why

Responses Lite cannot lower a remote image URL emitted from a structured
tool output. Rejecting HTTP(S) values in the Codex harness preserves the
tool-call metadata and gives the model a recoverable next turn instead
of invalidating the sample.

## Test coverage

The regression is covered primarily by a `test_codex()` agent
integration test that simulates the Responses API exchange and asserts
the failed model-visible exec output. A supplemental runtime test covers
both `http://` and `https://` inputs across both image output helpers.

## Test plan

- `cd codex-rs && just test -p codex-code-mode`
- `cd codex-rs && just test -p codex-code-mode-protocol`
- `cd codex-rs && just test -p codex-core
code_mode_image_helper_rejects_remote_url`
- `cd codex-rs && just fmt`
- `git diff --check origin/main...HEAD`

Related context: https://github.com/openai/openai/pull/1022346
2026-06-12 02:49:17 -07:00
jifandGitHub 693082f3c4 Make MCP server contributions thread-scoped (#27670)
## Why

`selectedCapabilityRoots` belongs to one thread, but MCP contributors
previously received only the global Codex config. That left no clean way
for a selected executor capability to contribute MCP servers to its own
thread.

## What this PR does

- Gives MCP contributors a small context containing the config and, for
a running thread, its frozen host-seeded inputs.
- Uses the same thread inputs during startup, status queries, refreshes,
and skill dependency checks.
- Keeps threadless MCP operations and the existing hosted Apps behavior
unchanged.
- Adds coverage showing that two threads resolve independent
registrations and that later lifecycle mutations do not change the
frozen MCP inputs.

This PR does not discover plugin manifests, add MCP servers, or launch
anything new. It only establishes the thread-scoped registration
boundary.

## Follow-ups

- Resolve selected executor plugin roots through their owning
environment filesystem.
- Convert their stdio MCP declarations into environment-bound
registrations and add an executor MCP end-to-end test.

## Verification

- `just fmt`
- `cargo check --tests -p codex-protocol -p codex-extension-api -p
codex-mcp-extension -p codex-core -p codex-app-server`

Tests and Clippy were not run.
2026-06-12 11:20:34 +02:00
Adam Perry @ OpenAIandGitHub bf667c7003 [codex] Load AGENTS.md from all bound environments (#27696)
## Why

We already have the machinery to support multiple environments on a
single thread, but we only show the model the contents of `AGENTS.md`
files in the primary environment.

We should show the model all of the relevant project instructions when
we know there's more than one environment.

## Known Gaps

As discussed in the RFC, this implementation:

1. doesn't handle environments being added/removed to/from the thread
after its creation
2. it doesn't enforce an aggregate context budget across environments,
and instead applies the configured project maximum independently to each
environment

## Implementation

- Discover project instructions in environment order with an independent
byte budget per environment and preserve source provenance/order.
- Keep the legacy fragment byte-for-byte when exactly one environment
contributes project instructions; use environment-labeled sections when
two or more environments contribute.
- Freeze the complete rendered fragment in `LoadedAgentsMd`, insert it
directly into requests, and recognize both layouts in contextual and
memory filtering.
- Add exact rendering, independent-budget, source-order,
creation-snapshot, and consumer coverage without changing app-server
schemas.
2026-06-12 00:10:06 -07:00
Shijie RaoandGitHub 7a19b14229 Keep request_user_input direct-model only (#27316)
## Why

`request_user_input` has direct blocking semantics when invoked by the
model. When it is exposed as a nested code-mode tool, the call has to
flow through code-mode waiting and continuation behavior instead, which
is not the behavior we want for this user-input request surface.

## What changed

- Mark `request_user_input` with `ToolExposure::DirectModelOnly` when
registering the core utility tool.
- Keep `request_user_input` direct-model visible, including in
code-mode-only planning.
- Add focused `spec_plan_tests` coverage that verifies
`request_user_input` remains visible and registered as
direct-model-only, while it is omitted from the nested code-mode tool
description.

No active goal suppression or runtime unavailability behavior is
included in this PR.

## Validation

- No new build/test run for this housekeeping pass, per maintainer
request.
- Earlier targeted run, confirmed from session context: `just test -p
codex-core request_user_input` passed.
2026-06-11 23:23:44 -07:00
Eric TrautandGitHub a94deb5fa7 Translate non-English issues (#27778)
Issues written in languages other than English, such as #26979, require
manual translation before the development team can triage them.

This adds an `Issue Translator` workflow that uses Codex when an issue
is opened. For non-English reports, it replaces the title with an
English translation, preserves the original body, and posts the
translated body as an idempotent issue comment.

The translation scripts were run manually against non-English issue
content and produced the expected English title and comment output.
2026-06-11 23:20:36 -07:00
Channing CongerandGitHub aa46f2debf 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.
2026-06-11 22:37:26 -07:00
Shijie RaoandGitHub 216ce03031 Add request_user_input auto-resolution window contract (#27256)
## Why

`request_user_input` is moving beyond its original plan-mode-only
workflow, and future default/goal-mode usage needs a way for the model
to ask helpful but non-blocking questions without forcing the turn to
wait forever. This PR adds an explicit `autoResolutionMs` contract so a
later client/runtime change can auto-resolve unanswered prompts after a
bounded window while leaving truly blocking questions unchanged.

This is contract plumbing only; it does not implement the client-side
timer or auto-selection behavior, and the model-facing description
treats the field as reserved unless the current runtime explicitly
supports auto-resolution.

## What Changed

- Added optional `autoResolutionMs` to the model-facing
`request_user_input` args and core `RequestUserInputEvent`.
- Added model-facing schema text for `autoResolutionMs` while marking it
reserved for runtimes that explicitly support auto-resolution.
- Bounds `autoResolutionMs` to `60_000..=240_000` ms during argument
normalization by clamping out-of-range model-provided values.
- Propagated the field through app-server v2
`ToolRequestUserInputParams`, app-server request forwarding, generated
TypeScript, and JSON schema fixtures.
- Updated app-server, core, protocol, and TUI call sites/tests so
omitted values preserve existing `None`/`null` behavior and coverage
verifies a `Some(60_000)` round trip.

## Verification

- `just test -p codex-app-server-protocol`
- `just test -p codex-core request_user_input`
- `just test -p codex-app-server request_user_input_round_trip`
- `just test -p codex-tui request_user_input`
- `just test -p codex-protocol`
2026-06-11 22:30:41 -07:00
Eric TrautandGitHub 78bab04116 [1 of 3] Support long raw TUI goal objectives (#27508)
## Stack

1. **[1 of 3] Support long raw TUI goal objectives** - this PR
2. [2 of 3] Support long pasted text in TUI goals - #27509
3. [3 of 3] Support images in TUI goals - #27510

## Why

`thread/goal/set` limits persisted objective text to 4000 characters.
The TUI used to reject raw `/goal` objectives above that limit, even
though the client can make them usable by writing the long text to a
file and storing a short objective that points at that file.

This also needs to work for remote app-server sessions: filesystem API
calls must create files on the app-server host, and the stored path must
be meaningful to the agent on that host.

## What Changed

- Adds an app-server-host path helper so TUI code can build paths that
are resolved on the app-server host rather than the TUI host.
- Adds TUI app-server session helpers for `fs/createDirectory`,
`fs/writeFile`, `fs/readFile`, and `fs/remove` that work for embedded
and remote app-server sessions without changing the app-server protocol.
- Materializes oversized raw `/goal` objectives into
`$CODEX_HOME/attachments/<uuid>/goal-objective.md` through the
app-server filesystem APIs, then stores a short, readable objective that
directs the agent to that file.
- Reads managed objective files back for `/goal edit`. Other goal UI
renders the readable stored objective normally, without
managed-file-specific presentation logic.
- Recognizes managed references only when they name the expected
generated file under the app server's reported `$CODEX_HOME`, and cleans
up newly materialized files when goal replacement or setting does not
complete.

## Verification

- Added/updated TUI tests for raw oversized `/goal` submission, large
inline-paste expansion, queued oversized goals, app-facing
materialization before `thread/goal/set`, managed-path validation,
editing, and cleanup.
- Added/updated app-server-client remote coverage for initialized remote
Codex home handling.

## Manual Testing

- Ran the real TUI against a Unix-socket app server with different local
and server `$CODEX_HOME` directories. Oversized goals wrote only under
the server home, and persisted references used the server-canonical path
rather than the TUI path.
- Exercised 3,999-, 4,000-, and 4,001-character raw objectives. The
first two stayed inline without new files; the 4,001-character objective
became a managed objective file.
- Submitted a larger 8,275-character objective, verified its full
contents on the app-server host, and observed the goal continuation open
the referenced server-side file.
- Opened `/goal edit` for a managed objective and verified the full text
was restored through remote `fs/readFile`.
- Submitted an oversized replacement while a goal was active, verified
no file was written before confirmation, then canceled and confirmed
that the existing goal and attachment count were unchanged.
2026-06-11 22:26:31 -07:00
Anton PanasenkoandGitHub d61dfeb23a feat(app-server): persist remote-control desired state (#27445)
## Why

Remote-control runtime enablement and persisted enrollment preference
were represented by separate flags. That made startup rehydration, RPC
persistence, and new-enrollment seeding race with one another, and it
did not cleanly distinguish runtime-only CLI or daemon starts from
durable app-server RPC changes.

## What Changed

- Replace the parallel enablement, seed, and rehydration flags with one
transport-owned `RemoteControlDesiredState`.
- Add nullable enrollment-scoped persistence and preserve existing
preferences during enrollment upserts.
- Rehydrate plain startup only after auth and client scope resolve,
without overwriting a concurrent RPC transition.
- Make ordinary `remoteControl/enable` and `remoteControl/disable`
durable while retaining `ephemeral: true` for runtime-only callers.
- Have the daemon explicitly request ephemeral enablement and regenerate
the app-server schemas.

## Verification

- Covered migration and `NULL`/`0`/`1` persistence round trips.
- Covered plain-start rehydration and runtime-only versus durable
enrollment seeding.
- Covered durable enable, durable disable, and ephemeral enable through
app-server RPC.
- Covered the daemon's exact `{ "ephemeral": true }` request payload.

Related issue: N/A (internal remote-control persistence architecture
change).
2026-06-11 21:28:52 -07:00
pakrym-oaiandGitHub be338ee9a2 [codex] resolve environment shell metadata eagerly (#27709)
## Why

Turn construction passed resolved environments through several layers
while leaving the environment shell unresolved. As a result,
model-visible environment context could fall back to the session shell
instead of reporting the selected remote environment's shell.

Resolve environment metadata at the turn-context boundary so each turn
carries the shell that belongs to its selected environment. Keep request
validation in app-server, where invalid selections can be returned as
straightforward JSON-RPC errors without coupling core turn construction
to that policy.

## What changed

- resolve environment selections eagerly in
`new_turn_context_from_configuration`
- store the full resolved `Shell` on each `TurnEnvironment`
- simplify the now-redundant resolved-environment constructor plumbing
- keep duplicate and unknown-environment validation as a small
app-server preflight
- add a remote-environment integration test that runs a full
`test_codex` turn and verifies the model-visible environment message
reports `bash`

## Testing

- `cargo check -p codex-core --test all -p codex-app-server`
- `remote_test_env_exposes_bash_shell_to_model` on the Linux
remote-executor harness
2026-06-11 20:35:28 -07:00
Tamir DubersteinandGitHub e23d4df4ff [codex] parallelize release code generation (#27702)
The release profile still uses one codegen unit, which serializes LLVM
code generation within each crate. That setting was selected alongside
fat LTO for optimization quality and binary size, but releases now use
ThinLTO and code generation dominates the critical-path build.

Use four codegen units. On an Apple M4 Max with 16 cores and 128 GiB
RAM, using rustc 1.96.0, four and eight units took 507.486 and 505.325
seconds respectively. Four therefore keeps the build-time gain while
limiting the stripped `codex` increase to 14.7%, compared with 21.5% at
eight units. The gzip-compressed binary grows 7.8% at four units.

The one-unit build from an empty target directory took 981.150 seconds.
That comparison also populated dependency and native build caches, so it
is directional rather than controlled. It agrees with the earlier clean
matrix where eight units reduced 671 seconds to 303 seconds:
https://gist.github.com/anp/4b88393a0acd35783d9f42156f3243d5

At the local 48% reduction, the current release's 55m22s critical-path
macOS Cargo step would save about 26 minutes from the 71m28s workflow:
https://github.com/openai/codex/actions/runs/27367405663

The prompt-image medians ranged from 3.9% faster to 0.9% slower. CLI
startup shifted by 1-2 ms while user and system CPU time were unchanged.

This is a draft because the release-latency improvement may not justify
the binary-size increase.
2026-06-11 19:44:36 -07:00
Channing CongerandGitHub 16c7c79540 ci(v8): gate Windows source builds on relevant changes (#27715)
Avoid rebuilding sandboxed Windows MSVC V8 artifacts for unrelated
changes to `codex-rs/Cargo.toml`.

The V8 canary now compares the resolved V8 version between the base and
head commits and only runs the Windows source-build matrix when:

- the resolved V8 crate version changes;
- Windows artifact-production scripts or workflows change; or
- the workflow is manually dispatched.

The existing Bazel V8 matrix is unchanged.

## Why

The Windows MSVC source builds take roughly two to three hours and
currently run whenever any entry in the broad `v8-canary` path filter
changes.
2026-06-11 18:44:42 -07:00
David de RegtandGitHub 69b0f52b2a fix: Recover from sqlite directory being a file (#27719)
Missed this file in the last PR -- this ensures that if you're in the
really-weird edge case of your sqlite directory being a file, that it
will fix it and recover properly.
2026-06-11 18:23:16 -07:00
Adam Perry @ OpenAIandGitHub 5a56caf18c [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`
2026-06-11 18:16:39 -07:00
Adam Perry @ OpenAIandGitHub 1829ed1122 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`.
2026-06-12 00:15:19 +00:00
Mitsuhiro KotakeandGitHub 44403dd3dd tui: clear stale hook row after turn completion (#27619)
Fixes #27210.

## Why
When the app server reports a visible `HookStarted` event for a
`PostToolUse` hook but the turn reaches `TurnCompleted` before a
matching hook completion event arrives, the TUI can leave the transient
`Running PostToolUse hook` row visible after the agent is done.
Interrupted and failed turn cleanup already drops transient live hook
rows; the normal completion path did not.

## What Changed
- Added `ChatWidget::clear_active_hook_cell()` for dropping transient
live hook status without writing it to history.
- Call that cleanup from normal task completion, while reusing it for
the existing start/finalize cleanup paths.
- Added `completed_turn_clears_visible_running_hook` snapshot coverage
for the reported `PostToolUse` case.

## Tests
- `just test -p codex-tui completed_turn_clears_visible_running_hook`
- `just test -p codex-tui` (fails on current `main` in unrelated
guardian tests:
`update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
and
`update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`)
2026-06-12 09:15:04 +09:00
mchen-oaiandGitHub 92d9036910 Add spans to turn lifecycle gaps (#27623)
## Why
Codex app-server latency traces do not granularly cover turn task
startup and inter-request handoffs. These spans help attribute time
across task execution, startup prewarm, in-flight tool completion, and
rollout persistence.

## What changed
- Add `session_task.run` spans around task execution and
`session_task.flush_rollout` around flushing pending conversation
transcript writes to durable storage
- Add `regular_task.prepare_run_turn` around regular-turn startup (Send
the `TurnStarted` event, reset turn-specific reasoning state, and
resolve any startup prewarm)
- Add `startup_prewarm.resolve` around waiting for background session
prewarming to finish, fail, time out, or be cancelled
- Add a function-level trace span around draining in-flight tool calls
(Wait for tool calls to complete, record tool result in conversation
history, and other bookkeeping)

## Verification
Trigger Codex rollout and observe new spans are included
2026-06-11 16:55:01 -07:00
Won ParkandGitHub 19ce6394af 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.
2026-06-11 16:32:52 -07:00
TomandGitHub b2cc01fc7c [codex] Move persistence policy application into ThreadStore (#27318)
Move the application of the persistence policy into the thread store, so
thread stores can get raw append items rather than canonical append
items. This will enable store-specific projections over the raw input
items.
2026-06-11 16:24:12 -07:00
AbhinavandGitHub eddc5c75ed Warn when hooks.json has unsupported top-level fields (#26426)
Addresses #25875.

## Summary

`hooks.json` accepted unknown top-level fields. A file with
`SessionStart` at the root parsed as an empty hook configuration without
warning.

## Repro

```json
{ "SessionStart": [...] }
```

Previously: zero hooks, zero warnings.

Now:

```text
unknown field `SessionStart`, expected `hooks`
```

The supported shape remains:

```json
{ "hooks": { "SessionStart": [...] } }
```

## Fix

Reject unknown top-level fields and surface the parse warning in human
and JSONL `codex exec` output.
2026-06-11 23:08:07 +00:00
Adam Perry @ OpenAIandGitHub e069153f2a Remove fs/join and fs/parent from exec-server protocol (#27700)
## Summary

Path composition is already handled by `PathUri`, leaving `fs/join` and
`fs/parent` as redundant exec-server protocol surface. Because
app-server and exec-server are deployed atomically, these obsolete
methods can be removed without a compatibility shim.

This removes the protocol constants and payloads, public client APIs,
server registrations and handlers, and endpoint-only tests. Existing
in-process `PathUri` join/parent coverage remains.

## Validation

- `just test -p codex-exec-server` (215 passed, 2 skipped)
2026-06-11 15:48:53 -07:00
Celia ChenandGitHub b7a5d81f84 feat: prefer managed Bedrock auth in model provider (#27689)
## Why

The Amazon Bedrock model provider currently discards the shared
`AuthManager`, so a Codex-managed Bedrock API key cannot reach
request-time provider auth. Bedrock instead falls through to AWS
environment or SDK credentials, and the request endpoint can be resolved
from a different region than the managed credential.

Managed Bedrock login should control both the bearer credential and
Mantle region. Unrelated OpenAI or ChatGPT credentials must remain
isolated from Bedrock.

## What changed

- Pass the shared `AuthManager` into `AmazonBedrockModelProvider`.
- Select `CodexAuth::BedrockApiKey` before the existing
`AWS_BEARER_TOKEN_BEDROCK` and AWS SDK/SigV4 paths.
- Use the managed Bedrock auth region when resolving the Mantle
endpoint.
- Filter other `CodexAuth` variants so OpenAI and ChatGPT auth are not
exposed to Bedrock request auth or unauthorized recovery.
- Add focused coverage for provider construction, managed-auth
precedence, bearer headers, endpoint selection, and OpenAI-auth
isolation.
2026-06-11 15:33:38 -07:00
AbhinavandGitHub 0d8dee9427 [codex] Avoid duplicate hooks.json discovery with profiles (#26418)
## Summary

V2 profiles add both `config.toml` and `<profile>.config.toml` to the
config stack. Because both user layers resolve hook discovery to the
same Codex home, Codex loaded the same `hooks.json` twice. This
duplicated hook rows and caused each matching command to run twice.

Deduplicate JSON hook discovery by absolute config folder within each
effective config stack. TOML hooks remain layer-specific, and multi-cwd
`hooks/list` results remain independently resolved per cwd.

## Reproduction

1. Add `config.toml` and `work.config.toml` under `$CODEX_HOME`.
2. Add one command hook to `$CODEX_HOME/hooks.json`.
3. Run Codex with `--profile work`.
4. Trigger the hook.

Before this change, one declaration creates two handlers. Afterward, it
creates one.

Fixes #25645 and addresses the single-cwd duplication in #25437.

## Validation

- `cargo nextest run -p codex-hooks`
- `just fix -p codex-hooks`
- `just fmt`
- `just argument-comment-lint -p codex-hooks`
2026-06-11 15:25:55 -07:00
pakrym-oaiandGitHub 7516eb5c70 Include thread id in token budget context (#27663)
## Why

The token budget full-context fragment identifies the current context
window, but not the thread that owns that window. Including the thread
id makes the initial context-window metadata self-contained, and
`get_context_remaining` also needs to be usable from Code Mode without
forcing callers to parse the model-facing fragment string.

## What changed

- Include the session thread id in the initial `<token_budget>` context
fragment.
- Expose `get_context_remaining` as a Code Mode nested tool while
keeping `new_context` direct-model-only.
- Keep direct model-facing `get_context_remaining` output as the
existing `<token_budget>` text fragment.
- Return only `tokens_left` from the Code Mode structured result for
`get_context_remaining`.
- Update token-budget integration tests and add Code Mode coverage for
the structured result.

## Verification

- `just test -p codex-core token_budget`
- `just test -p codex-core
code_mode_get_context_remaining_returns_structured_result`
- `just test -p core_test_support redacted_text_mode_normalizes_uuids`
2026-06-11 15:10:29 -07:00
Adam Perry @ OpenAIandGitHub d23bb22f25 [codex] migrate exec-server filesystem protocol to PathUri (#27653)
Exec-server filesystem calls should preserve cross-platform `file:` URIs
across the remote boundary instead of converting them through paths
native to the client host.

This changes the exec-server filesystem protocol DTOs to use `PathUri`,
carries those values directly through remote and sandbox-helper
transports, and keeps legacy native absolute-path request strings
readable for compatibility. It also updates protocol documentation and
coverage for URI serialization and non-native URI forwarding.
2026-06-11 15:09:12 -07:00
cooper-oaiandGitHub b5f1bb75d4 [codex-rs] enforce PAT workspace restrictions (#27450)
## Summary

- validate a hydrated personal access token's workspace against
`forced_chatgpt_workspace_id` before persisting `codex login
--with-access-token`
- apply the same PAT-only check when restricted auth managers load
environment, ephemeral, or persisted credentials
- enforce PAT workspace restrictions in the existing central
login-restriction path
- leave Agent Identity and cloud bootstrap behavior unchanged

## Scope

This is intentionally the small PAT-only change. It does not attempt the
broader auth-manager/bootstrap unification; that needs separate design
work.

## Validation

- `CARGO_INCREMENTAL=0 CARGO_TARGET_DIR=/tmp/codex-pat-target just test
-p codex-login -p codex-cli` (410 passed)
- `CARGO_INCREMENTAL=0 CARGO_TARGET_DIR=/tmp/codex-pat-target just fix
-p codex-login -p codex-cli`
- `just fmt`
- `git diff --check`

Context: https://openai.slack.com/archives/D0AUPLV03RQ/p1781138331548269
2026-06-11 14:17:37 -07:00
Owen LinandGitHub 14df0e8833 core: Consolidate Responses API Codex metadata (#27122)
## What
Introduce a `CodexResponsesMetadata` struct that defines all the core
metadata we send to Responses API. Example fields are `thread_id`,
`turn_id`, `window_id`, etc.

Going forward, `client_metadata["x-codex-turn-metadata"]` will be the
canonical way Codex sends metadata to Responses API across both HTTP and
websocket transports.

For now, we continue to emit the existing top-level HTTP headers and
top-level `client_metadata` fields from the same
`CodexResponsesMetadata` struct for compatibility reasons.

Also, app-server clients who specify additional
`responsesapi_client_metadata` via `turn/start` and `turn/steer` will
have those fields merged into
`client_metadata["x-codex-turn-metadata"]`, but cannot override the
reserved fields that core uses (i.e. the fields in
`CodexResponsesMetadata`).

## Why

Responses API request instrumentation is the source of truth for
downstream Codex analytics that join requests by Codex IDs such as
session, thread, turn, and context window. Before this change, those
values were assembled through several request-specific paths: HTTP
request bodies, websocket handshake headers, websocket `response.create`
payloads, compaction requests, and the rich `x-codex-turn-metadata`
envelope all had their own wiring.

That made metadata propagation easy to drift across API-key/direct
Responses API requests, ChatGPT-auth/proxied requests, websocket
requests, and compaction requests. It also made additions like
`window_id` error-prone because a field could be added to one transport
projection but missed in another.

## What changed

- Added `CodexResponsesMetadata` as the core-owned snapshot for Codex
metadata sent to ResponsesAPI.
- Render `client_metadata["x-codex-turn-metadata"]`, flat
`client_metadata` projections, and direct compatibility headers from
that same snapshot.
- Include the known Codex-owned fields in the turn metadata blob,
including installation/session/thread/turn/window IDs, request kind,
lineage, sandbox/workspace metadata, timing, and compaction details.
- Treat app-server `responsesapi_client_metadata` as enrichment for the
Codex turn metadata blob while preventing those extras from overriding
Codex-owned fields.
- Use the same metadata path for normal turns, websocket prewarm, local
compaction, remote v1 compaction, and remote v2 compaction.
- Keep websocket connection-only preconnect metadata separate so
handshakes carry compatibility identity headers without inventing a fake
turn metadata blob.

## Verification

- `cargo check -p codex-core`
- `just fix -p codex-core`
2026-06-11 13:42:09 -07:00
jifandGitHub 4a5a676499 Resolve MCP server registrations through a catalog (#27634)
## Why

MCP servers currently come from user config, local plugins,
compatibility Apps synthesis, and host extensions. Those sources were
composed by mutating a shared map, leaving registration identity,
precedence, removal, and provenance implicit in assembly order.

Before adding executor-owned MCPs, Codex needs one durable resolution
boundary above `McpConnectionManager`. This PR introduces that boundary
while preserving current server configuration, policy, and runtime
behavior. Executor-scoped registrations and explicit policy layers
remain follow-ups.

## What changed

- Add typed `McpServerRegistration` inputs and an immutable
`ResolvedMcpCatalog` in `codex-mcp`.
- Retain each registration's complete `McpServerConfig`, including its
environment binding, while recording its source and provenance.
- Preserve the existing structural precedence between plugin, config,
compatibility, and ordered extension sources.
- Resolve equal-precedence actions by contribution order; provenance IDs
are used only for diagnostics and cannot affect the winner.
- Preserve extension removals and the existing name-scoped `enabled =
false` veto.
- Report same-tier conflicts with every contender and the final catalog
outcome, including whether the winning action registers or removes the
server.
- Require MCP contributors to provide a stable diagnostic identity.
- Derive materialized server maps and plugin ownership from the resolved
catalog.

`McpConnectionManager`, transport startup, tool calls, and resource
routing continue to consume the same effective `McpServerConfig` values.

## Scope

This PR does not add new MCP capabilities or change user-visible
behavior. It does not add executor plugin discovery, thread-scoped
registrations, dynamic refresh generations, or new user/managed policy
semantics.

## Verification

- Added focused catalog coverage for source precedence, complete
configuration preservation, disabled vetoes, plugin ownership,
contribution-order tie breaking, removal outcomes, and conflict
diagnostics.
- Extended hosted Apps coverage for ordered extension removal and
Apps-disabled hosts with and without the hosted extension installed.
- `cargo check -p codex-mcp --tests -p codex-extension-api -p
codex-core`
2026-06-11 21:54:52 +02:00
Adam Perry @ OpenAIandGitHub 236b50125d [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`
2026-06-11 19:28:47 +00:00
Adam Perry @ OpenAIandGitHub b2a4e3be27 [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.
2026-06-11 18:44:18 +00:00
Adam Perry @ OpenAIandGitHub 4a05d3b282 [codex] remove EnvironmentPathRef (#27433)
We're switching to using a static encoding of the host path in
`PathUri`. We may need a type like this again but we can add it when
it's more compelling.

Stacked on #27454.
2026-06-11 18:26:12 +00:00