Commit Graph

3486 Commits

  • core: add focused diagnostics for remote compaction overflows (#11133)
    ## Summary
    - add targeted remote-compaction failure diagnostics in compact_remote
    logging
    - log the specific values needed to explain overflow timing:
      - last_api_response_total_tokens
      - estimated_tokens_of_items_added_since_last_successful_api_response
      - estimated_bytes_of_items_added_since_last_successful_api_response
      - failing_compaction_request_body_bytes
    - simplify breakdown naming and remove
    last_api_response_total_bytes_estimate (it was an approximation and not
    useful for debugging)
    
    ## Why
    When compaction fails with context_length_exceeded, we need concrete,
    low-ambiguity numbers that map directly to:
    1) what the API most recently reported, and
    2) what local history added since then.
    
    This keeps the failure logs actionable without adding broad, noisy
    metrics.
    
    ## Testing
    - just fmt
    - cargo test -p codex-core
  • TUI: fix request_user_input wrapping for long option labels (#11123)
    ## Summary
    
    This PR fixes long-text rendering in the `request_user_input` TUI
    overlay while preserving a clear two-column option layout. (Issue
    https://github.com/openai/codex/issues/11093)
    
    Before:
    - very long option labels could push description text into a narrow
    right-edge strip
    - option labels were effectively single-line when descriptions were
    present, causing truncation/poor readability
    - label and description wrapping interacted in one combined wrapped line
    
    <img width="504" height="409" alt="Screenshot 2026-02-08 at 2 27 25 PM"
    src="https://github.com/user-attachments/assets/a9afd108-d792-4522-bce1-e43b3cce882b"
    />
    
    After:
    - option labels wrap inside the left column
    - descriptions wrap independently inside the right column
    - row measurement and row rendering use the same wrapping path, so
    layout stays stable
    
    <img width="582" height="211" alt="Screenshot 2026-02-09 at 10 28 02 AM"
    src="https://github.com/user-attachments/assets/47885a1c-07e5-4b0f-b992-032b149f1b0d"
    />
    
    ## Problem
    
    `request_user_input` needs to handle verbose prompts/options. With
    oversized labels:
    - descriptions could collapse into a thin, hard-to-read column
    - important label context was lost
    
    ## Root Cause
    
    In shared row rendering (`selection_popup_common`):
    - rows were wrapped as a single combined line
    - auto column sizing could still place `desc_col` too far right for long
    labels
    - `request_user_input` rows did not provide wrap metadata to align
    continuation lines after the option prefix
    
    ## What Changed
    
    ### 1) `request_user_input` rows opt into wrapped labels
    File: `codex-rs/tui/src/bottom_pane/request_user_input/mod.rs`
    
    - In `option_rows()`, compute the rendered option prefix (`› 1. ` / ` 2.
    `) and set `wrap_indent` from its display width.
    - Apply the same behavior to the synthetic “None of the above” row.
    - Add long-text snapshot test coverage
    (`question_with_very_long_option_text` +
    `request_user_input_long_option_text_snapshot`).
    
    ### 2) Shared renderer now has an opt-in two-column wrapping path
    File: `codex-rs/tui/src/bottom_pane/selection_popup_common.rs`
    
    - Add focused helpers:
      - `should_wrap_name_in_column`
      - `wrap_two_column_row`
      - `wrap_standard_row`
      - `wrap_row_lines`
      - `apply_row_state_style`
    - For opted-in rows (plain option rows with `wrap_indent` +
    description), wrap label and description independently in their own
    columns.
    - Keep the legacy standard wrapping path for non-opted rows.
    - Use the same `wrap_row_lines` function in both rendering and height
    measurement to keep them in sync.
    
    ### 3) Keep column sizing simple and derived from existing fixed split
    constants
    File: `codex-rs/tui/src/bottom_pane/selection_popup_common.rs`
    
    - Keep fixed mode at `3/10` left column (`30/70` split).
    - In auto modes, cap label width using those same fixed constants (max
    70% label, min 30% description), instead of extra special-case
    constants/branches.
    - Add/keep narrow-width safety guard in `wrap_two_column_row` so
    extremely small widths do not panic.
    
    ### 4) Snapshot coverage
    File: `codex-rs/tui/src/bottom_pane/request_user_input/snapshots/
    
    codex_tui__bottom_pane__request_user_input__tests__request_user_input_long_option_text.snap`
    
    - Add snapshot for long-label/long-description two-column rendering
    behavior.
  • chore: remove network-proxy-cli crate (#11158)
    ## Summary
    - remove `network-proxy-cli` from the Rust workspace members
    - delete the dedicated `codex-network-proxy-cli` crate files
    - remove the stale `codex-network-proxy-cli` package entry from
    `Cargo.lock`
    
    ## Testing
    - just fmt
    - cargo test -p codex-network-proxy
  • Move warmup to the task level (#11216)
    Instead of storing a special connection on the client level make the
    regular task responsible for establishing a normal client session and
    open a connection on it.
    
    Then when the turn is started we pass in a pre-established session.
  • Move warmup to the task level (#11216)
    Instead of storing a special connection on the client level make the
    regular task responsible for establishing a normal client session and
    open a connection on it.
    
    Then when the turn is started we pass in a pre-established session.
  • Fixed bug in file watcher that results in spurious skills update events and large log files (#11217)
    On some platforms, the "notify" file watcher library emits events for
    file opens and reads, not just file modifications or deletes. The
    previous implementation didn't take this into account.
    
    Furthermore, the `tracing.info!` call that I previously added was
    emitting a lot of logs. I had assumed incorrectly that `info` level
    logging was disabled by default, but it's apparently enabled for this
    crate. This is resulting in large logs (hundreds of MB) for some users.
  • Translate websocket errors (#10937)
    When getting errors over a websocket connection, translate the error
    into our regular API error format
  • tools: remove get_memory tool and tests (#11198)
    Drop this memory tool as the design changed
  • core: account for all post-response items in auto-compact token checks (#11132)
    ## Summary
    - change compaction pre-check accounting to include all items added
    after the last model-generated item, not only trailing codex-generated
    outputs
    - use that boundary consistently in get_total_token_usage() and
    get_total_token_usage_breakdown()
    - update history tests to cover user/tool-output items after the last
    model item
    
    ## Why
    last_token_usage.total_tokens is API-reported for the last successful
    model response. After that point, local history may gain additional
    items (user messages, injected context, tool outputs). Compaction
    triggering must account for all of those items to avoid late compaction
    attempts that can overflow context.
    
    ## Testing
    - just fmt
    - cargo test -p codex-core
  • Load requirements on windows (#10770)
    We support requirements on Unix, loading from
    `/etc/codex/requirements.toml`. On MacOS, we also support MDM.
    
    Now, on Windows, we'll load requirements from
    `%ProgramData%\OpenAI\Codex\requirements.toml`
  • Deflake mixed parallel tools timing test (#11193)
    ```
            FAIL [   1.903s] (1926/3311) codex-core::all suite::tool_parallelism::mixed_parallel_tools_run_in_parallel
      stdout ───
    
        running 1 test
        test suite::tool_parallelism::mixed_parallel_tools_run_in_parallel ... FAILED
    
        failures:
    
        failures:
            suite::tool_parallelism::mixed_parallel_tools_run_in_parallel
    
        test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 684 filtered out; finished in 1.86s
        
      stderr ───
    
        thread 'suite::tool_parallelism::mixed_parallel_tools_run_in_parallel' (205083) panicked at core/tests/suite/tool_parallelism.rs:74:5:
        expected parallel execution to finish quickly, got 1.406255993s
        stack backtrace:
           0: __rustc::rust_begin_unwind
                     at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/std/src/panicking.rs:689:5
           1: core::panicking::panic_fmt
                     at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/core/src/panicking.rs:80:14
           2: all::suite::tool_parallelism::assert_parallel_duration
                     at ./tests/suite/tool_parallelism.rs:74:5
           3: all::suite::tool_parallelism::mixed_parallel_tools_run_in_parallel::{{closure}}
                     at ./tests/suite/tool_parallelism.rs:206:5
           4: <core::pin::Pin<P> as core::future::future::Future>::poll
                     at /home/runner/.rustup/toolchains/1.93.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/future/future.rs:133:9
           5: tokio::runtime::park::CachedParkThread::block_on::{{closure}}
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/park.rs:284:71
           6: tokio::task::coop::with_budget
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/task/coop/mod.rs:167:5
           7: tokio::task::coop::budget
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/task/coop/mod.rs:133:5
           8: tokio::runtime::park::CachedParkThread::block_on
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/park.rs:284:31
           9: tokio::runtime::context::blocking::BlockingRegionGuard::block_on
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/context/blocking.rs:66:14
          10: tokio::runtime::scheduler::multi_thread::MultiThread::block_on::{{closure}}
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/scheduler/multi_thread/mod.rs:89:22
          11: tokio::runtime::context::runtime::enter_runtime
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/context/runtime.rs:65:16
          12: tokio::runtime::scheduler::multi_thread::MultiThread::block_on
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/scheduler/multi_thread/mod.rs:88:9
          13: tokio::runtime::runtime::Runtime::block_on_inner
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/runtime.rs:370:50
          14: tokio::runtime::runtime::Runtime::block_on
                     at /home/runner/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.49.0/src/runtime/runtime.rs:342:18
          15: all::suite::tool_parallelism::mixed_parallel_tools_run_in_parallel
                     at ./tests/suite/tool_parallelism.rs:208:7
          16: all::suite::tool_parallelism::mixed_parallel_tools_run_in_parallel::{{closure}}
                     at ./tests/suite/tool_parallelism.rs:178:52
          17: core::ops::function::FnOnce::call_once
                     at /home/runner/.rustup/toolchains/1.93.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
          18: core::ops::function::FnOnce::call_once
                     at /rustc/254b59607d4417e9dffbc307138ae5c86280fe4c/library/core/src/ops/function.rs:250:5
        note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    ```
  • feat: do not close unified exec processes across turns (#10799)
    With this PR we do not close the unified exec processes (i.e. background
    terminals) at the end of a turn unless:
    * The user interrupt the turn
    * The user decide to clean the processes through `app-server` or
    `/clean`
    
    I made sure that `codex exec` correctly kill all the processes
  • tui: avoid no-op status-line redraws (#11155)
    Rate-limit snapshots are polled every 60s, which causes unconditional
    redraws.
    This causes spurious "tab changed" indicators in terminal apps.
  • feat: include NetworkConfig through ExecParams (#11105)
    This PR adds the following field to `Config`:
    
    ```rust
    pub network: Option<NetworkProxy>,
    ```
    
    Though for the moment, it will always be initialized as `None` (this
    will be addressed in a subsequent PR).
    
    This PR does the work to thread `network` through to `execute_exec_env()`, `process_exec_tool_call()`, and `UnifiedExecRuntime.run()` to ensure it is available whenever we span a process.
  • [apps] Improve app loading. (#10994)
    There are two concepts of apps that we load in the harness:
    
    - Directory apps, which is all the apps that the user can install.
    - Accessible apps, which is what the user actually installed and can be
    $ inserted and be used by the model. These are extracted from the tools
    that are loaded through the gateway MCP.
    
    Previously we wait for both sets of apps before returning the full apps
    list. Which causes many issues because accessible apps won't be
    available to the UI or the model if directory apps aren't loaded or
    failed to load.
    
    In this PR we are separating them so that accessible apps can be loaded
    separately and are instantly available to be shown in the UI and to be
    provided in model context. We also added an app-server event so that
    clients can subscribe to also get accessible apps without being blocked
    on the full app list.
    
    - [x] Separate accessible apps and directory apps loading.
    - [x] `app/list` request will also emit `app/list/updated` notifications
    that app-server clients can subscribe. Which allows clients to get
    accessible apps list to render in the $ menu without being blocked by
    directory apps.
    - [x] Cache both accessible and directory apps with 1 hour TTL to avoid
    reloading them when creating new threads.
    - [x] TUI improvements to redraw $ menu and /apps menu when app list is
    updated.
  • feat: include [experimental_network] in <environment_context> (#11044)
    If `NetworkConstraints` is set, then include the relevant settings on `<environment_context>`. Example:
    
    ```xml
    <environment_context>
      <cwd>/repo</cwd>
      <shell>bash</shell>
      <network enabled="true">
        <allowed>api.example.com</allowed>
        <allowed>*.openai.com</allowed>
        <denied>blocked.example.com</denied>
      </network>
    </environment_context>
    ```
  • Upgrade rmcp to 0.14 (#10718)
    - [x] Upgrade rmcp to 0.14
  • chore: refactor network-proxy so that ConfigReloader is injectable behavior (#11114)
    Currently, `codex-network-proxy` depends on `codex-core`, but this
    should be the other way around. As a first step, refactor out
    `ConfigReloader`, which should make it easier to move
    `codex-rs/network-proxy/src/state.rs` to `codex-core` in a subsequent
    commit.
  • Gate view_image tool by model input_modalities (#11051)
    - Plumb input modalities from model catalog through the openai model
    protocol. Default to text and image.
    - Conditionally add the view_image tool only if input modalities support
    image.
  • fix: remove config.schema.json from tag check (#10980)
    Given that we have https://github.com/openai/codex/pull/10977, the
    existing "Verify config schema fixture" step seems unnecessary. Further,
    because it happens as part of the `tag-check` job (which is meant to be
    fast), it slows down the entire build process because it delays the more
    expensive steps from starting.
  • Defer persistence of rollout file (#11028)
    - Defer rollout persistence for fresh threads (`InitialHistory::New`):
    keep rollout events in memory and only materialize rollout file + state
    DB row on first `EventMsg::UserMessage`.
    - Keep precomputed rollout path available before materialization.
    - Change `thread/start` to build thread response from live config
    snapshot and optional precomputed path.
    - Improve pre-materialization behavior in app-server/TUI: clearer
    invalid-request errors for file-backed ops and a friendlier `/fork` “not
    ready yet” UX.
    - Update tests to match deferred semantics across
    start/read/archive/unarchive/fork/resume/review flows.
    - Improved resilience of user_shell test, which should be unrelated to
    this change but must be affected by timing changes
    
    For Reviewers:
    * The primary change is in recorder.rs
    * Most of the other changes were to fix up broken assumptions in
    existing tests
    
    Testing:
    * Manually tested CLI
    * Exercised app server paths by manually running IDE Extension with
    rebuilt CLI binary
    * Only user-visible change is that `/fork` in TUI generates visible
    error if used prior to first turn
  • Fallback to HTTP on UPGRADE_REQUIRED (#10824)
    Allow the server to trigger a connection downgrade in case the protocol
    changes in incompatible ways.
  • fix(tui): rehydrate drafts and restore image placeholders (#9040)
    Fixes #9050
    
    When a draft is stashed with Ctrl+C, we now persist the full draft state
    (text elements, local image paths, and pending paste payloads) in local
    history. Up/Down recall rehydrates placeholder elements and attachments
    so styling remains correct and large pastes still expand on submit.
    Persistent (cross‑session) history remains text‑only.
    
    Backtrack prefills now reuse the selected user message’s text elements
    and local image paths, so image placeholders/attachments rehydrate when
    rolling back.
    
    External editor replacements keep only attachments whose placeholders
    remain and then normalize image placeholders to `[Image #1]..[Image #N]`
    to keep the attachment mapping consistent.
    
    Docs:
    - docs/tui-chat-composer.md
    
    Testing:
    - just fix -p codex-tui
    - cargo test -p codex-tui
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • feat: enable premessage-deflate for websockets (#10966)
    note:
    unfortunately, tokio-tungstenite / tungstenite upgrade triggers some
    problems with linker of rama-tls-boring with openssl:
    ```
    error: linking with `/Users/apanasenko/Library/Caches/cargo-zigbuild/0.20.1/zigcc-x86_64-unknown-linux-musl-ff6a.sh` failed: exit status: 1
      |
      = note:  "/Users/apanasenko/Library/Caches/cargo-zigbuild/0.20.1/zigcc-x86_64-unknown-linux-musl-ff6a.sh" "-m64" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained/rcrt1.o" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained/crti.o" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained/crtbeginS.o" "<1 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/var/folders/kt/52y_g75x3ng8ktvk3rfwm6400000gp/T/rustcyGQdYm/{liblzma_sys-662a82316f96ec30,libbzip2_sys-bf78a2d58d5cbce6,liblibsqlite3_sys-6c004987fd67a36a,libtree_sitter_bash-220b99a97d331ab7,libtree_sitter-858f0a1dbfea58bd,libzstd_sys-6eb237deec748c5b,libring-2a87376483bf916f,libopenssl_sys-7c189e68b37fe2bb,liblibz_sys-4344eef4345520b1,librama_boring_sys-0414e98115015ee0}.rlib" "-lc++" "-lc++abi" "-lunwind" "-lc" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib/libcompiler_builtins-*.rlib" "-L" "/var/folders/kt/52y_g75x3ng8ktvk3rfwm6400000gp/T/rustcyGQdYm/raw-dylibs" "-Wl,-Bdynamic" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-nostartfiles" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/libz-sys-ff5ea50d88c28ffb/out/lib" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/ring-bdec3dddc19f5a5e/out" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/openssl-sys-96e0870de3ca22bc/out/openssl-build/install/lib" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/zstd-sys-0cc37a5da1481740/out" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/tree-sitter-72d2418073317c0f/out" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/tree-sitter-bash-bfd293a9f333ce6a/out" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/libsqlite3-sys-b78b2cfb81a330fc/out" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/bzip2-sys-69a145cc859ef275/out/lib" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/lzma-sys-07e92d0b6baa6fd4/out" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/rama-boring-sys-0bc2dfbf669addc4/out/build/crypto/" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/rama-boring-sys-0bc2dfbf669addc4/out/build/ssl/" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/rama-boring-sys-0bc2dfbf669addc4/out/build/" "-L" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/rama-boring-sys-0bc2dfbf669addc4/out/build" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib" "-o" "/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/deps/codex_network_proxy-d08268b863517761" "-Wl,--gc-sections" "-static-pie" "-Wl,-z,relro,-z,now" "-Wl,-O1" "-Wl,--strip-all" "-nodefaultlibs" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained/crtendS.o" "<sysroot>/lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained/crtn.o"
      = note: some arguments are omitted. use `--verbose` to show all linker arguments
      = note: warning: ignoring deprecated linker optimization setting '1'
              warning: unable to open library directory '/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/rama-boring-sys-0bc2dfbf669addc4/out/build/crypto/': FileNotFound
              ld.lld: error: duplicate symbol: SSL_export_keying_material
              >>> defined at ssl_lib.c:3816 (ssl/ssl_lib.c:3816)
              >>>            libssl-lib-ssl_lib.o:(SSL_export_keying_material) in archive /var/folders/kt/52y_g75x3ng8ktvk3rfwm6400000gp/T/rustcyGQdYm/libopenssl_sys-7c189e68b37fe2bb.rlib
              >>> defined at t1_enc.cc:205 (/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/rama-boring-sys-0bc2dfbf669addc4/out/boringssl/ssl/t1_enc.cc:205)
              >>>            t1_enc.cc.o:(.text.SSL_export_keying_material+0x0) in archive /var/folders/kt/52y_g75x3ng8ktvk3rfwm6400000gp/T/rustcyGQdYm/librama_boring_sys-0414e98115015ee0.rlib
    
              ld.lld: error: duplicate symbol: d2i_ASN1_TIME
              >>> defined at a_time.c:27 (crypto/asn1/a_time.c:27)
              >>>            libcrypto-lib-a_time.o:(d2i_ASN1_TIME) in archive /var/folders/kt/52y_g75x3ng8ktvk3rfwm6400000gp/T/rustcyGQdYm/libopenssl_sys-7c189e68b37fe2bb.rlib
              >>> defined at a_time.cc:34 (/Users/apanasenko/code/codex/codex-rs/target/x86_64-unknown-linux-musl/release/build/rama-boring-sys-0bc2dfbf669addc4/out/boringssl/crypto/asn1/a_time.cc:34)
              >>>            a_time.cc.o:(.text.d2i_ASN1_TIME+0x0) in archive /var/folders/kt/52y_g75x3ng8ktvk3rfwm6400000gp/T/rustcyGQdYm/librama_boring_sys-0414e98115015ee0.rlib
    ``` 
    
    that force me to migrate away from rama-tls-boring to rama-tls-rustls
    and pin `ring` for rustls.
  • feat: include state of [experimental_network] in /debug-config output (#11039)
    #10958 introduced experimental support for a network config in
    `/etc/codex/requirements.toml`, so this extends `/debug-config` to
    surface this information, if set, which should make it easier to debug.
  • app-server: treat null mode developer instructions as built-in defaults (#10983)
    ## Summary
    - make `turn/start` normalize
    `collaborationMode.settings.developer_instructions: null` to the
    built-in instructions for the selected mode
    - prevent app-server clients from accidentally clearing mode-switch
    developer instructions by sending `null`
    - document this behavior in the v2 protocol and app-server docs
    
    ## What changed
    - `codex-rs/app-server/src/codex_message_processor.rs`
      - added a small `normalize_turn_start_collaboration_mode` helper
      - in `turn_start`, apply normalization before `OverrideTurnContext`
    - `codex-rs/app-server/tests/suite/v2/turn_start.rs`
    - extended `turn_start_accepts_collaboration_mode_override_v2` to assert
    the outgoing request includes default-mode instruction text when the
    client sends `developer_instructions: null`
    - `codex-rs/app-server-protocol/src/protocol/v2.rs`
    - clarified `TurnStartParams.collaboration_mode` docs:
    `settings.developer_instructions: null` means use built-in mode
    instructions
    - regenerated schema fixture:
    - `codex-rs/app-server-protocol/schema/typescript/v2/TurnStartParams.ts`
    - docs:
      - `codex-rs/app-server/README.md`
      - `codex-rs/docs/codex_mcp_interface.md`
  • feat(core): add network constraints schema to requirements.toml (#10958)
    ## Summary
    
    Add `requirements.toml` schema support for admin-defined network
    constraints in the requirements layer
    
    example config:
    
    ```
    [experimental_network]
    enabled = true
    allowed_domains = ["api.openai.com"]
    denied_domains = ["example.com"]
    ```
  • Fixed a flaky Windows test that is consistently causing a CI failure (#10987)
    Loop wait_for_complete/wait_for_updates_at_least until deadline to
    prevent Windows CI false timeouts in query-change session tests.
  • Fix flaky windows CI test (#10993)
    Hardens PTY Python REPL test and make MCP test startup deterministic
    
    **Summary**
    - `utils/pty/src/tests.rs`
    - Added a REPL readiness handshake (`wait_for_python_repl_ready`) that
    repeatedly sends a marker and waits for it in PTY output before sending
    test commands.
      - Updated `pty_python_repl_emits_output_and_exits` to:
        - wait for readiness first,
        - preserve startup output,
        - append output collected through process exit.
    - Reduces Windows/ConPTY flakiness from early stdin writes racing REPL
    startup.
    
    - `mcp-server/tests/suite/codex_tool.rs`
    - Avoid remote model refresh during MCP test startup, reducing
    timeout-prone nondeterminism.
  • Bootstrap shell commands via user shell snapshot (#10909)
    Summary
    - wrap `shell -lc` executions that use a snapshot with the session shell
    so the saved environment is sourced before delegating to the original
    shell
    - escape single quotes in the generated wrapper and add tests covering
    Bash/Zsh/sh session bootstrapping
    
    Testing
    - Not run (not requested)
  • Add resume_agent collab tool (#10903)
    Summary
    - add the new resume_agent collab tool path through core, protocol, and
    the app server API, including the resume events
    - update the schema/TypeScript definitions plus docs so resume_agent
    appears in generated artifacts and README
    - note that resumed agents rehydrate rollout history without overwriting
    their base instructions
    
    Testing
    - Not run (not requested)
  • fix: normalize line endings when reading file on Windows (#10988)
    I did not wait for CI on https://github.com/openai/codex/pull/10980
    because it was blocking an alpha release, but apparently it broken the
    Windows build.
  • Show left/right arrows to navigate in tui request_user_input (#10921)
    <img width="785" height="185" alt="Screenshot 2026-02-06 at 10 25 13 AM"
    src="https://github.com/user-attachments/assets/402a6e79-4626-4df9-b3da-bc2f28e64611"
    />
    
    <img width="784" height="213" alt="Screenshot 2026-02-06 at 10 26 37 AM"
    src="https://github.com/user-attachments/assets/cf9614b2-aa1e-4c61-8579-1d2c7e1c7dc1"
    />
    
    "left/right to navigate questions" in request_user_input footer
  • Do not poll for usage when using API Key auth (#10973)
    Fixes #10869
    
    - Gate TUI rate-limit polling on ChatGPT-auth providers only.
    - `prefetch_rate_limits()` now checks `should_prefetch_rate_limits()`.
    - New gate requires:
      - `config.model_provider.requires_openai_auth`
      - cached auth is ChatGPT (`CodexAuth::is_chatgpt_auth`)
    - Prevents `/wham/usage` polling in API/custom-endpoint profiles.
  • feat: add support for allowed_web_search_modes in requirements.toml (#10964)
    This PR makes it possible to disable live web search via an enterprise
    config even if the user is running in `--yolo` mode (though cached web
    search will still be available). To do this, create
    `/etc/codex/requirements.toml` as follows:
    
    ```toml
    # "live" is not allowed; "disabled" is allowed even though not listed explicitly.
    allowed_web_search_modes = ["cached"]
    ```
    
    Or set `requirements_toml_base64` MDM as explained on
    https://developers.openai.com/codex/security/#locations.
    
    ### Why
    - Enforce admin/MDM/`requirements.toml` constraints on web-search
    behavior, independent of user config and per-turn sandbox defaults.
    - Ensure per-turn config resolution and review-mode overrides never
    crash when constraints are present.
    
    ### What
    - Add `allowed_web_search_modes` to requirements parsing and surface it
    in app-server v2 `ConfigRequirements` (`allowedWebSearchModes`), with
    fixtures updated.
    - Define a requirements allowlist type (`WebSearchModeRequirement`) and
    normalize semantics:
      - `disabled` is always implicitly allowed (even if not listed).
      - An empty list is treated as `["disabled"]`.
    - Make `Config.web_search_mode` a `Constrained<WebSearchMode>` and apply
    requirements via `ConstrainedWithSource<WebSearchMode>`.
    - Update per-turn resolution (`resolve_web_search_mode_for_turn`) to:
    - Prefer `Live → Cached → Disabled` when
    `SandboxPolicy::DangerFullAccess` is active (subject to requirements),
    unless the user preference is explicitly `Disabled`.
    - Otherwise, honor the user’s preferred mode, falling back to an allowed
    mode when necessary.
    - Update TUI `/debug-config` and app-server mapping to display
    normalized `allowed_web_search_modes` (including implicit `disabled`).
    - Fix web-search integration tests to assert cached behavior under
    `SandboxPolicy::ReadOnly` (since `DangerFullAccess` legitimately prefers
    `live` when allowed).
  • Process-group cleanup for stdio MCP servers to prevent orphan process storms (#10710)
    This PR changes stdio MCP child processes to run in their own process
    group
    * Add guarded teardown in codex-rmcp-client: send SIGTERM to the group
    first, then SIGKILL after a short grace period.
    * Add terminate_process_group helper in process_group.rs.
    * Add Unix regression test in process_group_cleanup.rs to verify wrapper
    + grandchild are reaped on client drop.
    
    Addresses reported MCP process/thread storm: #10581
  • Fixed a flaky test (#10970)
    ## Summary
    
    Stabilize v2 review integration tests by making them hermetic with
    respect to model discovery.
    
    `app-server` review tests were intermittently timing out in CI
    (especially on Windows runners) because their test config allowed remote
    model refresh. During `thread/start`, the test process could issue live
    `/v1/models` requests, introducing external network latency and
    nondeterministic timing before review flow assertions.
    
    This change disables remote model fetching in the review test config
    helper used by these tests.
  • refactor(network-proxy): flatten network config under [network] (#10965)
    Summary:
    - Rename config table from network_proxy to network.
    - Flatten allowed_domains, denied_domains, allow_unix_sockets, and
    allow_local_binding onto NetworkProxySettings.
    - Update runtime, state constraints, tests, and README to the new config
    shape.
  • fix(tui): conditionally restore status indicator using message phase (#10947)
    TLDR: use new message phase field emitted by preamble-supported models
    to determine whether an AgentMessage is mid-turn commentary. if so,
    restore the status indicator afterwards to indicate the turn has not
    completed.
    
    ### Problem
    `commit_tick` hides the status indicator while streaming assistant text.
    For preamble-capable models, that text can be commentary mid-turn, so
    hiding was correct during streaming but restore timing mattered:
    - restoring too aggressively caused jitter/flashing
    - not restoring caused indicator to stay hidden before subsequent work
    (tool calls, web search, etc.)
    
    ### Fix
    - Add optional `phase` to `AgentMessageItem` and propagate it from
    `ResponseItem::Message`
    - Keep indicator hidden during streamed commit ticks, restore only when:
      - assistant item completes as `phase=commentary`, and
      - stream queues are idle + task is still running.
    - Treat `phase=None` as final-answer behavior (no restore) to keep
    existing behavior for non-preamble models
    
    ### Tests
    Add/update tests for:
    - no idle-tick restore without commentary completion
    - commentary completion restoring status before tool begin
    - snapshot coverage for preamble/status behavior
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • Mark Config.apps as experimental, correct schema generation issue (#10938)
    This PR makes `Config.apps `experimental-only and fixes a TS schema
    post-processing bug that removed needed imports. The bug happened
    because import pruning only checked the inner type body after filtering,
    not the full alias, so `JsonValue` got dropped from `Config.ts`. We now
    prune against the full alias body and added a regression test for this
    scenario.