Commit Graph

355 Commits

  • fix: apply patch issue when using different cwd (#942)
    If you run a codex instance outside of the current working directory
    from where you launched the codex binary it won't be able to apply
    patches correctly, even if the sandbox policy allows it. This manifests
    weird behaviours, such as
    
    * Reading the same filename in the binary working directory, and
    overwriting it in the session working directory. e.g. if you have a
    `readme` in both folders it will overwrite the readme in the session
    working directory with the readme in the binary working directory
    *applied with the suggested patch*.
    * The LLM ends up in weird loops trying to verify and debug why the
    apply_patch won't work, and it can result in it applying patches by
    manually writing python or javascript if it figures out that either is
    supported by the system instead.
    
    I added a test-case to ensure that the patch contents are based on the
    cwd.
    
    ## Issue: mixing relative & absolute paths in apply_patch
    
    1. The apply_patch tool use relative paths based on the session working
    directory.
    2. `unified_diff_from_chunks` eventually ends up [reading the source
    file](https://github.com/reflectionai/codex/blob/main/codex-rs/apply-patch/src/lib.rs#L410)
    to figure out what the diff is, by using the relative path.
    3. The changes are targeted using an absolute path derived from the
    current working directory.
    
    The end-result in case session working directory differs from the binary
    working directory: we get the diff for a file relative to the binary
    working directory, and apply it on a file in the session working
    directory.
  • fix: diff command for filenames with special characters (#954)
    ## Summary
    - fix quoting issues in `/diff` to correctly handle files with special
    characters
    - add regression test for `getGitDiff` when filenames contain `$`
    - relax timeout in raw-exec-process-group test
    
    Fixes https://github.com/openai/codex/issues/943
    
    ## Testing
    - `pnpm test`
  • bump(version): 0.1.2505160811 codex-mini-latest (#953)
    ## `0.1.2505160811`
    
    - `codex-mini-latest` (#951)
  • chore: update exec crate to use std::time instead of chrono (#952)
    When I originally wrote `elapsed.rs`, I realized we were using both
    `std::time` and `chrono` with no real benefit of having both. We should
    try to keep the `exec` subcommand trim (as it also buildable as a
    standalone executable), so this helps tighten things up.
  • add: codex-mini-latest (#951)
    💽
    
    ---------
    
    Co-authored-by: Trevor Creech <tcreech@openai.com>
  • feat: record messages from user in ~/.codex/history.jsonl (#939)
    This is a large change to support a "history" feature like you would
    expect in a shell like Bash.
    
    History events are recorded in `$CODEX_HOME/history.jsonl`. Because it
    is a JSONL file, it is straightforward to append new entries (as opposed
    to the TypeScript file that uses `$CODEX_HOME/history.json`, so to be
    valid JSON, each new entry entails rewriting the entire file). Because
    it is possible for there to be multiple instances of Codex CLI writing
    to `history.jsonl` at once, we use advisory file locking when working
    with `history.jsonl` in `codex-rs/core/src/message_history.rs`.
    
    Because we believe history is a sufficiently useful feature, we enable
    it by default. Though to provide some safety, we set the file
    permissions of `history.jsonl` to be `o600` so that other users on the
    system cannot read the user's history. We do not yet support a default
    list of `SENSITIVE_PATTERNS` as the TypeScript CLI does:
    
    
    https://github.com/openai/codex/blob/3fdf9df1335ac9501e3fb0e61715359145711e8b/codex-cli/src/utils/storage/command-history.ts#L10-L17
    
    We are going to take a more conservative approach to this list in the
    Rust CLI. For example, while `/\b[A-Za-z0-9-_]{20,}\b/` might exclude
    sensitive information like API tokens, it would also exclude valuable
    information such as references to Git commits.
    
    As noted in the updated documentation, users can opt-out of history by
    adding the following to `config.toml`:
    
    ```toml
    [history]
    persistence = "none" 
    ```
    
    Because `history.jsonl` could, in theory, be quite large, we take a[n
    arguably overly pedantic] approach in reading history entries into
    memory. Specifically, we start by telling the client the current number
    of entries in the history file (`history_entry_count`) as well as the
    inode (`history_log_id`) of `history.jsonl` (see the new fields on
    `SessionConfiguredEvent`).
    
    The client is responsible for keeping new entries in memory to create a
    "local history," but if the user hits up enough times to go "past" the
    end of local history, then the client should use the new
    `GetHistoryEntryRequest` in the protocol to fetch older entries.
    Specifically, it should pass the `history_log_id` it was given
    originally and work backwards from `history_entry_count`. (It should
    really fetch history in batches rather than one-at-a-time, but that is
    something we can improve upon in subsequent PRs.)
    
    The motivation behind this crazy scheme is that it is designed to defend
    against:
    
    * The `history.jsonl` being truncated during the session such that the
    index into the history is no longer consistent with what had been read
    up to that point. We do not yet have logic to enforce a `max_bytes` for
    `history.jsonl`, but once we do, we will aspire to implement it in a way
    that should result in a new inode for the file on most systems.
    * New items from concurrent Codex CLI sessions amending to the history.
    Because, in absence of truncation, `history.jsonl` is an append-only
    log, so long as the client reads backwards from `history_entry_count`,
    it should always get a consistent view of history. (That said, it will
    not be able to read _new_ commands from concurrent sessions, but perhaps
    we will introduce a `/` command to reload latest history or something
    down the road.)
    
    Admittedly, my testing of this feature thus far has been fairly light. I
    expect we will find bugs and introduce enhancements/fixes going forward.
  • chore: introduce AppEventSender to help fix clippy warnings and update to Rust 1.87 (#948)
    Moving to Rust 1.87 introduced a clippy warning that
    `SendError<AppEvent>` was too large.
    
    In practice, the only thing we ever did when we got this error was log
    it (if the mspc channel is closed, then the app is likely shutting down
    or something, so there's not much to do...), so this finally motivated
    me to introduce `AppEventSender`, which wraps
    `std::sync::mpsc::Sender<AppEvent>` with a `send()` method that invokes
    `send()` on the underlying `Sender` and logs an `Err` if it gets one.
    
    This greatly simplifies the code, as many functions that previously
    returned `Result<(), SendError<AppEvent>>` now return `()`, so we don't
    have to propagate an `Err` all over the place that we don't really
    handle, anyway.
    
    This also makes it so we can upgrade to Rust 1.87 in CI.
  • chore: pin Rust version to 1.86 and use io::Error::other to prepare for 1.87 (#947)
    Previously, our GitHub actions specified the Rust toolchain as
    `dtolnay/rust-toolchain@stable`, which meant the version could change
    out from under us. In this case, the move from 1.86 to 1.87 introduced
    new clippy warnings, causing build failures.
    
    Because it will take a little time to fix all the new clippy warnings,
    this PR pins things to 1.86 for now to unbreak the build.
    
    It also replaces `io::Error::new(io::ErrorKind::Other)` with
    `io::Error::other()` in preparation for 1.87.
  • fix: properly wrap lines in the Rust TUI (#937)
    As discussed on
    https://github.com/openai/codex/commit/699ec5a87f09796d17c0202cd92a1dd4d8b4f3f5#commitcomment-156776835,
    to properly support scrolling long content in Ratatui for a sequence of
    cells, we need to:
    
    * take the `Vec<Line>` for each cell
    * using the wrapping logic we want to use at render time, compute the
    _effective line count_ using `Paragraph::line_count()` (see
    `wrapped_line_count_for_cell()` in this PR)
    * sum up the effective line count to compute the height of the area
    being scrolled
    * given a `scroll_position: usize`, index into the list of "effective
    lines" and accumulate the appropriate `Vec<Line>` for the cells that
    should be displayed
    * take that `Vec<Line>` to create a `Paragraph` and use the same
    line-wrapping policy that was used in `wrapped_line_count_for_cell()`
    * display the resulting `Paragraph` and use the accounting to display a
    scrollbar with the appropriate thumb size and offset without having to
    render the `Vec<Line>` for the full history
    
    With this change, lines wrap as I expect and everything appears to
    redraw correctly as I resize my terminal!
  • chore: handle all cases for EventMsg (#936)
    For now, this removes the `#[non_exhaustive]` directive on `EventMsg` so
    that we are forced to handle all `EventMsg` by default. (We may revisit
    this if/when we publish `core/` as a `lib` crate.) For now, it is
    helpful to have this as a forcing function because we have effectively
    two UIs (`tui` and `exec`) and usually when we add a new variant to
    `EventMsg`, we want to be sure that we update both.
  • feat: add mcp subcommand to CLI to run Codex as an MCP server (#934)
    Previously, running Codex as an MCP server required a standalone binary
    in our Cargo workspace, but this PR makes it available as a subcommand
    (`mcp`) of the main CLI.
    
    Ran this with:
    
    ```
    RUST_LOG=debug npx @modelcontextprotocol/inspector cargo run --bin codex -- mcp
    ```
    
    and verified it worked as expected in the inspector at
    `http://127.0.0.1:6274/`.
  • feat: add support for commands in the Rust TUI (#935)
    Introduces support for slash commands like in the TypeScript CLI. We do
    not support the full set of commands yet, but the core abstraction is
    there now.
    
    In particular, we have a `SlashCommand` enum and due to thoughtful use
    of the [strum](https://crates.io/crates/strum) crate, it requires
    minimal boilerplate to add a new command to the list.
    
    The key new piece of UI is `CommandPopup`, though the keyboard events
    are still handled by `ChatComposer`. The behavior is roughly as follows:
    
    * if the first character in the composer is `/`, the command popup is
    displayed (if you really want to send a message to Codex that starts
    with a `/`, simply put a space before the `/`)
    * while the popup is displayed, up/down can be used to change the
    selection of the popup
    * if there is a selection, hitting tab completes the command, but does
    not send it
    * if there is a selection, hitting enter sends the command
    * if the prefix of the composer matches a command, the command will be
    visible in the popup so the user can see the description (commands could
    take arguments, so additional text may appear after the command name
    itself)
    
    
    https://github.com/user-attachments/assets/39c3e6ee-eeb7-4ef7-a911-466d8184975f
    
    Incidentally, Codex wrote almost all the code for this PR!
  • chore: move each view used in BottomPane into its own file (#928)
    `BottomPane` was getting a bit unwieldy because it maintained a
    `PaneState` enum with three variants and many of its methods had `match`
    statements to handle each variant. To replace the enum, this PR:
    
    * Introduces a `trait BottomPaneView` that has two implementations:
    `StatusIndicatorView` and `ApprovalModalView`.
    * Migrates `PaneState::TextInput` into its own struct, `ChatComposer`,
    that does **not** implement `BottomPaneView`.
    * Updates `BottomPane` so it has `composer: ChatComposer` and
    `active_view: Option<Box<dyn BottomPaneView<'a> + 'a>>`. The idea is
    that `active_view` takes priority and is displayed when it is `Some`;
    otherwise, `ChatComposer` is displayed.
    * While methods of `BottomPane` often have to check whether
    `active_view` is present to decide which component to delegate to, the
    code is more straightforward than before and introducing new
    implementations of `BottomPaneView` should be less painful.
    
    Because we want to retain the `TextArea` owned by `ChatComposer` even
    when another view is displayed, to keep the ownership logic simple, it
    seemed best to keep `ChatComposer` distinct from `BottomPaneView`.
  • fix: increase timeout for test_dev_null_write (#933)
    After updating this test in https://github.com/openai/codex/pull/923, I
    have been getting some timeouts with this test in CI, so increasing the
    timeout to match that of `test_writable_root`:
    
    
    https://github.com/openai/codex/blob/327cf41f0ff7f0816a141a260704270ed38c9fa4/codex-rs/core/src/landlock.rs#L211-L213
  • Add codespell support (config, workflow to detect/not fix) and make it fix some typos (#903)
    More about codespell: https://github.com/codespell-project/codespell .
    
    I personally introduced it to dozens if not hundreds of projects already
    and so far only positive feedback.
    
    CI workflow has 'permissions' set only to 'read' so also should be safe.
    
    Let me know if just want to take typo fixes in and get rid of the CI
    
    ---------
    
    Signed-off-by: Yaroslav O. Halchenko <debian@onerussian.com>
  • bump(version): 0.1.2505140839 (#932)
    ## `0.1.2505140839`
    
    ### 🪲 Bug Fixes
    
    - Gpt-4.1 apply_patch handling (#930)
    - Add support for fileOpener in config.json (#911)
    - Patch in #366 and #367 for marked-terminal (#916)
    - Remember to set lastIndex = 0 on shared RegExp (#918)
    - Always load version from package.json at runtime (#909)
    - Tweak the label for citations for better rendering (#919)
    - Tighten up some logic around session timestamps and ids (#922)
    - Change EventMsg enum so every variant takes a single struct (#925)
    - Reasoning default to medium, show workdir when supplied (#931)
    - Test_dev_null_write() was not using echo as intended (#923)
  • feat: Ctrl+J for newline in Rust TUI, default to one line of height (#926)
    While the `TextArea` used in the Rust TUI is "multiline," it is not like
    an HTML `<textarea>` in that it does not wrap, so there was not much
    benefit to setting `MIN_TEXTAREA_ROWS` to `3`, so this PR changes it to
    `1`. Though there are now three ways to "increase" the height due to
    actual linebreaks:
    
    * paste in multiline content (this worked before this PR)
    * pressing `Ctrl+J` will insert a newline
    * if you have your terminal emulator set such that it is possible to
    press something that `crossterm` interprets as "Enter plus some
    modifier," then now that will also work
    
    Now things look a bit more compact on startup:
    
    <img width="745" alt="image"
    src="https://github.com/user-attachments/assets/86e2857f-f31c-46f5-a80b-1ab2120b266e"
    />
  • fix: test_dev_null_write() was not using echo as intended (#923)
    I believe this test meant to verify that echoing content to `/dev/null`
    succeeded, but instead, I believe it was testing the equivalent to `echo
    'blah > /dev/null'`.
  • fix: change EventMsg enum so every variant takes a single struct (#925)
    https://github.com/openai/codex/pull/922 did this for the
    `SessionConfigured` enum variant, and I think it is generally helpful to
    be able to work with the values as each enum variant as their own type,
    so this converts the remaining variants and updates all of the
    callsites.
    
    Added a simple unit test to verify that the JSON-serialized version of
    `Event` does not have any unexpected nesting.
  • fix: tighten up some logic around session timestamps and ids (#922)
    * update `SessionConfigured` event to include the UUID for the session
    * show the UUID in the Rust TUI
    * use local timestamps in log files instead of UTC
    * include timestamps in log file names for easier discovery
  • feat: introduce --profile for Rust CLI (#921)
    This introduces a much-needed "profile" concept where users can specify
    a collection of options under one name and then pass that via
    `--profile` to the CLI.
    
    This PR introduces the `ConfigProfile` struct and makes it a field of
    `CargoToml`. It further updates
    `Config::load_from_base_config_with_overrides()` to respect
    `ConfigProfile`, overriding default values where appropriate. A detailed
    unit test is added at the end of `config.rs` to verify this behavior.
    
    Details on how to use this feature have also been added to
    `codex-rs/README.md`.
  • restructure flake for codex-rs (#888)
    Right now since the repo is having two different implementations of
    codex, flake was updated to work with both typescript implementation and
    rust implementation
  • feat: auto-approve nl and support piping to sed (#920)
    Auto-approved:
    
    ```
    ["nl", "-ba", "README.md"]
    ["sed", "-n", "1,200p", "filename.txt"]
    ["bash", "-lc", "sed -n '1,200p' filename.txt"]
    ["bash", "-lc", "nl -ba README.md | sed -n '1,200p'"]
    ```
    
    Not auto approved:
    
    ```
    ["sed", "-n", "'1,200p'", "filename.txt"]
    ["sed", "-n", "1,200p", "file1.txt", "file2.txt"]
    ```
  • fix: tweak the label for citations for better rendering (#919)
    Adds a space so that sequential citations have some more breathing room.
    
    As I had to update the tests for this change, I also introduced a
    `toDiffableString()` helper to make the test easier to update as we make
    formatting changes to the output.
  • fix: patch in #366 and #367 for marked-terminal (#916)
    This PR uses [`pnpm
    patch`](https://www.petermekhaeil.com/til/pnpm-patch/) to pull in the
    following proposed fixes for `marked-terminal`:
    
    * https://github.com/mikaelbr/marked-terminal/pull/366
    * https://github.com/mikaelbr/marked-terminal/pull/367
    
    This adds a substantial test to `codex-cli/tests/markdown.test.tsx` to
    verify the new behavior.
    
    Note that one of the tests shows two citations being split across a line
    even though the rendered version would fit comfortably on one line.
    Changing this likely requires a subtle fix to `marked-terminal` to
    account for "rendered length" when determining line breaks.
  • fix: remember to set lastIndex = 0 on shared RegExp (#918)
    I had not observed an issue in the wild because of this yet, but it
    feels like it was only a matter of time...
  • fix: add support for fileOpener in config.json (#911)
    This PR introduces the following type:
    
    ```typescript
    export type FileOpenerScheme = "vscode" | "cursor" | "windsurf";
    ```
    
    and uses it as the new type for a `fileOpener` option in `config.json`.
    If set, this will be used to linkify file annotations in the output
    using the URI-based file opener supported in VS Code-based IDEs.
    
    Currently, this does not pass:
    
    Updated `codex-cli/tests/markdown.test.tsx` to verify the new behavior.
    Note it required mocking `supports-hyperlinks` and temporarily modifying
    `chalk.level` to yield the desired output.
  • fix: always load version from package.json at runtime (#909)
    Note the high-level motivation behind this change is to avoid the need
    to make temporary changes in the source tree in order to cut a release
    build since that runs the risk of leaving things in an inconsistent
    state in the event of a failure. The existing code:
    
    ```
    import pkg from "../../package.json" assert { type: "json" };
    ```
    
    did not work as intended because, as written, ESBuild would bake the
    contents of the local `package.json` into the release build at build
    time whereas we want it to read the contents at runtime so we can use
    the `package.json` in the tree to build the code and later inject a
    modified version into the release package with a timestamped build
    version.
    
    Changes:
    
    * move `CLI_VERSION` out of `src/utils/session.ts` and into
    `src/version.ts` so `../package.json` is a correct relative path both
    from `src/version.ts` in the source tree and also in the final
    `dist/cli.js` build output
    * change `assert` to `with` in `import pkg` as apparently `with` became
    standard in Node 22
    * mark `"../package.json"` as external in `build.mjs` so the version is
    not baked into the `.js` at build time
    
    After using `pnpm stage-release` to build a release version, if I use
    Node 22.0 to run Codex, I see the following printed to stderr at
    startup:
    
    ```
    (node:71308) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
    (Use `node --trace-warnings ...` to show where the warning was created)
    ```
    
    Note it is a warning and does not prevent Codex from running.
    
    In Node 22.12, the warning goes away, but the warning still appears in
    Node 22.11. For Node 22, 22.15.0 is the current LTS version, so LTS
    users will not see this.
    
    Also, something about moving the definition of `CLI_VERSION` caused a
    problem with the mocks in `check-updates.test.ts`. I asked Codex to fix
    it, and it came up with the change to the test configs. I don't know
    enough about vitest to understand what it did, but the tests seem
    healthy again, so I'm going with it.
  • fix: agent instructions were not being included when ~/.codex/instructions.md was empty (#908)
    I had seen issues where `codex-rs` would not always write files without
    me pressuring it to do so, and between that and the report of
    https://github.com/openai/codex/issues/900, I decided to look into this
    further. I found two serious issues with agent instructions:
    
    (1) We were only sending agent instructions on the first turn, but
    looking at the TypeScript code, we should be sending them on every turn.
    
    (2) There was a serious issue where the agent instructions were
    frequently lost:
    
    * The TypeScript CLI appears to keep writing `~/.codex/instructions.md`:
    https://github.com/openai/codex/blob/55142e3e6caddd1e613b71bcb89385ce5cc708bf/codex-cli/src/utils/config.ts#L586
    * If `instructions.md` is present, the Rust CLI uses the contents of it
    INSTEAD OF the default prompt, even if `instructions.md` is empty:
    https://github.com/openai/codex/blob/55142e3e6caddd1e613b71bcb89385ce5cc708bf/codex-rs/core/src/config.rs#L202-L203
    
    The combination of these two things means that I have been using
    `codex-rs` without these key instructions:
    https://github.com/openai/codex/blob/main/codex-rs/core/prompt.md
    
    Looking at the TypeScript code, it appears we should be concatenating
    these three items every time (if they exist):
    
    * `prompt.md`
    * `~/.codex/instructions.md`
    * nearest `AGENTS.md`
    
    This PR fixes things so that:
    
    * `Config.instructions` is `None` if `instructions.md` is empty
    * `Payload.instructions` is now `&'a str` instead of `Option<&'a
    String>` because we should always have _something_ to send
    * `Prompt` now has a `get_full_instructions()` helper that returns a
    `Cow<str>` that will always include the agent instructions first.
  • fix: navigate initialization phase before tools/list request in MCP client (#904)
    Apparently the MCP server implemented in JavaScript did not require the
    `initialize` handshake before responding to tool list/call, so I missed
    this.
  • fix: Normalize paths in resolvePathAgainstWorkdir to prevent path traversal vulnerability (#895)
    This PR fixes a potential path traversal vulnerability by ensuring all
    paths are properly normalized in the `resolvePathAgainstWorkdir`
    function.
    
    ## Changes
    - Added path normalization for both absolute and relative paths
    - Ensures normalized paths are used in all subsequent operations
    - Prevents potential path traversal attacks through non-normalized paths
    
    This minimal change addresses the security concern without adding
    unnecessary complexity, while maintaining compatibility with existing
    code.
  • chore: introduce new --native flag to Node module release process (#844)
    This PR introduces an optional build flag, `--native`, that will build a
    version of the Codex npm module that:
    
    - Includes both the Node.js and native Rust versions (for Mac and Linux)
    - Will run the native version if `CODEX_RUST=1` is set
    - Runs the TypeScript version otherwise
    
    Note this PR also updates the workflow URL to
    https://github.com/openai/codex/actions/runs/14872557396, as that is a
    build from today that includes everything up through
    https://github.com/openai/codex/pull/843.
    
    Test Plan:
    
    In `~/code/codex/codex-cli`, I ran:
    
    ```
    pnpm stage-release --native
    ```
    
    The end of the output was:
    
    ```
    Staged version 0.1.2505121317 for release in /var/folders/wm/f209bc1n2bd_r0jncn9s6j_00000gp/T/tmp.xd2p5ETYGN
    Test Node:
        node /var/folders/wm/f209bc1n2bd_r0jncn9s6j_00000gp/T/tmp.xd2p5ETYGN/bin/codex.js --help
    Test Rust:
        CODEX_RUST=1 node /var/folders/wm/f209bc1n2bd_r0jncn9s6j_00000gp/T/tmp.xd2p5ETYGN/bin/codex.js --help
    Next:  cd "/var/folders/wm/f209bc1n2bd_r0jncn9s6j_00000gp/T/tmp.xd2p5ETYGN" && npm publish --tag native
    ```
    
    I verified that running each of these commands ran the expected version
    of Codex.
    
    While here, I also added `bin` to the `files` list in `package.json`,
    which should have been done as part of
    https://github.com/openai/codex/pull/757, as that added new entries to
    `bin` that were matched by `.gitignore` but should have been included in
    a release.
  • Disallow expect via lints (#865)
    Adds `expect()` as a denied lint. Same deal applies with `unwrap()`
    where we now need to put `#[expect(...` on ones that we legit want. Took
    care to enable `expect()` in test contexts.
    
    # Tests
    
    ```
    cargo fmt
    cargo clippy --all-features --all-targets --no-deps -- -D warnings
    cargo test
    ```
  • fix: fix border style for BottomPane (#893)
    This PR fixes things so that:
    
    * when the `BottomPane` is in the `StatusIndicator` state, the border
    should be dim
    * when the `BottomPane` does not have input focus, the border should be
    dim
    
    To make it easier to enforce this invariant, this PR introduces
    `BottomPane::set_state()` that will:
    
    * update `self.state`
    * call `update_border_for_input_focus()`
    * request a repaint
    
    This should make it easier to enforce other updates for state changes
    going forward.
  • feat: include "reasoning" messages in Rust TUI (#892)
    As shown in the screenshot, we now include reasoning messages from the
    model in the TUI under the heading "codex reasoning":
    
    
    ![image](https://github.com/user-attachments/assets/d8eb3dc3-2f9f-4e95-847e-d24b421249a8)
    
    To ensure these are visible by default when using `o4-mini`, this also
    changes the default value for `summary` (formerly `generate_summary`,
    which is deprecated in favor of `summary` according to the docs) from
    unset to `"auto"`.
  • feat: add support for AGENTS.md in Rust CLI (#885)
    The TypeScript CLI already has support for including the contents of
    `AGENTS.md` in the instructions sent with the first turn of a
    conversation. This PR brings this functionality to the Rust CLI.
    
    To be considered, `AGENTS.md` must be in the `cwd` of the session, or in
    one of the parent folders up to a Git/filesystem root (whichever is
    encountered first).
    
    By default, a maximum of 32 KiB of `AGENTS.md` will be included, though
    this is configurable using the new-in-this-PR `project_doc_max_bytes`
    option in `config.toml`.
  • fix: flex-mode via config/flag (#813)
    * Add flexMode to stored config, and use it during config loading unless
    the flag is explicitly passed.
    * If the config asks for flexMode and the model doesn't support it,
    silently disable flexMode.
    
    Resolves #803
  • feat: added arceeai as a provider (#818)
    - Added ArceeAI as a provider  - https://conductor.arcee.ai/v1
    - Compatible with ArceeAI SLMs (Virtuoso, Maestro)
    - Works with ArceeAI's Conductor auto‑router models (auto, auto‑tool),
    once #817 is merged
  • fix: guard against missing choices (#817)
    - Fixes guard by using optional chaining to safely check
    chunk.choices?.[0] before accessing.
    - Currently, accessing chunk.choices[0] without checking could throw if
    choices was missing from the chunk.
  • Add reasoning effort option to CLI help text (#815)
    Reasoning effort was already available, but not expressed into the help
    text, so it was non-discoverable.
    
    Other issues discovered, but will fix in separate PR since they are
    larger:
    * #816 reasoningEffort isn't displayed in the terminal-header, making it
    rather hard to see the state of configuration
    * I don't think the config file setting works, as the CLI option always
    "wins" and overwrites it
  • fix: migrate to AGENTS.md (#764)
    Migrate from `codex.md` to `AGENTS.md`
  • fix: retry on OpenAI server_error even without status code (#814)
    Fix: retry on server_error responses that lack an HTTP status code
    
    ### What happened
    
    1. An OpenAI endpoint returned a **5xx** (transient server-side
    failure).
    2. The SDK surfaced it as an `APIError` with
    
    { "type": "server_error", "message": "...", "status": undefined }
    
               (The SDK does not always populate `status` for these cases.)
    3. Our retry logic in `src/utils/agent/agent-loop.ts` determined
    
    isServerError = typeof status === "number" && status >= 500;
    
    Because `status` was *undefined*, the error was **not** recognised as
    retriable, the exception bubbled out, and the CLI crashed with a stack
               trace similar to:
    
                   Error: An error occurred while processing the request.
                       at .../cli.js:474:1514
    
    ### Root cause
    
    The transient-error detector ignored the semantic flag type ===
    "server_error" that the SDK provides when the numeric status is missing.
    
    #### Fix (1 loc + comment)
    
    Extend the check:
    
    const status = errCtx?.status ?? errCtx?.httpStatus ??
    errCtx?.statusCode;
    
    const isServerError = (typeof status === "number" && status >= 500) ||
    // classic 5xx
    errCtx?.type === "server_error";                   // <-- NEW
    
    Now the agent:
    
    * Retries up to **5** times (existing logic) when the backend reports a
    transient failure, even if `status` is absent.
    * If all retries fail, surfaces the existing friendly system message
    instead of an uncaught exception.
    
    ### Tests & validation
    
    pnpm test # all suites green (17 agent-level tests now include this
    path)
    pnpm run lint    # 0 errors / warnings
    pnpm run typecheck
    
    A new unit-test file isn’t required—the behaviour is already covered by
    tests/agent-server-retry.test.ts, which stubs type: "server_error" and
    now passes with the updated logic.
    
    ### Impact
    
    * No API-surface changes.
    * Prevents CLI crashes on intermittent OpenAI outages.
    * Adds robust handling for other providers that may follow the same
    error-shape.
  • feat: experimental env var: CODEX_SANDBOX_NETWORK_DISABLED (#879)
    When using Codex to develop Codex itself, I noticed that sometimes it
    would try to add `#[ignore]` to the following tests:
    
    ```
    keeps_previous_response_id_between_tasks()
    retries_on_early_close()
    ```
    
    Both of these tests start a `MockServer` that launches an HTTP server on
    an ephemeral port and requires network access to hit it, which the
    Seatbelt policy associated with `--full-auto` correctly denies. If I
    wasn't paying attention to the code that Codex was generating, one of
    these `#[ignore]` annotations could have slipped into the codebase,
    effectively disabling the test for everyone.
    
    To that end, this PR enables an experimental environment variable named
    `CODEX_SANDBOX_NETWORK_DISABLED` that is set to `1` if the
    `SandboxPolicy` used to spawn the process does not have full network
    access. I say it is "experimental" because I'm not convinced this API is
    quite right, but we need to start somewhere. (It might be more
    appropriate to have an env var like `CODEX_SANDBOX=full-auto`, but the
    challenge is that our newer `SandboxPolicy` abstraction does not map to
    a simple set of enums like in the TypeScript CLI.)
    
    We leverage this new functionality by adding the following code to the
    aforementioned tests as a way to "dynamically disable" them:
    
    ```rust
    if std::env::var(CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR).is_ok() {
        println!(
            "Skipping test because it cannot execute when network is disabled in a Codex sandbox."
        );
        return;
    }
    ```
    
    We can use the `debug seatbelt --full-auto` command to verify that
    `cargo test` fails when run under Seatbelt prior to this change:
    
    ```
    $ cargo run --bin codex -- debug seatbelt --full-auto -- cargo test
    ---- keeps_previous_response_id_between_tasks stdout ----
    
    thread 'keeps_previous_response_id_between_tasks' panicked at /Users/mbolin/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/wiremock-0.6.3/src/mock_server/builder.rs:107:46:
    Failed to bind an OS port for a mock server.: Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    
    
    failures:
        keeps_previous_response_id_between_tasks
    
    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
    
    error: test failed, to rerun pass `-p codex-core --test previous_response_id`
    ```
    
    Though after this change, the above command succeeds! This means that,
    going forward, when Codex operates on Codex itself, when it runs `cargo
    test`, only "real failures" should cause the command to fail.
    
    As part of this change, I decided to tighten up the codepaths for
    running `exec()` for shell tool calls. In particular, we do it in `core`
    for the main Codex business logic itself, but we also expose this logic
    via `debug` subcommands in the CLI in the `cli` crate. The logic for the
    `debug` subcommands was not quite as faithful to the true business logic
    as I liked, so I:
    
    * refactored a bit of the Linux code, splitting `linux.rs` into
    `linux_exec.rs` and `landlock.rs` in the `core` crate.
    * gating less code behind `#[cfg(target_os = "linux")]` because such
    code does not get built by default when I develop on Mac, which means I
    either have to build the code in Docker or wait for CI signal
    * introduced `macro_rules! configure_command` in `exec.rs` so we can
    have both sync and async versions of this code. The synchronous version
    seems more appropriate for straight threads or potentially fork/exec.
  • Adds Azure OpenAI support (#769)
    ## Summary
    
    This PR introduces support for Azure OpenAI as a provider within the
    Codex CLI. Users can now configure the tool to leverage their Azure
    OpenAI deployments by specifying `"azure"` as the provider in
    `config.json` and setting the corresponding `AZURE_OPENAI_API_KEY` and
    `AZURE_OPENAI_API_VERSION` environment variables. This functionality is
    added alongside the existing provider options (OpenAI, OpenRouter,
    etc.).
    
    Related to #92
    
    **Note:** This PR is currently in **Draft** status because tests on the
    `main` branch are failing. It will be marked as ready for review once
    the `main` branch is stable and tests are passing.
    
    ---
    
    ## What’s Changed
    
    -   **Configuration (`config.ts`, `providers.ts`, `README.md`):**
    - Added `"azure"` to the supported `providers` list in `providers.ts`,
    specifying its name, default base URL structure, and environment
    variable key (`AZURE_OPENAI_API_KEY`).
    - Defined the `AZURE_OPENAI_API_VERSION` environment variable in
    `config.ts` with a default value (`2025-03-01-preview`).
        -   Updated `README.md` to:
            -   Include "azure" in the list of providers.
    - Add a configuration section for Azure OpenAI, detailing the required
    environment variables (`AZURE_OPENAI_API_KEY`,
    `AZURE_OPENAI_API_VERSION`) with examples.
    - **Client Instantiation (`terminal-chat.tsx`, `singlepass-cli-app.tsx`,
    `agent-loop.ts`, `compact-summary.ts`, `model-utils.ts`):**
    - Modified various components and utility functions where the OpenAI
    client is initialized.
    - Added conditional logic to check if the configured `provider` is
    `"azure"`.
    - If the provider is Azure, the `AzureOpenAI` client from the `openai`
    package is instantiated, using the configured `baseURL`, `apiKey` (from
    `AZURE_OPENAI_API_KEY`), and `apiVersion` (from
    `AZURE_OPENAI_API_VERSION`).
    - Otherwise, the standard `OpenAI` client is instantiated as before.
    -   **Dependencies:**
    - Relies on the `openai` package's built-in support for `AzureOpenAI`.
    No *new* external dependencies were added specifically for this Azure
    implementation beyond the `openai` package itself.
    
    ---
    
    ## How to Test
    
    *This has been tested locally and confirmed working with Azure OpenAI.*
    
    1.  **Configure `config.json`:**
    Ensure your `~/.codex/config.json` (or project-specific config) includes
    Azure and sets it as the active provider:
        ```json
        {
          "providers": {
            // ... other providers
            "azure": {
              "name": "AzureOpenAI",
    "baseURL": "https://YOUR_RESOURCE_NAME.openai.azure.com", // Replace
    with your Azure endpoint
              "envKey": "AZURE_OPENAI_API_KEY"
            }
          },
          "provider": "azure", // Set Azure as the active provider
          "model": "o4-mini" // Use your Azure deployment name here
          // ... other config settings
        }
        ```
    2.  **Set up Environment Variables:**
        ```bash
        # Set the API Key for your Azure OpenAI resource
        export AZURE_OPENAI_API_KEY="your-azure-api-key-here"
    
    # Set the API Version (Optional - defaults to `2025-03-01-preview` if
    not set)
    # Ensure this version is supported by your Azure deployment and endpoint
        export AZURE_OPENAI_API_VERSION="2025-03-01-preview"
        ```
    3.  **Get the Codex CLI by building from this PR branch:**
    Clone your fork, checkout this branch (`feat/azure-openai`), navigate to
    `codex-cli`, and build:
        ```bash
        # cd /path/to/your/fork/codex
        git checkout feat/azure-openai # Or your branch name
        cd codex-cli
        corepack enable
        pnpm install
        pnpm build
        ```
    4.  **Invoke Codex:**
    Run the locally built CLI using `node` from the `codex-cli` directory:
        ```bash
        node ./dist/cli.js "Explain the purpose of this PR"
        ```
    *(Alternatively, if you ran `pnpm link` after building, you can use
    `codex "Explain the purpose of this PR"` from anywhere)*.
    5. **Verify:** Confirm that the command executes successfully and
    interacts with your configured Azure OpenAI deployment.
    
    ---
    
    ## Tests
    
    - [x] Tested locally against an Azure OpenAI deployment using API Key
    authentication. Basic commands and interactions confirmed working.
    
    ---
    
    ## Checklist
    
    - [x] Added Azure provider details to configuration files
    (`providers.ts`, `config.ts`).
    - [x] Implemented conditional `AzureOpenAI` client initialization based
    on provider setting.
    -   [x] Ensured `apiVersion` is passed correctly to the Azure client.
    -   [x] Updated `README.md` with Azure OpenAI setup instructions.
    - [x] Manually tested core functionality against a live Azure OpenAI
    endpoint.
    - [x] Add/update automated tests for the Azure code path (pending `main`
    stability).
    
    cc @theabhinavdas @nikodem-wrona @fouad-openai @tibo-openai (adjust as
    needed)
    
    ---
    
    I have read the CLA Document and I hereby sign the CLA