Commit Graph

3074 Commits

  • Add MCP server scopes config and use it as fallback for OAuth login (#9647)
    ### Motivation
    - Allow MCP OAuth flows to request scopes defined in `config.toml`
    instead of requiring users to always pass `--scopes` on the CLI.
    CLI/remote parameters should still override config values.
    
    ### Description
    - Add optional `scopes: Option<Vec<String>>` to `McpServerConfig` and
    `RawMcpServerConfig`, and propagate it through deserialization and the
    built config types.
    - Serialize `scopes` into the MCP server TOML via
    `serialize_mcp_server_table` in `core/src/config/edit.rs` and include
    `scopes` in the generated config schema (`core/config.schema.json`).
    - CLI: update `codex-rs/cli/src/mcp_cmd.rs` `run_login` to fall back to
    `server.scopes` when the `--scopes` flag is empty, with explicit CLI
    scopes still taking precedence.
    - App server: update
    `codex-rs/app-server/src/codex_message_processor.rs`
    `mcp_server_oauth_login` to use `params.scopes.or_else(||
    server.scopes.clone())` so the RPC path also respects configured scopes.
    - Update many test fixtures to initialize the new `scopes` field (set to
    `None`) so test code builds with the new struct field.
    
    ### Testing
    - Ran config tooling and formatters: `just write-config-schema`
    (succeeded), `just fmt` (succeeded), and `just fix -p codex-core`, `just
    fix -p codex-cli`, `just fix -p codex-app-server` (succeeded where
    applicable).
    - Ran unit tests for the CLI: `cargo test -p codex-cli` (passed).
    - Ran unit tests for core: `cargo test -p codex-core` (ran; many tests
    passed but several failed, including model refresh/403-related tests,
    shell snapshot/timeouts, and several `unified_exec` expectations).
    - Ran app-server tests: `cargo test -p codex-app-server` (ran; many
    integration-suite tests failed due to mocked/remote HTTP 401/403
    responses and wiremock expectations).
    
    If you want, I can split the tests into smaller focused runs or help
    debug the failing integration tests (they appear to be unrelated to the
    config change and stem from external HTTP/mocking behaviors encountered
    during the test runs).
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_69718f505914832ea1f334b3ba064553)
  • ensure codex bundle zip is created in dist/ (#9934)
    cd-ing into the tmp bundle directory was putting the .zip in the wrong
    place
  • Aligned feature stage names with public feature maturity stages (#9929)
    We've recently standardized a [feature maturity
    model](https://developers.openai.com/codex/feature-maturity) that we're
    using in our docs and support forums to communicate expectations to
    users. This PR updates the internal stage names and descriptions to
    match.
    
    This change involves a simple internal rename and updates to a few
    user-visible strings. No functional change.
  • Add thread/unarchive to restore archived rollouts (#9843)
    ## Summary
    - Adds a new `thread/unarchive` RPC to move archived thread rollouts
    back into the active `sessions/` tree.
    
    ## What changed
    - **Protocol**
      - Adds `thread/unarchive` request/response types and wiring.
    - **Server**
      - Implements `thread_unarchive` in the app server.
      - Validates the archived rollout path and thread ID.
    - Restores the rollout to `sessions/YYYY/MM/DD/...` based on the rollout
    filename timestamp.
    - **Core**
    - Adds `find_archived_thread_path_by_id_str` helper for archived
    rollouts.
    - **Docs**
      - Documents the new RPC and usage example.
    - **Tests**
      - Adds an end-to-end server test that:
        1) starts a thread,
        2) archives it,
        3) unarchives it,
        4) asserts the file is restored to `sessions/`.
    
    ## How to use
    ```json
    { "method": "thread/unarchive", "id": 24, "params": { "threadId": "<thread-id>" } }
    ```
    
    ## Author Codex Session
    
    `codex resume 019bf158-54b6-7960-a696-9d85df7e1bc1` (soon I'll make this
    kind of session UUID forkable by anyone with the right
    `session_object_storage_url` line in their config, but for now just
    pasting it here for my reference)
  • prompt (#9928)
    # 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.
  • fix: attempt to reduce high cpu usage when using collab (#9776)
    Reproduce with a prompt like this with collab enabled:
    ```
    Examine the code at <some subdirectory with a deeply nested project>.  Find the most urgent issue to resolve and describe it to me.
    ```
    
    Existing behavior causes the top-level agent to busy wait on subagents.
  • Fix flakey shell snapshot test (#9919)
    Sometimes fails with:
    
    ```
    failures:
    
      ---- shell_snapshot::tests::timed_out_snapshot_shell_is_terminated stdout ----
    
      thread 'shell_snapshot::tests::timed_out_snapshot_shell_is_terminated' panicked at codex-rs/core/src/shell_snapshot.rs:588:9:
      expected timeout error, got Failed to execute sh
    
      Caused by:
          Text file busy (os error 26)
    
    
      failures:
          shell_snapshot::tests::timed_out_snapshot_shell_is_terminated
    
      test result: FAILED. 815 passed; 1 failed; 4 ignored; 0 measured; 0 filtered out; finished in 18.00s
    ```
  • Feat: add isOther to question returned by request user input tool (#9890)
    ### Summary
    Add `isOther` to question object from request_user_input tool input and
    remove `other` option from the tool prompt to better handle tool input.
  • Fix up config disabled err msg (#9916)
    **Before:**
    <img width="745" height="375" alt="image"
    src="https://github.com/user-attachments/assets/d6c23562-b87f-4af9-8642-329aab8e594d"
    />
    
    **After:**
    <img width="1042" height="354" alt="image"
    src="https://github.com/user-attachments/assets/c9a2413c-c945-4c34-8b7e-c6c9b8fbf762"
    />
    
    Two changes:
    1. only display if there is a `config.toml` that is skipped (i.e. if
    there is just `.codex/skills` but no `.codex/config.toml` we do not
    display the error)
    2. clarify the implications and the fix in the error message.
  • Fix flakey conversation flow test (#9784)
    I've seen this test fail with:
    
    ```
     - Mock #1.
            	Expected range of matching incoming requests: == 2
            	Number of matched incoming requests: 1
    ```
    
    This is because we pop the wrong task_complete events and then the test
    exits. I think this is because the MCP events are now buffered after
    https://github.com/openai/codex/pull/8874.
    
    So:
    1. clear the buffer before we do any user message sending
    2. additionally listen for task start before task complete
    3. use the ID from task start to find the correct task complete event.
  • Fix flakey resume test (#9789)
    Sessions' `updated_at` times are truncated to seconds, with the UUID
    session ID used to break ties. If the two test sessions are created in
    the same second, AND the session B UUID < session A UUID, the test
    fails.
    
    Fix this by mutating the session mtimes, from which we derive the
    updated_at time, to ensure session B is updated_at later than session A.
  • feat: dynamic tools injection (#9539)
    ## Summary
    Add dynamic tool injection to thread startup in API v2, wire dynamic
    tool calls through the app server to clients, and plumb responses back
    into the model tool pipeline.
    
    ### Flow (high level)
    - Thread start injects `dynamic_tools` into the model tool list for that
    thread (validation is done here).
    - When the model emits a tool call for one of those names, core raises a
    `DynamicToolCallRequest` event.
    - The app server forwards it to the client as `item/tool/call`, waits
    for the client’s response, then submits a `DynamicToolResponse` back to
    core.
    - Core turns that into a `function_call_output` in the next model
    request so the model can continue.
    
    ### What changed
    - Added dynamic tool specs to v2 thread start params and protocol types;
    introduced `item/tool/call` (request/response) for dynamic tool
    execution.
    - Core now registers dynamic tool specs at request time and routes those
    calls via a new dynamic tool handler.
    - App server validates tool names/schemas, forwards dynamic tool call
    requests to clients, and publishes tool outputs back into the session.
    - Integration tests
  • chore(core) move model_instructions_template config (#9871)
    ## Summary
    Move `model_instructions_template` config to the experimental slug while
    we iterate on this feature
    
    ## Testing
    - [x] Tested locally, unit tests still pass
  • feat(tui) /personality (#9718)
    ## Summary
    Adds /personality selector in the TUI, which leverages the new core
    interface in #9644
    
    Notes:
    - We are doing some of our own state management for model_info loading
    here, but not sure if that's ideal. open to opinions on simpler
    approach, but would like to avoid blocking on a larger refactor
    - Right now, the `/personality` selector just hides when the model
    doesn't support it. we can update this behavior down the line
    
    ## Testing
    - [x] Tested locally
    - [x] Added snapshot tests
  • Plan prompt (#9877)
    # 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.
  • Prompt (#9874)
    # 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.
  • chore: remove extra newline in println (#9850)
    ## Summary
    
    This PR makes a minor formatting adjustment to a `println!` message by
    removing an extra empty line and explicitly using `\n` for clarity.
    
    ## Changes
    
    - Adjusted console output formatting for the success message.
    - No functional or behavioral changes.
  • feat: cap number of agents (#9855)
    Adding more guards to agent:
    * Max depth or 1 (i.e. a sub-agent can't spawn another one)
    * Max 12 sub-agents in total
  • Mark collab as beta (#9834)
    Co-authored-by: jif-oai <jif@openai.com>
  • Use collaboration mode masks without mutating base settings (#9806)
    Keep an unmasked base collaboration mode and apply the active mask on
    demand. Simplify the TUI mask helpers and update tests/docs to match the
    mask contract.
  • Ask for cwd choice when resuming session from different cwd (#9731)
    # Summary
    - Fix resume/fork config rebuild so cwd changes inside the TUI produce a
    fully rebuilt Config (trust/approval/sandbox) instead of mutating only
    the cwd.
    - Preserve `--add-dir` behavior across resume/fork by normalizing
    relative roots to absolute paths once (based on the original cwd).
    - Prefer latest `TurnContext.cwd` for resume/fork prompts but fall back
    to `SessionMeta.cwd` if the latest cwd no longer exists.
    - Align resume/fork selection handling and ensure UI config matches the
    resumed thread config.
    - Fix Windows test TOML path escaping in trust-level test.
    
    # Details
    - Rebuild Config via `ConfigBuilder` when resuming into a different cwd;
    carry forward runtime approval/sandbox overrides.
    - Add `normalize_harness_overrides_for_cwd` to resolve relative
    `additional_writable_roots` against the initial cwd before reuse.
    - Guard `read_session_cwd` with filesystem existence check for the
    latest `TurnContext.cwd`.
    - Update naming/flow around cwd comparison and prompt selection.
    
    <img width="603" height="150" alt="Screenshot 2026-01-23 at 5 42 13 PM"
    src="https://github.com/user-attachments/assets/d1897386-bb28-4e8a-98cf-187fdebbecb0"
    />
    
    And proof the model understands the new cwd:
    
    <img width="828" height="353" alt="Screenshot 2026-01-22 at 5 36 45 PM"
    src="https://github.com/user-attachments/assets/12aed8ca-dec3-4b64-8dae-c6b8cff78387"
    />
  • Raise welcome animation breakpoint to 37 rows (#9778)
    ### Motivation
    - The large ASCII welcome animation can push onboarding content below
    the fold on default-height terminals, making the CLI appear
    unresponsive; raising the breakpoint prevents that.
    - The existing test measured an arbitrary row count rather than
    asserting the welcome line position relative to the animation frame,
    which made the intent unclear.
    
    ### Description
    - Increase `MIN_ANIMATION_HEIGHT` from `20` to `37` in
    `codex-rs/tui/src/onboarding/welcome.rs` so the animation is skipped
    unless there is enough vertical space.
    - Replace the brittle measurement logic in the welcome render test with
    a `row_containing` helper and assert the welcome row equals the frame
    height plus the spacer line (`frame_lines + 1`).
    - Add a regression test
    `welcome_skips_animation_below_height_breakpoint` that verifies the
    animation is not rendered when the viewport height is one row below the
    breakpoint.
    
    ### Testing
    - Ran formatting with `~/.cargo/bin/just fmt` which completed
    successfully.
    - Ran unit tests for the crate with `cargo test -p codex-tui --lib` and
    they passed (unit test suite succeeded).
    - Ran `cargo test -p codex-tui` which reported a failing integration
    test in this environment because the test cannot locate the `codex`
    binary, so full crate tests are blocked here (environment limitation).
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_6973b0a710d4832c9ff36fac26eb1519)
  • Prevent backspace from removing a text element when the cursor is at the element’s left edge (#9630)
    **Summary**
    - Prevent backspace from removing a text element when the cursor is at
    the element’s left edge.
    - Instead just delete the char before the placeholder (moving it to the
    left).
  • fix(windows-sandbox): remove request files after read (#9316)
    ## Summary
    - Remove elevated runner request files after read (best-effort cleanup
    on errors)
    - Add a unit test to cover request file lifecycle
    
    ## Testing
    - `cargo test -p codex-windows-sandbox` (Windows)
    
    Fixes #9315
  • feat: ephemeral threads (#9765)
    Add ephemeral threads capabilities. Only exposed through the
    `app-server` v2
    
    The idea is to disable the rollout recorder for those threads.
  • Another round of improvements for config error messages (#9746)
    In a [recent PR](https://github.com/openai/codex/pull/9182), I made some
    improvements to config error messages so errors didn't leave app server
    clients in a dead state. This is a follow-on PR to make these error
    messages more readable and actionable for both TUI and GUI users. For
    example, see #9668 where the user was understandably confused about the
    source of the problem and how to fix it.
    
    The improved error message:
    1. Clearly identifies the config file where the error was found (which
    is more important now that we support layered configs)
    2. Provides a line and column number of the error
    3. Displays the line where the error occurred and underlines it
    
    For example, if my `config.toml` includes the following:
    ```toml
    [features]
    collaboration_modes = "true"
    ```
    
    Here's the current CLI error message:
    ```
    Error loading config.toml: invalid type: string "true", expected a boolean in `features`
    ```
    
    And here's the improved message:
    ```
    Error loading config.toml:
    /Users/etraut/.codex/config.toml:43:23: invalid type: string "true", expected a boolean
       |
    43 | collaboration_modes = "true"
       |                       ^^^^^^
    ```
    
    The bulk of the new logic is contained within a new module
    `config_loader/diagnostics.rs` that is responsible for calculating the
    text range for a given toml path (which is more involved than I would
    have expected).
    
    In addition, this PR adds the file name and text range to the
    `ConfigWarningNotification` app server struct. This allows GUI clients
    to present the user with a better error message and an optional link to
    open the errant config file. This was a suggestion from @.bolinfest when
    he reviewed my previous PR.
  • feat: introducing a network sandbox proxy (#8442)
    This add a new crate, `codex-network-proxy`, a local network proxy
    service used by Codex to enforce fine-grained network policy (domain
    allow/deny) and to surface blocked network events for interactive
    approvals.
    
    - New crate: `codex-rs/network-proxy/` (`codex-network-proxy` binary +
    library)
    - Core capabilities:
      - HTTP proxy support (including CONNECT tunneling)
      - SOCKS5 proxy support (in the later PR)
    - policy evaluation (allowed/denied domain lists; denylist wins;
    wildcard support)
      - small admin API for polling/reload/mode changes
    - optional MITM support for HTTPS CONNECT to enforce “limited mode”
    method restrictions (later PR)
    
    Will follow up integration with codex in subsequent PRs.
    
    ## Testing
    
    - `cd codex-rs && cargo build -p codex-network-proxy`
    - `cd codex-rs && cargo run -p codex-network-proxy -- proxy`
  • change collaboration mode to struct (#9793)
    Shouldn't cause behavioral change
  • bundle sandbox helper binaries in main zip, for winget. (#9707)
    Winget uses the main codex.exe value as its target.
    The elevated sandbox requires these two binaries to live next to
    codex.exe
  • Remove stale TODO comment from defs.bzl (#9787)
    ### Motivation
    - Remove an outdated comment in `defs.bzl` referencing
    `cargo_build_script` that is no longer relevant.
    
    ### Description
    - Delete the stale `# TODO(zbarsky): cargo_build_script support?` line
    so the logic flows directly from `binaries` to `lib_srcs` in `defs.bzl`.
    
    ### Testing
    - Ran `git diff --check` which produced no errors.
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_6973d9ac757c8331be475a8fb0f90a88)
  • Fix resume picker when user event appears after head (#9512)
    Fixes #9501
    
    Contributing guide:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    ## Summary
    The resume picker requires a session_meta line and at least one
    user_message event within the initial head scan. Some rollout files
    contain multiple session_meta entries before the first user_message, so
    the user event can fall outside the default head window and the session
    is omitted from the picker even though it is resumable by ID.
    
    This PR keeps the head summary bounded but extends scanning for a
    user_message once a session_meta has been observed. The summary still
    caps stored head entries, but we allow a small, bounded extra scan to
    find the first user event so valid sessions are not filtered out.
    
    ## Changes
    - Continue scanning past the head limit (bounded) when session_meta is
    present but no user_message has been seen yet.
    - Mark session_meta as seen even if the head summary buffer is already
    full.
    - Add a regression test with multiple session_meta lines before the
    first user_message.
    
    ## Why This Is Safe
    - The head summary remains bounded to avoid unbounded memory usage.
    - The extra scan is capped (USER_EVENT_SCAN_LIMIT) and only triggers
    after a session_meta is seen.
    - Behavior is unchanged for typical files where the user_message appears
    early.
    
    ## Testing
    - cargo test -p codex-core --lib
    test_list_threads_scans_past_head_for_user_event