Commit Graph

5333 Commits

  • [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.
  • [codex] Initialize ICU data for code mode V8 (#17709)
    Link ICU data into code mode, otherwise locale-dependent methods cause a
    panic and a crash.
  • 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`
  • fix: pin inputs (#17471)
    ## Summary
    - Pin Rust git patch dependencies to immutable revisions and make
    cargo-deny reject unknown git and registry sources unless explicitly
    allowlisted.
    - Add checked-in SHA-256 coverage for the current rusty_v8 release
    assets, wire those hashes into Bazel, and verify CI override downloads
    before use.
    - Add rusty_v8 MODULE.bazel update/check tooling plus a Bazel CI guard
    so future V8 bumps cannot drift from the checked-in checksum manifest.
    - Pin release/lint cargo installs and all external GitHub Actions refs
    to immutable inputs.
    
    ## Future V8 bump flow
    Run these after updating the resolved `v8` crate version and checksum
    manifest:
    
    ```bash
    python3 .github/scripts/rusty_v8_bazel.py update-module-bazel
    python3 .github/scripts/rusty_v8_bazel.py check-module-bazel
    ```
    
    The update command rewrites the matching `rusty_v8_<crate_version>`
    `http_file` SHA-256 values in `MODULE.bazel` from
    `third_party/v8/rusty_v8_<crate_version>.sha256`. The check command is
    also wired into Bazel CI to block drift.
    
    ## Notes
    - This intentionally excludes RustSec dependency upgrades and
    bubblewrap-related changes per request.
    - The branch was rebased onto the latest origin/main before opening the
    PR.
    
    ## Validation
    - cargo fetch --locked
    - cargo deny check advisories
    - cargo deny check
    - cargo deny check sources
    - python3 .github/scripts/rusty_v8_bazel.py check-module-bazel
    - python3 .github/scripts/rusty_v8_bazel.py update-module-bazel
    - python3 -m unittest discover -s .github/scripts -p
    'test_rusty_v8_bazel.py'
    - python3 -m py_compile .github/scripts/rusty_v8_bazel.py
    .github/scripts/rusty_v8_module_bazel.py
    .github/scripts/test_rusty_v8_bazel.py
    - repo-wide GitHub Actions `uses:` audit: all external action refs are
    pinned to 40-character SHAs
    - yq eval on touched workflows and local actions
    - git diff --check
    - just bazel-lock-check
    
    ## Hash verification
    - Confirmed `MODULE.bazel` hashes match
    `third_party/v8/rusty_v8_146_4_0.sha256`.
    - Confirmed GitHub release asset digests for denoland/rusty_v8
    `v146.4.0` and openai/codex `rusty-v8-v146.4.0` match the checked-in
    hashes.
    - Streamed and SHA-256 hashed all 10 `MODULE.bazel` rusty_v8 asset URLs
    locally; every downloaded byte stream matched both `MODULE.bazel` and
    the checked-in manifest.
    
    ## Pin verification
    - Confirmed signing-action pins match the peeled commits for their tag
    comments: `sigstore/cosign-installer@v3.7.0`, `azure/login@v2`, and
    `azure/trusted-signing-action@v0`.
    - Pinned the remaining tag-based action refs in Bazel CI/setup:
    `actions/setup-node@v6`, `facebook/install-dotslash@v2`,
    `bazelbuild/setup-bazelisk@v3`, and `actions/cache/restore@v5`.
    - Normalized all `bazelbuild/setup-bazelisk@v3` refs to the peeled
    commit behind the annotated tag.
    - Audited Cargo git dependencies: every manifest git dependency uses
    `rev` only, every `Cargo.lock` git source has `?rev=<sha>#<same-sha>`,
    and `cargo deny check sources` passes with `required-git-spec = "rev"`.
    - Shallow-fetched each distinct git dependency repo at its pinned SHA
    and verified Git reports each object as a commit.
  • [codex] Remove unused Rust helpers (#17146)
    ## Summary
    
    Removes high-confidence unused Rust helper functions and exports across
    `codex-tui`, `codex-shell-command`, and utility crates.
    
    The cleanup includes dead TUI helper methods, unused
    path/string/elapsed/fuzzy-match utilities, an unused Windows PowerShell
    lookup helper, and the unused terminal palette version counter. This
    keeps the remaining public surface smaller without changing behavior.
    
    ## Validation
    
    - `just fmt`
    - `cargo test -p codex-tui -p codex-shell-command -p codex-utils-elapsed
    -p codex-utils-fuzzy-match -p codex-utils-string -p codex-utils-path`
    - `just fix -p codex-tui -p codex-shell-command -p codex-utils-elapsed
    -p codex-utils-fuzzy-match -p codex-utils-string -p codex-utils-path`
    - `git diff --check`
  • [codex] Add symlink flag to fs metadata (#17719)
    Add `is_symlink` to FsMetadata struct.
  • guardian timeout fix pr 3 - ux touch for timeouts (#17557)
    This PR teaches the TUI to render guardian review timeouts as explicit
    terminal history entries instead of dropping them from the live
    timeline.
    It adds timeout-specific history cells for command, patch, MCP tool, and
    network approval reviews.
    It also adds snapshot tests covering both the direct guardian event path
    and the app-server notification path.
  • 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
  • change realtime tool description (#17699)
    # 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.
  • 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.
  • Update phase 2 memory model to gpt-5.4 (#17384)
    ### Motivation
    - Switch the default model used for memory Phase 2 (consolidation) to
    the newer `gpt-5.4` model.
    
    ### Description
    - Change the Phase 2 model constant from `"gpt-5.3-codex"` to
    `"gpt-5.4"` in `codex-rs/core/src/memories/mod.rs`.
    
    ### Testing
    - Ran `just fmt`, which completed successfully.
    - Attempted `cargo test -p codex-core`, but the build failed in this
    environment because the `codex-linux-sandbox` crate requires the system
    `libcap` pkg-config entry and the required system packages could not be
    installed, so the test run was blocked.
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/cloud/tasks/task_i_69d977693b48832a967e78d73c66dc8e)
  • Fix tui compilation (#17691)
    The recent release broke, codex suggested this as the fix
    
    Source failure:
    https://github.com/openai/codex/actions/runs/24362949066/job/71147202092
    
    Probably from
    https://github.com/openai/codex/commit/ac82443d073f7f9a2248bad51bae2fa424ef4946
    
    For why it got in:
    ```
    The relevant setup:
    
    .github/workflows/rust-ci.yml (line 1) runs on PRs, but for codex-rs it only does:
    
    cargo fmt --check
    cargo shear
    argument-comment lint via Bazel
    no cargo check, no cargo clippy over the workspace, no cargo test over codex-tui
    .github/workflows/rust-ci-full.yml (line 1) runs on pushes to main and branches matching **full-ci**. That one does compile TUI because:
    
    codex-rs/Cargo.toml includes "tui" as a workspace member
    lint_build runs cargo clippy --target ... --tests --profile ...
    the matrix includes both dev and release profiles
    tests runs cargo nextest run ..., but only dev-profile tests
    Release CI also compiles it indirectly. .github/workflows/rust-release.yml (line 235) builds --bin codex, and cli/Cargo.toml (line 46) depends on codex-tui.
    ```
    
    Codex tested locally with `cargo check -p codex-tui --release` and was
    able to repro, and verified that this fixed it
  • only specify remote ports when the rule needs them (#17669)
    Windows gives an error when you combine `protocol = ANY` with
    `SetRemotePorts`
    This fixes that
  • app-server: Only unload threads which were unused for some time (#17398)
    Currently app-server may unload actively running threads once the last
    connection disconnects, which is not expected.
    Instead track when was the last active turn & when there were any
    subscribers the last time, also add 30 minute idleness/no subscribers
    timer to reduce the churn.
  • 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
    ```
  • Include legacy deny paths in elevated Windows sandbox setup (#17365)
    ## Summary
    
    This updates the Windows elevated sandbox setup/refresh path to include
    the legacy `compute_allow_paths(...).deny` protected children in the
    same deny-write payload pipe added for split filesystem carveouts.
    
    Concretely, elevated setup and elevated refresh now both build
    deny-write payload paths from:
    
    - explicit split-policy deny-write paths, preserving missing paths so
    setup can materialize them before applying ACLs
    - legacy `compute_allow_paths(...).deny`, which includes existing
    `.git`, `.codex`, and `.agents` children under writable roots
    
    This lets the elevated backend protect `.git` consistently with the
    unelevated/restricted-token path, and removes the old janky hard-coded
    `.codex` / `.agents` elevated setup helpers in favor of the shared
    payload path.
    
    ## Root Cause
    
    The landed split-carveout PR threaded a `deny_write_paths` pipe through
    elevated setup/refresh, but the legacy workspace-write deny set from
    `compute_allow_paths(...).deny` was not included in that payload. As a
    result, elevated workspace-write did not apply the intended deny-write
    ACLs for existing protected children like `<cwd>/.git`.
    
    ## Notes
    
    The legacy protected children still only enter the deny set if they
    already exist, because `compute_allow_paths` filters `.git`, `.codex`,
    and `.agents` with `exists()`. Missing explicit split-policy deny paths
    are preserved separately because setup intentionally materializes those
    before applying ACLs.
    
    ## Validation
    
    - `cargo fmt --check -p codex-windows-sandbox`
    - `cargo test -p codex-windows-sandbox`
    - `cargo build -p codex-cli -p codex-windows-sandbox --bins`
    - Elevated `codex exec` smoke with `windows.sandbox='elevated'`: fresh
    git repo, attempted append to `.git/config`, observed `Access is
    denied`, marker not written, Deny ACE present on `.git`
    - Unelevated `codex exec` smoke with `windows.sandbox='unelevated'`:
    fresh git repo, attempted append to `.git/config`, observed `Access is
    denied`, marker not written, Deny ACE present on `.git`
  • Do not fail thread start when trust persistence fails (#17595)
    Addresses #17593
    
    Problem: A regression introduced in
    https://github.com/openai/codex/pull/16492 made thread/start fail when
    Codex could not persist trusted project state, which crashes startup for
    users with read-only config.toml.
    
    Solution: Treat trusted project persistence as best effort and keep the
    current thread's config trusted in memory when writing config.toml
    fails.
  • Fix TUI compaction item replay (#17657)
    Problem: PR #17601 updated context-compaction replay to call a new
    ChatWidget handler, but the handler was never implemented, breaking
    codex-tui compilation on main.
    
    Solution: Render context-compaction replay through the existing
    info-message path, preserving the intended `Context compacted` UI marker
    without adding a one-off handler.
  • Suppress duplicate compaction and terminal wait events (#17601)
    Addresses #17514
    
    Problem: PR #16966 made the TUI render the deprecated context-compaction
    notification, while v2 could also receive legacy unified-exec
    interaction items alongside terminal-interaction notifications, causing
    duplicate "Context compacted" and "Waited for background terminal"
    messages.
    
    Solution: Suppress deprecated context-compaction notifications and
    legacy unified-exec interaction command items from the app-server v2
    projection, and render canonical context-compaction items through the
    existing TUI info-event path.
  • Wrap status reset timestamps in narrow layouts (#17481)
    Addresses #17453
    
    Problem: /status rate-limit reset timestamps can be truncated in narrow
    layouts, leaving users with partial times or dates.
    
    Solution: Let narrow rate-limit rows drop the fixed progress bar to
    preserve the percent summary, and wrap reset timestamps onto
    continuation lines instead of truncating them.
  • Emit plan-mode prompt notifications for questionnaires (#17417)
    Addresses #17252
    
    Problem: Plan-mode clarification questionnaires used the generic
    user-input notification type, so configs listening for plan-mode-prompt
    did not fire when request_user_input waited for an answer.
    
    Solution: Map request_user_input prompts to the plan-mode-prompt
    notification and remove the obsolete user-input TUI notification
    variant.
  • 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"
    />
  • Stabilize exec-server process tests (#17605)
    Problem: After #17294 switched exec-server tests to launch the top-level
    `codex exec-server` command, parallel remote exec-process cases can
    flake while waiting for the child server's listen URL or transport
    shutdown.
    
    Solution: Serialize remote exec-server-backed process tests and harden
    the harness so spawned servers are killed on drop and shutdown waits for
    the child process to exit.
  • 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.
  • fix(mcp) pause timer for elicitations (#17566)
    ## Summary
    Stop counting elicitation time towards mcp tool call time. There are
    some tradeoffs here, but in general I don't think time spent waiting for
    elicitations should count towards tool call time, or at least not
    directly towards timeouts.
    
    Elicitations are not exactly like exec_command escalation requests, but
    I would argue it's ~roughly equivalent.
    
    ## Testing
    - [x] Added unit tests
    - [x] Tested locally
  • Expose instruction sources (AGENTS.md) via app server (#17506)
    Addresses #17498
    
    Problem: The TUI derived /status instruction source paths from the local
    client environment, which could show stale <none> output or incorrect
    paths when connected to a remote app server.
    
    Solution: Add an app-server v2 instructionSources snapshot to thread
    start/resume/fork responses, default it to an empty list when older
    servers omit it, and render TUI /status from that server-provided
    session data.
    
    Additional context: The app-server field is intentionally named
    instructionSources rather than AGENTS.md-specific terminology because
    the loaded instruction sources can include global instructions, project
    AGENTS.md files, AGENTS.override.md, user-defined instruction files, and
    future dynamic sources.
  • 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.
  • feat(tui): add reverse history search to composer (#17550)
    ## Problem
    
    The TUI had shell-style Up/Down history recall, but `Ctrl+R` did not
    provide the reverse incremental search workflow users expect from
    shells. Users needed a way to search older prompts without immediately
    replacing the current draft, and the interaction needed to handle async
    persistent history, repeated navigation keys, duplicate prompt text,
    footer hints, and preview highlighting without making the main composer
    file even harder to review.
    
    
    https://github.com/user-attachments/assets/5165affd-4c9a-46e9-adbd-89088f5f7b6b
    
    <img width="1227" height="722" alt="image"
    src="https://github.com/user-attachments/assets/8bc83289-eeca-47c7-b0c3-8975101901af"
    />
    
    ## Mental model
    
    `Ctrl+R` opens a temporary search session owned by the composer. The
    footer line becomes the search input, the composer body previews the
    current match only after the query has text, and `Enter` accepts that
    preview as an editable draft while `Esc` restores the draft that existed
    before search started. The history layer provides a combined offset
    space over persistent and local history, but search navigation exposes
    unique prompt text rather than every physical history row.
    
    ## Non-goals
    
    This change does not rewrite stored history, change normal Up/Down
    browsing semantics, add fuzzy matching, or add persistent metadata for
    attachments in cross-session history. Search deduplication is
    deliberately scoped to the active Ctrl+R search session and uses exact
    prompt text, so case, whitespace, punctuation, and attachment-only
    differences are not normalized.
    
    ## Tradeoffs
    
    The implementation keeps search state in the existing composer and
    history state machines instead of adding a new cross-module controller.
    That keeps ownership local and testable, but it means the composer still
    coordinates visible search status, draft restoration, footer rendering,
    cursor placement, and match highlighting while `ChatComposerHistory`
    owns traversal, async fetch continuation, boundary clamping, and
    unique-result caching. Unique-result caching stores cloned
    `HistoryEntry` values so known matches can be revisited without cache
    lookups; this is simple and robust for interactive search sizes, but it
    is not a global history index.
    
    ## Architecture
    
    `ChatComposer` detects `Ctrl+R`, snapshots the current draft, switches
    the footer to `FooterMode::HistorySearch`, and routes search-mode keys
    before normal editing. Query edits call `ChatComposerHistory::search`
    with `restart = true`, which starts from the newest combined-history
    offset. Repeated `Ctrl+R` or Up searches older; Down searches newer
    through already discovered unique matches or continues the scan.
    Persistent history entries still arrive asynchronously through
    `on_entry_response`, where a pending search either accepts the response,
    skips a duplicate, or requests the next offset.
    
    The composer-facing pieces now live in
    `codex-rs/tui/src/bottom_pane/chat_composer/history_search.rs`, leaving
    `chat_composer.rs` responsible for routing and rendering integration
    instead of owning every search helper inline.
    `codex-rs/tui/src/bottom_pane/chat_composer_history.rs` remains the
    owner of stored history, combined offsets, async fetch state, boundary
    semantics, and duplicate suppression. Match highlighting is computed
    from the current composer text while search is active and disappears
    when the match is accepted.
    
    ## Observability
    
    There are no new logs or telemetry. The practical debug path is state
    inspection: `ChatComposer.history_search` tells whether the footer query
    is idle, searching, matched, or unmatched; `ChatComposerHistory.search`
    tracks selected raw offsets, pending persistent fetches, exhausted
    directions, and unique match cache state. If a user reports skipped or
    repeated results, first inspect the exact stored prompt text, the
    selected offset, whether an async persistent response is still pending,
    and whether a query edit restarted the search session.
    
    ## Tests
    
    The change is covered by focused `codex-tui` unit tests for opening
    search without previewing the latest entry, accepting and canceling
    search, no-match restoration, boundary clamping, footer hints,
    case-insensitive highlighting, local duplicate skipping, and persistent
    duplicate skipping through async responses. Snapshot coverage captures
    the footer-mode visual changes. Local verification used `just fmt`,
    `cargo test -p codex-tui history_search`, `cargo test -p codex-tui`, and
    `just fix -p codex-tui`.
  • 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>
  • build(pnpm): require reviewed dependency build scripts (#17558)
    ## Description
    
    Enable pnpm's reviewed build-script gate for this repo.
    
    ## What changed
    
    - added `strictDepBuilds: true` to `pnpm-workspace.yaml`
    
    ## Why
    
    The repo already uses pinned pnpm and frozen installs in CI. This adds
    the remaining guard so dependency build scripts do not run unless they
    are explicitly reviewed.
    
    ## Validation
    
    - ran `pnpm install --frozen-lockfile`
    
    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.
  • [codex] Support bubblewrap in secure Docker devcontainer (#17547)
    ## Summary
    
    - leave the default contributor devcontainer on its lightweight
    platform-only Docker runtime
    - install bubblewrap in setuid mode only in the secure devcontainer
    image for running Codex inside Docker
    - add Docker run args to the secure profile for bubblewrap's required
    capabilities
    - use explicit `seccomp=unconfined` and `apparmor=unconfined` in the
    secure profile instead of shipping a custom seccomp profile
    - document that the relaxed Docker security options are scoped to the
    secure profile
    
    ## Why
    
    Docker's default seccomp profile blocks bubblewrap with `pivot_root:
    Operation not permitted`, even when the container has `CAP_SYS_ADMIN`.
    Docker's default AppArmor profile also blocks bubblewrap with `Failed to
    make / slave: Permission denied`.
    
    A custom seccomp profile works, but it is hard for customers to audit
    and understand. Using Docker's standard `seccomp=unconfined` option is
    clearer: the secure profile intentionally relaxes Docker's outer sandbox
    just enough for Codex to construct its own bubblewrap/seccomp sandbox
    inside the container. The default contributor profile does not get these
    expanded runtime settings.
    
    ## Validation
    
    - `sed '/\\/\\*/,/\\*\\//d' .devcontainer/devcontainer.json | jq empty`
    - `jq empty .devcontainer/devcontainer.secure.json`
    - `git diff --check`
    - `docker build --platform=linux/arm64 -t
    codex-devcontainer-bwrap-test-arm64 ./.devcontainer`
    - `docker build --platform=linux/arm64 -f
    .devcontainer/Dockerfile.secure -t
    codex-devcontainer-secure-bwrap-test-arm64 .`
    - interactive `docker run -it` smoke tests:
      - verified non-root users `ubuntu` and `vscode`
      - verified secure image `/usr/bin/bwrap` is setuid
    - verified user/pid namespace, user/network namespace, and preserved-fd
    `--ro-bind-data` bwrap commands
    - reran secure-image smoke test with simplified `seccomp=unconfined`
    setup:
      - `bwrap-basic-ok`
      - `bwrap-netns-ok`
      - `codex-ok`
    - ran Codex inside the secure image:
      - `codex --version` -> `codex-cli 0.120.0`
    - `codex sandbox linux --full-auto -- /bin/sh -lc '...'` -> exited 0 and
    printed `codex-inner-ok`
    
    Note: direct `bwrap --proc /proc` is still denied by this Docker
    runtime, and Codex's existing proc-mount preflight fallback handles that
    by retrying without `--proc`.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Clarify guardian timeout guidance (#17521)
    ## Summary
    - update the guardian timeout guidance to say permission approval review
    timed out
    - simplify the retry guidance to say retry once or ask the user for
    guidance or explicit approval
    
    ## Testing
    - cargo test -p codex-core
    guardian_timeout_message_distinguishes_timeout_from_policy_denial
    - cargo test -p codex-core
    guardian_review_decision_maps_to_mcp_tool_decision
  • changing decision semantics after guardian timeout (#17486)
    **Summary**
    
    This PR treats Guardian timeouts as distinct from explicit denials in
    the core approval paths.
    Timeouts now return timeout-specific guidance instead of Guardian
    policy-rejection messaging.
    It updates the command, shell, network, and MCP approval flows and adds
    focused test coverage.