## Why
Paginated thread history needs durable ordering so consumers can process a rollout suffix without rebuilding all earlier history.
## What changed
- Add optional, zero-based ordinals to `RolloutLine` records in paginated rollouts while leaving legacy rollout serialization unchanged.
- Continue ordinals from the last valid record when appending or resuming, including after gaps or an incomplete tail, and reject overflow without appending.
- Add a stateless `project_rollout_line` helper that maps canonical turn lifecycle and completed-item records into thread-history change sets.
## Testing
- Cover ordinal assignment, legacy compatibility, resume and tail recovery, overflow handling, and thread-history projection for completed, failed, and interrupted turns.
GitOrigin-RevId: 3a9bb6cd2a1f674a9f154342e96e9aa3d8330781
## What changed
Update the links in `codex-rs/config.md` to point directly to the configuration documentation on GitHub, including the MCP servers section.
GitOrigin-RevId: 8bf830b7062f83e44b5121dd11b1f1a20bb68e43
## What changed
Select the first model availability announcement in catalog order before
checking its display count. Once that announcement reaches its display limit,
show no announcement instead of falling back to a lower-priority model.
## Testing
- Update the model catalog test to verify that an exhausted higher-priority
announcement does not expose an older announcement.
GitOrigin-RevId: 65f23b34e1ecb38934effd5305704d7ab2353492
## What changed
- Add a `ResponseItemId` type that generates item-specific prefixes with UUIDv7 suffixes and use it across response items.
- Keep deserialization permissive for legacy histories, but omit empty or unprefixed item IDs from HTTP and WebSocket requests.
- Export the new type in the generated TypeScript protocol schema.
## Testing
- Cover prefixed ID generation, legacy deserialization, prefix recognition, and outbound request filtering.
GitOrigin-RevId: 0209fe430c826d0ae88bc4648652c4ebf390c4a4
## Why
Blob upload failures previously surfaced the full signed upload URL and offered limited information for diagnosing transport and service errors.
## What changed
- Add a unique `x-ms-client-request-id` to each blob upload.
- Report transport failures with the upload host, elapsed time, error category, and client request ID, while stripping the signed URL from the underlying error.
- Report unsuccessful responses with Azure request and error IDs, and emit structured warning events with upload metadata and available Azure and Cloudflare identifiers.
## Testing
- Verify successful uploads include the client request ID header.
- Verify response and transport errors expose diagnostic fields without leaking signed URL parameters or response bodies.
GitOrigin-RevId: 9ae2cb2a9aacec4df237b3ee79a6467a6b9107e7
## What changed
- Look for the Unix IDE context socket at `CODEX_HOME/ipc/ipc.sock` first.
- Fall back to the existing per-user temp-directory socket paths, including both legacy paths for UID 0.
- Apply one request deadline across all connection attempts, and stop fallback after a timeout or a protocol error on a connected socket.
## Testing
- Added coverage for socket path selection, primary preference, legacy fallbacks, and timeout and protocol-error behavior.
GitOrigin-RevId: 560c827ad3d446a82ec503779995757096ac33e0
## What changed
- Carry newly installed or updated remote plugin metadata through effective-plugin refresh callbacks, including coalesced refreshes.
- After a successful refresh, record the current hook hashes for listed workspace plugins associated with the active account while preserving existing hook settings and unrelated state.
- Serialize the background trust write with config mutations, and leave hooks untrusted if the write fails or the active account changes.
## Testing
- Cover eligible plugin selection and escaped hook config keys.
- Verify end-to-end trust for newly materialized plugin hooks, preservation of existing config, and fail-closed behavior when config cannot be written.
GitOrigin-RevId: 0b150766415be6fccc117f7856a241e10ad456f2
## What changed
- Add `supports_reasoning_summary_parameter` to model metadata, defaulting to
`true` for backward compatibility.
- Omit `reasoning.summary` and its summary-delivery stream option when the
selected model does not support the parameter.
- Apply the capability of the final selected model when a spawned agent uses a
different model.
## Testing
- Cover unsupported models in regular requests and spawned-agent model
overrides.
GitOrigin-RevId: 72b783799fc0685cef1501ef2dbf62d1308ceead
## What changed
- Allow the local thread store to create paginated threads while keeping them unsupported through the app-server API.
- Filter live append items using the history mode recorded with the thread's live recorder, so paginated threads persist canonical `ItemCompleted` events instead of legacy history events.
## Testing
- Add a local-store test that creates a paginated thread and verifies that a paginated item is persisted while a legacy user-message event is omitted.
GitOrigin-RevId: 83d93660afd5f0217213d4f21b5bf2a97745ff19
## What changed
- Prioritize the GPT-5.6 Sol, Terra, and Luna variants ahead of GPT-5.5 and GPT-5.4 in the static Amazon Bedrock catalog, making Sol the default.
- Use each GPT-5.6 variant's bundled description and default reasoning level while retaining Bedrock's `max` reasoning support.
## Testing
- Update model-provider and app-server tests to cover catalog ordering, variant metadata, and provider-aware fallback to GPT-5.6 Sol.
GitOrigin-RevId: 1761390254deae47b62c043b1ba707c384cde5e9
## What changed
- Rename `Keep waiting` to `Dismiss and keep waiting`.
- Explain that no action is required, waiting continues, and the menu closes when the response is ready.
- Replace the generic confirmation hint with the new explanatory footer.
## Testing
- Update snapshots for safety-buffering prompts with and without the retry option.
GitOrigin-RevId: 2d336c59066e2689f291c5098ecc300921f39977
## What changed
- Add an optional `error` payload to `TurnCompleteEvent` and omit it when a turn completes without an error.
- Preserve the full terminal `ErrorEvent` through the turn lifecycle so the completion event includes the same error details emitted separately by `EventMsg::Error`.
## Testing
- Extend the stream-error integration test to verify that `TurnCompleteEvent` contains the emitted error and that the next turn can still proceed.
GitOrigin-RevId: 8d32942a44132763076130102d8b89ab356d59d0
## Why
Model catalog instructions can include a baked-in `# Personality` section. An
explicit `none` setting should omit that section instead of sending it as part
of the model's base instructions.
## What changed
- Pass the configured personality into the models manager.
- When personality support is enabled and the setting is explicitly `none`,
remove the `# Personality` section through the next level-one heading from
catalog base instructions and instruction templates.
- Preserve explicit `base_instructions` overrides and avoid warning when no
personality was requested.
## Testing
Added unit and integration coverage for section removal, heading boundaries,
CRLF input, preserved configurations, and explicit base instructions.
GitOrigin-RevId: 452c88d3ac6001c2ac7d4fef269cd75dc239fa61
## Why
Appending directly to a non-empty rollout that lacks a trailing newline joins the
next JSON object to the existing record, producing invalid JSONL.
## What changed
- Ensure non-empty rollout files end with a newline before opening them for
append, including resumed, compressed, and direct append paths.
- Perform the synchronous tail inspection outside the async runtime.
## Testing
- Add a regression test covering newline repair and repeated opens.
GitOrigin-RevId: a3ca84cc1fd3b811caa9f4c5c8761a4b5b791357
## What changed
- Stop the TUI and app server from inspecting existing sessions at startup to
set `personality = "pragmatic"` automatically.
- Remove the migration marker, helper APIs, and associated tests.
GitOrigin-RevId: 9e963bf113aff21651696bbc463f2749ac0f510a
## What changed
- Add optional `scheduledTasks` metadata to `plugin/read` responses for remote
plugins, including hourly, daily, weekday, and weekly schedules.
- Preserve the distinction between unavailable metadata (`null`) and a catalog
response containing no scheduled tasks (`[]`). Local plugin details return
`null`.
- Export the corresponding Rust, JSON Schema, and TypeScript protocol types.
## Testing
- Cover scheduled-task deserialization and propagation through `plugin/read`.
- Verify missing and empty remote metadata remain distinct.
GitOrigin-RevId: 7af223ed0a1bf6d8f054293084a73f34c6d0332d
## What changed
- Add an optional `started_at` Unix timestamp to `TurnCompleteEvent` and
`TurnAbortedEvent`.
- Populate the timestamp from turn timing state when a turn completes or is
aborted.
- Preserve the timestamp when synthesizing interrupted fork history and when
importing external sessions.
## Testing
- Verify that interrupting a turn emits a `TurnAbortedEvent` with a start
timestamp.
GitOrigin-RevId: 75b3911b95c060e5fc1843a5e293d8fe47377186
## Why
Drive-shaped POSIX paths such as `/C:/workspace` can be mistaken for Windows
paths when an automatic approval request converts them from `PathUri`.
## What changed
- Keep approval paths as `PathUri` values together with their environment ID
until the automatic review request is built.
- Recover host-native paths for local working directories when strict
conversion cannot determine the path convention.
- Continue rejecting incompatible paths from remote environments.
## Testing
Add coverage for drive-shaped local POSIX paths, foreign remote paths, and
preserving apply-patch path URIs while building approval actions.
GitOrigin-RevId: 3fd31cfb4e8b46f9968ff66d5e986ca777430185
## What changed
- Emit `responsesapi.websocket_timing` payloads as opt-in trace events with request context, while excluding them from diagnostic uploads and persisted logs by default.
- Preserve fractional-millisecond TBT values in telemetry histograms and runtime summaries, rounding only when formatting the TUI label.
## Testing
- Cover timing-log filtering, fractional TBT collection and display, and existing whole-millisecond duration behavior.
GitOrigin-RevId: 5f0a1c60c237abed17cc8b2d569ca77fbbc6ec41
## What changed
- Add a generic `ReverseJsonlScanner` that reads seekable JSONL data from the
end in bounded chunks, skips blank records, and reports malformed records
without stopping the scan.
- Use the scanner for reverse session-index lookups while preserving the
existing behavior of ignoring invalid entries.
## Testing
- Add coverage for unterminated final records, malformed JSON, blank lines,
chunk boundaries, and records spanning multiple chunks.
- Verify session-index lookup can skip an invalid record and still find valid
entries on either side of it.
GitOrigin-RevId: 66255f48492f74726d4ac4831cdc82f748de17d6
## Why
Paginated thread history needs its own SQLite database to avoid adding lock
contention to the main state store.
## What changed
- Add the `thread_history_1.sqlite` path and migration scaffolding.
- Create tables and pagination indexes for projected turns and items, plus a
per-thread projection checkpoint.
- Register the database with runtime diagnostics, Bazel inputs, and database
telemetry.
GitOrigin-RevId: d194310835f1df2a2a29c7827d77ca37eabbd0a3
## What changed
- Run permission-request hooks before routing approvals to the automated reviewer or user, including when `strict_auto_review` is enabled.
- Centralize approval resolution so hook, automated-reviewer, and user decisions share rejection handling and report the correct telemetry source.
## Testing
- Add an integration test showing that an allow hook can approve a shell command during strict auto-review without invoking the automated reviewer.
GitOrigin-RevId: 18e9d76baee6cbae9d35ae517250f2f82270a9d2
## Why
Remote environment provisioning can finish after a thread starts, before an
exec-server WebSocket URL is available.
## What changed
- Add `EnvironmentManager::register_pending_environment` and a one-shot
`PendingEnvironmentRegistration` handle that resolves to either a validated
WebSocket URL or a terminal provisioning error.
- Let lazy remote exec-server clients wait for that result, while preserving
reconnection behavior after a successful registration.
- Keep replacement registrations isolated so completing an older handle does
not resolve the current environment with the same ID.
## Testing
Add coverage for successful connection and reconnection, provisioning and
dropped-registration failures, invalid URLs, replacement isolation, and the
deferred-executor startup flow.
GitOrigin-RevId: 5c05be2b72291b77a1f71176d7075b1ad63332a5
## Why
Concurrent Codex processes can otherwise refresh the same rotating token, and a
cancelled or partially persisted refresh can leave durable and in-memory MCP
credentials out of sync.
## What changed
- Serialize each credential's read-refresh-write transaction across processes,
reread the authoritative store after locking, and adopt credentials refreshed
by another process.
- Keep refresh persistence running after caller cancellation, bound lock and
provider waits independently, and preserve omitted refresh tokens and scopes.
- Fail MCP startup and operations when refresh or persistence fails instead of
continuing with stale credentials, while requiring reauthorization for
missing, unusable, or rejected refresh tokens.
- Exclude OAuth refresh time from the MCP initialization timeout.
## Testing
Add coverage for lock contention, concurrent refreshes, rejected and missing
credentials, storage failures, caller cancellation, and provider timeouts.
GitOrigin-RevId: 4d29b879bec646d2ceb922b526dc793b1a1f5423
## What changed
- Pass configured workspace roots from core to the exec server so filesystem and process sandbox permissions are materialized against the intended roots.
- Preserve an explicitly empty workspace-root list instead of treating the sandbox working directory as an implicit root.
- Initialize filesystem sandbox contexts with their working directory as the default workspace root.
## Testing
- Add end-to-end coverage for patch and command writes inside and outside workspace roots.
- Verify remote filesystem and process sandboxes do not grant access through an empty workspace-root list.
GitOrigin-RevId: 6684c8f7de50970b45a29e2a6323df954c96f9f6
## What changed
Assign a fresh UUIDv7 to each synthesized user and assistant message recorded
when exiting review mode, instead of reusing fixed IDs across review runs.
GitOrigin-RevId: 8524176895e2d8c750760554f515f397728a8554
## What changed
- Build a reasoning payload for every Responses request and always include `reasoning.encrypted_content`.
- Remove `supports_reasoning_summaries` from model metadata and retire the `model_supports_reasoning_summaries` configuration override.
- Use configured or model-default reasoning effort without a capability gate, including for guardian reviews and tracing.
GitOrigin-RevId: 2c9f194a5d2d4d688a2235299e6358f82ab8e1ea
## What changed
- Add `SkillInvocationContributor` and registration support to the extension API.
- Provide invocation callbacks with session-, thread-, and turn-scoped extension data, the turn ID, skill resource, and explicit or implicit invocation kind.
- Notify registered contributors when Codex observes a deduplicated implicit skill invocation.
## Testing
- Extend the extension registry round-trip test to cover skill invocation contributors.
GitOrigin-RevId: f428336728889d9bf4fba41a7dd8d3a6f9b9728c
## Why
The memory consolidation agent changes its working directory to the memory
root, but applying its sandbox policy directly to the permissions object can
leave workspace roots inherited from the parent configuration.
## What changed
Apply the consolidation sandbox policy through `Config` so its workspace roots
are synchronized with the memory root. Add a test covering the working
directory, workspace roots, and effective legacy sandbox policy.
GitOrigin-RevId: dc6e75aef1ffa84a2f66fec6ed3a6fedcf9aa672
## Why
A completed Phase 2 agent run does not guarantee that its required outputs were
created correctly. Treating a clean workspace as success can also preserve a
state where those outputs are missing.
## What changed
- Require `MEMORY.md` to be a file and `memory_summary.md` to start with `v1`
before marking consolidation successful.
- Fail completed runs with invalid artifacts without resetting the workspace
baseline, allowing the job to be retried.
- Run consolidation for a clean workspace when its required artifacts are
invalid instead of taking the no-change success path.
## Testing
Added coverage for rejecting an invalid summary and retrying a clean workspace
whose consolidation artifacts are missing.
GitOrigin-RevId: ac57b2ba9d062c5203ca51afd716795a91814bb3
## Why
Unified exec can drain process output multiple times while waiting for a command. Collecting those drains into an uncapped buffer allows large commands to exceed the output collection limit.
## What changed
- Accumulate drained output through the capped head/tail buffer so collection remains bounded while preserving the beginning and end of the stream.
- Include a `... N bytes omitted ...` marker when the collection cap drops output.
- Calculate the original token estimate from all observed bytes and preserve omission metadata through truncation and sandbox-denial responses.
## Testing
- Cover repeated drains, previously omitted output, omission markers, and large-output summaries.
GitOrigin-RevId: c6e2efeb875ed8f35914365eab7431f25fd3484c
## Why
The process-start background task can move to a Tokio worker thread, where the
caller's thread-local tracing subscriber is otherwise unavailable. This can
break propagation of the caller's trace context to the exec-server request.
## What changed
- Attach both the current span and current tracing subscriber to spawned
process-start tasks.
- Run exec-server Bazel unit tests serially because their tracing setup uses
process-global state.
## Testing
Run the trace-context regression test on a multi-thread Tokio runtime so it
exercises propagation across the background task.
GitOrigin-RevId: a586eefd6983916d670fc5a90f0decd0468d273b
## What changed
Update the exact-size-limit stdio connection test to exercise both `\n` and
`\r\n` line endings, sizing the duplex buffer for each delimiter.
GitOrigin-RevId: 949e28bef3f1a34d379f3623f6aa7d99c0ecea80
## What changed
Add regression coverage that verifies ancestor metadata searches:
- keep at most 256 project-root marker or repository skill-root probes in flight;
- start the next probe as capacity becomes available; and
- preserve `AGENTS.md` and repository skill-root discovery order.
GitOrigin-RevId: e7ac90bbeb94573d01e67705001af85ce59165b6
## Why
Newline-delimited stdio input could buffer an unterminated JSON-RPC message without a per-message limit. Apply the same 64 MiB ceiling used by the other exec-server transports.
## What changed
- Read stdio messages with bounded lookahead and disconnect when a message exceeds the limit.
- Preserve LF and CRLF framing, including messages whose payload is exactly at the limit.
## Testing
Added tests for accepting a limit-sized CRLF message and rejecting an unterminated overlong message.
GitOrigin-RevId: 73eaf883324a7777960725037cc5b9c34720084f
## Testing
Add a concurrent-stream regression test that fills the connection-wide queued
body budget across two HTTP responses. Verify that the overflowing stream
reports the byte-budget error while the other stream still drains successfully.
GitOrigin-RevId: 65efacb15f1368b1de3b98e7ef65ebca66a3840b
## Why
Frame-count backpressure does not bound the amount of executor-controlled data
retained in streamed HTTP response queues, and a single body delta could exceed
the intended wire size.
## What changed
- Limit each decoded `http/request/bodyDelta` payload to 1 MiB, split locally
produced response chunks at that boundary, and reject oversized incoming
deltas.
- Apply a shared 16 MiB byte budget across queued HTTP response streams. Release
capacity as deltas are consumed and fail a stream when the budget is
exhausted.
## Testing
Added coverage for rejecting an oversized delta and for failing a stream after
its queued deltas exhaust the shared byte budget.
GitOrigin-RevId: be9205fef44b0ec96b84b31a8e059b1cb9cd3f3b
## Why
Serial metadata probes add remote round trips while Codex discovers project
instructions, repository skills, and project-root markers during startup.
## What changed
- Probe ancestor directories concurrently while preserving discovery order.
- Raise the shared find-up probe window to cover typical project hierarchies.
- Refresh project instructions in parallel with plugin and skill warmup.
## Testing
Add coverage that blocks one metadata request and verifies all expected project-root
and `AGENTS.md` ancestor probes have started before it is released.
GitOrigin-RevId: 11449837c7a212ec8ed385e7290476e926d93531
## What changed
- Delete the `codex-execpolicy-legacy` crate, its default policy, and its tests.
- Remove the crate from the Cargo and Bazel workspaces and clean up its unused dependencies.
- Remove the legacy matcher reference from the current exec policy documentation.
GitOrigin-RevId: ee756958b46bf759ad43dec8aa1379c1cd4d8b0d
## Why
Sandboxed exec-server process requests can use a restricted filesystem
profile that does not expose the exec-server binary. On Linux, the outer
bubblewrap stage re-enters that binary with the `codex-linux-sandbox`
argv0 to install seccomp, so hiding the binary prevents the requested
process from starting.
## What changed
- add the configured `codex_self_exe` to the process permission profile
before constructing the outer platform sandbox
- add a Linux exec-server integration test that starts a real remote
process with restricted reads and verifies it can read an allowed
workspace file
## Test plan
- `just test -p codex-exec-server process_sandbox`
- `just test -p codex-exec-server --test exec_process
remote_process_keeps_sandbox_helper_visible_with_restricted_reads`
## Why
Bazel-backed end-to-end macrobenchmark plumbing needs a small,
deterministic first consumer that does not couple the shared
infrastructure to the remote-skill scenario.
## What
- add `codex_e2e_benchmark`, a small macro for Bazel-only Divan
benchmarks and runtime binary runfiles
- keep benchmark sources under `e2e_benches/` so Cargo does not
auto-discover them
- add a CLI example that resolves the real `codex` binary and measures
`codex --help`
- assert the spawned command succeeds
## Validation
- `bazel test --compilation_mode=fastbuild
--@rules_rust//rust/settings:extra_rustc_flag=-Cdebug-assertions=no
--@rules_rust//rust/settings:extra_exec_rustc_flag=-Cdebug-assertions=no
--cache_test_results=no --test_output=errors --test_arg=--test
//codex-rs/cli:codex-help-bench`
## Stack
1. [#31295 bench: add codex help e2e
macrobenchmark](https://github.com/openai/codex/pull/31295)
2. [#31428 bench: add e2e benchmark
entrypoints](https://github.com/openai/codex/pull/31428)
3. [#31429 ci: smoke Bazel e2e
benchmarks](https://github.com/openai/codex/pull/31429)
## Why
App-server clients can report whether Amazon Bedrock is using
AWS-managed credentials or a Codex-managed API key, but they do not have
a matching API for creating the managed login. This PR defines that
experimental wire contract independently from its implementation.
Managed Bedrock API keys are already a primary `CodexAuth` mode. The API
therefore describes a normal Codex login that replaces the current
stored auth rather than introducing provider-scoped credential storage.
## What changed
- Add the experimental `amazonBedrock` variant to `account/login/start`.
- Accept an API key and AWS region and return a matching discriminated
response.
- Gate the request behind the app-server `experimentalApi` capability.
- Regenerate the JSON and TypeScript protocol schemas.
- Document the login contract, notifications, primary-auth replacement
semantics, restart boundary, and non-transactional durable writes.
## Impact
This PR defines the API shape but does not implement login behavior. The
next PR adds validation, persistence through the existing Codex auth
lifecycle, provider selection, and notifications.
## Validation
- `just test -p codex-app-server-protocol`
## Stack
1. **#31327 Managed Bedrock experimental API** — base: `main`
2. #31326 Managed Bedrock login — base: `codex/managed-bedrock-api`
3. #31325 Managed Bedrock logout — base:
`codex/managed-bedrock-login-v2`
Filesystem helper requests currently turn symbolic `:workspace_roots`
permissions into a sandbox policy before applying the workspace roots
from the filesystem sandbox context. This can accidentally broaden
filesystem access to the cwd instead of limiting it to the selected
workspace roots.
Materialize project-root permissions using the context workspace roots
before deriving the filesystem sandbox policy. The same converted roots
are then reused when constructing the sandbox command, keeping policy
enforcement and process setup aligned.
Adds a remote filesystem integration test that verifies a file inside
the selected workspace root is readable while a sibling under the cwd is
denied.
## Validation
- `just test -p codex-exec-server
remote_read_file_materializes_environment_workspace_roots` (macOS,
outside the outer Seatbelt sandbox)
[Codex Thread
019edd6d-6f14-74e2-853c-345d1803d4a6](https://codex-thread-link.openai.chatgpt-team.site/thread/019edd6d-6f14-74e2-853c-345d1803d4a6)
## Stack
Review and merge in order. Every layer is independently correct and
documents its safe stopping point.
1. [openai/codex#30292](https://github.com/openai/codex/pull/30292) —
aggregate File/Secrets store locking
2. [openai/codex#30293](https://github.com/openai/codex/pull/30293) —
resolve and lifecycle-pin the exact OAuth store
3. [openai/codex#30416](https://github.com/openai/codex/pull/30416) —
serialized authoritative refresh transaction
4. [openai/codex#30294](https://github.com/openai/codex/pull/30294) —
Codex-owned transport refresh and one-shot 401 recovery
5. [openai/codex#30295](https://github.com/openai/codex/pull/30295) —
login/logout transaction serialization
6. [openai/codex#30296](https://github.com/openai/codex/pull/30296) —
diagnostic-only Auto store drift reporting
**This PR is layer 2.**
## Why
`Auto` is keyring-first with a File fallback, but re-evaluating that
policy during transport reconstruction or persistence can make one MCP
client read from one store and later write to another. With rotating
refresh tokens, the second store may contain an older token. This layer
makes the source selected at client startup explicit and keeps that
authority stable for the client lifecycle.
## What this PR does
- Keeps `resolve_oauth_tokens_from_store_policy` as the single
configured-policy entry point and returns both credentials and the
concrete File or Keyring source that supplied them.
- Puts exact `load`, `save`, and `delete` operations on
`ResolvedOAuthCredentialStore`, making “resolve configured policy” and
“use the selected authority” distinct at call sites.
- Pins the first concrete source in `pinned_credential_store` in the
transport recipe, so initialization retries and session reconstruction
cannot re-evaluate `Auto` and adopt another store.
- Gives `OAuthPersistor` the resolved store and keeps subsequent
persistence and removal on that authority.
- Uses a typed keyring-load error to distinguish aggregate-store
coordination failures from ordinary backend failures; a coordination
failure is surfaced instead of triggering File fallback.
- Keeps login-time `Auto` behavior unchanged: prefer Keyring, fall back
to File when unavailable, and clean up legacy File state after a
successful keyring save.
- Adds structured server/backend context when fallback cleanup fails.
## Explicit decisions and non-goals
- The selection is lifecycle-local and in memory. This PR does not add a
durable backend selector, migration, reconciliation registry, or global
source of truth outside `CODEX_HOME`.
- `Auto` may choose File at the start of a later process if keyring
availability changes. Once this client resolves, a selected-store
failure is returned instead of hot-switching.
- Different `CODEX_HOME` instances remain independent even when they can
access the same Direct keyring credential.
- Cross-process refresh serialization is intentionally not part of this
layer.
## Safe stopping point
This PR can merge alone. A single MCP client no longer hot-switches
credential stores across transport rebuilds or persistence. Two
processes can still refresh the same selected credential concurrently
until layer 3.
## Review size
The net layer is 9 files, +668/−144. The production change remains
focused on store resolution and lifecycle pinning; the largest follow-up
is integration coverage that drives real session recovery.
## Validation
- `just test -p codex-rmcp-client` (99 passed; 5 expected skips)
- Real-client 404 recovery coverage with different Keyring and File
tokens; captured bearer headers prove the stale File token is never sent
- Mutation check: removing the lifecycle pin makes that integration
regression fail by observing the stale File token
## Why
Remote MCP stdio buffers executor-provided stdout until a JSON-RPC line
completes and stderr until a diagnostic line completes. A malicious or
broken executor can keep sending chunks without a newline, making
orchestrator memory grow without bound.
Executor event boundaries are arbitrary, so a valid message before an
oversized line must not be lost merely because both arrived in one
event.
## What changed
- Limit one stdout JSON-RPC line to 8 MiB.
- Limit one stderr diagnostic line to 1 MiB.
- Check each logical line before copying its bytes into the retained
buffer.
- Preserve complete stdout messages that precede an oversized line and
deliver them before closing the stream.
- Close the MCP transport on overflow; existing transport cleanup
terminates the executor-managed process.
- Preserve multiple lines per chunk, CRLF framing, and final
unterminated messages at EOF.
- Box the pending stdio transport so the added framing state does not
inflate every `ClientState` value.
- Add regression coverage for cross-chunk overflow, bounded lines in a
larger chunk, and a valid prefix before an oversized line.
## Scope
This bounds pre-newline buffering for executor-backed MCP stdio only. It
does not change local stdio framing or address memory amplification
while parsing a complete JSON message.
## Why
Not every Codex distribution currently includes the
`codex-code-mode-host` companion binary. Enabling the process-host
feature should not make code mode unavailable on those surfaces while
packaging support is being completed.
## What changed
- Fall back to an in-process code-mode session only when spawning the
companion binary returns `io::ErrorKind::NotFound`.
- Keep permission, handshake, timeout, and other host failures visible
instead of silently falling back.
- Store the provider's owned-process/in-process choice as one
enum-backed state so later sessions reuse the fallback decision.
- Preserve the underlying spawn `io::Error` while retaining the host
path in the displayed error.
- Update provider, `CodeModeService`, and end-to-end coverage to verify
successful fallback execution.
## Test plan
- `just test -p codex-code-mode`
- `just test -p codex-core missing_process_host`
## Summary
Codex Apps file parameters are exposed to the model as local paths,
uploaded at execution time, and rewritten into provided-file payloads
before the MCP tool call.
The rewrite currently includes the documented optional fields
`mime_type` and `file_name` for every file parameter. Apps with strict
schemas can reject those fields when they are not declared.
## Changes
- Derive the supported optional file fields from each
`openai/fileParams` parameter's raw input schema before replacing it
with the model-visible local-path schema.
- Always include `download_url` and `file_id`.
- Include `mime_type` and `file_name` only when that specific file
parameter's schema accepts them, including schemas that allow additional
properties.
- Handle scalar and array file parameters, including items-only arrays,
composed schemas, and local JSON Schema references.
- Preserve the existing restriction that only the host-owned Codex Apps
MCP server can use this upload path.
This supports tools with different file contracts in the same app: one
parameter can accept the optional fields while another remains strict.
## Validation
- `just test -p codex-mcp`
- `just test -p codex-core mcp_openai_file`
- `just test -p codex-core codex_apps_file_params_`
- `just fix -p codex-mcp`
- `just fix -p codex-core`
- `just fmt`
- `git diff --check`
- Manually verified in the Codex Electron app that:
- a strict file schema receives only `download_url` and `file_id`
- a rich file schema also receives `mime_type` and `file_name`
Related: #31330
## Why
Login already honors `respect_system_proxy`, but several login-owned
auth flows still construct and pass around raw `reqwest::Client` values.
That keeps those request paths coupled to the underlying transport and
leaves `codex-login` on the temporary direct-`reqwest` allowlist
introduced by #31431.
Auth endpoints also have a stricter logging boundary than ordinary API
requests: custom issuer URLs and response headers may contain
credentials. Moving these requests behind the shared HTTP abstraction
must preserve that boundary while retaining route-aware proxy and
custom-CA behavior.
This is a bounded login migration. The separate Agent Identity and
shared default-client compatibility migrations remain follow-up work.
## What changed
- Add `HttpClientFactory::build_client` to construct the shared
`HttpClient` abstraction for a resolved destination and route class.
- Add a route-aware construction path that suppresses request URL,
response-header, and transport-error diagnostics for sensitive auth
endpoints.
- Route device-code user-code/polling requests, OAuth authorization-code
exchange, and API-key token exchange through `HttpClient`.
- Build the revoke timeout test client through the same factory API.
- Use the transport-neutral `http::StatusCode` in the migrated
device-code flow.
- Add an end-to-end log-capture regression test covering successful
responses and transport failures after `RequestBuilder` transformations.
## Review guidance
The request behavior is intended to be unchanged: each issuer/token
endpoint selects the same auth route, including the existing system/PAC
proxy and custom-CA handling, and raw auth clients still omit Codex
default headers. The intentional logging change is limited to raw auth
requests, whose URL userinfo, query credentials, response headers, and
transport errors must not cross the auth redaction boundary.
This PR deliberately does **not** remove `codex-login` from #31431's
allowlist. The remaining direct `reqwest` surface belongs primarily to:
- Agent Identity APIs that still accept `reqwest::Client`.
- Exported default-client compatibility helpers used by other workspace
crates.
- A small number of tests and concrete error/header types.
## Testing
- `cargo check -p codex-http-client -p codex-login --tests`
- `just test -p codex-http-client` (41 tests)
- `just test -p codex-login` (155 tests)
- `just bazel-lock-check`
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/31637).
* #31837
* #31828
* #31825
* #31821
* __->__ #31637