Commit Graph

82 Commits

  • Refactor config loading to use filesystem abstraction (#18209)
    Initial pass propagating FileSystem through config loading.
  • Async config loading (#18022)
    Parts of config will come from executor. Prepare for that by making
    config loading methods async.
  • TUI: enforce core boundary (#17399)
    Problem: The TUI still depended on `codex-core` directly in a number of
    places, and we had no enforcement from keeping this problem from getting
    worse.
    
    Solution: Route TUI core access through
    `codex-app-server-client::legacy_core`, add CI enforcement for that
    boundary, and re-export this legacy bridge inside the TUI as
    `crate::legacy_core` so the remaining call sites stay readable. There is
    no functional change in this PR — just changes to import targets.
    
    Over time, we can whittle away at the remaining symbols in this legacy
    namespace with the eventual goal of removing them all. In the meantime,
    this linter rule will prevent us from inadvertently importing new
    symbols from core.
  • [codex] Support remote exec cwd in TUI startup (#17142)
    When running with remote executor the cwd is the remote path. Today we
    check for existence of a local directory on startup and attempt to load
    config from it.
    
    For remote executors don't do that.
  • feat: single app-server bootstrap in TUI (#16582)
    Before this, the TUI was starting 2 app-server. One to check the login
    status and one to actually start the session
    
    This PR make only one app-server startup and defer the login check in
    async, outside of the frame rendering path
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] reduce module visibility (#16978)
    ## Summary
    - reduce public module visibility across Rust crates, preferring private
    or crate-private modules with explicit crate-root public exports
    - update external call sites and tests to use the intended public crate
    APIs instead of reaching through module trees
    - add the module visibility guideline to AGENTS.md
    
    ## Validation
    - `cargo check --workspace --all-targets --message-format=short` passed
    before the final fix/format pass
    - `just fix` completed successfully
    - `just fmt` completed successfully
    - `git diff --check` passed
  • Refactor config types into a separate crate (#16962)
    Move config types into a separate crate because their macros expand into
    a lot of new code.
  • tui: route device-code auth through app server (#16827)
    Addresses #7646
    Also enables device code auth for remote TUI sessions
    
    Problem: TUI onboarding handled device-code login directly rather than
    using the recently-added app server support for device auth. Also, auth
    screens kept animating while users needed to copy login details.
    
    Solution: Route device-code onboarding through app-server login APIs and
    make the auth screens static while those copy-oriented flows are
    visible.
  • core: remove cross-crate re-exports from lib.rs (#16512)
    ## Why
    
    `codex-core` was re-exporting APIs owned by sibling `codex-*` crates,
    which made downstream crates depend on `codex-core` as a proxy module
    instead of the actual owner crate.
    
    Removing those forwards makes crate boundaries explicit and lets leaf
    crates drop unnecessary `codex-core` dependencies. In this PR, this
    reduces the dependency on `codex-core` to `codex-login` in the following
    files:
    
    ```
    codex-rs/backend-client/Cargo.toml
    codex-rs/mcp-server/tests/common/Cargo.toml
    ```
    
    ## What
    
    - Remove `codex-rs/core/src/lib.rs` re-exports for symbols owned by
    `codex-login`, `codex-mcp`, `codex-rollout`, `codex-analytics`,
    `codex-protocol`, `codex-shell-command`, `codex-sandboxing`,
    `codex-tools`, and `codex-utils-path`.
    - Delete the `default_client` forwarding shim in `codex-rs/core`.
    - Update in-crate and downstream callsites to import directly from the
    owning `codex-*` crate.
    - Add direct Cargo dependencies where callsites now target the owner
    crate, and remove `codex-core` from `codex-rs/backend-client`.
  • Rename tui_app_server to tui (#16104)
    This is a follow-up to https://github.com/openai/codex/pull/15922. That
    previous PR deleted the old `tui` directory and left the new
    `tui_app_server` directory in place. This PR renames `tui_app_server` to
    `tui` and fixes up all references.
  • Remove the legacy TUI split (#15922)
    This is the part 1 of 2 PRs that will delete the `tui` /
    `tui_app_server` split. This part simply deletes the existing `tui`
    directory and marks the `tui_app_server` feature flag as removed. I left
    the `tui_app_server` feature flag in place for now so its presence
    doesn't result in an error. It is simply ignored.
    
    Part 2 will rename the `tui_app_server` directory `tui`. I did this as
    two parts to reduce visible code churn.
  • Use AbsolutePathBuf for cwd state (#15710)
    Migrate `cwd` and related session/config state to `AbsolutePathBuf` so
    downstream consumers consistently see absolute working directories.
    
    Add test-only `.abs()` helpers for `Path`, `PathBuf`, and `TempDir`, and
    update branch-local tests to use them instead of
    `AbsolutePathBuf::try_from(...)`.
    
    For the remaining TUI/app-server snapshot coverage that renders absolute
    cwd values, keep the snapshots unchanged and skip the Windows-only cases
    where the platform-specific absolute path layout differs.
  • Add legal link to TUI /plugin details (#15692)
    - Adds language and "[learn
    more](https://help.openai.com/en/articles/11487775-apps-in-chatgpt)"
    link to plugin details pages.
    -  Message is hidden when plugin is installed
    
    <img width="1970" height="498" alt="image"
    src="https://github.com/user-attachments/assets/f14330f7-661e-4860-8538-6dc9e8bbd90a"
    />
  • Move git utilities into a dedicated crate (#15564)
    - create `codex-git-utils` and move the shared git helpers into it with
    file moves preserved for diff readability
    - move the `GitInfo` helpers out of `core` so stacked rollout work can
    depend on the shared crate without carrying its own git info module
    
    ---------
    
    Co-authored-by: Ahmed Ibrahim <219906144+aibrahim-oai@users.noreply.github.com>
    Co-authored-by: Codex <noreply@openai.com>
  • Apply argument comment lint across codex-rs (#14652)
    ## Why
    
    Once the repo-local lint exists, `codex-rs` needs to follow the
    checked-in convention and CI needs to keep it from drifting. This commit
    applies the fallback `/*param*/` style consistently across existing
    positional literal call sites without changing those APIs.
    
    The longer-term preference is still to avoid APIs that require comments
    by choosing clearer parameter types and call shapes. This PR is
    intentionally the mechanical follow-through for the places where the
    existing signatures stay in place.
    
    After rebasing onto newer `main`, the rollout also had to cover newly
    introduced `tui_app_server` call sites. That made it clear the first cut
    of the CI job was too expensive for the common path: it was spending
    almost as much time installing `cargo-dylint` and re-testing the lint
    crate as a representative test job spends running product tests. The CI
    update keeps the full workspace enforcement but trims that extra
    overhead from ordinary `codex-rs` PRs.
    
    ## What changed
    
    - keep a dedicated `argument_comment_lint` job in `rust-ci`
    - mechanically annotate remaining opaque positional literals across
    `codex-rs` with exact `/*param*/` comments, including the rebased
    `tui_app_server` call sites that now fall under the lint
    - keep the checked-in style aligned with the lint policy by using
    `/*param*/` and leaving string and char literals uncommented
    - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo
    registry/git metadata in the lint job
    - split changed-path detection so the lint crate's own `cargo test` step
    runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes
    - continue to run the repo wrapper over the `codex-rs` workspace, so
    product-code enforcement is unchanged
    
    Most of the code changes in this commit are intentionally mechanical
    comment rewrites or insertions driven by the lint itself.
    
    ## Verification
    
    - `./tools/argument-comment-lint/run.sh --workspace`
    - `cargo test -p codex-tui-app-server -p codex-tui`
    - parsed `.github/workflows/rust-ci.yml` locally with PyYAML
    
    ---
    
    * -> #14652
    * #14651
  • Update Codex docs success link (#12805)
    Fix a stale documentation link in the sign-in flow
  • fix(tui): preserve URL clickability across all TUI views (#12067)
    ## Problem
    
    Long URLs containing `/` and `-` characters are split across multiple
    terminal lines by `textwrap`'s default hyphenation rules. This breaks
    terminal link detection: emulators can no longer identify the URL as
    clickable, and copy-paste yields a truncated fragment. The issue affects
    every view that renders user or agent text — exec output, history cells,
    markdown, the app-link setup screen, and the VT100 scrollback path.
    
    A secondary bug compounds the first: `desired_height()` calculations
    count logical lines rather than viewport rows. When a URL overflows its
    line and wraps visually, the height budget is too small, causing content
    to clip or leave gaps.
    
    Here is how the complete URL is interpreted by the terminal before
    (first line only) and after (complete URL):
    
    | Before | After |
    |---|---|
    | <img width="777" height="1002" alt="Screenshot 2026-02-17 at 7 59 11
    PM"
    src="https://github.com/user-attachments/assets/193a89a0-7e56-49c5-8b76-53499a76e7e3"
    /> | <img width="777" height="1002" alt="Screenshot 2026-02-17 at 7 58
    40 PM"
    src="https://github.com/user-attachments/assets/0b9b4c14-aafb-439f-9ffe-f6bba556f95e"
    /> |
    
    ## Mental model
    
    The TUI now treats URL-like tokens as atomic units that must never be
    split by the wrapping engine. Every call site that previously used
    `word_wrap_*` has been migrated to `adaptive_wrap_*`, which inspects
    each line for URL-like tokens and switches wrapping strategy
    accordingly:
    
    - **Non-URL lines** follow the existing `textwrap` path unchanged (word
    boundaries, optional indentation, hyphenation).
    - **URL-only lines** (with at most decorative markers like `│`, `-`,
    `1.`) are emitted unwrapped so terminal link detection works; ratatui's
    `Wrap { trim: false }` handles the final character wrap at render time.
    - **Mixed lines** (URL + substantive non-URL prose) flow through
    `adaptive_wrap_line` so prose wraps naturally at word boundaries while
    URL tokens remain unsplit.
    
    Height measurement everywhere now delegates to
    `Paragraph::line_count(width)`, which accounts for the visual row cost
    of overflowed lines. This single source of truth replaces ad-hoc line
    counting in individual cells.
    
    For terminal scrollback (the VT100 path that prints history when the TUI
    exits), URL-only lines are emitted unwrapped so the terminal's own link
    detector can find them. Mixed URL+prose lines use adaptive wrapping so
    surrounding text wraps naturally. Continuation rows are pre-cleared to
    avoid stale content artifacts.
    
    ## Non-goals
    
    - Full RFC 3986 URL parsing. The detector is a conservative heuristic
    that covers `scheme://host`, bare domains (`example.com/path`),
    `localhost:port`, and IPv4 hosts. IPv6 (`[::1]:8080`) and exotic schemes
    are intentionally excluded from v1.
    - Changing wrapping behavior for non-URL content.
    - Reflowing or reformatting existing terminal scrollback on resize.
    
    ## Tradeoffs
    
    | Decision | Upside | Downside |
    |----------|--------|----------|
    | Heuristic URL detection vs. full parser | Fast, zero-alloc on the hot
    path; conservative enough to reject file paths like `src/main.rs` |
    False negatives on obscure URL formats (they get split as before) |
    | Adaptive (three-path) wrapping | Non-URL lines are untouched — no
    behavior change, no perf cost; mixed lines wrap prose naturally while
    preserving URLs | Three wrapping strategies to reason about when
    debugging layout |
    | Row-based truncation with line-unit ellipsis | Accurate viewport
    budget; stable "N lines omitted" count across terminal widths |
    `truncate_lines_middle` is more complex (must compute per-line row cost)
    |
    | Unwrapped URL-only lines in scrollback | Terminal emulators detect
    clickable links; copy-paste gets the full URL | TUI and scrollback
    formatting diverge for URL-only lines |
    | Default `desired_height` via `Paragraph::line_count` | DRY — most
    cells inherit correct measurement | Cells with custom layout must
    remember to override |
    
    ## Architecture
    
    ```mermaid
    flowchart TD
        A["adaptive_wrap_*()"] --> B{"line_contains_url_like?"}
        B -- No URL tokens --> C["word_wrap_line<br/>(textwrap default)"]
        B -- Has URL tokens --> D{"mixed URL + prose?"}
        D -- "URL-only<br/>(+ decorative markers)" --> E["emit unwrapped<br/>(terminal char-wraps)"]
        D -- "Mixed<br/>(URL + substantive text)" --> F["adaptive_wrap_line<br/>(AsciiSpace + custom WordSplitter)"]
        C --> G["Paragraph::line_count(w)<br/>(single height truth)"]
        E --> G
        F --> G
    ```
    
    **Changed files:**
    
    | File | Role |
    |------|------|
    | `wrapping.rs` | URL detection heuristics, mixed-line detection,
    `adaptive_wrap_*` functions, custom `WordSplitter` |
    | `exec_cell/render.rs` | Row-aware `truncate_lines_middle`, adaptive
    wrapping for command/output display |
    | `history_cell.rs` | Migrate all cell types to `adaptive_wrap_*`;
    default `desired_height` via `Paragraph::line_count` |
    | `insert_history.rs` | Three-path scrollback wrapping (unwrapped
    URL-only, adaptive mixed, word-wrapped text); continuation row clearing
    |
    | `app_link_view.rs` | Adaptive wrapping for setup URL; `desired_height`
    via `Paragraph::line_count` |
    | `markdown_render.rs` | Adaptive wrapping in `finish_paragraph` |
    | `model_migration.rs` | Viewport-aware wrapping for narrow-pane
    markdown |
    | `pager_overlay.rs` | `Wrap { trim: false }` for transcript and
    streaming chunks |
    | `queued_user_messages.rs` | Migrate to `adaptive_wrap_lines` |
    | `status/card.rs` | Migrate to `adaptive_wrap_lines` |
    
    ## Observability
    
    - **Ellipsis message** in truncated exec output reports omitted count in
    logical lines (stable across resize) rather than viewport rows
    (fluctuates).
    - URL detection is deterministic and stateless — no hidden caching or
    memoization to go stale.
    - Height mismatch bugs surface immediately as visual clipping or gaps;
    the `Paragraph::line_count` path is the same code ratatui uses at render
    time, so measurement and rendering cannot diverge.
    
    ## Tests
    
    26 new unit tests across 7 files, covering:
    
    - **URL integrity**: assert a URL-like token appears on exactly one
    rendered line (not split across two).
    - **Height accuracy**: compare `desired_height()` against
    `Paragraph::line_count()` for URL-containing content.
    - **Row-aware truncation**: verify ellipsis counts logical lines and
    output fits within the row budget.
    - **Scrollback rendering**: VT100 backend tests confirm prefix and URL
    land on the same row; continuation rows are cleared; mixed URL+prose
    lines wrap prose while preserving URL tokens.
    - **Mixed URL+prose detection**: `line_has_mixed_url_and_non_url_tokens`
    correctly distinguishes lines with substantive non-URL text from lines
    with only decorative markers alongside a URL.
    - **Heuristic correctness**: positive matches (`https://...`,
    `example.com/path`, `localhost:3000/api`, `192.168.1.1:8080/health`) and
    negative matches (`src/main.rs`, `foo/bar`, `hello-world`).
    
    ## Risks and open items
    
    1. **URL-like tokens in code output** (e.g. `example.com/api` inside a
    JSON blob) will trigger URL-preserving wrap on that line. This is
    acceptable — the worst case is a slightly wider line, not broken output.
    2. **Very long non-URL tokens on a URL line** can only break at
    character boundaries (the custom splitter emits all char indices for
    non-URL words). On extremely narrow terminals this could overflow, but
    narrow terminals already degrade gracefully.
    3. **No IPv6 support** — `[::1]:8080/path` will be treated as a non-URL
    and may get split. Can be added later without API changes.
    
    Fixes #5457
  • Promote Windows Sandbox (#11341)
    1. Move Windows Sandbox NUX to right after trust directory screen
    2. Don't offer read-only as an option in Sandbox NUX.
    Elevated/Legacy/Quit
    3. Don't allow new untrusted directories. It's trust or quit
    4. move experimental sandbox features to `[windows]
    sandbox="elevated|unelevatd"`
    5. Copy tweaks = elevated -> default, non-elevated -> non-admin
  • fix(auth): isolate chatgptAuthTokens concept to auth manager and app-server (#10423)
    So that the rest of the codebase (like TUI) don't need to be concerned
    whether ChatGPT auth was handled by Codex itself or passed in via
    app-server's external auth mode.
  • chore: rename ChatGpt -> Chatgpt in type names (#10244)
    When using ChatGPT in names of types, we should be consistent, so this
    renames some types with `ChatGpt` in the name to `Chatgpt`. From
    https://rust-lang.github.io/api-guidelines/naming.html:
    
    > In `UpperCamelCase`, acronyms and contractions of compound words count
    as one word: use `Uuid` rather than `UUID`, `Usize` rather than `USize`
    or `Stdin` rather than `StdIn`. In `snake_case`, acronyms and
    contractions are lower-cased: `is_xid_start`.
    
    This PR updates existing uses of `ChatGpt` and changes them to
    `Chatgpt`. Though in all cases where it could affect the wire format, I
    visually inspected that we don't change anything there. That said, this
    _will_ change the codegen because it will affect the spelling of type
    names.
    
    For example, this renames `AuthMode::ChatGPT` to `AuthMode::Chatgpt` in
    `app-server-protocol`, but the wire format is still `"chatgpt"`.
    
    This PR also updates a number of types in `codex-rs/core/src/auth.rs`.
  • feat(app-server): support external auth mode (#10012)
    This enables a new use case where `codex app-server` is embedded into a
    parent application that will directly own the user's ChatGPT auth
    lifecycle, which means it owns the user’s auth tokens and refreshes it
    when necessary. The parent application would just want a way to pass in
    the auth tokens for codex to use directly.
    
    The idea is that we are introducing a new "auth mode" currently only
    exposed via app server: **`chatgptAuthTokens`** which consist of the
    `id_token` (stores account metadata) and `access_token` (the bearer
    token used directly for backend API calls). These auth tokens are only
    stored in-memory. This new mode is in addition to the existing `apiKey`
    and `chatgpt` auth modes.
    
    This PR reuses the shape of our existing app-server account APIs as much
    as possible:
    - Update `account/login/start` with a new `chatgptAuthTokens` variant,
    which will allow the client to pass in the tokens and have codex
    app-server use them directly. Upon success, the server emits
    `account/login/completed` and `account/updated` notifications.
    - A new server->client request called
    `account/chatgptAuthTokens/refresh` which the server can use whenever
    the access token previously passed in has expired and it needs a new one
    from the parent application.
    
    I leveraged the core 401 retry loop which typically triggers auth token
    refreshes automatically, but made it pluggable:
    - **chatgpt** mode refreshes internally, as usual.
    - **chatgptAuthTokens** mode calls the client via
    `account/chatgptAuthTokens/refresh`, the client responds with updated
    tokens, codex updates its in-memory auth, then retries. This RPC has a
    10s timeout and handles JSON-RPC errors from the client.
    
    Also some additional things:
    - chatgpt logins are blocked while external auth is active (have to log
    out first. typically clients will pick one OR the other, not support
    both)
    - `account/logout` clears external auth in memory
    - Ensures that if `forced_chatgpt_workspace_id` is set via the user's
    config, we respect it in both:
    - `account/login/start` with `chatgptAuthTokens` (returns a JSON-RPC
    error back to the client)
    - `account/chatgptAuthTokens/refresh` (fails the turn, and on next
    request app-server will send another `account/chatgptAuthTokens/refresh`
    request to the client).
  • fix: ignore key release events during onboarding (#10131)
    ## Summary
    - guard onboarding key handling to ignore KeyEventKind::Release
    - handle key events at the onboarding screen boundary to avoid
    double-triggering widgets
    
    ## Related
    - https://github.com/ratatui/ratatui/issues/347
    
    ## Testing
    - cd codex-rs && just fmt
    - cd codex-rs && cargo test -p codex-tui
  • 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)
  • [device-auth] When headless environment is detected, show device login flow instead. (#8756)
    When headless environment is detected, show device login flow instead.
  • [device-auth] Update login instruction for headless environments. (#8753)
    We've seen reports that people who try to login on a remote/headless
    machine will open the login link on their own machine and got errors.
    Update the instructions to ask those users to use `codex login
    --device-auth` instead.
    
    <img width="1434" height="938" alt="CleanShot 2026-01-05 at 11 35 02@2x"
    src="https://github.com/user-attachments/assets/2b209953-6a42-4eb0-8b55-bb0733f2e373"
    />
  • Change "Team" to "Buisness" and add Education (#8221)
    This pull request updates the ChatGPT login description in the
    onboarding authentication widgets to clarify which plans include usage.
    The description now lists "Business" rather than "Team" and adds
    "Education" plans in addition to the previously mentioned plans.
    
    I have read the CLA Document and I hereby sign the CLAs.
    
    ---------
    
    Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
  • fix: dont quit on 'q' in onboarding ApiKeyEntry state (#7869)
    ### What
    
    Don't treat `q` as a special quit character on the API key paste page in
    the onboarding flow.
    
    This addresses #7413, where pasting API keys with `q` would cause codex
    to quit on Windows.
    
    ### Test Plan
    
    Tested on Windows and MacOS.
  • Add Enterprise plan to ChatGPT login description (#6918)
    ## Summary
    - update ChatGPT onboarding login description to mention Enterprise
    plans alongside Plus, Pro, and Team
    
    ## Testing
    - just fmt
    
    
    ------
    [Codex
    Task](https://chatgpt.com/codex/tasks/task_i_691e088daf20832c88d8b667adf45128)
  • Added feature switch to disable animations in TUI (#6870)
    This PR adds support for a new feature flag `tui.animations`. By
    default, the TUI uses animations in its welcome screen, "working"
    spinners, and "shimmer" effects. This animations can interfere with
    screen readers, so it's good to provide a way to disable them.
    
    This change is inspired by [a
    PR](https://github.com/openai/codex/pull/4014) contributed by @Orinks.
    That PR has faltered a bit, but I think the core idea is sound. This
    version incorporates feedback from @aibrahim-oai. In particular:
    1. It uses a feature flag (`tui.animations`) rather than the unqualified
    CLI key `no-animations`. Feature flags are the preferred way to expose
    boolean switches. They are also exposed via CLI command switches.
    2. It includes more complete documentation.
    3. It disables a few animations that the other PR omitted.
  • Fix tests so they don't emit an extraneous config.toml in the source tree (#6853)
    This PR fixes the `release_event_does_not_change_selection` test so it
    doesn't cause an extra `config.toml` to be emitted in the sources when
    running the tests locally. Prior to this fix, I needed to delete this
    file every time I ran the tests to prevent it from showing up as an
    uncommitted source file.
  • Prompt to turn on windows sandbox when auto mode selected. (#6618)
    - stop prompting users to install WSL 
    - prompt users to turn on Windows sandbox when auto mode requested.
    
    <img width="1660" height="195" alt="Screenshot 2025-11-17 110612"
    src="https://github.com/user-attachments/assets/c67fc239-a227-417e-94bb-599a8ed8f11e"
    />
    <img width="1684" height="168" alt="Screenshot 2025-11-17 110637"
    src="https://github.com/user-attachments/assets/d18c3370-830d-4971-8746-04757ae2f709"
    />
    <img width="1655" height="293" alt="Screenshot 2025-11-17 110719"
    src="https://github.com/user-attachments/assets/d21f6ce9-c23e-4842-baf6-8938b77c16db"
    />
  • Handle "Don't Trust" directory selection in onboarding (#4941)
    Fixes #4940
    Fixes #4892
    
    When selecting "No, ask me to approve edits and commands" during
    onboarding, the code wasn't applying the correct approval policy,
    causing Codex to block all write operations instead of requesting
    approval.
    
    This PR fixes the issue by persisting the "DontTrust" decision in
    config.toml as `trust_level = "untrusted"` and handling it in the
    sandbox and approval policy logic, so Codex correctly asks for approval
    before making changes.
    
    ## Before (bug)
    <img width="709" height="500" alt="bef"
    src="https://github.com/user-attachments/assets/5aced26d-d810-4754-879a-89d9e4e0073b"
    />
    
    ## After (fixed)
    <img width="713" height="359" alt="aft"
    src="https://github.com/user-attachments/assets/9887bbcb-a9a5-4e54-8e76-9125a782226b"
    />
    
    ---------
    
    Co-authored-by: Eric Traut <etraut@openai.com>
  • Support exiting from the login menu (#6419)
    I recently fixed a bug in [this
    PR](https://github.com/openai/codex/pull/6285) that prevented Ctrl+C
    from dismissing the login menu in the TUI and leaving the user unauthed.
    
    A [user pointed out](https://github.com/openai/codex/issues/6418) that
    this makes Ctrl+C can no longer be used to exit the app. This PR changes
    the behavior so we exit the app rather than ignoring the Ctrl+C.
  • Prevent dismissal of login menu in TUI (#6285)
    We currently allow the user to dismiss the login menu via Ctrl+C. This
    leaves them in a bad state where they're not auth'ed but have an input
    prompt. In the extension, this isn't a problem because we don't allow
    the user to dismiss the login screen.
    
    Testing: I confirmed that Ctrl+C no longer dismisses the login menu.
    
    This is an alternative (simpler) fix for a [community
    PR](https://github.com/openai/codex/pull/3234).
  • fix: pasting api key stray character (#4903)
    When signing in with an API key, pasting (with command+v on mac) adds a
    stray `v` character to the end of the api key.
    
    
    
    demo video (where I'm pasting in `sk-something-super-secret`)
    
    
    https://github.com/user-attachments/assets/b2b34b5f-c7e4-4760-9657-c35686dd8bb8
  • chore: config editor (#5878)
    The goal is to have a single place where we actually write files
    
    In a follow-up PR, will move everything config related in a dedicated
    module and move the helpers in a dedicated file
  • [Auth] Choose which auth storage to use based on config (#5792)
    This PR is a follow-up to #5591. It allows users to choose which auth
    storage mode they want by using the new
    `cli_auth_credentials_store_mode` config.
  • fix(tui): Update WSL instructions (#5307)
    ## Summary
    Clearer and more complete WSL instructions in our shell message.
    
    ## Testing
    - [x] Tested locally
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • Add forced_chatgpt_workspace_id and forced_login_method configuration options (#5303)
    This PR adds support for configs to specify a forced login method
    (chatgpt or api) as well as a forced chatgpt account id. This lets
    enterprises uses [managed
    configs](https://developers.openai.com/codex/security#managed-configuration)
    to force all employees to use their company's workspace instead of their
    own or any other.
    
    When a workspace id is set, a query param is sent to the login flow
    which auto-selects the given workspace or errors if the user isn't a
    member of it.
    
    This PR is large but a large % of it is tests, wiring, and required
    formatting changes.
    
    API login with chatgpt forced
    <img width="1592" height="116" alt="CleanShot 2025-10-19 at 22 40 04"
    src="https://github.com/user-attachments/assets/560c6bb4-a20a-4a37-95af-93df39d057dd"
    />
    
    ChatGPT login with api forced
    <img width="1018" height="100" alt="CleanShot 2025-10-19 at 22 40 29"
    src="https://github.com/user-attachments/assets/d010bbbb-9c8d-4227-9eda-e55bf043b4af"
    />
    
    Onboarding with api forced
    <img width="892" height="460" alt="CleanShot 2025-10-19 at 22 41 02"
    src="https://github.com/user-attachments/assets/cc0ed45c-b257-4d62-a32e-6ca7514b5edd"
    />
    
    Onboarding with ChatGPT forced
    <img width="1154" height="426" alt="CleanShot 2025-10-19 at 22 41 27"
    src="https://github.com/user-attachments/assets/41c41417-dc68-4bb4-b3e7-3b7769f7e6a1"
    />
    
    Logging in with the wrong workspace
    <img width="2222" height="84" alt="CleanShot 2025-10-19 at 22 42 31"
    src="https://github.com/user-attachments/assets/0ff4222c-f626-4dd3-b035-0b7fe998a046"
    />
  • feat: Auto update approval (#5185)
    Adds an update prompt when the CLI starts:
    
    <img width="1410" height="608" alt="Screenshot 2025-10-14 at 5 53 17 PM"
    src="https://github.com/user-attachments/assets/47c8bafa-7bed-4be8-b597-c4c6c79756b8"
    />
  • tui: fix wrapping in trust_directory (#5007)
    Refactor trust_directory to use ColumnRenderable & friends, thus
    correcting wrapping behavior at small widths. Also introduce
    RowRenderable with fixed-width rows.
    
    - fixed wrapping in trust_directory
    - changed selector cursor to match other list item selections
    - allow y/n to work as well as 1/2
    - fixed key_hint to be standard
    
    before:
    <img width="661" height="550" alt="Screenshot 2025-10-09 at 9 50 36 AM"
    src="https://github.com/user-attachments/assets/e01627aa-bee4-4e25-8eca-5575c43f05bf"
    />
    
    after:
    <img width="661" height="550" alt="Screenshot 2025-10-09 at 9 51 31 AM"
    src="https://github.com/user-attachments/assets/cb816cbd-7609-4c83-b62f-b4dba392d79a"
    />
  • feat: tweak windows wsl copy (#4795)
    Tweaked the WSL dialogue and the installation instructions.
  • fix: remove mcp-types from app server protocol (#4537)
    We continue the separation between `codex app-server` and `codex
    mcp-server`.
    
    In particular, we introduce a new crate, `codex-app-server-protocol`,
    and migrate `codex-rs/protocol/src/mcp_protocol.rs` into it, renaming it
    `codex-rs/app-server-protocol/src/protocol.rs`.
    
    Because `ConversationId` was defined in `mcp_protocol.rs`, we move it
    into its own file, `codex-rs/protocol/src/conversation_id.rs`, and
    because it is referenced in a ton of places, we have to touch a lot of
    files as part of this PR.
    
    We also decide to get away from proper JSON-RPC 2.0 semantics, so we
    also introduce `codex-rs/app-server-protocol/src/jsonrpc_lite.rs`, which
    is basically the same `JSONRPCMessage` type defined in `mcp-types`
    except with all of the `"jsonrpc": "2.0"` removed.
    
    Getting rid of `"jsonrpc": "2.0"` makes our serialization logic
    considerably simpler, as we can lean heavier on serde to serialize
    directly into the wire format that we use now.