## Why
External-agent migration treated symlinked empty text targets as overwritable files. Writing migrated configuration through such a target could modify a file outside the repository.
## What changed
- Use symlink metadata when checking whether a migration target is missing or empty, so only regular files are considered overwritable.
- Preserve symlinked `AGENTS.md` and `.codex/hooks.json` targets during both detection and import.
## Testing
Added Unix regression coverage for existing and dangling symlink targets for both guidance and hooks migration.
See https://github.com/openai/codex/pull/26021.
GitOrigin-RevId: 13c78e7458d1c02abdb22b38ba88ed66bb5a154b
## What changed
- Treat `codex.tool.call` and `codex.tool.call.duration_ms` as runtime-only metrics when using the built-in Statsig exporter.
- Continue exporting both metrics through explicitly configured OTLP exporters.
## Testing
- Verify the Statsig configuration omits the tool-call metrics while retaining unrelated metrics.
- Extend the OTLP HTTP loopback test to cover the tool-call counter and duration histogram.
GitOrigin-RevId: 46dd2642063b34e9a4c69b67d58b45721609fcf2
## Why
OAuth discovery failures do not establish that an MCP server lacks OAuth
support. Reporting those failures as `unsupported` conflates an inconclusive
check with a confirmed result.
## What changed
- Add an `unknown` MCP authentication status across the protocol, app server,
CLI, and TUI.
- Preserve OAuth discovery errors so callers can report `unknown`, while
retaining `unsupported` for servers known not to support OAuth.
- Document the distinction in the app server API.
## Testing
- Verify transient HTTP discovery errors are preserved.
- Verify `codex mcp list --json` reports `unknown` when discovery is rate
limited.
GitOrigin-RevId: e4562985971606740538e542ec7eeee502111964
## What changed
Classify `codex-responses-api-proxy` as an intentional `reqwest` exception in
`deny.toml` instead of a temporary migration exception. The proxy independently
owns its blocking upstream HTTP transport, and the allowed wrapper set remains
unchanged.
GitOrigin-RevId: 3db3281a13d67c9514051ea0009013ce50c439e6
## Why
MCP catalog discovery must not allow a server to keep pagination running or
growing without bounds.
## What changed
- Apply the shared pagination collector to tool, resource, and resource-template
discovery.
- Limit each catalog to 100 pages and 1,024 items, and reject pagination cursors
larger than 64 KiB or any repeated cursor.
- Bound the entire pagination operation by the configured tool timeout, falling
back to 30 seconds when no timeout is configured.
## Testing
Add unit coverage for every limit and an end-to-end MCP test that preserves
valid multi-page tools while excluding a server that returns an oversized
cursor.
GitOrigin-RevId: 961a1bfa5fe8a265daf56e342a919c980cd720fa
## Why
A failed network policy amendment must not grant access to the requested host or approve it for the rest of the session.
## What changed
- Only approve the host for the session after the allow amendment is applied successfully.
- Otherwise deny the pending request and record a policy-denial outcome for its owning call.
## Testing
Added a managed-network regression test that submits an invalid allow amendment, verifies that the request is blocked, and confirms that retrying the host prompts for approval again.
GitOrigin-RevId: b2014d19128133abd5e19b8a7e4eb27810a45306
## What changed
- Accept an optional thread name with `/fork`, trimming surrounding whitespace.
- Apply the name to the newly forked thread and update the active session metadata.
- Keep the successful fork active and show an error when naming it fails.
## Testing
- Cover unnamed and named `/fork` dispatch, persisted names, and naming failures.
GitOrigin-RevId: 1799576f82ef0856f992a0378f041e4bab89621b
## Why
Closing stdin could leave the app-server running when a remote-control client
was still connected.
## What changed
Track each connection's origin and shut down a stdio app-server when its stdio
connection closes, regardless of whether other connections remain. Report the
shutdown reason as `stdio_connection_closed`.
## Testing
Added a regression test that closes stdio while a remote-control connection is
active and verifies that the app-server exits and disconnects the remote client.
GitOrigin-RevId: 51ab14d45dfea7f40a0657a8bb167b54efaf0e48
## What changed
- Replace direct `reqwest` error types in `codex-protocol` with
`codex_http_client::HttpError`.
- Build the response-stream error test through
`codex_http_client::HttpResponse`.
- Remove `codex-protocol` from the direct `reqwest` dependency allowlist.
## Testing
- Update the response-stream failure test to cover status and URL propagation
through the shared HTTP response wrapper.
GitOrigin-RevId: 7abcbbe55f994acb13cccefef806a53c7008acde
## What changed
- Load the cloud configuration bundle before `codex mcp list`, `get`, `login`, and `logout` so those commands can resolve enterprise-managed MCP servers.
- Keep `codex mcp add` and `remove` scoped to user configuration, preventing managed server definitions from being copied into or deleted from `config.toml`.
## Testing
- Add CLI integration coverage for listing and inspecting a managed server, completing its OAuth login and logout flow, and preserving user configuration during add and remove operations.
GitOrigin-RevId: 9b64d70535aaba11303c42e44b9ad751c8745445
## What changed
- Pass server notifications to analytics tracking by reference.
- Clone only the notification variants that are recorded as analytics facts.
## Testing
- Add unit coverage that verifies a turn diff notification is enqueued and a command output delta notification is ignored.
GitOrigin-RevId: 2fa0711dbdcca33dce82c3ef78ee53a3f5a65bd9
## What changed
- Make targeted official documentation search and page retrieval the default first step, while retaining a manual-first path for broad Codex orientation and setup questions.
- Split Codex self-knowledge, documentation integration diagnostics, model migration, model selection, and general official documentation guidance into focused references, with at most one primary route loaded per request.
- Preserve explicitly requested model targets, reserve the latest-model resolver for dynamic migrations, and treat bundled model guidance as a disclosed fallback to current official sources.
- Expand the skill metadata and interface description to cover Codex self-knowledge, ChatGPT Work, and OpenAI model and API workflows.
GitOrigin-RevId: 22aba3fc6f58dac8a6cef637504b1fe6d2aaf0d0
## Why
Each connection set could restart the one-second startup grace for the same
cacheable optional MCP server, repeatedly delaying catalog capture while that
server was still pending.
## What changed
- Store the optional startup deadline in the shared tool catalog cache entry.
- Reuse that deadline until a catalog is published, and allow a fresh grace
period after the cached catalog expires.
- Preserve per-connection-set startup grace for servers that disable catalog
caching.
## Testing
Added a paused-time test covering shared deadlines, immediate cached-tool reuse,
cache expiration, and disabled caching.
GitOrigin-RevId: 3494969ee7002c70ce9e4ffd370e46a22d38cc11
## Why
Built-in pet downloads used a standalone blocking client, so CDN redirects did
not use Codex's configured route handling.
## What changed
- Download pet spritesheets asynchronously with a reusable
`RouteAwareClientPool`.
- Keep cache validation, asset installation, and pet decoding off the async
runtime while sharing one asset-and-load path across startup, previews, and
selection.
- Preserve the download size limit while consuming streamed response chunks,
and remove the TUI's direct `reqwest` dependency.
## Testing
Add coverage for oversized response chunks, cached built-in assets, pet loads
without an existing Tokio runtime, and stale preview and selection completions.
GitOrigin-RevId: 725e76f3ddb7e84b7212769892f28dc0add15741
## What changed
- Add `thread/section/move` to atomically move a thread into, within, or out of a section. Threads can be inserted before an existing member or appended, and moves within a section preserve `sectionEnteredAt`.
- Add `section_position` sorting to `thread/list`, with ascending order as its default, and expose `sectionEnteredAt` in thread responses.
- Persist section positions and entry times in SQLite, including migration of existing section members into recency order. Section membership is no longer updated through `thread/metadata/update`.
## Testing
- Cover section moves, reordering, pagination, persistence across restarts and rollout reconciliation, concurrent updates, and rank renumbering.
GitOrigin-RevId: aec6d7ddedca5277029b5caf5c074975397e956c
## What changed
- Keep `ClientResponsePayload` typed through the app-server outgoing queue and serialize it at the transport boundary, avoiding an intermediate `serde_json::Value` while preserving the JSON-RPC wire shape.
- Return a JSON-RPC internal error when a response cannot be serialized, including over remote control, and skip unserializable analytics responses.
- Scan reverse JSONL input a chunk at a time with a larger buffer instead of processing each byte individually.
## Testing
- Cover typed response serialization and serialization failures for direct and remote-control transports.
- Cover filtering unserializable responses from analytics.
GitOrigin-RevId: cc4fd7a43461a273315bb95261bd1ae3ff65fbf7
## Why
File arguments for MCP app tools can use a path convention that differs from
the host running Codex. Resolving those arguments with host-native path handling
can therefore point uploads at the wrong file.
## What changed
- Resolve file arguments against the selected turn environment's working
directory with `PathUri::join`.
- Use the resolved URI's inferred native spelling for errors and derive the
uploaded filename without converting through a host-native path.
## Testing
Run the existing MCP file upload integration test under Wine and reduce its
streaming fixture to 2 MiB.
GitOrigin-RevId: 0a659c19e73f5a26ddfc864e39dad6a4a404057b
## What changed
- Update the Rust MCP SDK from `3.0.0-beta.3` to `3.0.0` and adapt to its renamed metadata and server discovery types.
- Accept discovery responses without server identity metadata, using the configured server name as a fallback, and rely on the SDK's native support for namespaced server identity metadata.
- Preserve typed OAuth HTTP errors so transport failures, cross-origin redirects, and transient HTTP responses are reported instead of being treated as anonymous access.
## Testing
- Cover modern discovery with namespaced or missing server identity over HTTP, SSE, and stdio.
- Cover OAuth discovery error propagation for transport failures, redirects, and transient status codes.
GitOrigin-RevId: 12c1e45136cca89ce4fb15986c2b5df14608682a
## What changed
- Remove the `v8` 146.4.0 crate archive from `MODULE.bazel`.
- Remove the corresponding bindings, static libraries, and platform filegroups
from `third_party/v8/BUILD.bazel`, leaving the 150.4.0 targets in place.
GitOrigin-RevId: 86f93819c3f3f69217a1273df50702abe04682f4
## What changed
- Move the migration flow, model, and source picker under the
`external_agent_config_migration` module.
- Keep their tests and snapshots alongside the corresponding module files and
update imports and snapshot source paths.
GitOrigin-RevId: 4b2f83ca689534e4d9cd1dc7aaa8424e76166bba
## Why
The executor protocol supports Codex releases back to `0.145.0`, so compatibility needs to hold when either side of the app-server/exec-server connection is upgraded first.
## What changed
- Define `MINIMUM_SUPPORTED_CODEX_VERSION` in `codex-exec-server-protocol`.
- Add a Unix test harness that runs current-to-released and released-to-current command execution over authenticated Noise connections.
- Test the current binary against itself, the latest release, and the minimum supported release by default, while allowing explicit release versions.
- Verify that the remote command runs successfully and relay payloads remain encrypted, and increase the relay test timeout to accommodate the end-to-end scenarios.
GitOrigin-RevId: faea8d44fce161f40ed15170876a1282a6de4c22
## What changed
- Treat a single non-empty bold span as a title-only reasoning summary instead of transcript-only content.
- Render title-only summaries consistently in the TUI history and transcript.
- Add a regression test covering both render paths.
GitOrigin-RevId: e3cda451b3fa0ad92985463b14427384bcae4a8d
## What changed
- Consume owned rollout vectors when truncating fork and subagent history, reusing their allocations instead of copying slices.
- Project ephemeral fork responses and token-usage ownership before moving the source history into the new thread.
- Preserve canonical `beforeTurnId` validation for rolled-back and synthetic legacy turns.
## Testing
- Add truncation tests covering rolled-back and synthetic legacy `beforeTurnId` values.
GitOrigin-RevId: 5785d004b74d7e057b82379a172676b023bcfb4f
## What changed
- Use Ratatui-compatible terminal widths throughout TUI layout, preserving
full-width counters for long lines.
- Wrap and truncate on grapheme boundaries so halfwidth kana sound marks and
emoji sequences stay intact.
- Apply the corrected sizing to text input, selection popups, status and
history cells, Markdown, hyperlinks, and scrollable cloud diffs.
## Testing
- Add focused unit and snapshot coverage for wrapping, truncation, cursor and
mask alignment, popup columns, status output, session headers, Markdown
tables, process output, and scrollable diffs.
GitOrigin-RevId: 294ec0bcff743c6bb16d55ec26308524ce741879
## What changed
- Mark OSC 8 hyperlink cells with their visible width so Ratatui's buffer diff handles wide and halfwidth characters correctly.
- Use Ratatui's diff iterator while explicitly clearing styled trailing cells when a forced-width cell replaces a wider cell.
## Testing
- Add coverage for forced-width hyperlink rendering, always-update cells, and styled trailing-cell cleanup.
GitOrigin-RevId: 041128f43beb1e09d40179a3ac16dca1fbdcbc44
## What changed
- Upgrade `ratatui`, `ratatui-macros`, `crossterm`, and `ansi-to-tui`, and adapt the TUI to their updated rendering, backend, color-conversion, and cell APIs.
- Use Ratatui's cell-width and continuation-cell metadata when mapping OSC 8 hyperlinks so links remain aligned across wrapped wide glyphs and halfwidth characters with dakuten.
- Preserve explicit hyperlinks in the sign-in success screen and empty MCP state without embedding escape sequences in the text passed to Ratatui.
## Testing
- Add regression coverage for hyperlink placement across wide glyphs and halfwidth dakuten, hyperlink preservation in onboarding and MCP output, and display-width handling.
GitOrigin-RevId: 8460873e5a266923acd0417bc46264845eab0134
## Why
Pending MCP server startup can outlive an agent turn. Treating its shared
running indicator as an active user turn prevents queued follow-ups and slash
commands from advancing after the turn completes.
## What changed
- Allow the input queue to drain while only MCP startup remains active.
- Keep queued input blocked while a review, foreground shell command, or
compaction is pending or running.
- Resume queue draining after session-selection flows close.
## Testing
Add TUI tests covering queued follow-ups, slash commands, reviews, shell
commands, and compaction while MCP startup is pending.
GitOrigin-RevId: f5684f61c32e3728ff71cf222f0486df637dc3a5
## What changed
- Enrich `thread/list` and `thread/search` results for loaded spawned threads with live status and `canAcceptDirectInput`.
- Report `true` for V1 agents that accept direct input and `false` for parent-owned V2 agents, while leaving the capability `null` when it is unavailable or inapplicable.
- Distinguish untracked threads from threads known to have shut down when resolving loaded status.
## Testing
- Cover list, search, ancestor-filtered list, and rejected V2 direct-input behavior.
GitOrigin-RevId: d5faf2fc379a236661ff9167391541473ce5c1eb
## What changed
- Set `encrypted_function_args` when constructing the router test's local tool call.
- Box the TUI test's app-server request payload to match `AppServerEvent::ServerRequest`.
GitOrigin-RevId: 45195f362bc912d202d95ea67271bcb102bf1e2a
## What changed
- Limit model-facing MCP namespace descriptions to 1,000 bytes without splitting UTF-8 characters or mutating the stored server metadata.
- Cap the aggregate source-description list in `tool_search` at 4 KiB while retaining source names and discovery instructions.
- Cover direct and deferred MCP tool exposure, including multibyte descriptions and tool visibility.
GitOrigin-RevId: 92736ec39475a1d6b3b03f5e3063e28225d8a5f6
## Why
Cached MCP definitions can make a tool callable before its server has finished
starting. Waiting for that server while holding the tool execution gate blocks
unrelated calls in the same response.
## What changed
- Expose the owning MCP server through tool runtime metadata, including tools
with exposure overrides.
- Refresh MCP state and wait for that specific server before entering the
parallel execution gate.
## Testing
Extend the cached MCP tool regression test to verify that an unrelated plan
update completes while MCP startup remains pending.
GitOrigin-RevId: 884d154bc403dfc1d347d265da3d6a887948e7b6
## Why
With deferred execution, an environment can become ready before a later step
spawns a sub-agent. The child must inherit the environment selections available
to that step.
## What changed
- Use the current step context's environment selections when spawning agents in
both multi-agent implementations.
- Add coverage that waits for a remote environment to become ready, spawns an
agent, and verifies that the child receives both remote and local selections.
GitOrigin-RevId: 97c37d541342bbefc9217bf341a19ebdfead2c76
## Why
Switching away from a side conversation should not wait for its interrupt and
unsubscribe requests to finish.
## What changed
- Remove a side conversation from local TUI state immediately when switching
threads, then interrupt and unsubscribe it in a background task.
- Retry interruption with the active turn ID when the original turn races with
cleanup.
- Ignore late notifications and reject server requests for abandoned side
conversations.
## Testing
- Added coverage that background cleanup removes local state and ignores late
events and approval requests.
GitOrigin-RevId: 7a1d1c34f16ab023d1d1e235451b55404731190c
## What changed
- Display `Blocked` goal statuses as “stalled” in the goal menu and goal status footer.
- Update the goal menu snapshot and footer formatting test expectations.
GitOrigin-RevId: f3d8212d939f0d76354048231346328972226274
## Why
An MCP tool call can run after its selected environment becomes ready, while the
turn context still contains the earlier starting-state snapshot. File argument
rewriting must use the environment available to the current step so it can
resolve and upload local files in that case.
## What changed
- Pass `StepContext` through MCP file argument rewriting.
- Resolve the primary environment from the step snapshot while retaining
turn-scoped configuration and metadata.
- Add coverage for an environment that transitions from starting to ready
during a turn.
GitOrigin-RevId: 935bea18ee425aabeacf4505eaff90565f9751e9
## What changed
- Add `EnvironmentManager::publish_ready_info` to update the selected capability
roots for an existing environment without replacing it.
- Store readiness as an atomically replaceable snapshot so repeated publications
expose the latest roots while deferred completion still controls connection
readiness.
- Validate published roots and reject updates for missing environments.
## Testing
- Cover publication, replacement, repeated and invalid updates, and interaction
with deferred environment completion.
GitOrigin-RevId: 1477f60e1319f840e6b33703ef2af052713779fd
## Why
When a turn uses multiple environments, the environment context lists each one but did not identify which environment is primary.
## What changed
- Add a `primary` attribute to each environment in multi-environment model context.
- Persist primary selection in world-state snapshots and emit updates when the primary environment changes.
- Restate environments when transitioning between single- and multi-environment context, while preserving the existing single-environment format.
## Testing
- Cover primary-environment changes, single/multi-environment transitions, legacy snapshot compatibility, and deferred-executor promotion after environment startup.
GitOrigin-RevId: 73a1d794a227edef6e9b7844e7f947b7f598dc80
## What changed
- Preserve the original title when importing an external-agent session and return it with successful session entries from `externalAgentConfig/import/readHistories`.
- Add dedicated history-record success types so externally completed imports can optionally supply a session title without changing the live import result type.
## Testing
- Verify imported session titles are returned by the app server and persisted when session import ledger entries are created or refreshed.
GitOrigin-RevId: e896688a5763c238f1e1dc8b4672a7aa7bc1ed4c
## What changed
- Add nullable `installedAt` metadata to `PluginSummary` and its generated schemas, expressed as a Unix timestamp in seconds.
- Preserve the backend installation time for remote plugins across plugin list, installed, read, and share-list responses. Return `null` when the timestamp is unavailable, including for local or uninstalled plugins and older backend responses.
## Testing
- Cover timestamp conversion in the remote plugin list integration test and the field's serialization and backward-compatible default in protocol tests.
GitOrigin-RevId: 8a1640320adb298874e1074e9891d1017ad06937
## Why
`codex_rust_crate` generated unit test targets for libraries but not for the
binary targets declared by a crate.
## What changed
- Generate a `<binary>-bin-unit-tests` target for every Rust binary.
- Run binary unit tests through the repository-root wrapper so test arguments,
timeouts, sharding, retries, environment, data, and tags match library unit
tests.
- Add `binary_test_target_compatible_with` for constraining generated binary
unit test targets to supported platforms.
GitOrigin-RevId: 7f3c5bff0162c82d19eff80d5d668c9e91b2fe97
## Why
Imported session attribution can identify an MCP server by its configured name
instead of the UUID stored in the session manifest.
## What changed
Match attributed MCP servers against normalized manifest names without regard to
case, while retaining UUID matching.
## Testing
Add focused coverage for both name- and UUID-based attribution.
GitOrigin-RevId: 827443f9e7f14028e17b5c5775ca372bfe2e217e
## What changed
- Store `ServerNotification` and `ServerRequest` payloads behind `Box` in
`AppServerEvent`, `InProcessServerEvent`, and TUI `ThreadBufferedEvent` values.
- Update app-server delivery, TUI routing and replay, exec, onboarding, and tests
to borrow or consume the boxed payloads as appropriate.
GitOrigin-RevId: 7d0dab9aba47487114128ce55c914af5bb46c5b5
## What changed
- Convert Windows device-namespace drive paths such as `\\?\D:\reports` and
`\\.\D:\reports` to canonical drive-based `file:` URIs.
- Convert device-namespace UNC paths to canonical hosted `file:` URIs.
- Preserve unsupported or ambiguous namespace paths as opaque path URIs instead
of interpreting them as filesystem paths.
## Testing
Add coverage for namespace path conversion and joining, including malformed UNC
paths, reserved device names, and volume identifiers.
GitOrigin-RevId: 234f69bc2787e5d318bc0320b94e7392abfb5602
## Why
Background terminal working directories can use a path convention from a
different platform than the app-server host. Converting them to host-native
absolute paths can reject otherwise valid terminal entries and fail the list
request.
## What changed
- Represent `ThreadBackgroundTerminal.cwd` with `LegacyAppPathString` at the
protocol boundary.
- Convert terminal `PathUri` values directly to their inferred native path
strings instead of validating them against the host platform.
## Testing
Add protocol round-trip coverage for POSIX, Windows drive, and Windows UNC
working directories.
GitOrigin-RevId: d766d54bdc191e75955fb419bec6e60c65f52298
## What changed
- Preserve `encrypted_function_args` on function calls so an empty list can mark plaintext collaboration arguments across request replay.
- Deliver `spawn_agent`, `send_message`, and `followup_task` payloads as structured plaintext agent messages when that marker is present; retain encrypted delivery otherwise.
- Redact plaintext collaboration arguments from tool and communication logs, and omit the metadata when sending requests to non-OpenAI providers.
## Testing
- Cover serialization of empty encrypted-argument metadata and plaintext versus encrypted subagent message delivery.
- Verify plaintext tool arguments are redacted and provider-specific metadata is removed from non-OpenAI requests.
GitOrigin-RevId: 64db98ff0b61a3af2f04ed609292363f2e2362a8
## What changed
- Add `--exit-on-stdin-close` and the `CODEX_EXEC_SERVER_EXIT_ON_STDIN_CLOSE` environment variable as opt-in controls for remote exec servers.
- Gracefully drain active sessions and processes when the parent closes stdin, then flush telemetry before exiting.
- Remove the parent-lifetime environment variable from child process environments.
## Testing
- Cover parent disconnects after signal-listener failures.
- Exercise remote shutdown end to end, including child termination and final telemetry metrics.
- Verify that explicitly disabling the environment variable preserves local exec-server behavior.
GitOrigin-RevId: 63063bc097b54684c370bd545cd32d17c4e55d90
## Why
Some legacy MCP servers reject `server/discover` before creating a session and
return a null-ID JSON-RPC error with a non-JSON content type or without echoing
the rejected protocol version. These responses prevented the client from
falling back to legacy initialization.
## What changed
- Parse HTTP 400 discovery errors without a session ID regardless of their
declared content type.
- Fall back to `initialize` when error code `-32000` reports a missing session
or advertises only known legacy protocol versions, including supported
versions other than `2025-06-18`.
- Continue rejecting unrelated error codes, correlated responses, non-400
statuses, malformed version lists, and lists containing modern or unknown
versions.
## Testing
Added MCP discovery coverage for legacy error variants, server-selected legacy
protocol versions, non-JSON content types, and non-legacy rejection cases.
GitOrigin-RevId: 4d3ee2d7d852ce0d0ab3f486da23cb653a7ff5ca
## What changed
- Add the stable, disabled-by-default `recommended_plugins` feature flag.
- Load recommended plugin candidates when apps and plugins are enabled and
either `tool_suggest` or `recommended_plugins` is active.
- Keep the `request_plugin_install` tool gated by `tool_suggest`.
## Testing
- Cover the first turn after external login with `tool_suggest` both enabled
and disabled, including the expected install-tool availability.
GitOrigin-RevId: 06d9a1c2e8dd2498a47796d833eb6d25ba528351