mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
2ada9e1b2df1c96c888fd007e1fadd218ef67ae6
1148 Commits
-
feat(tui): support Alt-d delete-forward-word (#12455)
Alt-d should delete the next word. It didn’t. Now it does. Added a small test so it stays that way. Details: File updated: [codex-rs/tui/src/bottom_pane/textarea.rs](./codex-rs/tui/src/bottom_pane/textarea.rs) Test added: delete_forward_word_alt_d — verifies Alt-d deletes the next word and keeps the cursor position correct. Solves Issue #12453
Douglas Chimento ·
2026-02-22 11:22:17 -08:00 -
Handle orphan exec ends without clobbering active exploring cell (#12313)
Summary - distinguish exec end handling targets (active tracking, active orphan history, new cell) so unified exec responses don’t clobber unrelated exploring cells - ensure orphan ends flush existing exploring history when complete, insert standalone history entries, and keep active cells correct - add regression tests plus a snapshot covering the new behavior and expose the ExecCell completion result for verification Fix for https://github.com/openai/codex/issues/12278 --------- Co-authored-by: Josh McKinney <joshka@openai.com>
jif-oai ·
2026-02-22 14:26:58 +00:00 -
feat(tui) /clear (#12444)
# /clear feature! /clear will clear your terminal while preserving the context/state of the thread.
Won Park ·
2026-02-21 22:06:56 -08:00 -
feat(tui): syntax highlighting via syntect with theme picker (#11447)
## Summary Adds syntax highlighting to the TUI for fenced code blocks in markdown responses and file diffs, plus a `/theme` command with live preview and persistent theme selection. Uses syntect (~250 grammars, 32 bundled themes, ~1 MB binary cost) — the same engine behind `bat`, `delta`, and `xi-editor`. Includes guardrails for large inputs, graceful fallback to plain text, and SSH-aware clipboard integration for the `/copy` command. <img width="1554" height="1014" alt="image" src="https://github.com/user-attachments/assets/38737a79-8717-4715-b857-94cf1ba59b85" /> <img width="2354" height="1374" alt="image" src="https://github.com/user-attachments/assets/25d30a00-c487-4af8-9cb6-63b0695a4be7" /> ## Problem Code blocks in the TUI (markdown responses and file diffs) render without syntax highlighting, making it hard to scan code at a glance. Users also have no way to pick a color theme that matches their terminal aesthetic. ## Mental model The highlighting system has three layers: 1. **Syntax engine** (`render::highlight`) -- a thin wrapper around syntect + two-face. It owns a process-global `SyntaxSet` (~250 grammars) and a `RwLock<Theme>` that can be swapped at runtime. All public entry points accept `(code, lang)` and return ratatui `Span`/`Line` vectors or `None` when the language is unrecognized or the input exceeds safety guardrails. 2. **Rendering consumers** -- `markdown_render` feeds fenced code blocks through the engine; `diff_render` highlights Add/Delete content as a whole file and Update hunks per-hunk (preserving parser state across hunk lines). Both callers fall back to plain unstyled text when the engine returns `None`. 3. **Theme lifecycle** -- at startup the config's `tui.theme` is resolved to a syntect `Theme` via `set_theme_override`. At runtime the `/theme` picker calls `set_syntax_theme` to swap themes live; on cancel it restores the snapshot taken at open. On confirm it persists `[tui] theme = "..."` to config.toml. ## Non-goals - Inline diff highlighting (word-level change detection within a line). - Semantic / LSP-backed highlighting. - Theme authoring tooling; users supply standard `.tmTheme` files. ## Tradeoffs | Decision | Upside | Downside | | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | syntect over tree-sitter / arborium | ~1 MB binary increase for ~250 grammars + 32 themes; battle-tested crate powering widely-used tools (`bat`, `delta`, `xi-editor`). tree-sitter would add ~12 MB for 20-30 languages or ~35 MB for full coverage. | Regex-based; less structurally accurate than tree-sitter for some languages (e.g. language injections like JS-in-HTML). | | Global `RwLock<Theme>` | Enables live `/theme` preview without threading Theme through every call site | Lock contention risk (mitigated: reads vastly outnumber writes, single UI thread) | | Skip background / italic / underline from themes | Terminal BG preserved, avoids ugly rendering on some themes | Themes that rely on these properties lose fidelity | | Guardrails: 512 KB / 10k lines | Prevents pathological stalls on huge diffs or pastes | Very large files render without color | ## Architecture ``` config.toml ─[tui.theme]─> set_theme_override() ─> THEME (RwLock) │ ┌───────────────────────────────────────────┘ │ markdown_render ─── highlight_code_to_lines(code, lang) ─> Vec<Line> diff_render ─── highlight_code_to_styled_spans(code, lang) ─> Option<Vec<Vec<Span>>> │ │ (None ⇒ plain text fallback) │ /theme picker ─── set_syntax_theme(theme) // live preview swap ─── current_syntax_theme() // snapshot for cancel ─── resolve_theme_by_name(name) // lookup by kebab-case ``` Key files: - `tui/src/render/highlight.rs` -- engine, theme management, guardrails - `tui/src/diff_render.rs` -- syntax-aware diff line wrapping - `tui/src/theme_picker.rs` -- `/theme` command builder - `tui/src/bottom_pane/list_selection_view.rs` -- side content panel, callbacks - `core/src/config/types.rs` -- `Tui::theme` field - `core/src/config/edit.rs` -- `syntax_theme_edit()` helper ## Observability - `tracing::warn` when a configured theme name cannot be resolved. - `Config::startup_warnings` surfaces the same message as a TUI banner. - `tracing::error` when persisting theme selection fails. ## Tests - Unit tests in `highlight.rs`: language coverage, fallback behavior, CRLF stripping, style conversion, guardrail enforcement, theme name mapping exhaustiveness. - Unit tests in `diff_render.rs`: snapshot gallery at multiple terminal sizes (80x24, 94x35, 120x40), syntax-highlighted wrapping, large-diff guardrail, rename-to-different-extension highlighting, parser state preservation across hunk lines. - Unit tests in `theme_picker.rs`: preview rendering (wide + narrow), dim overlay on deletions, subtitle truncation, cancel-restore, fallback for unavailable configured theme. - Unit tests in `list_selection_view.rs`: side layout geometry, stacked fallback, buffer clearing, cancel/selection-changed callbacks. - Integration test in `lib.rs`: theme warning uses the final (post-resume) config. ## Cargo Deny: Unmaintained Dependency Exceptions This PR adds two `cargo deny` advisory exceptions for transitive dependencies pulled in by `syntect v5.3.0`: | Advisory | Crate | Status | |----------|-------|--------| | RUSTSEC-2024-0320 | `yaml-rust` | Unmaintained (maintainer unreachable) | | RUSTSEC-2025-0141 | `bincode` | Unmaintained (development ceased; v1.3.3 considered complete) | **Why this is safe in our usage:** - Neither advisory describes a known security vulnerability. Both are "unmaintained" notices only. - `bincode` is used by syntect to deserialize pre-compiled syntax sets. Again, these are **static vendored artifacts** baked into the binary at build time. No user-supplied bincode data is ever deserialized. - Attack surface is zero for both crates; exploitation would require a supply-chain compromise of our own build artifacts. - These exceptions can be removed when syntect migrates to `yaml-rust2` and drops `bincode`, or when alternative crates are available upstream.
Felipe Coury ·
2026-02-21 20:26:58 -08:00 -
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
Felipe Coury ·
2026-02-21 15:31:41 -08:00 -
Prevent replayed runtime events from forcing active status (#12420)
Fixes #11852 Resume replay was applying transient runtime events (`TurnStarted`, `StreamError`) as if they were live, which could leave the TUI stuck in a stale `Working` / `Reconnecting...` state after resuming an interrupted reconnect. This change makes replay transcript-oriented for these events by: - skipping retry-status restoration for replayed non-stream events - ignoring replayed `TurnStarted` for task-running state - ignoring replayed `StreamError` for reconnect/status UI Also adds TUI regression tests and snapshot coverage for the interrupted reconnect replay case.
Eric Traut ·
2026-02-21 11:55:03 -08:00 -
chore: remove codex-core public protocol/shell re-exports (#12432)
## Why `codex-rs/core/src/lib.rs` re-exported a broad set of types and modules from `codex-protocol` and `codex-shell-command`. That made it easy for workspace crates to import those APIs through `codex-core`, which in turn hides dependency edges and makes it harder to reduce compile-time coupling over time. This change removes those public re-exports so call sites must import from the source crates directly. Even when a crate still depends on `codex-core` today, this makes dependency boundaries explicit and unblocks future work to drop `codex-core` dependencies where possible. ## What Changed - Removed public re-exports from `codex-rs/core/src/lib.rs` for: - `codex_protocol::protocol` and related protocol/model types (including `InitialHistory`) - `codex_protocol::config_types` (`protocol_config_types`) - `codex_shell_command::{bash, is_dangerous_command, is_safe_command, parse_command, powershell}` - Migrated workspace Rust call sites to import directly from: - `codex_protocol::protocol` - `codex_protocol::config_types` - `codex_protocol::models` - `codex_shell_command` - Added explicit `Cargo.toml` dependencies (`codex-protocol` / `codex-shell-command`) in crates that now import those crates directly. - Kept `codex-core` internal modules compiling by using `pub(crate)` aliases in `core/src/lib.rs` (internal-only, not part of the public API). - Updated the two utility crates that can already drop a `codex-core` dependency edge entirely: - `codex-utils-approval-presets` - `codex-utils-cli` ## Verification - `cargo test -p codex-utils-approval-presets` - `cargo test -p codex-utils-cli` - `cargo check --workspace --all-targets` - `just clippy`Michael Bolin ·
2026-02-20 23:45:35 -08:00 -
Collapse waited message (#12430)
<img width="1349" height="148" alt="image" src="https://github.com/user-attachments/assets/98c96523-4cec-4bb1-9998-59d38e0bebb8" />
pakrym-oai ·
2026-02-20 23:32:59 -08:00 -
Improve Plan mode reasoning selection flow (#12303)
Addresses https://github.com/openai/codex/issues/11013 ## Summary - add a Plan implementation path in the TUI that lets users choose reasoning before switching to Default mode and implementing - add Plan-mode reasoning scope handling (Plan-only override vs all-modes default), including config/schema/docs plumbing for `plan_mode_reasoning_effort` - remove the hardcoded Plan preset medium default and make the reasoning popup reflect the active Plan override as `(current)` - split the collaboration-mode switch notification UI hint into #12307 to keep this diff focused If I have `plan_mode_reasoning_effort = "medium"` set in my `config.toml`: <img width="699" height="127" alt="Screenshot 2026-02-20 at 6 59 37 PM" src="https://github.com/user-attachments/assets/b33abf04-6b7a-49ed-b2e9-d24b99795369" /> If I don't have `plan_mode_reasoning_effort` set in my `config.toml`: <img width="704" height="129" alt="Screenshot 2026-02-20 at 7 01 51 PM" src="https://github.com/user-attachments/assets/88a086d4-d2f1-49c7-8be4-f6f0c0fa1b8d" /> ## Codex author `codex resume 019c78a2-726b-7fe3-adac-3fa4523dcc2a`
Charley Cunningham ·
2026-02-20 20:08:56 -08:00 -
Wire realtime api to core (#12268)
- Introduce `RealtimeConversationManager` for realtime API management - Add `op::conversation` to start conversation, insert audio, insert text, and close conversation. - emit conversation lifecycle and realtime events. - Move shared realtime payload types into codex-protocol and add core e2e websocket tests for start/replace/transport-close paths. Things to consider: - Should we use the same `op::` and `Events` channel to carry audio? I think we should try this simple approach and later we can create separate one if the channels got congested. - Sending text updates to the client: we can start simple and later restrict that. - Provider auth isn't wired for now intentionally
Ahmed Ibrahim ·
2026-02-20 19:06:35 -08:00 -
fix(tui): queued-message edit shortcut unreachable in some terminals (#12240)
## Problem The TUI's "edit queued message" shortcut (Alt+Up) is either silently swallowed or recognized as another key combination by Apple Terminal, Warp, and VSCode's integrated terminal on macOS. Users in those environments see the hint but pressing the keys does nothing. ## Mental model When a model turn is in progress the user can still type follow-up messages. These are queued and displayed below the composer with a hint line showing how to pop the most recent one back into the editor. The hint text and the actual key handler must agree on which shortcut is used, and that shortcut must actually reach the TUI—i.e. it must not be intercepted by the host terminal. Three terminals are known to intercept Alt+Up: Apple Terminal (remaps it to cursor movement), Warp (consumes it for its own command palette), and VSCode (maps it to "move line up"). For these we use Shift+Left instead. <p align="center"> <img width="283" height="182" alt="image" src="https://github.com/user-attachments/assets/4a9c5d13-6e47-4157-bb41-28b4ce96a914" /> </p> | macOS Native Terminal | Warp | VSCode Terminal | |---|---|---| | <img width="1557" height="1010" alt="SCR-20260219-kigi" src="https://github.com/user-attachments/assets/f4ff52f8-119e-407b-a3f3-52f564c36d70" /> | <img width="1479" height="1261" alt="SCR-20260219-krrf" src="https://github.com/user-attachments/assets/5807d7c4-17ae-4a2b-aa27-238fd49d90fd" /> | <img width="1612" height="1312" alt="SCR-20260219-ksbz" src="https://github.com/user-attachments/assets/1cedb895-6966-4d63-ac5f-0eea0f7057e8" /> | ## Non-goals - Making the binding user-configurable at runtime (deferred to a broader keybinding-config effort). - Remapping any other shortcuts that might be terminal-specific. ## Tradeoffs - **Exhaustive match instead of a wildcard default.** The `queued_message_edit_binding_for_terminal` function explicitly lists every `TerminalName` variant. This is intentional: adding a new terminal to the enum will produce a compile error, forcing the author to decide which binding that terminal should use. - **Binding lives on `ChatWidget`, hint lives on `QueuedUserMessages`.** The key event handler that actually acts on the press is in `ChatWidget`, but the rendered hint text is inside `QueuedUserMessages`. These are kept in sync by `ChatWidget` calling `bottom_pane.set_queued_message_edit_binding(self.queued_message_edit_binding)` during construction. A mismatch would show the wrong hint but would not lose data. ## Architecture ```mermaid graph TD TI["terminal_info().name"] --> FN["queued_message_edit_binding_for_terminal(name)"] FN --> KB["KeyBinding"] KB --> CW["ChatWidget.queued_message_edit_binding<br/><i>key event matching</i>"] KB --> BP["BottomPane.set_queued_message_edit_binding()"] BP --> QUM["QueuedUserMessages.edit_binding<br/><i>rendered in hint line</i>"] subgraph "Special terminals (Shift+Left)" AT["Apple Terminal"] WT["Warp"] VS["VSCode"] end subgraph "Default (Alt+Up)" GH["Ghostty"] IT["iTerm2"] OT["Others…"] end AT --> FN WT --> FN VS --> FN GH --> FN IT --> FN OT --> FN ``` No new crates or public API surface. The only cross-crate dependency added is `codex_core::terminal::{TerminalName, terminal_info}`, which already existed for telemetry. ## Observability No new logging. Terminal detection already emits a `tracing::debug!` log line at startup with the detected terminal name, which is sufficient to diagnose binding mismatches. ## Tests - Existing `alt_up_edits_most_recent_queued_message` test is preserved and explicitly sets the Alt+Up binding to isolate from the host terminal. - New parameterized async tests verify Shift+Left works for Apple Terminal, Warp, and VSCode. - A sync unit test asserts the mapping table covers the three special terminals (Shift+Left) and that iTerm2 still gets Alt+Up. Fixes #4490
Felipe Coury ·
2026-02-20 16:56:41 -08:00 -
Show model/reasoning hint when switching modes (#12307)
## Summary - show an info message when switching collaboration modes changes the effective model or reasoning - include the target mode in the message (for example `... for Plan mode.`) - add TUI tests for model-change and reasoning-only change notifications on mode switch <img width="715" height="184" alt="Screenshot 2026-02-20 at 2 01 40 PM" src="https://github.com/user-attachments/assets/18d1beb3-ab87-4e1c-9ada-a10218520420" />
Charley Cunningham ·
2026-02-20 15:22:10 -08:00 -
Add ability to attach extra files to feedback (#12370)
Allow clients to provide extra files.
pakrym-oai ·
2026-02-20 22:26:14 +00:00 -
fix(network-proxy): add unix socket allow-all and update seatbelt rules (#11368)
## Summary Adds support for a Unix socket escape hatch so we can bypass socket allowlisting when explicitly enabled. ## Description * added a new flag, `network.dangerously_allow_all_unix_sockets` as an explicit escape hatch * In codex-network-proxy, enabling that flag now allows any absolute Unix socket path from x-unix-socket instead of requiring each path to be explicitly allowlisted. Relative paths are still rejected. * updated the macOS seatbelt path in core so it enforces the same Unix socket behavior: * allowlisted sockets generate explicit network* subpath rules * allow-all generates a broad network* (subpath "/") rule --------- Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
viyatb-oai ·
2026-02-20 10:56:57 -08:00 -
Refactor network approvals to host/protocol/port scope (#12140)
## Summary Simplify network approvals by removing per-attempt proxy correlation and moving to session-level approval dedupe keyed by (host, protocol, port). Instead of encoding attempt IDs into proxy credentials/URLs, we now treat approvals as a destination policy decision. - Concurrent calls to the same destination share one approval prompt. - Different destinations (or same host on different ports) get separate prompts. - Allow once approves the current queued request group only. - Allow for session caches that (host, protocol, port) and auto-allows future matching requests. - Never policy continues to deny without prompting. Example: - 3 calls: - a.com (line 443) - b.com (line 443) - a.com (line 443) => 2 prompts total (a, b), second a waits on the first decision. - a.com:80 is treated separately from a.com line 443 ## Testing - `just fmt` (in `codex-rs`) - `cargo test -p codex-core tools::network_approval::tests` - `cargo test -p codex-core` (unit tests pass; existing integration-suite failures remain in this environment)
viyatb-oai ·
2026-02-20 10:39:55 -08:00 -
feat: better agent picker in TUI (#12332)
<img width="486" height="112" alt="Screenshot 2026-02-20 at 15 04 52" src="https://github.com/user-attachments/assets/0d744f58-d902-4638-aeaf-27e7389ccd73" />
jif-oai ·
2026-02-20 15:40:34 +00:00 -
feat: cleaner TUI for sub-agents (#12327)
<img width="760" height="496" alt="Screenshot 2026-02-20 at 14 31 25" src="https://github.com/user-attachments/assets/1983b825-bb47-417e-9925-6f727af56765" />
jif-oai ·
2026-02-20 15:26:33 +00:00 -
feat: add nick name to sub-agents (#12320)
Adding random nick name to sub-agents. Used for UX At the same time, also storing and wiring the role of the sub-agent
jif-oai ·
2026-02-20 14:39:49 +00:00 -
[apps] Store apps tool cache in disk to reduce startup time. (#11822)
We now write MCP tools from installed apps to disk cache so that they can be picked up instantly at startup. We still do a fresh fetch from remote MCP server but it's non blocking unless there's a cache miss. - [x] Store apps tool cache in disk to reduce startup time.
Matthew Zeng ·
2026-02-19 22:06:51 -08:00 -
client side modelinfo overrides (#12101)
TL;DR Add top-level `model_catalog_json` config support so users can supply a local model catalog override from a JSON file path (including adding new models) without backend changes. ### Problem Codex previously had no clean client-side way to replace/overlay model catalog data for local testing of model metadata and new model entries. ### Fix - Add top-level `model_catalog_json` config field (JSON file path). - Apply catalog entries when resolving `ModelInfo`: 1. Base resolved model metadata (remote/fallback) 2. Catalog overlay from `model_catalog_json` 3. Existing global top-level overrides (`model_context_window`, `model_supports_reasoning_summaries`, etc.) ### Note Will revisit per-field overrides in a follow-up ### Tests Added tests
sayan-oai ·
2026-02-19 10:38:57 -08:00 -
Jack Mousseau ·
2026-02-19 09:56:56 -08:00 -
Enable default status line indicators in TUI config (#12015)
Default statusline to something <img width="307" height="83" alt="Screenshot 2026-02-17 at 18 16 12" src="https://github.com/user-attachments/assets/44e16153-0aa2-4c1a-9b4a-02e2feb8b7f6" />
jif-oai ·
2026-02-18 09:51:15 +00:00 -
won-openai ·
2026-02-17 21:10:30 -08:00 -
feat(core): plumb distinct approval ids for command approvals (#12051)
zsh fork PR stack: - https://github.com/openai/codex/pull/12051 👈 - https://github.com/openai/codex/pull/12052 With upcoming support for a fork of zsh that allows us to intercept `execve` and run execpolicy checks for each subcommand as part of a `CommandExecution`, it will be possible for there to be multiple approval requests for a shell command like `/path/to/zsh -lc 'git status && rg \"TODO\" src && make test'`. To support that, this PR introduces a new `approval_id` field across core, protocol, and app-server so that we can associate approvals properly for subcommands.
Owen Lin ·
2026-02-18 01:55:57 +00:00 -
tui: exit session on Ctrl+C in cwd change prompt (#12040)
## Summary - change the cwd-change prompt (shown when resuming/forking across different directories) so `Ctrl+C`/`Ctrl+D` exits the session instead of implicitly selecting "Use session directory" - introduce explicit prompt and resolver exit outcomes so this intent is propagated cleanly through both startup resume/fork and in-app `/resume` flows - add a unit test that verifies `Ctrl+C` exits rather than selecting an option ## Why Previously, pressing `Ctrl+C` on this prompt silently picked one of the options, which made it hard to abort. This aligns the prompt with the expected quit behavior. ## Codex author `codex resume 019c6d39-bbfb-7dc3-8008-1388a054e86d`
Charley Cunningham ·
2026-02-17 14:48:12 -08:00 -
[apps] Expose more fields from apps listing endpoints. (#11706)
- [x] Expose app_metadata, branding, and labels in AppInfo.
Matthew Zeng ·
2026-02-17 11:45:04 -08:00 -
chore: rm remote models fflag (#11699)
rm `remote_models` feature flag. We see issues like #11527 when a user has `remote_models` disabled, as we always use the default fallback `ModelInfo`. This causes issues with model performance. Builds on #11690, which helps by warning the user when they are using the default fallback. This PR will make that happen much less frequently as an accidental consequence of disabling `remote_models`.
sayan-oai ·
2026-02-17 11:43:16 -08:00 -
Feat: add model reroute notification (#12001)
### Summary Builiding off https://github.com/openai/codex/pull/11964/files/5c75aa7b89a70bc2cc410a6fd238749306ec4c5e#diff-058ae8f109a8b84b4b79bbfa45f522c2233b9d9e139696044ae374d50b6196e0, we have created a `model/rerouted` notification that captures the event so that consumers can render as expected. Keep the `EventMsg::Warning` path in core so that this does not affect TUI rendering. `model/rerouted` is meant to be generic to account for future usage including capacity planning etc.
Shijie Rao ·
2026-02-17 11:02:23 -08:00 -
Exit early when session initialization fails (#11908)
Summary - wait for the initial session startup loop to finish and handle exit before waiting for the first message in fresh sessions - propagate AppRunControl::Exit to return immediately when initialization fails
jif-oai ·
2026-02-17 11:22:30 +00:00 -
Hide /debug slash commands from popup menu (#11974)
Summary - filter command popup builtins to remove any `/debug*` entries so they stay usable but are not listed - added regression tests to ensure the popup hides debug commands while dispatch still resolves them
jif-oai ·
2026-02-17 10:30:17 +00:00 -
Fixed screen reader regression in CLI (#11860)
The `tui.animations` switch should gate all animations in the TUI, but a recent change introduced a regression that didn't include the gate. This makes it difficult to use the TUI with a screen reader. This fix addresses #11856
Eric Traut ·
2026-02-16 18:17:52 -08:00 -
add(feedback): over-refusal / safety check (#11948)
Add new feedback option for "Over-refusal / safety check"
Fouad Matin ·
2026-02-16 16:24:47 -08:00 -
Rename collab modules to multi agents (#11939)
Summary - rename the `collab` handlers and UI files to `multi_agents` to match the new naming - update module references and specs so the handlers and TUI widgets consistently use the renamed files - keep the existing functionality while aligning file and module names with the multi-agent terminology
jif-oai ·
2026-02-16 19:05:13 +00:00 -
feat(tui) Permissions update history item (#11550)
## Summary We should document in the tui when you switch permissions! ## Testing - [x] Added unit tests - [x] Tested locally
Dylan Hurd ·
2026-02-13 23:44:27 -08:00 -
feat(tui): render structured network approval prompts in approval overlay (#11674)
### Description #### Summary Adds the TUI UX layer for structured network approvals #### What changed - Updated approval overlay to display network-specific approval context (host/protocol). - Added/updated TUI wiring so approval prompts show correct network messaging. - Added tests covering the new approval overlay behavior. #### Why Core orchestration can now request structured network approvals; this ensures users see clear, contextual prompts in the TUI. #### Notes - UX behavior activates only when network approval context is present. --------- Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
viyatb-oai ·
2026-02-13 22:38:36 -08:00 -
feat(core): add structured network approval plumbing and policy decision model (#11672)
### Description #### Summary Introduces the core plumbing required for structured network approvals #### What changed - Added structured network policy decision modeling in core. - Added approval payload/context types needed for network approval semantics. - Wired shell/unified-exec runtime plumbing to consume structured decisions. - Updated related core error/event surfaces for structured handling. - Updated protocol plumbing used by core approval flow. - Included small CLI debug sandbox compatibility updates needed by this layer. #### Why establishes the minimal backend foundation for network approvals without yet changing high-level orchestration or TUI behavior. #### Notes - Behavior remains constrained by existing requirements/config gating. - Follow-up PRs in the stack handle orchestration, UX, and app-server integration. --------- Co-authored-by: Codex <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
viyatb-oai ·
2026-02-14 04:18:12 +00:00 -
feat(skills): add permission profiles from openai.yaml metadata (#11658)
## Summary This PR adds support for skill-level permissions in .codex/openai.yaml and wires that through the skill loading pipeline. ## What’s included 1. Added a new permissions section for skills (network, filesystem, and macOS-related access). 2. Implemented permission parsing/normalization and translation into runtime permission profiles. 3. Threaded the new permission profile through SkillMetadata and loader flow. ## Follow-up A follow-up PR will connect these permission profiles to actual sandbox enforcement and add user approval prompts for executing binaries/scripts from skill directories. ## Example `openai.yaml` snippet: ``` permissions: network: true fs_read: - "./data" - "./data" fs_write: - "./output" macos_preferences: "readwrite" macos_automation: - "com.apple.Notes" macos_accessibility: true macos_calendar: true ``` compiled skill permission profile metadata (macOS): ``` SkillPermissionProfile { sandbox_policy: SandboxPolicy::WorkspaceWrite { writable_roots: vec![ AbsolutePathBuf::try_from("/ABS/PATH/TO/SKILL/output").unwrap(), ], read_only_access: ReadOnlyAccess::Restricted { include_platform_defaults: true, readable_roots: vec![ AbsolutePathBuf::try_from("/ABS/PATH/TO/SKILL/data").unwrap(), ], }, network_access: true, exclude_tmpdir_env_var: false, exclude_slash_tmp: false, }, // Truncated for readability; actual generated profile is longer. macos_seatbelt_permission_file: r#" (allow user-preference-write) (allow appleevent-send (appleevent-destination "com.apple.Notes")) (allow mach-lookup (global-name "com.apple.axserver")) (allow mach-lookup (global-name "com.apple.CalendarAgent")) ... "#.to_string(), ```Celia Chen ·
2026-02-14 01:43:44 +00:00 -
tui: preserve remote image attachments across resume/backtrack (#10590)
## Summary This PR makes app-server-provided image URLs first-class attachments in TUI, so they survive resume/backtrack/history recall and are resubmitted correctly. <img width="715" height="491" alt="Screenshot 2026-02-12 at 8 27 08 PM" src="https://github.com/user-attachments/assets/226cbd35-8f0c-4e51-a13e-459ef5dd1927" /> Can delete the attached image upon backtracking: <img width="716" height="301" alt="Screenshot 2026-02-12 at 8 27 31 PM" src="https://github.com/user-attachments/assets/4558d230-f1bd-4eed-a093-8e1ab9c6db27" /> In both history and composer, remote images are rendered as normal `[Image #N]` placeholders, with numbering unified with local images. ## What changed - Plumb remote image URLs through TUI message state: - `UserHistoryCell` - `BacktrackSelection` - `ChatComposerHistory::HistoryEntry` - `ChatWidget::UserMessage` - Show remote images as placeholder rows inside the composer box (above textarea), and in history cells. - Support keyboard selection/deletion for remote image rows in composer (`Up`/`Down`, `Delete`/`Backspace`). - Preserve remote-image-only turns in local composer history (Up/Down recall), including restore after backtrack. - Ensure submit/queue/backtrack resubmit include remote images in model input (`UserInput::Image`), and keep request shape stable for remote-image-only turns. - Keep image numbering contiguous across remote + local images: - remote images occupy `[Image #1]..[Image #M]` - local images start at `[Image #M+1]` - deletion renumbers consistently. - In protocol conversion, increment shared image index for remote images too, so mixed remote/local image tags stay in a single sequence. - Simplify restore logic to trust in-memory attachment order (no placeholder-number parsing path). - Backtrack/replay rollback handling now queues trims through `AppEvent::ApplyThreadRollback` and syncs transcript overlay/deferred lines after trims, so overlay/transcript state stays consistent. - Trim trailing blank rendered lines from user history rendering to avoid oversized blank padding. ## Docs + tests - Updated: `docs/tui-chat-composer.md` (remote image flow, selection/deletion, numbering offsets) - Added/updated tests across `tui/src/chatwidget/tests.rs`, `tui/src/app.rs`, `tui/src/app_backtrack.rs`, `tui/src/history_cell.rs`, and `tui/src/bottom_pane/chat_composer.rs` - Added snapshot coverage for remote image composer states, including deleting the first of two remote images. ## Validation - `just fmt` - `cargo test -p codex-tui` ## Codex author `codex fork 019c2636-1571-74a1-8471-15a3b1c3f49d`
Charley Cunningham ·
2026-02-13 14:54:06 -08:00 -
[apps] Improve app listing filtering. (#11697)
- [x] If an installed app is not on the app listing, remove it from the final list.
Matthew Zeng ·
2026-02-13 11:54:16 -08:00 -
Report syntax errors in rules file (#11686)
Currently, if there are syntax errors detected in the starlark rules file, the entire policy is silently ignored by the CLI. The app server correctly emits a message that can be displayed in a GUI. This PR changes the CLI (both the TUI and non-interactive exec) to fail when the rules file can't be parsed. It then prints out an error message and exits with a non-zero exit code. This is consistent with the handling of errors in the config file. This addresses #11603
Eric Traut ·
2026-02-13 10:33:40 -08:00 -
feat(tui): prevent macOS idle sleep while turns run (#11711)
## Summary - add a shared `codex-core` sleep inhibitor that uses native macOS IOKit assertions (`IOPMAssertionCreateWithName` / `IOPMAssertionRelease`) instead of spawning `caffeinate` - wire sleep inhibition to turn lifecycle in `tui` (`TurnStarted` enables; `TurnComplete` and abort/error finalization disable) - gate this behavior behind a `/experimental` feature toggle (`[features].prevent_idle_sleep`) instead of a dedicated `[tui]` config flag - expose the toggle in `/experimental` on macOS; keep it under development on other platforms - keep behavior no-op on non-macOS targets <img width="1326" height="577" alt="image" src="https://github.com/user-attachments/assets/73fac06b-97ae-46a2-800a-30f9516cf8a3" /> ## Testing - `cargo check -p codex-core -p codex-tui` - `cargo test -p codex-core sleep_inhibitor::tests -- --nocapture` - `cargo test -p codex-core tui_config_missing_notifications_field_defaults_to_enabled -- --nocapture` - `cargo test -p codex-core prevent_idle_sleep_is_ -- --nocapture` ## Semantics and API references - This PR targets `caffeinate -i` semantics: prevent *idle system sleep* while allowing display idle sleep. - `caffeinate -i` mapping in Apple open source (`assertionMap`): - `kIdleAssertionFlag -> kIOPMAssertionTypePreventUserIdleSystemSleep` - Source: https://github.com/apple-oss-distributions/PowerManagement/blob/PowerManagement-1846.60.12/caffeinate/caffeinate.c#L52-L54 - Apple IOKit docs for assertion types and API: - https://developer.apple.com/documentation/iokit/iopmlib_h/iopmassertiontypes - https://developer.apple.com/documentation/iokit/1557092-iopmassertioncreatewithname - https://developer.apple.com/library/archive/qa/qa1340/_index.html ## Codex Electron vs this PR (full stack path) - Codex Electron app requests sleep blocking with `powerSaveBlocker.start("prevent-app-suspension")`: - https://github.com/openai/codex/blob/main/codex/codex-vscode/electron/src/electron-message-handler.ts - Electron maps that string to Chromium wake lock type `kPreventAppSuspension`: - https://github.com/electron/electron/blob/main/shell/browser/api/electron_api_power_save_blocker.cc - Chromium macOS backend maps wake lock types to IOKit assertion constants and calls IOKit: - `kPreventAppSuspension -> kIOPMAssertionTypeNoIdleSleep` - `kPreventDisplaySleep / kPreventDisplaySleepAllowDimming -> kIOPMAssertionTypeNoDisplaySleep` - https://github.com/chromium/chromium/blob/main/services/device/wake_lock/power_save_blocker/power_save_blocker_mac.cc ## Why this PR uses a different macOS constant name - This PR uses `"PreventUserIdleSystemSleep"` directly, via `IOPMAssertionCreateWithName`, in `codex-rs/core/src/sleep_inhibitor.rs`. - Apple’s IOKit header documents `kIOPMAssertionTypeNoIdleSleep` as deprecated and recommends `kIOPMAssertPreventUserIdleSystemSleep` / `kIOPMAssertionTypePreventUserIdleSystemSleep`: - https://github.com/apple-oss-distributions/IOKitUser/blob/IOKitUser-100222.60.2/pwr_mgt.subproj/IOPMLib.h#L1000-L1030 - So Chromium and this PR are using different constant names, but semantically equivalent idle-system-sleep prevention behavior. ## Future platform support The architecture is intentionally set up for multi-platform extensions: - UI code (`tui`) only calls `SleepInhibitor::set_turn_running(...)` on turn lifecycle boundaries. - Platform-specific behavior is isolated in `codex-rs/core/src/sleep_inhibitor.rs` behind `cfg(...)` blocks. - Feature exposure is centralized in `core/src/features.rs` and surfaced via `/experimental`. - Adding new OS backends should not require additional TUI wiring; only the backend internals and feature stage metadata need to change. Potential follow-up implementations: - Windows: - Add a backend using Win32 power APIs (`SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)` as baseline). - Optionally move to `PowerCreateRequest` / `PowerSetRequest` / `PowerClearRequest` for richer assertion semantics. - Linux: - Add a backend using logind inhibitors over D-Bus (`org.freedesktop.login1.Manager.Inhibit` with `what="sleep"`). - Keep a no-op fallback where logind/D-Bus is unavailable. This PR keeps the cross-platform API surface minimal so future PRs can add Windows/Linux support incrementally with low churn. --------- Co-authored-by: jif-oai <jif@openai.com>
Yaroslav Volovich ·
2026-02-13 10:31:39 -08:00 -
feat: switch on dying sub-agents (#11477)
[codex-generated] ## Updated PR Description (Ready To Paste) ## Problem When a sub-agent thread emits `ShutdownComplete`, the TUI switches back to the primary thread. That was also happening for user-requested exits (for example `Ctrl+C`), which could prevent a clean app exit and unexpectedly resurrect the main thread. ## Mental model The app has one primary thread and one active thread. A non-primary active thread shutting down usually means "agent died, fail back to primary," but during `ExitMode::ShutdownFirst` shutdown means "the user is exiting," not "recover this session." ## Non-goals No change to thread lifecycle, thread-manager ownership, or shutdown protocol wire format. No behavioral changes to non-shutdown events. ## Tradeoffs This adds a small local marker (`pending_shutdown_exit_thread_id`) instead of inferring intent from event timing. It is deterministic and simple, but relies on correctly setting and clearing that marker around exit. ## Architecture `App` tracks which thread is intentionally being shut down for exit. `active_non_primary_shutdown_target` centralizes failover eligibility for `ShutdownComplete` and skips failover when shutdown matches the pending-exit thread. `handle_active_thread_event` handles non-primary failover before generic forwarding and clears the pending-exit marker only when the matching active thread completes shutdown. ## Observability User-facing info/error messages continue to indicate whether failover to the main thread succeeded. The shutdown-intent path is now explicitly documented inline for easier debugging. ## Tests Added targeted tests for `active_non_primary_shutdown_target` covering non-shutdown events, primary-thread shutdown, non-primary shutdown failover, pending exit on active thread (no failover), and pending exit for another thread (still failover). Validated with: - `cargo test -p codex-tui` (pass) --------- Co-authored-by: Josh McKinney <joshka@openai.com>
jif-oai ·
2026-02-13 18:29:03 +00:00 -
sandbox NUX metrics update (#11667)
just updating metrics to match the NUX tweaks we made this week.
iceweasel-oai ·
2026-02-13 10:01:47 -08:00 -
Point Codex App tooltip links to app landing page (#11515)
### Motivation - Ensure the in-TUI Codex App call-to-action opens the app landing page variant `https://chatgpt.com/codex?app-landing-page=true` so users reach the intended landing experience. ### Description - Update tooltip constants in `codex-rs/tui/src/tooltips.rs` to replace `https://chatgpt.com/codex` with `https://chatgpt.com/codex?app-landing-page=true` for the PAID and OTHER tooltip variants. ### Testing - Ran `just fmt` in `codex-rs` and `cargo test -p codex-tui`, and the test suite completed successfully. ------ [Codex Task](https://chatgpt.com/codex/tasks/task_i_698d20cf6f088329bb82b07d3ce76e61)
Josh McKinney ·
2026-02-12 23:35:57 -08:00 -
fix: dont show NUX for upgrade-target models that are hidden (#11679)
dont show NUX for models marked with `visibility:hide`. Tested locally
sayan-oai ·
2026-02-12 20:29:22 -08:00 -
Persist complete TurnContextItem state via canonical conversion (#11656)
## Summary This PR delivers the first small, shippable step toward model-visible state diffing by making `TurnContextItem` more complete and standardizing how it is built. Specifically, it: - Adds persisted network context to `TurnContextItem`. - Introduces a single canonical `TurnContext -> TurnContextItem` conversion path. - Routes existing rollout write sites through that canonical conversion helper. No context injection/diff behavior changes are included in this PR. ## Why this change The design goal is to make `TurnContextItem` the canonical source of truth for context-diff decisions. Before this PR: - `TurnContextItem` did not include all TurnContext-derived environment inputs needed for v1 completeness. - Construction was duplicated at multiple write sites. This PR addresses both with a minimal, reviewable change. ## Changes ### 1) Extend `TurnContextItem` with network state - Added `TurnContextNetworkItem { allowed_domains, denied_domains }`. - Added `network: Option<TurnContextNetworkItem>` to `TurnContextItem`. - Kept backward compatibility by making the new field optional and skipped when absent. Files: - `codex-rs/protocol/src/protocol.rs` ### 2) Canonical conversion helper - Added `TurnContext::to_turn_context_item(collaboration_mode)` in core. - Added internal helper to derive network fields from `config_layer_stack.requirements().network`. Files: - `codex-rs/core/src/codex.rs` ### 3) Use canonical conversion at rollout write sites - Replaced ad hoc `TurnContextItem { ... }` construction with `to_turn_context_item(...)` in: - sampling request path - compaction path Files: - `codex-rs/core/src/codex.rs` - `codex-rs/core/src/compact.rs` ### 4) Update fixtures/tests for new optional field - Updated existing `TurnContextItem` literals in tests to include `network: None`. - Added protocol tests for: - deserializing old payloads with no `network` - serializing when `network` is present Files: - `codex-rs/core/tests/suite/resume_warning.rs` - No replay/diff logic changes. - Persisted rollout `TurnContextItem` now carries additional network context when available. - Older rollout lines without `network` remain readable.Charley Cunningham ·
2026-02-12 17:22:44 -08:00 -
[apps] Add is_enabled to app info. (#11417)
- [x] Add is_enabled to app info and the response of `app/list`. - [x] Update TUI to have Enable/Disable button on the app detail page.
Matthew Zeng ·
2026-02-13 00:30:52 +00:00 -
feat: introduce Permissions (#11633)
## Why We currently carry multiple permission-related concepts directly on `Config` for shell/unified-exec behavior (`approval_policy`, `sandbox_policy`, `network`, `shell_environment_policy`, `windows_sandbox_mode`). Consolidating these into one in-memory struct makes permission handling easier to reason about and sets up the next step: supporting named permission profiles (`[permissions.PROFILE_NAME]`) without changing behavior now. This change is mostly mechanical: it updates existing callsites to go through `config.permissions`, but it does not yet refactor those callsites to take a single `Permissions` value in places where multiple permission fields are still threaded separately. This PR intentionally **does not** change the on-disk `config.toml` format yet and keeps compatibility with legacy config keys. ## What Changed - Introduced `Permissions` in `core/src/config/mod.rs`. - Added `Config::permissions` and moved effective runtime permission fields under it: - `approval_policy` - `sandbox_policy` - `network` - `shell_environment_policy` - `windows_sandbox_mode` - Updated config loading/building so these effective values are still derived from the same existing config inputs and constraints. - Updated Windows sandbox helpers/resolution to read/write via `permissions`. - Threaded the new field through all permission consumers across core runtime, app-server, CLI/exec, TUI, and sandbox summary code. - Updated affected tests to reference `config.permissions.*`. - Renamed the struct/field from `EffectivePermissions`/`effective_permissions` to `Permissions`/`permissions` and aligned variable naming accordingly. ## Verification - `just fix -p codex-core -p codex-tui -p codex-cli -p codex-app-server -p codex-exec -p codex-utils-sandbox-summary` - `cargo build -p codex-core -p codex-tui -p codex-cli -p codex-app-server -p codex-exec -p codex-utils-sandbox-summary`
Michael Bolin ·
2026-02-12 14:42:54 -08:00 -
add a slash command to grant sandbox read access to inaccessible directories (#11512)
There is an edge case where a directory is not readable by the sandbox. In practice, we've seen very little of it, but it can happen so this slash command unlocks users when it does. Future idea is to make this a tool that the agent knows about so it can be more integrated.
iceweasel-oai ·
2026-02-12 12:48:36 -08:00 -
feat(app-server): experimental flag to persist extended history (#11227)
This PR adds an experimental `persist_extended_history` bool flag to app-server thread APIs so rollout logs can retain a richer set of EventMsgs for non-lossy Thread > Turn > ThreadItems reconstruction (i.e. on `thread/resume`). ### Motivation Today, our rollout recorder only persists a small subset (e.g. user message, reasoning, assistant message) of `EventMsg` types, dropping a good number (like command exec, file change, etc.) that are important for reconstructing full item history for `thread/resume`, `thread/read`, and `thread/fork`. Some clients want to be able to resume a thread without lossiness. This lossiness is primarily a UI thing, since what the model sees are `ResponseItem` and not `EventMsg`. ### Approach This change introduces an opt-in `persist_full_history` flag to preserve those events when you start/resume/fork a thread (defaults to `false`). This is done by adding an `EventPersistenceMode` to the rollout recorder: - `Limited` (existing behavior, default) - `Extended` (new opt-in behavior) In `Extended` mode, persist additional `EventMsg` variants needed for non-lossy app-server `ThreadItem` reconstruction. We now store the following ThreadItems that we didn't before: - web search - command execution - patch/file changes - MCP tool calls - image view calls - collab tool outcomes - context compaction - review mode enter/exit For **command executions** in particular, we truncate the output using the existing `truncate_text` from core to store an upper bound of 10,000 bytes, which is also the default value for truncating tool outputs shown to the model. This keeps the size of the rollout file and command execution items returned over the wire reasonable. And we also persist `EventMsg::Error` which we can now map back to the Turn's status and populates the Turn's error metadata. #### Updates to EventMsgs To truly make `thread/resume` non-lossy, we also needed to persist the `status` on `EventMsg::CommandExecutionEndEvent` and `EventMsg::PatchApplyEndEvent`. Previously it was not obvious whether a command failed or was declined (similar for apply_patch). These EventMsgs were never persisted before so I made it a required field.
Owen Lin ·
2026-02-12 19:34:22 +00:00