Commit Graph

5041 Commits

  • Fix resume picker initial loading state (#16591)
    Addresses #16514
    
    Problem: Resume picker could show “No sessions yet” before the initial
    session fetch finished.
    
    Solution: Render a loading message while the first page is pending, and
    keep the empty state for truly empty results.
  • fix: increase timeout to account for slow PowerShell startup (#16608)
    Similar to https://github.com/openai/codex/pull/16604, I am seeing
    failures on Windows Bazel that could be due to PowerShell startup
    timeouts, so try increasing.
  • fix: add more detail to test assertion (#16606)
    In https://github.com/openai/codex/pull/16528, I am trying to get tests
    running under Bazel on Windows, but currently I see:
    
    ```
    thread 'suite::user_shell_cmd::user_shell_command_does_not_set_network_sandbox_env_var' (10220) panicked at core/tests\suite\user_shell_cmd.rs:358:5:
    assertion failed: `(left == right)`
    
    Diff < left / right > :
    <1
    >0
    ```
    
    This PR updates the `assert_eq!()` to provide more information to help
    diagnose the failure.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16606).
    * #16608
    * __->__ #16606
  • test: deflake external bearer auth token tests on Windows (#16604)
    ## Why
    
    `external_bearer_only_auth_manager_uses_cached_provider_token` can fail
    on Windows when cold `powershell.exe` startup exceeds the provider-auth
    helper's 1s timeout. When that happens,
    `AuthManager::resolve_external_api_key_auth()` [logs the resolver error
    and returns
    `None`](https://github.com/openai/codex/blob/024b08b411fe/codex-rs/login/src/auth/manager.rs#L1449-L1455),
    which is exactly the assertion failure from the flake.
    
    ## What
    
    - Invoke `powershell.exe` explicitly in the Windows provider-auth test
    helpers in `login/src/auth/auth_tests.rs`.
    - Increase the helper timeout to `10_000` ms and document why that slack
    exists.
    
    ## Verification
    
    - `cargo test -p codex-login`
  • Fix non-determinism in rules_rs/crate_git_repository.bzl (#16590)
    Running multiple builds with no changes causes some differences, we see
    that
    https://app.buildbuddy.io/compare/a9719629-1660-4735-a477-d66357f234fb...df85310b-eb5c-4c10-8b79-4d0449ba6cdd#file
    shows the file-differences between two Bazel builds.
    
    These differences are caused by a non-deterministic `.git` entry in the
    rules_rs crates that are created with `crate_git_repository`.
    
    As a way to make these deterministic, we can remove this entry after we
    download the git source, so that the input to the compile action is
    deterministic.
    
    ### CLA
    
    I have read the CLA Document and I hereby sign the CLA
  • chore: move codex-exec unit tests into sibling files (#16581)
    ## Why
    
    `codex-rs/exec/src/lib.rs` already keeps unit tests in a sibling
    `lib_tests.rs` module so the implementation stays top-heavy and easier
    to read. This applies that same layout to the rest of
    `codex-rs/exec/src` so each production file keeps its entry points and
    helpers ahead of test code.
    
    ## What
    
    - Move inline unit tests out of `cli.rs`, `main.rs`,
    `event_processor_with_human_output.rs`, and
    `event_processor_with_jsonl_output.rs` into sibling `*_tests.rs` files.
    - Keep test modules wired through `#[cfg(test)]` plus `#[path = "..."]
    mod tests;`, matching the `lib.rs` pattern.
    - Preserve the existing test coverage and assertions while making this a
    source-layout-only refactor.
    
    ## Verification
    
    - `cargo test -p codex-exec`
  • ci: upload compact Bazel execution logs for bazel.yml (#16577)
    ## Why
    
    The main Bazel CI lanes need compact execution logs to investigate cache
    misses and unexpected rebuilds, but local users of the shared wrapper
    should not pay that log-generation cost by default.
    
    ## What Changed
    
    -
    [`.github/scripts/run-bazel-ci.sh`](https://github.com/openai/codex/blob/a6ec239a24fd21507bb75a28f17277653f52e3a2/.github/scripts/run-bazel-ci.sh#L149-L153)
    now appends `--execution_log_compact_file=...` only when
    `CODEX_BAZEL_EXECUTION_LOG_COMPACT_DIR` is set; the caller owns creating
    that directory.
    -
    [`.github/workflows/bazel.yml`](https://github.com/openai/codex/blob/a6ec239a24fd21507bb75a28f17277653f52e3a2/.github/workflows/bazel.yml#L66-L174)
    enables that env var only for the main `test` and `clippy` jobs, creates
    the temp log directory in each job, and uploads the resulting `*.zst`
    files from `runner.temp`.
    
    ## Verification
    
    - `bash -n .github/scripts/run-bazel-ci.sh`
    - Parsed `.github/workflows/bazel.yml` as YAML.
    - Ran a local opt-in wrapper smoke test and confirmed it writes
    `execution-log-cquery-local-*.zst` when the caller pre-creates
    `CODEX_BAZEL_EXECUTION_LOG_COMPACT_DIR`.
  • [codex] Remove codex-core config type shim (#16529)
    ## Why
    
    This finishes the config-type move out of `codex-core` by removing the
    temporary compatibility shim in `codex_core::config::types`. Callers now
    depend on `codex-config` directly, which keeps these config model types
    owned by the config crate instead of re-expanding `codex-core` as a
    transitive API surface.
    
    ## What Changed
    
    - Removed the `codex-rs/core/src/config/types.rs` re-export shim and the
    `core::config::ApprovalsReviewer` re-export.
    - Updated `codex-core`, `codex-cli`, `codex-tui`, `codex-app-server`,
    `codex-mcp-server`, and `codex-linux-sandbox` call sites to import
    `codex_config::types` directly.
    - Added explicit `codex-config` dependencies to downstream crates that
    previously relied on the `codex-core` re-export.
    - Regenerated `codex-rs/core/config.schema.json` after updating the
    config docs path reference.
  • fix: move some test utilities out of codex-rs/core/src/tools/spec.rs (#16524)
    The `#[cfg(test)]` in `codex-rs/core/src/tools/spec.rs` smelled funny to
    me and it turns out these members were straightforward to move.
  • [codex] Move config types into codex-config (#16523)
    ## Why
    
    `codex-rs/core/src/config/types.rs` is a plain config-type module with
    no dependency on `codex-core`. Moving it into `codex-config` shrinks the
    core crate and gives config-only consumers a more natural dependency
    boundary.
    
    ## What Changed
    
    - Added `codex_config::types` with the moved structs, enums, constants,
    and unit tests.
    - Kept `codex_core::config::types` as a compatibility re-export to avoid
    a broad call-site migration in this PR.
    - Switched notice-table writes in `core/src/config/edit.rs` to a local
    `NOTICE_TABLE_KEY` constant.
    - Added the `wildmatch` runtime dependency and `tempfile` test
    dependency to `codex-config`.
  • Move tool registry plan tests into codex-tools (#16521)
    ## Why
    
    #16513 moved pure tool-registry planning into `codex-tools`, but much of
    the corresponding spec/feature-gating coverage still lived in
    `codex-core`. That leaves the tests for planner behavior in the crate
    that no longer owns that logic and makes the next extraction steps
    harder to review.
    
    ## What
    
    Move the planner-only `spec_tests.rs` coverage into
    `codex-rs/tools/src/tool_registry_plan_tests.rs` and wire it up from
    `codex-rs/tools/src/tool_registry_plan.rs` using the crate-local `#[path
    = "tool_registry_plan_tests.rs"] mod tests;` pattern.
    
    The `codex-core` test file now keeps the core-side integration checks:
    router-visible model tool lists, namespaced handler alias registration,
    shell adapter behavior, and MCP schema edge cases that still exercise
    the `core` binding layer.
    
    ## Verification
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
  • Extract tool registry planning into codex-tools (#16513)
    ## Why
    This is a larger step in the `codex-core` -> `codex-tools` migration
    called out in `AGENTS.md`.
    
    `codex-rs/core/src/tools/spec.rs` had become mostly pure tool-spec
    assembly plus handler registration. That made it hard to move more of
    the tool-definition layer into `codex-tools`, because the runtime
    binding and the crate-independent planning logic were still interleaved
    in one function.
    
    Splitting those concerns gives `codex-tools` ownership of the
    declarative registry plan while keeping `codex-core` responsible for
    instantiating concrete handlers.
    
    ## What Changed
    - Add a `codex-tools` registry-plan layer in
    `codex-rs/tools/src/tool_registry_plan.rs` and
    `codex-rs/tools/src/tool_registry_plan_types.rs`.
    - Move feature-gated tool-spec assembly, MCP/dynamic tool conversion,
    tool-search aliases, and code-mode nested-plan expansion into
    `codex-tools`.
    - Keep `codex-rs/core/src/tools/spec.rs` as the core-side adapter that
    maps each planned handler kind to concrete runtime handler instances.
    - Update `spec_tests.rs` to import the moved `codex_tools` symbols
    directly instead of relying on top-level `spec.rs` re-exports.
    
    This is intended to be a straight refactor with no behavior change and
    no new test surface.
    
    ## Verification
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16513).
    * #16521
    * __->__ #16513
  • fix: add update to Cargo.lock that was missed in #16512 (#16516)
    This PR updates `Cargo.lock` to remove `codex-core` from
    `mcp_test_support`, which corresponds to
    `codex-rs/mcp-server/tests/common/Cargo.toml`. As noted in #16512, it
    updated that crate to drop its `codex-core` dependency.
  • core: remove cross-crate re-exports from lib.rs (#16512)
    ## Why
    
    `codex-core` was re-exporting APIs owned by sibling `codex-*` crates,
    which made downstream crates depend on `codex-core` as a proxy module
    instead of the actual owner crate.
    
    Removing those forwards makes crate boundaries explicit and lets leaf
    crates drop unnecessary `codex-core` dependencies. In this PR, this
    reduces the dependency on `codex-core` to `codex-login` in the following
    files:
    
    ```
    codex-rs/backend-client/Cargo.toml
    codex-rs/mcp-server/tests/common/Cargo.toml
    ```
    
    ## What
    
    - Remove `codex-rs/core/src/lib.rs` re-exports for symbols owned by
    `codex-login`, `codex-mcp`, `codex-rollout`, `codex-analytics`,
    `codex-protocol`, `codex-shell-command`, `codex-sandboxing`,
    `codex-tools`, and `codex-utils-path`.
    - Delete the `default_client` forwarding shim in `codex-rs/core`.
    - Update in-crate and downstream callsites to import directly from the
    owning `codex-*` crate.
    - Add direct Cargo dependencies where callsites now target the owner
    crate, and remove `codex-core` from `codex-rs/backend-client`.
  • Extract code-mode nested tool collection into codex-tools (#16509)
    ## Why
    This is another small step in the `codex-core` -> `codex-tools`
    migration described in `AGENTS.md`.
    
    `core/src/tools/spec.rs` and `core/src/tools/code_mode/mod.rs` were both
    hand-rolling the same pure transformation: convert visible `ToolSpec`s
    into code-mode nested tool definitions, then sort and deduplicate by
    tool name. That logic does not depend on core runtime state or handlers,
    so keeping it in `codex-core` makes `spec.rs` harder to peel out later
    than it needs to be.
    
    ## What Changed
    - Add `collect_code_mode_tool_definitions()` to
    `codex-rs/tools/src/code_mode.rs`.
    - Reuse that helper from `codex-rs/core/src/tools/spec.rs` when
    assembling the `exec` tool description.
    - Reuse the same helper from `codex-rs/core/src/tools/code_mode/mod.rs`
    when exposing nested tool metadata to the code-mode runtime.
    
    This is intended to be a straight refactor with no behavior change and
    no new test surface.
    
    ## Verification
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    - `cargo test -p codex-core code_mode_only_`
  • core: use codex-mcp APIs directly (#16510)
    ## Why
    
    `codex-mcp` already owns the shared MCP API surface, including `auth`,
    `McpConfig`, `CODEX_APPS_MCP_SERVER_NAME`, and tool-name helpers in
    [`codex-rs/codex-mcp/src/mcp/mod.rs`](https://github.com/openai/codex/blob/f61e85dbfb5373cde6827d232ac8ea447c237e81/codex-rs/codex-mcp/src/mcp/mod.rs#L1-L35).
    Re-exporting that surface from `codex_core::mcp` gives downstream crates
    two import paths for the same API and hides the real crate dependency.
    
    This PR keeps `codex_core::mcp` focused on the local `McpManager`
    wrapper in
    [`codex-rs/core/src/mcp.rs`](https://github.com/openai/codex/blob/f61e85dbfb5373cde6827d232ac8ea447c237e81/codex-rs/core/src/mcp.rs#L13-L40)
    and makes consumers import shared MCP APIs from `codex_mcp` directly.
    
    ## What
    
    - Remove the `codex_mcp::mcp` re-export surface from `core/src/mcp.rs`.
    - Update `codex-core` internals plus `codex-app-server`, `codex-cli`,
    and `codex-tui` test code to import MCP APIs from `codex_mcp::mcp`
    directly.
    - Add explicit `codex-mcp` dependencies where those crates now use that
    API surface, and refresh `Cargo.lock`.
    
    ## Verification
    
    - `just bazel-lock-check`
    - `cargo test -p codex-core -p codex-cli -p codex-tui`
      - `codex-cli` passed.
    - `codex-core` still fails five unrelated config tests in
    `core/src/config/config_tests.rs` (`approvals_reviewer_*` and
    `smart_approvals_alias_*`).
    - A broader `cargo test -p codex-core -p codex-app-server -p codex-cli
    -p codex-tui` run previously hung in `codex-app-server` test
    `in_process_start_uses_requested_session_source_for_thread_start`.
  • Extract request_user_input normalization into codex-tools (#16503)
    ## Why
    This is another incremental step in the `codex-core` -> `codex-tools`
    migration called out in `AGENTS.md`: keep pure tool-definition and
    wire-shaping logic out of `codex-core` so the core crate can stay
    focused on runtime orchestration.
    
    `request_user_input` already had its spec and mode-availability helpers
    in `codex-tools` after #16471. The remaining argument validation and
    normalization still lived in the core runtime handler, which left that
    tool split across the two crates.
    
    ## What Changed
    - Export `REQUEST_USER_INPUT_TOOL_NAME` and
    `normalize_request_user_input_args()` from
    `codex-rs/tools/src/request_user_input_tool.rs`.
    - Use that `codex-tools` surface from `codex-rs/core/src/tools/spec.rs`
    and `codex-rs/core/src/tools/handlers/request_user_input.rs`.
    - Keep the core handler responsible for payload parsing, session
    dispatch, cancellation handling, and response serialization.
    
    This is intended to be a straight refactor with no behavior change.
    
    ## Verification
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core request_user_input`
  • core: use codex-tools config types directly (#16504)
    ## Why
    
    `codex-rs/tools/src/lib.rs` already defines the [canonical `codex_tools`
    export
    surface](https://github.com/openai/codex/blob/bf081b9e286e620d25c1d61cf0f38f74a0f982ce/codex-rs/tools/src/lib.rs#L83-L88)
    for `ToolsConfig`, `ToolsConfigParams`, and the shell backend config
    types. Re-exporting those same types from `core/src/tools/spec.rs` gives
    `codex-core` two import paths for one API and blurs which crate owns
    those config definitions.
    
    This PR removes that duplicate path so `codex-core` callsites depend on
    `codex_tools` directly.
    
    ## What
    
    - Remove the five `codex_tools` re-exports from
    `core/src/tools/spec.rs`.
    - Update `codex-core` production and test callsites to import
    `ShellCommandBackendConfig`, `ToolsConfig`, `ToolsConfigParams`,
    `UnifiedExecShellMode`, and `ZshForkConfig` from `codex_tools`.
    
    ## Verification
    
    - Ran `cargo test -p codex-core`.
    - The package run is currently red in five unrelated config tests in
    `core/src/config/config_tests.rs` (`approvals_reviewer_*` and
    `smart_approvals_alias_*`), while the tool/spec and shell tests touched
    by this import cleanup passed.
  • Fix paste-driven bottom pane completion teardown (#16202)
    Fix paste-driven bottom-pane completion teardown (#16192)
    
    `BottomPane::handle_paste()` could leave a completed modal flow mounted
    while re-enabling the composer, putting the TUI in an inconsistent state
    where stale views could still affect rendering and input routing. Align
    the paste path with the existing key-driven completion logic by tearing
    down the active modal flow before restoring composer input, and add a
    regression test covering the stacked-view case that exposed the bug.
    
    Big thanks to @iqdoctor for identifying the root cause for this issue.
  • Fix TUI app-server permission profile conversions (#16284)
    Addresses #16283
    
    Problem: TUI app-server permission approvals could drop filesystem
    grants because request and response payloads were round-tripped through
    mismatched camelCase and snake_case JSON shapes.
    Solution: Replace the lossy JSON round-trips with typed app-server/core
    permission conversions so requested and granted permission profiles,
    including filesystem paths and scope, are preserved end to end.
  • Extract tool-suggest wire helpers into codex-tools (#16499)
    ## Why
    
    This is another straight-refactor step in the `codex-tools` migration.
    
    `core/src/tools/handlers/tool_suggest.rs` still owned request/response
    payload structs, elicitation metadata shaping, and connector-completion
    predicates that do not depend on `codex-core` session/runtime internals.
    Per the `AGENTS.md` guidance to keep shrinking `codex-core`, this moves
    that pure wire-format logic into `codex-rs/tools` so the core handler
    keeps only session orchestration, plugin/config refresh, and MCP cache
    updates.
    
    ## What changed
    
    - Added `codex-rs/tools/src/tool_suggest.rs` and exported its API from
    `codex-rs/tools/src/lib.rs`.
    - Moved `ToolSuggestArgs`, `ToolSuggestResult`, `ToolSuggestMeta`,
    `build_tool_suggestion_elicitation_request()`,
    `all_suggested_connectors_picked_up()`, and
    `verified_connector_suggestion_completed()` into `codex-tools`.
    - Rewired `core/src/tools/handlers/tool_suggest.rs` to consume those
    exports directly.
    - Ported the existing pure helper tests from
    `core/src/tools/handlers/tool_suggest_tests.rs` to
    `tools/src/tool_suggest_tests.rs` without adding new behavior coverage.
    
    ## Validation
    
    ```shell
    cargo test -p codex-tools
    cargo test -p codex-core tools::handlers::tool_suggest::tests
    just argument-comment-lint
    ```
  • fix: guard guardian_command_source_tool_name with cfg(unix) (#16498)
    This currently contributing to `rust-ci-full.yml` being red on `main`
    for windows lint builds due to the cargo/bazel coverage gap that I'm
    working on. Hopefully this gets us back on track.
  • Extract tool-search output helpers into codex-tools (#16497)
    ## Why
    
    This is the next straight-refactor step in the `codex-tools` migration
    that follows #16493.
    
    `codex-rs/core` still owned a chunk of pure tool-discovery metadata and
    response shaping even though the corresponding `tool_search` /
    `tool_suggest` specs already live in `codex-rs/tools`. Per the guidance
    in `AGENTS.md`, this moves that crate-agnostic logic out of `codex-core`
    so the handler crate keeps only the BM25 ranking/orchestration and
    runtime glue.
    
    ## What changed
    
    - Moved the canonical `tool_search` / `tool_suggest` tool names and the
    `tool_search` default limit into `codex-rs/tools/src/tool_discovery.rs`.
    - Added `ToolSearchResultSource` and
    `collect_tool_search_output_tools()` in `codex-tools` so namespace
    grouping and deferred Responses API tool serialization happen outside
    `codex-core`.
    - Rewired `ToolSearchHandler`, `ToolSuggestHandler`, and
    `core/src/tools/spec.rs` to consume those exports directly from
    `codex-tools`.
    - Ported the existing `tool_search` serializer tests from
    `core/src/tools/handlers/tool_search_tests.rs` to
    `tools/src/tool_discovery_tests.rs` without adding new behavior
    coverage.
    
    ## Validation
    
    ```shell
    cargo test -p codex-tools
    cargo test -p codex-core tools::spec::tests
    just argument-comment-lint
    ```
  • Fix regression: "not available in TUI" error message (#16273)
    Addresses a recent TUI regression
    
    Problem: Pressing Ctrl+C during early TUI startup could route an
    interrupt with no active turn into the generic unsupported-op fallback,
    showing “Not available in app-server TUI yet for thread …” repeatedly.
    
    Solution: Treat interrupt requests as handled when no active turn exists
    yet, preventing fallback error spam during startup, and add a regression
    test covering interrupt-without-active-turn behavior.
  • Extract built-in tool spec constructors into codex-tools (#16493)
    ## Why
    
    `core/src/tools/spec.rs` still had a few built-in tool specs assembled
    inline even though those definitions are pure metadata and already live
    conceptually in `codex-tools`. Keeping that construction in `codex-core`
    makes `spec.rs` do more than registry orchestration and slows the
    migration toward a right-sized `codex-tools` crate.
    
    This continues the extraction stack from #16379, #16471, #16477, #16481,
    and #16482.
    
    ## What Changed
    
    - added `create_local_shell_tool()`, `create_web_search_tool(...)`, and
    `create_image_generation_tool(...)` to `codex-rs/tools/src/tool_spec.rs`
    - exported those helpers from `codex-rs/tools/src/lib.rs`
    - switched `codex-rs/core/src/tools/spec.rs` to call those helpers
    instead of constructing `ToolSpec::LocalShell`, `ToolSpec::WebSearch`,
    and `ToolSpec::ImageGeneration` inline
    - removed the remaining core-local web-search content-type constant and
    made the affected spec test assert the literal expected values directly
    
    This is intended to be a straight refactor: tool behavior and wire shape
    should not change.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
  • fix: remove unused import (#16495)
    This lint violation slipped through because our Bazel CI setup currently
    doesn't cover `--tests` when doing `cargo clippy`. I am working on
    fixing this via:
    
    - https://github.com/openai/codex/pull/16450
    - https://github.com/openai/codex/pull/16460
  • Remove client_common tool re-exports (#16482)
    ## Why
    
    `codex-rs/core/src/client_common.rs` still had a `tools` re-export
    module that forwarded `codex_tools` types back into `codex-core`. After
    the earlier extraction work in #16379, #16471, #16477, and #16481, that
    extra layer no longer adds value.
    
    Removing it keeps dependencies explicit: the `codex-core` modules that
    actually use `ToolSpec` and related types now depend on `codex_tools`
    directly instead of reaching through `client_common`.
    
    ## What Changed
    
    - removed the `client_common::tools` re-export module from
    `core/src/client_common.rs`
    - updated the remaining `codex-core` consumers to import `codex_tools`
    directly
    - adjusted the affected test code to reference
    `codex_tools::ResponsesApiTool` directly as well
    
    This is a mechanical cleanup only. It does not change tool behavior or
    runtime logic.
    
    ## Testing
    
    - `cargo test -p codex-core client_common::tests`
    - `cargo test -p codex-core tools::router::tests`
    - `cargo test -p codex-core tools::context::tests`
    - `cargo test -p codex-core tools::spec::tests`
  • Extract MCP into codex-mcp crate (#15919)
    - Split MCP runtime/server code out of `codex-core` into the new
    `codex-mcp` crate. New/moved public structs/types include `McpConfig`,
    `McpConnectionManager`, `ToolInfo`, `ToolPluginProvenance`,
    `CodexAppsToolsCacheKey`, and the `McpManager` API
    (`codex_mcp::mcp::McpManager` plus the `codex_core::mcp::McpManager`
    wrapper/shim). New/moved functions include `with_codex_apps_mcp`,
    `configured_mcp_servers`, `effective_mcp_servers`,
    `collect_mcp_snapshot`, `collect_mcp_snapshot_from_manager`,
    `qualified_mcp_tool_name_prefix`, and the MCP auth/skill-dependency
    helpers. Why: this creates a focused MCP crate boundary and shrinks
    `codex-core` without forcing every consumer to migrate in the same PR.
    
    - Move MCP server config schema and persistence into `codex-config`.
    New/moved structs/enums include `AppToolApproval`,
    `McpServerToolConfig`, `McpServerConfig`, `RawMcpServerConfig`,
    `McpServerTransportConfig`, `McpServerDisabledReason`, and
    `codex_config::ConfigEditsBuilder`. New/moved functions include
    `load_global_mcp_servers` and
    `ConfigEditsBuilder::replace_mcp_servers`/`apply`. Why: MCP TOML
    parsing/editing is config ownership, and this keeps config
    validation/round-tripping (including per-tool approval overrides and
    inline bearer-token rejection) in the config crate instead of
    `codex-core`.
    
    - Rewire `codex-core`, app-server, and plugin call sites onto the new
    crates. Updated `Config::to_mcp_config(&self, plugins_manager)`,
    `codex-rs/core/src/mcp.rs`, `codex-rs/core/src/connectors.rs`,
    `codex-rs/core/src/codex.rs`,
    `CodexMessageProcessor::list_mcp_server_status_task`, and
    `utils/plugins/src/mcp_connector.rs` to build/pass the new MCP
    config/runtime types. Why: plugin-provided MCP servers still merge with
    user-configured servers, and runtime auth (`CodexAuth`) is threaded into
    `with_codex_apps_mcp` / `collect_mcp_snapshot` explicitly so `McpConfig`
    stays config-only.
  • Extract update_plan tool spec into codex-tools (#16481)
    ## Why
    
    `codex-rs/core/src/tools/handlers/plan.rs` still owned both the
    `update_plan` runtime handler and the static tool definition. The tool
    definition is pure metadata, so keeping it in `codex-core` works against
    the ongoing effort to move tool-spec code into `codex-tools` and keep
    `codex-core` focused on orchestration and execution paths.
    
    This continues the extraction work from #16379, #16471, and #16477.
    
    ## What Changed
    
    - added `codex-rs/tools/src/plan_tool.rs` with
    `create_update_plan_tool()`
    - re-exported that constructor from `codex-rs/tools/src/lib.rs`
    - updated `codex-rs/core/src/tools/spec.rs` and
    `codex-rs/core/src/tools/spec_tests.rs` to use the `codex-tools` export
    instead of a core-local static
    - removed the old `PLAN_TOOL` definition from
    `codex-rs/core/src/tools/handlers/plan.rs`; the `PlanHandler` runtime
    logic still stays in `codex-core`
    - tightened two `codex-core` aliases to `#[cfg(test)]` now that
    production code no longer needs them
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16481).
    * #16482
    * __->__ #16481
  • fix(guardian): make GuardianAssessmentEvent.action strongly typed (#16448)
    ## Description
    
    Previously the `action` field on `EventMsg::GuardianAssessment`, which
    describes what Guardian is reviewing, was typed as an arbitrary JSON
    blob. This PR cleans it up and defines a sum type representing all the
    various actions that Guardian can review.
    
    This is a breaking change (on purpose), which is fine because:
    - the Codex app / VSCE does not actually use `action` at the moment
    - the TUI code that consumes `action` is updated in this PR as well
    - rollout files that serialized old `EventMsg::GuardianAssessment` will
    just silently drop these guardian events
    - the contract is defined as unstable, so other clients have a fair
    warning :)
    
    This will make things much easier for followup Guardian work.
    
    ## Why
    
    The old guardian review payloads worked, but they pushed too much shape
    knowledge into downstream consumers. The TUI had custom JSON parsing
    logic for commands, patches, network requests, and MCP calls, and the
    app-server protocol was effectively just passing through an opaque blob.
    
    Typing this at the protocol boundary makes the contract clearer.
  • login: treat provider auth refresh_interval_ms=0 as no auto-refresh (#16480)
    ## Why
    
    Follow-up to #16288: the new dynamic provider auth token flow currently
    defaults `refresh_interval_ms` to a non-zero value and rejects `0`
    entirely.
    
    For command-backed bearer auth, `0` should mean "never auto-refresh".
    That lets callers keep using the cached token until the backend actually
    returns `401 Unauthorized`, at which point Codex can rerun the auth
    command as part of the existing retry path.
    
    ## What changed
    
    - changed `ModelProviderAuthInfo.refresh_interval_ms` to accept `0` and
    documented that value as disabling proactive refresh
    - updated the external bearer token refresher to treat
    `refresh_interval_ms = 0` as an indefinitely reusable cached token,
    while still rerunning the auth command during unauthorized recovery
    - regenerated `core/config.schema.json` so the schema minimum is `0` and
    the new behavior is described in the field docs
    - added coverage for both config deserialization and the no-auto-refresh
    plus `401` recovery behavior
    
    ## How tested
    
    - `cargo test -p codex-protocol`
    - `cargo test -p codex-login`
    - `cargo test -p codex-core test_deserialize_provider_auth_config_`
  • Extract tool discovery helpers into codex-tools (#16477)
    ## Why
    
    Follow-up to #16379 and #16471.
    
    `codex-rs/core/src/tools/spec.rs` still owned the pure discovery-shaping
    helpers that turn app metadata and discoverable tool metadata into the
    inputs used by `tool_search` and `tool_suggest`. Those helpers do not
    need `codex-core` runtime state, so keeping them in `codex-core`
    continued to blur the crate boundary this migration is trying to
    tighten.
    
    This change keeps pushing spec-only logic behind the `codex-tools` API
    so `codex-core` can focus on wiring runtime handlers to the resulting
    tool definitions.
    
    ## What Changed
    
    - Added `collect_tool_search_app_infos` and
    `collect_tool_suggest_entries` to
    `codex-rs/tools/src/tool_discovery.rs`.
    - Added a small `ToolSearchAppSource` adapter type in `codex-tools` so
    `codex-core` can pass app metadata into that shared helper logic without
    exposing `ToolInfo` across the crate boundary.
    - Re-exported the new discovery helpers from
    `codex-rs/tools/src/lib.rs`, which remains exports-only.
    - Updated `codex-rs/core/src/tools/spec.rs` to use those `codex-tools`
    helpers instead of maintaining local `tool_search_app_infos` and
    `tool_suggest_entries` functions.
    - Removed the now-redundant helper implementations from `codex-core`.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
  • ci: stop running rust CI with --all-features (#16473)
    ## Why
    
    Now that workspace crate features have been removed and
    `.github/scripts/verify_cargo_workspace_manifests.py` hard-bans new
    ones, Rust CI should stop building and testing with `--all-features`.
    
    Keeping `--all-features` in CI no longer buys us meaningful coverage for
    `codex-rs`, but it still makes the workflow look like we rely on Cargo
    feature permutations that we are explicitly trying to eliminate. It also
    leaves stale examples in the repo that suggest `--all-features` is a
    normal or recommended way to run the workspace.
    
    ## What changed
    
    - removed `--all-features` from the Rust CI `cargo chef cook`, `cargo
    clippy`, and `cargo nextest` invocations in
    `.github/workflows/rust-ci-full.yml`
    - updated the `just test` guidance in `justfile` to reflect that
    workspace crate features are banned and there should be no need to add
    `--all-features`
    - updated the multiline command example and snapshot in
    `codex-rs/tui/src/history_cell.rs` to stop rendering `cargo test
    --all-features --quiet`
    - tightened the verifier docstring in
    `.github/scripts/verify_cargo_workspace_manifests.py` so it no longer
    talks about temporary remaining exceptions
    
    ## How tested
    
    - `python3 .github/scripts/verify_cargo_workspace_manifests.py`
    - `cargo test -p codex-tui`
  • Extract tool spec helpers into codex-tools (#16471)
    ## Why
    
    Follow-up to #16379.
    
    `codex-rs/core/src/tools/spec.rs` and the corresponding handlers still
    owned several pure tool-definition helpers even though they do not need
    `codex-core` runtime state. Keeping that spec-only logic in `codex-core`
    keeps the crate boundary blurry and works against the guidance in
    `AGENTS.md` to keep shared tooling out of `codex-core` when possible.
    
    This change takes another step toward a dedicated `codex-tools` crate by
    moving more metadata and schema-building code behind the `codex-tools`
    API while leaving the actual tool execution paths in `codex-core`.
    
    ## What Changed
    
    - Added `codex-rs/tools/src/apply_patch_tool.rs` to own
    `ApplyPatchToolArgs`, the freeform/json `apply_patch` tool specs, and
    the moved `tool_apply_patch.lark` grammar.
    - Updated `codex-rs/tools/BUILD.bazel` so Bazel exposes the moved
    grammar file to `codex-tools`.
    - Moved the `request_user_input` availability and description helpers
    into `codex-rs/tools/src/request_user_input_tool.rs`, with the related
    unit tests moved alongside that business logic.
    - Moved `request_permissions_tool_description()` into
    `codex-rs/tools/src/local_tool.rs`.
    - Rewired `codex-rs/core/src/tools/spec.rs`,
    `codex-rs/core/src/tools/handlers/apply_patch.rs`, and
    `codex-rs/core/src/tools/handlers/request_user_input.rs` to consume the
    new `codex-tools` exports instead of local helper code.
    - Removed the now-redundant helper implementations and tests from
    `codex-core`, plus a couple of stale `client_common` re-exports that
    became unused after the move.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    - `cargo test -p codex-core tools::handlers::apply_patch::tests`
  • otel: remove the last workspace crate feature (#16469)
    ## Why
    
    `codex-otel` still carried `disable-default-metrics-exporter`, which was
    the last remaining workspace crate feature.
    
    We are removing workspace crate features because they do not fit our
    current build model well:
    
    - our Bazel setup does not honor crate features today, which can let
    feature-gated issues go unnoticed
    - they create extra crate build permutations that we want to avoid
    
    For this case, the feature was only being used to keep the built-in
    Statsig metrics exporter off in test and debug-oriented contexts. This
    repo already treats `debug_assertions` as the practical proxy for that
    class of behavior, so OTEL should follow the same convention instead of
    keeping a dedicated crate feature alive.
    
    ## What changed
    
    - removed `disable-default-metrics-exporter` from
    `codex-rs/otel/Cargo.toml`
    - removed the `codex-otel` dev-dependency feature activation from
    `codex-rs/core/Cargo.toml`
    - changed `codex-rs/otel/src/config.rs` so the built-in
    `OtelExporter::Statsig` default resolves to `None` when
    `debug_assertions` is enabled, with a focused unit test covering that
    behavior
    - removed the final feature exceptions from
    `.github/scripts/verify_cargo_workspace_manifests.py`, so workspace
    crate features are now hard-banned instead of temporarily allowlisted
    - expanded the verifier error message to explain the Bazel mismatch and
    build-permutation cost behind that policy
    
    ## How tested
    
    - `python3 .github/scripts/verify_cargo_workspace_manifests.py`
    - `cargo test -p codex-otel`
    - `cargo test -p codex-core
    metrics_exporter_defaults_to_statsig_when_missing`
    - `cargo test -p codex-app-server app_server_default_analytics_`
    - `just bazel-lock-check`
  • Extract tool config into codex-tools (#16379)
    ## Why
    
    `codex-core` already owns too much of the tool stack, and `AGENTS.md`
    explicitly pushes us to move shared code out of `codex-core` instead of
    letting it keep growing. This PR takes the next incremental step in
    moving `core/src/tools` toward `codex-rs/tools` by extracting
    low-coupling tool configuration and image-detail gating logic into
    `codex-tools`.
    
    That gives later extraction work a cleaner boundary to build on without
    trying to move the entire tools subtree in one shot.
    
    ## What changed
    
    - moved `ToolsConfig`, `ToolsConfigParams`, shell backend config, and
    unified-exec session selection from `core/src/tools/spec.rs` into
    `codex-tools`
    - moved original image-detail gating and normalization into
    `codex-tools`
    - updated `codex-core` to consume the new `codex-tools` exports and pass
    a rendered agent-type description instead of raw role config
    - kept `codex-rs/tools/src/lib.rs` exports-only, with extracted unit
    tests living in sibling `*_tests.rs` modules
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
  • tui: remove the voice-input crate feature (#16467)
    ## Why
    
    `voice-input` is the only remaining TUI crate feature, but it is also a
    default feature and nothing in the workspace selects it explicitly. In
    practice it is just acting as a proxy for platform support, which is
    better expressed with target-specific dependencies and cfgs.
    
    ## What changed
    
    - remove the `voice-input` feature from `codex-tui`
    - make `cpal` a normal non-Linux target dependency
    - replace the feature-based voice and audio cfgs with pure
    Linux-vs-non-Linux cfgs
    - shrink the workspace-manifest verifier allowlist to remove the
    remaining `codex-tui` exception
    
    ## How tested
    
    - `python3 .github/scripts/verify_cargo_workspace_manifests.py`
    - `cargo test -p codex-tui`
    - `just bazel-lock-check`
    - `just argument-comment-lint -p codex-tui`
  • tui: remove debug/test-only crate features (#16457)
    ## Why
    
    The remaining `vt100-tests` and `debug-logs` features in `codex-tui`
    were only gating test-only and debug-only behavior. Those feature
    toggles add Cargo and Bazel permutations without buying anything, and
    they make it easier for more crate features to linger in the workspace.
    
    ## What changed
    
    - delete `vt100-tests` and `debug-logs` from `codex-tui`
    - always compile the VT100 integration tests in the TUI test target
    instead of hiding them behind a Cargo feature
    - remove the unused textarea debug logging branch instead of replacing
    it with another gate
    - add the required argument-comment annotations in the VT100 tests now
    that Bazel sees those callsites during linting
    - shrink the manifest verifier allowlist again so only the remaining
    real feature exceptions stay permitted
    
    ## How tested
    
    - `cargo test -p codex-tui`
    - `just argument-comment-lint -p codex-tui`
  • cloud-tasks: split the mock client out of cloud-tasks-client (#16456)
    ## Why
    
    `codex-cloud-tasks-client` was mixing two different roles: the real HTTP
    client and the mock implementation used by tests and local mock mode.
    Keeping both in the same crate forced Cargo feature toggles and Bazel
    `crate_features` just to pick an implementation.
    
    This change keeps `codex-cloud-tasks-client` focused on the shared API
    surface and real backend client, and moves the mock implementation into
    its own crate so we can remove those feature permutations cleanly.
    
    ## What changed
    
    - add a new `codex-cloud-tasks-mock-client` crate that owns `MockClient`
    - remove the `mock` and `online` features from
    `codex-cloud-tasks-client`
    - make `codex-cloud-tasks-client` unconditionally depend on
    `codex-backend-client` and export `HttpClient` directly
    - gate the mock-mode path in `codex-cloud-tasks` behind
    `#[cfg(debug_assertions)]`, so release builds always initialize the real
    HTTP client
    - update `codex-cloud-tasks` and its tests to use
    `codex-cloud-tasks-mock-client::MockClient` wherever mock behavior is
    needed
    - remove the matching Bazel `crate_features` override and shrink the
    manifest verifier allowlist accordingly
    
    ## How tested
    
    - `cargo test -p codex-cloud-tasks-client`
    - `cargo test -p codex-cloud-tasks-mock-client`
    - `cargo test -p codex-cloud-tasks`
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16456).
    * #16457
    * __->__ #16456
  • ci: block new workspace crate features (#16455)
    ## Why
    
    We already enforce workspace metadata and lint inheritance for
    `codex-rs` manifests, but we still allow new crate features to slip into
    the workspace. That makes it too easy to add more Cargo-only feature
    permutations while we are trying to eliminate them.
    
    ## What changed
    
    - extend `verify_cargo_workspace_manifests.py` to reject new
    `[features]` tables in workspace crates
    - reject new optional dependencies that create implicit crate features
    - reject new workspace-to-workspace `features = [...]` activations and
    `default-features = false`
    - add a narrow temporary allowlist for the existing feature-bearing
    manifests and internal feature activations
    - make the allowlist self-shrinking so a follow-up removal has to delete
    its corresponding exception
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16455).
    * #16457
    * #16456
    * __->__ #16455
  • Make fuzzy file search case insensitive (#15772)
    Makes fuzzy file search use case-insensitive matching instead of
    smart-case in `codex-file-search`. I find smart-case to be a poor user
    experience -using the wrong case for a letter drops its match so
    significantly, it often drops off the results list, effectively making a
    search case-sensitive.
  • fix: remove unused import (#16449)
    https://github.com/openai/codex/pull/16433 resulted in an unused import
    inside `mod tests`. This is flagged by `cargo clippy --tests`, which is
    run as part of
    https://github.com/openai/codex/actions/workflows/rust-ci-full.yml, but
    is not caught by our current Bazel setup for clippy.
    
    Fixing this ASAP to get
    https://github.com/openai/codex/actions/workflows/rust-ci-full.yml green
    again, but am looking at fixing the Bazel workflow in parallel.
  • docs: update argument_comment_lint instructions in AGENTS.md (#16375)
    I noticed that Codex was spending more time on running this lint check
    locally than I would like. Now that we have the linter running
    cross-platform using Bazel in CI, I find it's best just to update the PR
    ASAP to get CI going than to wait for `just argument-comment-lint` to
    finish locally before updating the PR.