Commit Graph

2729 Commits

  • register all mcp tools with namespace (#17404)
    stacked on #17402.
    
    MCP tools returned by `tool_search` (deferred tools) get registered in
    our `ToolRegistry` with a different format than directly available
    tools. this leads to two different ways of accessing MCP tools from our
    tool catalog, only one of which works for each. fix this by registering
    all MCP tools with the namespace format, since this info is already
    available.
    
    also, direct MCP tools are registered to responsesapi without a
    namespace, while deferred MCP tools have a namespace. this means we can
    receive MCP `FunctionCall`s in both formats from namespaces. fix this by
    always registering MCP tools with namespace, regardless of deferral
    status.
    
    make code mode track `ToolName` provenance of tools so it can map the
    literal JS function name string to the correct `ToolName` for
    invocation, rather than supporting both in core.
    
    this lets us unify to a single canonical `ToolName` representation for
    each MCP tool and force everywhere to use that one, without supporting
    fallbacks.
  • [codex] Fix current main CI blockers (#17917)
    ## Summary
    - Fix marketplace-add local path detection on Windows by using
    `Path::is_absolute()`.
    - Make marketplace-add local-source tests parse/write TOML through the
    same helpers instead of raw string matching.
    - Update `rand` 0.9.x to 0.9.3 and document the remaining audited `rand`
    0.8.5 advisory exception.
    - Refresh `MODULE.bazel.lock` after the Cargo.lock update.
    
    ## Why
    Latest `main` had two independent CI blockers: marketplace-add tests
    were not portable to Windows path/TOML escaping, and cargo-deny still
    reported `RUSTSEC-2026-0097` after the recent rustls-webpki fix.
    
    ## Validation
    - `cargo test -p codex-core marketplace_add -- --nocapture`
    - `cargo deny --all-features check`
    - `just bazel-lock-check`
    - `just fix -p codex-core`
    - `just fmt`
    - `git diff --check`
  • Send sandbox state through MCP tool metadata (#17763)
    ## Changes
    
    Allows MCPs to opt in to receiving sandbox config info through `_meta`
    on model-initiated tool calls. This lets MCPs adhere to the thread's
    sandbox if they choose to.
    
    ## Details
    
    - Adds the `codex/sandbox-state-meta` experimental MCP capability.
    - Tracks whether each MCP server advertises that capability.
    - When a server opts in, `codex-core` injects the current `SandboxState`
    into model-initiated MCP tool-call request `_meta`.
    
    ## Verification
    
    - added an integration test for the capability
  • fix: cleanup the contract of the general-purpose exec() function (#17870)
    `exec()` had a number of arguments that were unused, making the function
    signature misleading. This PR aims to clean things up to clarify the
    role of this function and to clarify which fields of `ExecParams` are
    unused and why.
  • sandbox: remove dead seatbelt helper and update tests (#17859)
    ## Why
    
    `spawn_command_under_seatbelt()` in `codex-rs/core/src/seatbelt.rs` had
    fallen out of production use and was only referenced by test-only
    wrappers. That left us with sandbox tests that could stay green even if
    the actual seatbelt exec path regressed, because production shell
    execution now flows through `SandboxManager::transform()` and
    `ExecRequest::from_sandbox_exec_request()` instead of that helper.
    
    Removing the dead helper also exposed one downstream `codex-exec`
    integration test that still imported it, which broke `just clippy`.
    
    ## What Changed
    
    - Removed `codex-rs/core/src/seatbelt.rs` and stopped exporting
    `codex_core::seatbelt`.
    - Removed the redundant `codex-rs/core/tests/suite/seatbelt.rs` coverage
    that only exercised the dead helper.
    - Kept the `openpty` regression check, but moved it into
    `codex-rs/core/tests/suite/exec.rs` so it now runs through
    `process_exec_tool_call()`.
    - Fixed the seatbelt denial test in `codex-rs/core/tests/suite/exec.rs`
    to use `/usr/bin/touch`, so it actually exercises the sandbox instead of
    a nonexistent path.
    - Updated `codex-rs/exec/tests/suite/sandbox.rs` on macOS to build the
    sandboxed command through `build_exec_request()` and spawn the
    transformed command, instead of importing the removed helper.
    - Left the lower-level seatbelt policy coverage in
    `codex-rs/sandboxing/src/seatbelt_tests.rs`, where the policy generator
    is still covered directly.
    
    ## Verification
    
    - `cargo test -p codex-core suite::exec::`
    - `cargo test -p codex-exec`
    - `cargo clippy -p codex-exec --tests -- -D warnings`
  • Reuse remote exec-server in core tests (#17837)
    ## Summary
    - reuse a shared remote exec-server for remote-aware codex-core
    integration tests within a test binary process
    - keep per-test remote cwd creation and cleanup so tests retain
    workspace isolation
    - leave codex_self_exe, codex_linux_sandbox_exe, cwd_path(), and
    workspace_path() behavior unchanged
    
    ## Validation
    - rustfmt codex-rs/core/tests/common/test_codex.rs
    - git diff --check
    - CI is running on the updated branch
  • Fix clippy warnings in external agent config migration (#17884)
    Fix clippy warnings in external agent config migration
    
    ```
    error: this expression creates a reference which is immediately dereferenced by the compiler
       --> core/src/external_agent_config.rs:188:55
        |
    188 |             let migrated = build_config_from_external(&settings)?;
        |                                                       ^^^^^^^^^ help: change this to: `settings`
        |
        = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.93.0/index.html#needless_borrow
        = note: requested on the command line with `-D clippy::needless-borrow`
    
    error: useless conversion to the same type: `codex_utils_absolute_path::AbsolutePathBuf`
       --> core/src/external_agent_config.rs:355:27
        |
    355 |                       match AbsolutePathBuf::try_from(
        |  ___________________________^
    356 | |                         add_marketplace_outcome
    357 | |                             .installed_root
    358 | |                             .join(INSTALLED_MARKETPLACE_MANIFEST_RELATIVE_PATH),
    359 | |                     ) {
        | |_____________________^
        |
        = help: consider removing `AbsolutePathBuf::try_from()`
        = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.93.0/index.html#useless_conversion
        = note: `-D clippy::useless-conversion` implied by `-D warnings`
        = help: to override `-D warnings` add `#[allow(clippy::useless_conversion)]`
    
    error: aborting due to 2 previous errors
    ```
  • Wrap delegated input text (#17868)
    ## Summary
    - wrap routed delegation text in a small XML envelope before submitting
    it as a user turn
    - escape XML text content so the envelope stays well formed
    - update focused coverage for the wrapper and the affected routed-turn
    expectations
  • Disable hooks in guardian review sessions (#17872)
    ## What
    Disable `Feature::CodexHooks` when building guardian review session
    config
    
    ## Why
    Guardian review sessions were respecting the Stop hook and could ingest
    synthetic `<hook_prompt>` user turns Guardian should ignore hooks, while
    the main session and regular subagents continue to respect them
    
    In other words Guardian was getting ralph-looped
    
    Co-authored-by: Codex <noreply@openai.com>
  • Fix for CI Tests failing from stack overflow (#17846)
    ### **Issue**
    guardian_parallel_reviews_fork_from_last_committed_trunk_history was
    failing on Windows/Bazel with a stack overflow:
    
    `thread
    'guardian::tests::guardian_parallel_reviews_fork_from_last_committed_trunk_history'
    has overflowed its stack`
    
    - This problem was a stack-headroom problem
    
    ### **Solution**
    
    Reduced stack pressure in the guardian async path by boxing thin wrapper
    futures, and run the affected test on a dedicated 2 MiB thread stack.
    
    Concretely:
    - added Box::pin(...) around thin async wrapper hops in the guardian
    review/delegate path
    - changed
    guardian_parallel_reviews_fork_from_last_committed_trunk_history to run
    inside an explicitly sized thread stack so it has enough headroom in
    low-stack environments
  • [codex] Support local marketplace sources (#17756)
    ## Summary
    
    - Port marketplace source support into the shared core marketplace-add
    flow
    - Support local marketplace directory sources
    - Support direct `marketplace.json` URL sources
    - Persist the new source types in config/schema and cover them in CLI
    and app-server tests
    
    ## Validation
    
    - `cargo test -p codex-core marketplace_add`
    - `cargo test -p codex-cli marketplace_add`
    - `cargo test -p codex-app-server marketplace_add`
    - `just write-config-schema`
    - `just fmt`
    - `just fix -p codex-core`
    - `just fix -p codex-cli`
    
    ## Context
    
    Current `main` moved marketplace-add behavior into shared core code and
    still assumed only git-backed sources. This change keeps that structure
    but restores support for local directories and direct manifest URLs in
    the shared path.
  • Make skill loading filesystem-aware (#17720)
    Migrates skill loading to support reading repo skills from the remote
    environment.
  • Adjust default tool search result caps (#17684)
    ## Summary
    
    - Allows selected MCP results to return a larger default result set.
    - Keeps the existing default cap for other MCP results.
    - Applies the cap consistently when higher explicit limits are
    requested.
    
    ## Testing
    
    - `cargo test -p codex-core tool_search`
    - Ran a local CLI smoke test with two stdio MCP servers exposing 100
    tools each; the selected-server query returned 20 tools and the
    regular-server query returned 8.
  • fix: apply patch bin refresh (#17808)
    Make sure the link to apply patch binary (i.e. codex) does not die in
    case of an update
    
    Fix this:
    https://openai.slack.com/archives/C08MGJXUCUQ/p1776183247771849
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Spread AbsolutePathBuf (#17792)
    Mechanical change to promote absolute paths through code.
  • Route apply_patch through the environment filesystem (#17674)
    ## Summary
    - route apply_patch runtime execution through the selected Environment
    filesystem instead of the local self-exec path
    - keep the standalone apply_patch command surface intact while restoring
    its launcher/test/docs contract
    - add focused apply_patch filesystem sandbox regression coverage
    
    ## Validation
    - remote devbox Bazel run in progress
    - passed: //codex-rs/apply-patch:apply-patch-unit-tests
    --test_filter=test_read_file_utf8_with_context_reports_invalid_utf8
    - in progress / follow-up: focused core and exec Bazel test slices on
    dev
    
    ## Follow-up under review
    - remote pre-verification and approval/retry behavior still need
    explicit scrutiny for delete/update flows
    - runtime sandbox-denial classification may need a tighter assertion
    path than rendered stderr matching
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix: Revert danger-full-access denylist-only mode (#17732)
    ## Summary
    
    - Reverts openai/codex#16946 and removes the danger-full-access
    denylist-only network mode.
    - Removes the corresponding config requirements, app-server
    protocol/schema, config API, TUI debug output, and network proxy
    behavior.
    - Drops stale tests that depended on the reverted mode while preserving
    newer managed allowlist-only coverage.
    
    ## Verification
    
    - `just write-app-server-schema`
    - `just fmt`
    - `cargo test -p codex-config network_requirements`
    - `cargo test -p codex-core network_proxy_spec`
    - `cargo test -p codex-core
    managed_network_proxy_decider_survives_full_access_start`
    - `cargo test -p codex-app-server map_requirements_toml_to_api`
    - `cargo test -p codex-tui debug_config_output`
    - `cargo test -p codex-app-server-protocol`
    - `just fix -p codex-config -p codex-core -p codex-app-server-protocol
    -p codex-app-server -p codex-tui`
    - `git diff --cached --check`
    
    Not run: full workspace `cargo test` (repo instructions ask for
    confirmation before that broader run).
  • [codex-analytics] add session source to client metadata (#17374)
    ## Summary
    
    Adds `thread_source` field to the existing Codex turn metadata sent to
    Responses API
    - Sends `thread_source: "user"` for user-initiated sessions: CLI, VS
    Code, and Exec
    - Sends `thread_source: "subagent"` for subagent sessions
    - Omits `thread_source` for MCP, custom, and unknown session sources
    - Uses the existing turn metadata transport:
      - HTTP requests send through the `x-codex-turn-metadata` header
    - WebSocket `response.create` requests send through
    `client_metadata["x-codex-turn-metadata"]`
    
    ## Testing
    - `cargo test -p codex-protocol
    session_source_thread_source_name_classifies_user_and_subagent_sources`
    - `cargo test -p codex-core turn_metadata_state`
    - `cargo test -p codex-core --test responses_headers
    responses_stream_includes_turn_metadata_header_for_git_workspace_e2e --
    --nocapture`
  • Always enable original image detail on supported models (#17665)
    ## Summary
    
    This PR removes `image_detail_original` as a runtime experiment and
    makes original image detail available whenever the selected model
    supports it.
    
    Concretely, this change:
    - drops the `image_detail_original` feature flag from the feature
    registry and generated config schema
    - makes tool-emitted image detail depend only on
    `ModelInfo.supports_image_detail_original`
    - updates `view_image` and `code_mode`/`js_repl` image emission to use
    that capability check directly
    - removes now-redundant experiment-specific tests and instruction
    coverage
    - keeps backward compatibility for existing configs by silently ignoring
    a stale `features.image_detail_original` entry
    
    The net effect is that `detail: "original"` is always available on
    supported models, without requiring an experiment toggle.
  • Add realtime output modality and transcript events (#17701)
    - Add outputModality to thread/realtime/start and wire text/audio output
    selection through app-server, core, API, and TUI.\n- Rename the realtime
    transcript delta notification and add a separate transcript done
    notification that forwards final text from item done without correlating
    it with deltas.
  • [codex-analytics] feature plumbing and emittance (#16640)
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16640).
    * #16870
    * #16706
    * #16641
    * __->__ #16640
  • [codex] drain mailbox only at request boundaries (#17749)
    This changes multi-agent v2 mailbox handling so incoming inter-agent
    messages no longer preempt an in-flight sampling stream at reasoning or
    commentary output-item boundaries.
  • Refactor plugin loading to async (#17747)
    Simplifies skills migration.
  • [codex] Refactor marketplace add into shared core flow (#17717)
    ## Summary
    
    Move `codex marketplace add` onto a shared core implementation so the
    CLI and app-server path can use one source of truth.
    
    This change:
    - adds shared marketplace-add orchestration in `codex-core`
    - switches the CLI command to call that shared implementation
    - removes duplicated CLI-only marketplace add helpers
    - preserves focused parser and add-path coverage while moving the shared
    behavior into core tests
    
    ## Why
    
    The new `marketplace/add` RPC should reuse the same underlying
    marketplace-add flow as the CLI. This refactor lands that consolidation
    first so the follow-up app-server PR can be mostly protocol and handler
    wiring.
    
    ## Validation
    
    - `cargo test -p codex-core marketplace_add`
    - `cargo test -p codex-cli marketplace_cmd`
    - `just fix -p codex-core`
    - `just fix -p codex-cli`
    - `just fmt`
  • Stabilize exec-server filesystem tests in CI (#17671)
    ## Summary\n- add an exec-server package-local test helper binary that
    can run exec-server and fs-helper flows\n- route exec-server filesystem
    tests through that helper instead of cross-crate codex helper
    binaries\n- stop relying on Bazel-only extra binary wiring for these
    tests\n\n## Testing\n- not run (per repo guidance for codex changes)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add turn item injection API (#17703)
    ## Summary
    - Add `turn/inject_items` app-server v2 request support for appending
    raw Responses API items to a loaded thread history without starting a
    turn.
    - Generate JSON schema and TypeScript protocol artifacts for the new
    params and empty response.
    - Document the new endpoint and include a request/response example.
    - Preserve compatibility with the typo alias `turn/injet_items` while
    returning the canonical method name.
    
    ## Testing
    - Not run (not requested)
  • Add supports_parallel_tool_calls flag to included mcps (#17667)
    ## Why
    
    For more advanced MCP usage, we want the model to be able to emit
    parallel MCP tool calls and have Codex execute eligible ones
    concurrently, instead of forcing all MCP calls through the serial block.
    
    The main design choice was where to thread the config. I made this
    server-level because parallel safety depends on the MCP server
    implementation. Codex reads the flag from `mcp_servers`, threads the
    opted-in server names into `ToolRouter`, and checks the parsed
    `ToolPayload::Mcp { server, .. }` at execution time. That avoids relying
    on model-visible tool names, which can be incomplete in
    deferred/search-tool paths or ambiguous for similarly named
    servers/tools.
    
    ## What was added
    
    Added `supports_parallel_tool_calls` for MCP servers.
    
    Before:
    
    ```toml
    [mcp_servers.docs]
    command = "docs-server"
    ```
    
    After:
    
    ```toml
    [mcp_servers.docs]
    command = "docs-server"
    supports_parallel_tool_calls = true
    ```
    
    MCP calls remain serial by default. Only tools from opted-in servers are
    eligible to run in parallel. Docs also now warn to enable this only when
    the server’s tools are safe to run concurrently, especially around
    shared state or read/write races.
    
    ## Testing
    
    Tested with a local stdio MCP server exposing real delay tools. The
    model/Responses side was mocked only to deterministically emit two MCP
    calls in the same turn.
    
    Each test called `query_with_delay` and `query_with_delay_2` with `{
    "seconds": 25 }`.
    
    | Build/config | Observed | Wall time |
    | --- | --- | --- |
    | main with flag enabled | serial | `58.79s` |
    | PR with flag enabled | parallel | `31.73s` |
    | PR without flag | serial | `56.70s` |
    
    PR with flag enabled showed both tools start before either completed;
    main and PR-without-flag completed the first delay before starting the
    second.
    
    Also added an integration test.
    
    Additional checks:
    
    - `cargo test -p codex-tools` passed
    - `cargo test -p codex-core
    mcp_parallel_support_uses_exact_payload_server` passed
    - `git diff --check` passed
  • Cap realtime mirrored user turns (#17685)
    Cap mirrored user text sent to realtime with the existing 300-token turn
    budget while preserving the full model turn.
    
    Adds integration coverage for capped realtime mirror payloads.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Remove unnecessary tests (#17395)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • feat: Avoid reloading curated marketplaces for tool-suggest discovera… (#17638)
    - stop `list_tool_suggest_discoverable_plugins()` from reloading the
    curated marketplace for each discoverable plugin
    - reuse a direct plugin-detail loader against the already-resolved
    marketplace entry
    
    
    The trigger was to stop those logs spamming:
    ```
    d=019d81cf-6f69-7230-98aa-74294ff2dc5a}:submission_dispatch{otel.name="op.dispatch.user_input" submission.id="019d86c8-0a8e-7013-b442-109aabbf75c9" codex.op="user_input"}:turn{otel.name="session_task.turn" thread.id=019d81cf-6f69-7230-98aa-74294ff2dc5a turn.id=019d86c8-0a8e-7013-b442-109aabbf75c9 model=gpt-5.4}: ignoring interface.defaultPrompt: prompt must be at most 128 characters path=/Users/jif/.codex/.tmp/plugins/plugins/life-science-research/.codex-plugin/plugin.json
    2026-04-13T12:27:30.402Z WARN  [019d81cf-6f69-7230-98aa-74294ff2dc5a] codex_core::plugins::manifest - session_loop{thread_id=019d81cf-6f69-7230-98aa-74294ff2dc5a}:submission_dispatch{otel.name="op.dispatch.user_input" submission.id="019d86c8-0a8e-7013-b442-109aabbf75c9" codex.op="user_input"}:turn{otel.name="session_task.turn" thread.id=019d81cf-6f69-7230-98aa-74294ff2dc5a turn.id=019d86c8-0a8e-7013-b442-109aabbf75c9 model=gpt-5.4}: ignoring interface.defaultPrompt: prompt must be at most 128 characters path=/Users/jif/.codex/.tmp/plugins/plugins/build-ios-apps/.codex-plugin/plugin.json
    2026-04-13T12:27:30.402Z WARN  [019d81cf-6f69-7230-98aa-74294ff2dc5a] codex_core::plugins::manifest - session_loop{thread_id=019d81cf-6f69-7230-98aa-74294ff2dc5a}:submission_dispatch{otel.name="op.dispatch.user_input" submission.id="019d86c8-0a8e-7013-b442-109aabbf75c9" codex.op="user_input"}:turn{otel.name="session_task.turn" thread.id=019d81cf-6f69-7230-98aa-74294ff2dc5a turn.id=019d86c8-0a8e-7013-b442-109aabbf75c9 model=gpt-5.4}: ignoring interface.defaultPrompt: prompt must be at most 128 characters path=/Users/jif/.codex/.tmp/plugins/plugins/life-science-research/.codex-plugin/plugin.json
    2026-04-13T12:27:30.405Z WARN  [019d81cf-6f69-7230-98aa-74294ff2dc5a] codex_core::plugins::manifest - session_loop{thread_id=019d81cf-6f69-7230-98aa-74294ff2dc5a}:submission_dispatch{otel.name="op.dispatch.user_input" submission.id="019d86c8-0a8e-7013-b442-109aabbf75c9" codex.op="user_input"}:turn{otel.name="session_task.turn" thread.id=019d81cf-6f69-7230-98aa-74294ff2dc5a turn.id=019d86c8-0a8e-7013-b442-109aabbf75c9 model=gpt-5.4}: ignoring interface.defaultPrompt: prompt must be at most 128 characters path=/Users/jif/.codex/.tmp/plugins/plugins/build-ios-apps/.codex-plugin/plugin.json
    2026-04-13T12:27:30.406Z WARN  [019d81cf-6f69-7230-98aa-74294ff2dc5a] codex_core::plugins::manifest - session_loop{thread_id=019d81cf-6f69-7230-98aa-74294ff2dc5a}:submission_dispatch{otel.name="op.dispatch.user_input" submission.id="019d86c8-0a8e-7013-b442-109aabbf75c9" codex.op="user_input"}:turn{otel.name="session_task.turn" thread.id=019d81cf-6f69-7230-98aa-74294ff2dc5a turn.id=019d86c8-0a8e-7013-b442-109aabbf75c9 model=gpt-5.4}: ignoring interface.defaultPrompt: prompt must be at most 128 characters path=/Users/jif/.codex/.tmp/plugins/plugins/life-science-research/.codex-plugin/plugin.json
    2026-04-13T12:27:30.408Z WARN  [019d81cf-6f69-7230-98aa-74294ff2dc5a] codex_core::plugins::manifest - session_loop{thread_id=019d81cf-6f69-7230-98aa-74294ff2dc5a}:submission_dispatch{otel.name="op.dispatch.user_input" submission.id="019d86c8-0a8e-7013-b442-109aabbf75c9" codex.op="user_input"}:turn{otel.name="session_task.turn" thread.id=019d81cf-6f69-7230-98aa-74294ff2dc5a turn.id=019d86c8-0a8e-7013-b442-109aabbf75c9 model=gpt-5.4}: ignoring interface.defaultPrompt: prompt must be at most 128 characters path=/Users/jif/.codex/.tmp/plugins/plugins/build-ios-apps/.codex-plugin/plugin.json
    ```
  • Fix custom tool output cleanup on stream failure (#17470)
    Addresses #16255
    
    Problem: Incomplete Responses streams could leave completed custom tool
    outputs out of cleanup and retry prompts, making persisted history
    inconsistent and retries stale.
    
    Solution: Route stream and output-item errors through shared cleanup,
    and rebuild retry prompts from fresh session history after the first
    attempt.
  • Make forked agent spawns keep parent model config (#17247)
    ## Summary
    
    When a `spawn_agent` call does a full-history fork, keep the parent's
    effective agent type and model configuration instead of applying child
    role/model overrides.
    
    This is the minimal config-inheritance slice of #16055. Prompt-cache key
    inheritance and MCP tool-surface stability are split into follow-up PRs.
    
    ## Design
    
    - Reject `agent_type`, `model`, and `reasoning_effort` for v1
    `fork_context` spawns.
    - Reject `agent_type`, `model`, and `reasoning_effort` for v2
    `fork_turns = "all"` spawns.
    - Keep v2 partial-history forks (`fork_turns = "N"`) configurable;
    requested model/reasoning overrides and role config still apply there.
    - Keep non-forked spawn behavior unchanged.
    
    ## Tests
    
    - `cargo +1.93.1 test -p codex-core spawn_agent_fork_context --lib`
    - `cargo +1.93.1 test -p codex-core multi_agent_v2_spawn_fork_turns
    --lib`
    - `cargo +1.93.1 test -p codex-core
    multi_agent_v2_spawn_partial_fork_turns_allows_agent_type_override
    --lib`
  • Build remote exec env from exec-server policy (#17216)
    ## Summary
    - add an exec-server `envPolicy` field; when present, the server starts
    from its own process env and applies the shell environment policy there
    - keep `env` as the exact environment for local/embedded starts, but
    make it an overlay for remote unified-exec starts
    - move the shell-environment-policy builder into `codex-config` so Core
    and exec-server share the inherit/filter/set/include behavior
    - overlay only runtime/sandbox/network deltas from Core onto the
    exec-server-derived env
    
    ## Why
    Remote unified exec was materializing the shell env inside Core and
    forwarding the whole map to exec-server, so remote processes could
    inherit the orchestrator machine's `HOME`, `PATH`, etc. This keeps the
    base env on the executor while preserving Core-owned runtime additions
    like `CODEX_THREAD_ID`, unified-exec defaults, network proxy env, and
    sandbox marker env.
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - `cargo test -p codex-exec-server --lib`
    - `cargo test -p codex-core --lib unified_exec::process_manager::tests`
    - `cargo test -p codex-core --lib exec_env::tests`
    - `cargo test -p codex-core --lib exec_env_tests` (compile-only; filter
    matched 0 tests)
    - `cargo test -p codex-config --lib shell_environment` (compile-only;
    filter matched 0 tests)
    - `just bazel-lock-update`
    
    ## Known local validation issue
    - `just bazel-lock-check` is not runnable in this checkout: it invokes
    `./scripts/check-module-bazel-lock.sh`, which is missing.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
    Co-authored-by: pakrym-oai <pakrym@openai.com>
  • feat: ignore keyring on 0.0.0 (#17221)
    To prevent the spammy: 
    <img width="424" height="172" alt="Screenshot 2026-04-09 at 13 36 16"
    src="https://github.com/user-attachments/assets/b5ece9e3-c561-422f-87ec-041e7bd6813d"
    />
  • Run exec-server fs operations through sandbox helper (#17294)
    ## Summary
    - run exec-server filesystem RPCs requiring sandboxing through a
    `codex-fs` arg0 helper over stdin/stdout
    - keep direct local filesystem execution for `DangerFullAccess` and
    external sandbox policies
    - remove the standalone exec-server binary path in favor of top-level
    arg0 dispatch/runtime paths
    - add sandbox escape regression coverage for local and remote filesystem
    paths
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - remote devbox: `cd codex-rs && bazel test --bes_backend=
    --bes_results_url= //codex-rs/exec-server:all` (6/6 passed)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add MCP tool wall time to model output (#17406)
    Include MCP wall time in the output so the model is aware of how long
    it's calls are taking.
  • Remove context status-line meter (#17420)
    Addresses #17313
    
    Problem: The visual context meter in the status line was confusing and
    continued to draw negative feedback, and context reporting should remain
    an explicit opt-in rather than part of the default footer.
    
    Solution: Remove the visual meter, restore opt-in context remaining/used
    percentage items that explicitly say "Context", keep existing
    context-usage configs working as a hidden alias, and update the setup
    text and snapshots.
  • Mirror user text into realtime (#17520)
    - Let typed user messages submit while realtime is active and mirror
    accepted text into the realtime text stream.
    - Add integration coverage and snapshot for outbound realtime text.
  • fix(sandboxing): reject WSL1 bubblewrap sandboxing (#17559)
    ## Summary
    
    - detect WSL1 before Codex probes or invokes the Linux bubblewrap
    sandbox
    - fail early with a clear unsupported-operation message when a command
    would require bubblewrap on WSL1
    - document that WSL2 follows the normal Linux bubblewrap path while WSL1
    is unsupported
    
    ## Why
    
    Codex 0.115.0 made bubblewrap the default Linux sandbox. WSL1 cannot
    create the user namespaces that bubblewrap needs, so shell commands
    currently fail later with a raw bwrap namespace error. This makes the
    unsupported environment explicit and keeps non-bubblewrap paths
    unchanged.
    
    The WSL detection reads /proc/version, lets an explicit WSL<version>
    marker decide WSL1 vs WSL2+, and only treats a bare Microsoft marker as
    WSL1 when no explicit WSL version is present.
    
    addresses https://github.com/openai/codex/issues/16076
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Support flattened deferred MCP tool calls (#17556)
    ## Summary
    - register flattened handler aliases for deferred MCP tools
    - cover the node_repl-shaped deferred MCP call path in tool registry
    tests
    
    ## Root Cause
    Deferred MCP tools were registered only under their namespaced handler
    key, e.g. `mcp__node_repl__:js`. If the model/bridge emitted the
    flattened qualified name `mcp__node_repl__js`, core parsed it as an MCP
    payload but dispatch looked up the flattened handler key and returned
    `unsupported call` before reaching the MCP handler.
    
    ## Validation
    - `just fmt`
    - `cargo test -p codex-tools
    search_tool_registers_deferred_mcp_flattened_handlers`
    - `cargo test -p codex-core
    search_tool_registers_namespaced_mcp_tool_aliases`
    - `git diff --check`
  • Budget realtime current thread context (#17519)
    Select Current Thread startup context by budget from newest turns, cap
    each rendered turn at 300 approximate tokens, and add formatter plus
    integration snapshot coverage.