mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
4c2e730488997145ad9bfa07f193293aeb30c083
1602 Commits
-
Add remote_sandbox_config to our config requirements (#18763)
## Why Customers need finer-grained control over allowed sandbox modes based on the host Codex is running on. For example, they may want stricter sandbox limits on devboxes while keeping a different default elsewhere. Our current cloud requirements can target user/account groups, but they cannot vary sandbox requirements by host. That makes remote development environments awkward because the same top-level `allowed_sandbox_modes` has to apply everywhere. ## What Adds a new `remote_sandbox_config` section to `requirements.toml`: ```toml allowed_sandbox_modes = ["read-only"] [[remote_sandbox_config]] hostname_patterns = ["*.org"] allowed_sandbox_modes = ["read-only", "workspace-write"] [[remote_sandbox_config]] hostname_patterns = ["*.sh", "runner-*.ci"] allowed_sandbox_modes = ["read-only", "danger-full-access"] ``` During requirements resolution, Codex resolves the local host name once, preferring the machine FQDN when available and falling back to the cleaned kernel hostname. This host classification is best effort rather than authenticated device proof. Each requirements source applies its first matching `remote_sandbox_config` entry before it is merged with other sources. The shared merge helper keeps that `apply_remote_sandbox_config` step paired with requirements merging so new requirements sources do not have to remember the extra call. That preserves source precedence: a lower-precedence requirements file with a matching `remote_sandbox_config` cannot override a higher-precedence source that already set `allowed_sandbox_modes`. This also wires the hostname-aware resolution through app-server, CLI/TUI config loading, config API reads, and config layer metadata so they all evaluate remote sandbox requirements consistently. ## Verification - `cargo test -p codex-config remote_sandbox_config` - `cargo test -p codex-config host_name` - `cargo test -p codex-core load_config_layers_applies_matching_remote_sandbox_config` - `cargo test -p codex-core system_remote_sandbox_config_keeps_cloud_sandbox_modes` - `cargo test -p codex-config` - `cargo test -p codex-core` unit tests passed; `tests/all.rs` integration matrix was intentionally stopped after the relevant focused tests passed - `just fix -p codex-config` - `just fix -p codex-core` - `cargo check -p codex-app-server`
Abhinav ·
2026-04-21 05:05:02 +00:00 -
feat(auto-review) Handle request_permissions calls (#18393)
## Summary When auto-review is enabled, it should handle request_permissions tool. We'll need to clean up the UX but I'm planning to do that in a separate pass ## Testing - [x] Ran locally <img width="893" height="396" alt="Screenshot 2026-04-17 at 1 16 13 PM" src="https://github.com/user-attachments/assets/4c045c5f-1138-4c6c-ac6e-2cb6be4514d8" /> --------- Co-authored-by: Codex <noreply@openai.com>
Dylan Hurd ·
2026-04-20 21:48:57 -07:00 -
Fallback display names for TUI skill mentions (#18786)
This updates TUI skill mentions to show a fallback label when a skill does not define a display name, so unnamed skills remain understandable in the picker without changing behavior for skills that already have one. <img width="1028" height="198" alt="Screenshot 2026-04-20 at 6 25 15 PM" src="https://github.com/user-attachments/assets/84077b85-99d0-4db9-b533-37e1887b4506" />
canvrno-oai ·
2026-04-20 20:46:55 -07:00 -
protocol: preserve glob scan depth in permission profiles (#18713)
## Why #18274 made `PermissionProfile` the canonical file-system permissions shape, but the round-trip from `FileSystemSandboxPolicy` to `PermissionProfile` still dropped one piece of policy metadata: `glob_scan_max_depth`. That field is security-relevant for deny-read globs such as `**/*.env`. On Linux, bubblewrap sandbox construction uses it to bound unreadable glob expansion. If a profile copied from active runtime permissions loses this value and is submitted back as an override, the resulting `FileSystemSandboxPolicy` can behave differently even though the visible permission entries look equivalent. ## What changed - Add `glob_scan_max_depth` to protocol `FileSystemPermissions` and preserve it when converting to/from `FileSystemSandboxPolicy`. - Keep legacy `read`/`write` JSON for simple path-only permissions, but force canonical JSON when glob scan depth is present so the metadata is not silently dropped. - Carry `globScanMaxDepth` through app-server `AdditionalFileSystemPermissions`, generated JSON/TypeScript schemas, and app-server/TUI conversion call sites. - Preserve the metadata through sandboxing permission normalization, merging, and intersection. - Carry the merged scan depth into the effective `FileSystemSandboxPolicy` used for command execution, so bounded deny-read globs reach Linux bubblewrap materialization. ## Verification - `cargo test -p codex-sandboxing glob_scan -- --nocapture` - `cargo test -p codex-sandboxing policy_transforms -- --nocapture` - `just fix -p codex-sandboxing` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/18713). * #18288 * #18287 * #18286 * #18285 * #18284 * #18283 * #18282 * #18281 * #18280 * #18279 * #18278 * #18277 * #18276 * #18275 * __->__ #18713
Michael Bolin ·
2026-04-20 19:42:45 -07:00 -
/statusline & /title - Shared preview values (#18435)
This PR makes the `/statusline` and `/title` setup UIs share one preview-value source instead of each surface using its own examples. Both pickers now render consistent live values when available, and stable placeholders when they are not. It also resolves live preview values at the shared preview-item layer, so `/title` preview can use real runtime values for title-specific cases like status text, task progress, and project-name fallback behavior. - Adds a shared preview data model for status surfaces - Maps status-line items and terminal-title items onto that shared preview list - Feeds both setup views from the same chatwidget-derived preview data, with terminal-title-specific formatting applied before `/title` preview renders - Keeps project-root preview aligned with status-line behavior while project in /title keeps its title fallback/truncation behavior - Adds snapshot coverage for live-only, hardcoded-only, and mixed cases Test Steps - Open Codex TUI and launch `/statusline`. - Toggle and reorder items, then verify the preview uses current session values when possible, and placeholder values for missing values (ex: no thread ID). - Open `/title` and verify it shows the same normalized values, including live status/task-progress values when available.
canvrno-oai ·
2026-04-20 17:46:11 -07:00 -
Warn when trusting Git subdirectories (#18602)
Addresses #18505 ## Summary When Codex is launched from a subdirectory of a Git repository, the onboarding trust prompt says it is trusting the current directory even though the persisted trust target is the repository root. That can make the scope of the trust decision unclear. This updates the TUI trust prompt to show a yellow note only when the current directory differs from the resolved trust target, explaining that trust applies to the repository root and displaying that root. It also removes the stale onboarding TODO now that the warning is implemented.
Eric Traut ·
2026-04-20 16:43:21 -07:00 -
Fix exec inheritance of root shared flags (#18630)
Addresses #18113 Problem: Shared flags provided before the exec subcommand were parsed by the root CLI but not inherited by the exec CLI, so exec sessions could run with stale or default sandbox and model configuration. Solution: Move shared TUI and exec flags into a common option block and merge root selections into exec before dispatch, while preserving exec's global subcommand flag behavior.
Eric Traut ·
2026-04-20 16:12:17 -07:00 -
Refactor TUI app module into submodules (#18753)
## Why The TUI app module had grown past the 512K source-file cap enforced by CI/CD. This keeps the app entry point below that limit while preserving the existing runtime behavior and test surface. ## What changed - Kept the top-level `App` state and run-loop wiring in `tui/src/app.rs`. - Split app responsibilities into focused private submodules under `tui/src/app/`, covering event dispatch, thread routing, session lifecycle, config persistence, background requests, startup prompts, input, history UI, platform actions, and thread event buffering. - Moved the existing app-level tests into `tui/src/app/tests.rs` and reused the existing snapshot location rather than adding new tests or snapshots. - Added module header comments for `app.rs` and the new submodules. ## Follow-up A future cleanup can move narrow unit tests from `tui/src/app/tests.rs` into the specific app submodules they exercise. This PR keeps the existing app-level tests together so the refactor stays focused on the source-file split. ## Verification - `cargo test -p codex-tui --lib app::tests::agent_picker_item_name_snapshot` - `cargo test -p codex-tui --lib app::tests::clear_ui` - `cargo test -p codex-tui --lib app::tests::ctrl_l_clear_ui_after_long_transcript_reuses_clear_header_snapshot` - `just fix -p codex-tui` Full `cargo test -p codex-tui` still fails on model-catalog drift unrelated to this refactor, including stale `gpt-5.3-codex`/`gpt-5.1-codex` snapshot and migration expectations now resolving to `gpt-5.4`.
Eric Traut ·
2026-04-20 16:10:35 -07:00 -
Add realtime silence tool (#18635)
## Summary Adds a second realtime v2 function tool, `remain_silent`, so the realtime model has an explicit non-speaking action when the collaboration mode or latest context says it should not answer aloud. This is stacked on #18597. ## Design - Advertise `remain_silent` alongside `background_agent` in realtime v2 conversational sessions. - Parse `remain_silent` function calls into a typed `RealtimeEvent::NoopRequested` event. - Have core answer that function call with an empty `function_call_output` and deliberately avoid `response.create`, so no follow-up realtime response is requested. - Keep the event hidden from app-server/TUI surfaces; it is operational plumbing, not user-visible conversation content.
guinness-oai ·
2026-04-20 15:43:20 -07:00 -
Use app server metadata for fork parent titles (#18632)
## Problem The TUI resolved fork parent titles from local CODEX_HOME metadata, which could show missing or stale titles when app-server metadata is authoritative. This is a lingering bug left over from the migration of the TUI to the app-server interface. I found it when I asked Codex to review all places where the TUI code was still directly accessing the local CODEX_HOME. ## Solution Route fork parent title metadata through the app-server session state and render only that supplied title, with focused snapshot coverage for stale local metadata. ## Testing I manually tested by renaming a thread then forking it and confirming that the "forked from" message indicated the parent thread's name.
Eric Traut ·
2026-04-20 15:37:31 -07:00 -
fix(tui): keep /copy aligned with rollback (#18739)
## Why Fixes #18718. After rewinding a thread, `/copy` could still copy the latest assistant response from before the rewind. The transcript cells were rolled back, but the copy source was a single `last_agent_markdown` cache that was not synchronized with backtracking, so the visible conversation and copied content could diverge. ## What changed `ChatWidget` now keeps a bounded copy history for the most recent 32 assistant responses, keyed by the visible user-turn count. When local rollback trims transcript cells, the copy cache is trimmed to the same surviving user-turn count so `/copy` uses the latest visible assistant response. If the user rewinds past the retained copy window, `/copy` now reports: ```text Cannot copy that response after rewinding. Only the most recent 32 responses are available to /copy. ``` The change also adds coverage for copying the latest surviving response after rollback and for the over-limit rewind message. ## Verification - Manually resumed a synthetic 35-turn session, rewound within the retained window, and verified `/copy` copied the surviving response. - Manually rewound past the retained window and verified `/copy` showed the 32-response limit message. - `cargo test -p codex-tui slash_copy` - `just fix -p codex-tui` - `cargo insta pending-snapshots` Note: `cargo test -p codex-tui` currently fails on unrelated model catalog and snapshot drift around the default model changing to `gpt-5.4`; the focused `/copy` tests pass after fixing the new test setup.
Felipe Coury ·
2026-04-20 19:24:10 -03:00 -
Fix stale model test fixtures (#18719)
Fixes stale test fixtures left after the active bundled model catalog updates in #18586 and #18388. Those changes made `gpt-5.4` the current default and removed several older hardcoded slugs, which left Windows Bazel shards failing TUI and config tests. What changed: - Refresh TUI model migration, availability NUX, plan-mode, status, and snapshot fixtures to use active bundled model slugs. - Update the config edit test expectation for the TOML-quoted `"gpt-5.2"` migration key. - Move the model catalog tests into `codex-rs/tui/src/app/tests/model_catalog.rs` so touching them does not trip the blob-size policy for `app.rs`. Verification: - CI Bazel/lint checks are expected to cover the affected test shards.
Ahmed Ibrahim ·
2026-04-20 21:52:30 +00:00 -
Surface TUI skills refresh failures (#18627)
## Why `skills/list` refreshes are best-effort metadata updates. If one fails during startup or thread switching, the TUI should keep running and show enough detail to diagnose the app-server failure instead of leaving the user with only a log entry. This addresses the recoverability and observability issue reported in #16914. ## What Changed - Preserve the full startup `skills/list` error chain before sending it back through the app event queue. - Surface failed skills refreshes as recoverable TUI error messages while still logging the warning. This is related to the recent bug fix from [PR #18370](https://github.com/openai/codex/pull/18370).
Eric Traut ·
2026-04-20 14:43:04 -07:00 -
Remove simple TUI legacy_core reexports (#18631)
## Problem The TUI still imported path utilities and config-loader symbols through app-server-client's legacy_core facade even though those APIs already exist in utility/config crates. This is part of our ongoing effort to whittle away at these old dependencies. ## Solution Rewire imports to avoid the TUI directly importing from the core crate and instead import from common lower-level crates. This PR doesn't include any functional changes; it's just a simple rewiring.
Eric Traut ·
2026-04-20 10:48:27 -07:00 -
Wire the PatchUpdated events through app_server (#18289)
Wires patch_updated events through app_server. These events are parsed and streamed while apply_patch is being written by the model. Also adds 500ms of buffering to the patch_updated events in the diff_consumer. The eventual goal is to use this to display better progress indicators in the codex app.
Akshay Nathan ·
2026-04-20 10:44:03 -07:00 -
Update models.json (#18586)
- Replace the active models-manager catalog with the deleted core catalog contents. - Replace stale hardcoded test model slugs with current bundled model slugs. - Keep this as a stacked change on top of the cleanup PR.
Ahmed Ibrahim ·
2026-04-20 10:27:01 -07:00 -
protocol: canonicalize file system permissions (#18274)
## Why `PermissionProfile` needs stable, canonical file-system semantics before it can become the primary runtime permissions abstraction. Without a canonical form, callers have to keep re-deriving legacy sandbox maps and profile comparisons remain lossy or order-dependent. ## What changed This adds canonicalization helpers for `FileSystemPermissions` and `PermissionProfile`, expands special paths into explicit sandbox entries, and updates permission request/conversion paths to consume those canonical entries. It also tightens the legacy bridge so root-wide write profiles with narrower carveouts are not silently projected as full-disk legacy access. ## Verification - `cargo test -p codex-protocol root_write_with_read_only_child_is_not_full_disk_write -- --nocapture` - `cargo test -p codex-sandboxing permission -- --nocapture` - `cargo test -p codex-tui permissions -- --nocapture`
Michael Bolin ·
2026-04-20 09:57:03 -07:00 -
Surface parent thread status in side conversations (#18591)
## Summary Side conversations can hide important state changes from the parent conversation while the user is focused on the side thread. In particular, the parent may finish, fail, need user input, or require an approval while the side conversation remains visible. Users need a lightweight signal for those states, but parent approval overlays should not interrupt the side conversation itself. This change adds parent-conversation status to the side conversation context label and defers parent interactive overlays while side mode is active. When the user exits side mode, pending parent approvals and input requests are restored in the main thread. The pending approval footer avoids duplicating the same parent approval status, and replayed notice cells are filtered when restoring a pending interactive request so tips or warnings do not crowd out the approval prompt. The change is contained to the TUI side-conversation and thread replay paths. Example 1: Approval pending <img width="752" height="35" alt="Screenshot 2026-04-19 at 12 56 07 PM" src="https://github.com/user-attachments/assets/1cc0f1a3-9cab-4d60-aed2-96523ccafc20" /> Example 2: Turn complete <img width="754" height="35" alt="Screenshot 2026-04-19 at 12 56 27 PM" src="https://github.com/user-attachments/assets/653521a5-e298-4366-ae1c-72b56eb88eeb" />
Eric Traut ·
2026-04-20 09:00:44 -07:00 -
Use app server thread names in TUI picker (#18633)
## Problem The TUI resume/fork picker was backfilling thread names from local rollout indexes. This was left over from before the TUI was moved to the app server. It should be using app-server APIs because the TUI might be connected to a remote connection. This bug wasn't (yet) reported by a user. I found it by asking Codex to review places in the TUI code where it was still directly accessing the CODEX_HOME directory rather than going through app-server APIs. ## Solution The resume picker and session lookups should use app-server thread APIs only. Remove legacy rollout name/list backfills, and avoid local name reads in fork history. ## Testing I manually tested `codex resume` and `codex resume --all` to look for functional or performance regressions in the resume picker.
Eric Traut ·
2026-04-20 08:16:24 -07:00 -
Add verbose diagnostics for /mcp (#18610)
Fixes #18539. ## Summary The recent `/mcp` performance work kept the default command fast by avoiding resource and resource-template inventory probes, but it also removed useful diagnostics for users trying to confirm MCP server state. This keeps bare `/mcp` on the fast tools/auth path and adds `/mcp verbose` for the slower diagnostic view. Verbose mode requests full MCP server status from the app-server and restores status, resources, and resource templates in the TUI output. ## Testing In addition to running automation, I manually tested the feature to confirm that it works.
Eric Traut ·
2026-04-20 08:13:44 -07:00 -
chore: drop review prompt from TUI UX (#18659)
Due to the app-server rebase of the TUI, the review prompt was leaked into the transcript on the TUI This is not a security issue but it was bad UX. This PR fixes this
jif-oai ·
2026-04-20 14:31:37 +01:00 -
[codex] Add workspace owner usage nudge UI (#18221)
## Summary Third PR in the split from #17956. Stacked on #18220. - shows workspace-owner/member-specific rate-limit messages behind `workspace_owner_usage_nudge` - prompts workspace members to notify the owner or request a usage-limit increase - sends the confirmed nudge through the app-server API and renders completion feedback - adds focused TUI snapshot coverage for prompts and completion states - feature gate ## Validation - `cargo test -p codex-backend-client` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-app-server rate_limits` - `cargo test -p codex-tui workspace_` - `cargo test -p codex-tui status_` - `just fmt` - `just fix -p codex-backend-client` - `just fix -p codex-app-server-protocol` - `just fix -p codex-app-server` - `just fix -p codex-tui`
richardopenai ·
2026-04-20 05:51:47 +00:00 -
TUI: remove simple legacy_core re-exports (#18605)
## Summary The TUI still imported several symbols through the transitional app-server-client `legacy_core` facade even though those symbols are already owned by smaller crates. This PR narrows that facade by rewiring those imports directly to their owner crates. ## Changes No functional changes, just import rewiring. This is part of our ongoing effort to whittle away at the `legacy_core` namespace, which represents all of the remaining symbols that the TUI imports from the core.
Eric Traut ·
2026-04-19 22:39:53 -07:00 -
Use thread IDs in TUI resume hints (#18440)
## Summary Fixes #18313. Recent TUI resume breadcrumbs could print a thread title instead of the stable thread UUID. For sessions whose title was auto-derived from the first prompt, that made the suggested codex resume command look like it should resume a long prompt rather than the session ID. This updates the TUI and CLI post-exit resume hints, plus the in-session summary shown when switching/forking threads, to always use the stable thread ID for these recovery breadcrumbs. Explicit name-based resume support remains available elsewhere.
Eric Traut ·
2026-04-19 22:38:48 -07:00 -
Soften Fast mode plan usage copy (#18601)
Fast mode TUI copy currently names a specific plan-usage multiplier in two lightweight promo/help surfaces. This swaps that exact multiplier language for the broader increased plan usage wording we use elsewhere. There are no behavior changes here; the slash command and startup tip still point users at the same Fast mode flow.
pash-openai ·
2026-04-20 00:37:40 +00:00 -
Avoid redundant memory enable notice (#18580)
## Summary Fixes #18554. The `/experimental` menu can submit the full experimental feature state even when the user presses Enter without toggling anything. Previously, Codex showed `Memories will be enabled in the next session.` whenever the submitted updates included `Feature::MemoryTool = true`, so sessions where Memories were already enabled could show a redundant warning on a no-op save. This change records whether `Feature::MemoryTool` was enabled before applying feature updates and only emits the next-session notice when Memories actually transitions from disabled to enabled.
Eric Traut ·
2026-04-19 13:48:15 -07:00 -
Add
/sideconversations (#18190)The TUI supports long-running turns and agent threads, but quick side questions have required interrupting the main flow or manually forking/navigating threads. This PR adds a guarded `/side` flow so users can ask brief side-conversation questions in an ephemeral fork while keeping the primary thread focused. This also helps address the feature request in #18125. The implementation creates one side conversation at a time, lets `/side` open either an empty side thread or immediately submit `/side <question>`, and returns to the parent with Esc or Ctrl+C. Side conversations get hidden developer guardrails that treat inherited history as reference-only and steer the model away from workspace mutations unless explicitly requested in the side conversation. The TUI hides most slash commands while side mode is active, leaving only `/copy`, `/diff`, `/mention`, and `/status` available there.
Eric Traut ·
2026-04-19 11:59:41 -07:00 -
Queue slash and shell prompts in the TUI (#18542)
## Why Users have asked to queue follow-up slash commands while a task is running, including in #14081, #14588, #14286, and #13779. The previous TUI behavior validated slash commands immediately, so commands that are only meaningful once the current turn is idle could not be queued consistently. The queue should preserve what the user typed and defer command parsing until the item is actually dispatched. This also gives `/fast`, `/review ...`, `/rename ...`, `/model`, `/permissions`, and similar slash workflows the same FIFO behavior as plain queued prompts. ## What Changed - Added a queued-input action enum so queued items can be dispatched as plain prompts, slash commands, or user shell commands. - Changed `Tab` queueing to accept slash-led prompts without validating them up front, then parse and dispatch them when dequeued. - Added `!` shell-command queueing for `Tab` while a task is running, while preserving existing `Enter` behavior for immediate shell execution. - Moved queued slash dispatch through shared slash-command parsing so inline commands, unavailable commands, unknown commands, and local config commands report at dequeue time. - Continued queue draining after local-only actions and after slash menu cancellation or selection when no task is running. - Preserved slash-popup completion behavior so `/mo<Tab>` completes to `/model ` instead of queueing the prefix. - Updated pending-input preview snapshots to show queued follow-up inputs. ## Verification I did a bunch of manual validation (and found and fixed a few bugs along the way).
Eric Traut ·
2026-04-19 10:52:16 -07:00 -
feat(tui): show context used in plan implementation prompt (#18573)
# Summary When a user finishes planning, the TUI asks whether to implement in the current conversation or start fresh with the approved plan. The clear-context choice is easier to evaluate when the prompt shows how much context has already been used, because the user can see when carrying the full prior conversation is likely to be less useful than preserving only the plan. <img width="1612" height="1312" alt="image" src="https://github.com/user-attachments/assets/694bcf87-8be5-4e88-a412-e562af62d5f7" /> This PR adds that context signal directly to the clear-context option while keeping the copy compact enough for the Plan-mode selection popup. # What Changed - Compute an optional context-usage label when opening the plan implementation prompt. - Show the label only on `Yes, clear context and implement`, where it informs the cleanup decision. - Prefer a percentage-used label when context-window information is available, with a compact token-used fallback when only token totals are known. - Preserve the original option description when usage is unknown or effectively zero. - Add rustdoc comments around the prompt-copy boundary so future changes keep the context label formatting and selection rendering responsibilities clear. # Testing - `cargo test -p codex-tui plan_implementation` # Notes The footer continues to show context remaining as ambient status. The implementation prompt intentionally shows context used because the user is choosing whether to clean up the current thread before implementation.
Felipe Coury ·
2026-04-19 14:01:58 -03:00 -
feat: Budget skill metadata and surface trimming as a warning (#18298)
Cap the model-visible skills section to a small share of the context window, with a fallback character budget, and keep only as many implicit skills as fit within that budget. Emit a non-fatal warning when enabled skills are omitted, and add a new app-server warning notification Record thread-start skill metrics for total enabled skills, kept skills, and whether truncation happened --------- Co-authored-by: Matthew Zeng <mzeng@openai.com> Co-authored-by: Codex <noreply@openai.com>
xl-openai ·
2026-04-17 18:11:47 -07:00 -
[TUI] add external config migration prompt when start TUI (#17891)
- add a TUI startup migration prompt for external agent config - support migrating external configs including config, skills, AGENTS.md and plugins - gate the prompt behind features.external_migrate (default false) <img width="1037" height="480" alt="Screenshot 2026-04-14 at 9 29 14 PM" src="https://github.com/user-attachments/assets/6060849b-03cb-429a-9c13-c7bb46ad2e65" /> <img width="713" height="183" alt="Screenshot 2026-04-14 at 9 29 26 PM" src="https://github.com/user-attachments/assets/d13f177e-d4c4-479c-8736-ef29636081e1" /> --------- Co-authored-by: Eric Traut <etraut@openai.com>
alexsong-oai ·
2026-04-17 17:58:32 -07:00 -
fix: trust-gate project hooks and exec policies (#14718)
## Summary - trust-gate project `.codex` layers consistently, including repos that have `.codex/hooks.json` or `.codex/execpolicy/*.rules` but no `.codex/config.toml` - keep disabled project layers in the config stack so nested trusted project layers still resolve correctly, while preventing hooks and exec policies from loading until the project is trusted - update app-server/TUI onboarding copy to make the trust boundary explicit and add regressions for loader, hooks, exec-policy, and onboarding coverage ## Security Before this change, an untrusted repo could auto-load project hooks or exec policies from `.codex/` as long as `config.toml` was absent. This makes trust the single gate for project-local config, hooks, and exec policies. ## Stack - Parent of #15936 ## Test - cargo test -p codex-core without_config_toml --------- Co-authored-by: Codex <noreply@openai.com>
viyatb-oai ·
2026-04-17 17:56:58 -07:00 -
/plugins: Add inline enablement toggles (#18395)
This PR adds inline enable/disable controls to the new /plugins browse menu. Installed plugins can now be toggled directly from the list with keyboard interaction, and the associated config-write plumbing is included so the UI and persisted plugin state stay in sync. This also includes the queued-write handling needed to avoid stale toggle completions overwriting newer intent. - Add toggleable plugin rows for installed plugins in /plugins - Support Space to enable or disable without leaving the list - Persist plugin enablement through the existing app/config write path - Preserve the current selection while the list refreshes after a toggle - Add tests and snapshot updates for toggling behavior --------- Co-authored-by: Codex <noreply@openai.com>
canvrno-oai ·
2026-04-17 17:33:11 -07:00 -
feat: Add remote plugin fields to plugin API (#17277)
## Summary Update the plugin API for the new remote plugin model. The mental model is no longer “keep local plugin state in sync with remote.” Instead, local and remote plugins are becoming separate sources. Remote catalog entries can be shown directly from the remote API before installation; after installation they are still downloaded into the local cache for execution, but remote installed state will come from the API and be held in memory rather than being read from config. • ## API changes - Remove `forceRemoteSync` from `plugin/list`, `plugin/install`, and `plugin/uninstall`. - Remove `remoteSyncError` from `plugin/list`. - Add remote-capable metadata to `plugin/list` / `plugin/read`: - nullable `marketplaces[].path` - `source: { type: "remote", downloadUrl }` - URL asset fields alongside local path fields: `composerIconUrl`, `logoUrl`, `screenshotUrls` - Make `plugin/read` and `plugin/install` source-compatible: - `marketplacePath?: AbsolutePathBuf | null` - `remoteMarketplaceName?: string | null` - exactly one source is required at runtimexl-openai ·
2026-04-17 16:47:58 -07:00 -
bazel: use native rust test sharding (#18082)
## Why The large Rust test suites are slow and include some of our flakiest tests, so we want to run them with Bazel native sharding while keeping shard membership stable between runs. This is the simpler follow-up to the explicit-label experiment in #17998. Since #18397 upgraded Codex to `rules_rs` `0.0.58`, which includes the stable test-name hashing support from hermeticbuild/rules_rust#14, this PR only needs to wire Codex's Bazel macros into that support. Using native sharding preserves BuildBuddy's sharded-test UI and Bazel's per-shard test action caching. Using stable name hashing avoids reshuffling every test when one test is added or removed. ## What Changed `codex_rust_crate` now accepts `test_shard_counts` and applies the right Bazel/rules_rust attributes to generated unit and integration test rules. Matched tests are also marked `flaky = True`, giving them Bazel's default three attempts. This PR shards these labels 8 ways: ```text //codex-rs/core:core-all-test //codex-rs/core:core-unit-tests //codex-rs/app-server:app-server-all-test //codex-rs/app-server:app-server-unit-tests //codex-rs/tui:tui-unit-tests ``` ## Verification `bazel query --output=build` over the selected public labels and their inner unit-test binaries confirmed the expected `shard_count = 8`, `flaky = True`, and `experimental_enable_sharding = True` attributes. Also verified that we see the shards as expected in BuildBuddy so they can be analyzed independently. Co-authored-by: Codex <noreply@openai.com>
Michael Bolin ·
2026-04-17 23:14:11 +00:00 -
[codex] Propagate rate limit reached type (#18227)
## Summary First PR in the split from #17956. - adds the core/app-server `RateLimitReachedType` shape - maps backend `rate_limit_reached_type` into Codex rate-limit snapshots - carries the field through app-server notifications/responses and generated schemas - updates existing constructors/tests for the new optional field ## Validation - `cargo test -p codex-backend-client` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-app-server rate_limits` - `cargo test -p codex-tui workspace_` - `cargo test -p codex-tui status_` - `just fmt` - `just fix -p codex-backend-client` - `just fix -p codex-app-server-protocol` - `just fix -p codex-app-server` - `just fix -p codex-tui`
richardopenai ·
2026-04-17 13:37:25 -07:00 -
/plugins: Add v2 tabbed marketplace menu (#18222)
This PR moves `/plugins` onto the shared tabbed selection-list infrastructure and introduces the new v2 menu. The menu now groups plugins into All Plugins, Installed, OpenAI Curated, and per-marketplace tabs. - Rebuild /plugins on top of the shared tabbed selection list - Add All Plugins, Installed, OpenAI Curated, and per-marketplace tabs - Preserve active tab and selected-row behavior across popup refreshes - Add duplicate marketplace tab-label disambiguation - Update browse-mode popup tests and snapshots Co-authored-by: Codex <noreply@openai.com>
canvrno-oai ·
2026-04-17 12:59:18 -07:00 -
perf(tui): defer startup skills refresh (#18370)
# Summary This removes startup `skills/list` from the critical path to first input. In release measurements, median startup-to-input time improved from `307.5 ms` to `191.0 ms` across 30 measured runs with 5 warmups. # Background Startup currently waits for a forced `skills/list` app-server request before scheduling the first usable TUI frame. That makes skill metadata freshness part of the process-launch-to-input path, even though the prompt can safely accept normal input before skill metadata has finished loading. I measured startup from process launch until the TUI reports that the user can type. The measurement harness watched the startup measurement record, killed Codex after a successful sample, and enforced a timeout so repeated runs would not leave TUI processes behind. The debug runs had enough outliers that I used median as the primary signal and ran a baseline self-compare to understand the noise floor. # Why skills/list The `skills/list` cut was the best practical optimization because it improved startup without changing the important readiness contract: when the prompt is shown, it is still backed by an active session. Only enrichment data arrives later. | Candidate | Result | Decision | | --- | --- | --- | | Defer startup `skills/list` | Debug median improved from `524.0 ms` to `348.0 ms`; release median improved from `307.5 ms` to `191.0 ms`. | Keep | | Defer fresh `thread/start` | Debug median improved from `494.0 ms` to `256.0 ms`, but the prompt could appear before an active thread was attached. | Reject as too risky for this PR | | Avoid forced skills config reload | Debug median moved from `509.0 ms` to `512.0 ms`. | Reject as neutral | | Skip fresh history metadata | Debug median moved from `496.5 ms` to `531.5 ms`. | Reject as regression/noise | | Defer app-server startup | Not implemented because it would only permit a loading frame unless the TUI gained a deliberate pre-server state. | Out of scope | # Implementation `App::refresh_startup_skills` now clones the app-server request handle, spawns a background task, and issues the same forced `skills/list` request after the first frame is scheduled. When the request completes, the task sends `AppEvent::SkillsListLoaded` back through the normal app event queue. The existing skills response handling still converts the app-server response, updates the chat widget, and emits invalid `SKILL.md` warnings. Explicit user-initiated skills refreshes still use the existing synchronous app command path, so callers that intentionally requested fresh skill state do not race ahead of their own refresh. # Tradeoffs The main tradeoff is a narrow theoretical race at startup: skill mention completion depends on a background `skills/list` response, so it could briefly show stale or empty metadata if opened before that response arrives. In manual testing, pressing `$` as soon as possible after launch still showed populated skill metadata, so this risk appears minimal in normal use. Plain input remains available immediately, and the UI updates through the existing skills response path once the refresh completes. This PR does not change how skills are discovered, cached, force-reloaded, displayed, enabled, or warned about. It only changes when the startup refresh is allowed to complete relative to the first usable TUI frame. # Verification - `cargo test -p codex-tui`
Felipe Coury ·
2026-04-17 16:55:00 -03:00 -
Show default reasoning in /status (#18373)
- Shows the model catalog default reasoning effort when no reasoning override is configured. - Adds /status coverage for the empty-config fallback.
Ahmed Ibrahim ·
2026-04-17 12:21:09 -07:00 -
Add sorting/backwardsCursor to thread/list and new thread/turns/list api (#17305)
To improve performance of UI loads from the app, add two main improvements: 1. The `thread/list` api now gets a `sortDirection` request field and a `backwardsCursor` to the response, which lets you paginate forwards and backwards from a window. This lets you fetch the first few items to display immediately while you paginate to fill in history, then can paginate "backwards" on future loads to catch up with any changes since the last UI load without a full reload of the entire data set. 2. Added a new `thread/turns/list` api which also has sortDirection and backwardsCursor for the same behavior as `thread/list`, allowing you the same small-fetch for immediate display followed by background fill-in and resync catchup.
David de Regt ·
2026-04-17 11:49:02 -07:00 -
feat(tui): add clear-context plan implementation (#17499)
## TL;DR - Adds a second Plan Mode handoff: implement the approved plan after clearing context. - Keeps the existing same-thread `Yes, implement this plan` action unchanged. - Reuses the `/clear` thread-start path and submits the approved plan as the fresh thread's first prompt. - Covers the new popup option, event plumbing, initial-message behavior, and disabled states in TUI tests. ## Problem Plan Mode already asks whether to implement an approved plan, but the only affirmative path continues in the same thread. That is useful when the planning conversation itself is still valuable, but it does not support the workflow where exploratory planning context is discarded and implementation starts from the final approved plan as the only model-visible handoff. <img width="1253" height="869" alt="image" src="https://github.com/user-attachments/assets/90023d75-c330-4919-bed8-518671c3474b" /> ## Mental model There are now two implementation choices after a proposed plan. The existing choice, `Yes, implement this plan`, is unchanged: it switches to Default mode and submits `Implement the plan.` in the current thread. The new choice, `Yes, clear context and implement`, treats the proposed plan as a handoff artifact. It clears the UI/session context through the same thread-start source used by `/clear`, then submits an initial prompt containing the approved plan after the fresh thread is configured. The important distinction is that the new path is not compaction. The model receives a deliberate implementation prompt built from the approved plan markdown, not a summary of the previous planning transcript. Both implementation choices require the Default collaboration preset to be available, so the popup does not offer a coding handoff when the fresh thread would fall back to another mode. ## Non-goals This change does not alter `/clear`, `/compact`, or the existing same-context Plan Mode implementation option. It does not add protocol surface area or app-server schema changes. It also does not carry the previous transcript path or a generated planning summary into the new model context. ## Tradeoffs The fresh-context option relies on the approved plan being sufficiently complete. That matches the Plan Mode contract, but it means vague plans will produce weaker implementation starts than a compacted transcript would. The upside is that rejected ideas, exploratory dead ends, and planning corrections do not leak into the implementation turn. The current implementation stores the latest proposed plan in `ChatWidget` rather than deriving it from history cells at selection time. This keeps the popup action simple and deterministic, but it makes the cache lifecycle important: it must be reset when a new task starts so an old plan cannot be submitted later. ## Architecture The TUI stores the most recent completed proposed-plan markdown when a plan item completes. The Plan Mode approval popup uses that cache to enable the fresh-context option and to build a first-turn prompt that instructs the model to implement the approved plan in a fresh context. Selecting the new option emits a TUI-internal `ClearUiAndSubmitUserMessage` event. `App` handles that event by reusing the existing clear flow: clear terminal state, reset app UI state, start a new app-server thread with `ThreadStartSource::Clear`, and attach a replacement `ChatWidget` with an initial user message. The existing initial-message suppression in `enqueue_primary_thread_session` ensures the prompt is submitted only after the new session is configured and any startup replay is rendered. ## Observability The previous thread remains resumable through the existing clear-session summary hint. There is no new telemetry or protocol event for this path, so debugging should start at the TUI event boundary: confirm the popup emitted `ClearUiAndSubmitUserMessage`, confirm the app-server thread start used `ThreadStartSource::Clear`, then confirm the fresh widget submitted the initial user message after `SessionConfigured`. ## Tests The Plan Mode popup snapshots cover the new option and preserve the original option as the first/default action. Unit coverage verifies the original same-context option still emits `SubmitUserMessageWithMode`, the new option emits `ClearUiAndSubmitUserMessage` with the approved plan embedded verbatim, and the clear-context option is disabled when Default mode is unavailable or no approved plan exists. The broader `codex-tui` test package passes with the updated fresh-thread initial-message plumbing.
Felipe Coury ·
2026-04-17 14:30:09 -03:00 -
feat: config aliases (#18140)
Rename `no_memories_if_mcp_or_web_search` → `disable_on_external_context` with backward compatibility While doing so, we add a key alias system on our layer merging system. What we try to avoid is a case where a company managed config use an old name while the user has a new name in it's local config (which would make the deserialization fail)
jif-oai ·
2026-04-17 18:26:09 +01:00 -
Guardian -> Auto-Review (#18021)
This PR is a user-facing change for our rebranding of guardian to auto-review.
Won Park ·
2026-04-17 09:56:24 -07:00 -
feat(config): support managed deny-read requirements (#17740)
## Summary - adds managed requirements support for deny-read filesystem entries - constrains config layers so managed deny-read requirements cannot be widened by user-controlled config - surfaces managed deny-read requirements through debug/config plumbing This PR lets managed requirements inject deny-read filesystem constraints into the effective filesystem sandbox policy. User-controlled config can still choose the surrounding permission profile, but it cannot remove or weaken the managed deny-read entries. ## Managed deny-read shape A managed requirements file can declare exact paths and glob patterns under `[permissions.filesystem]`: ```toml # /etc/codex/requirements.toml [permissions.filesystem] deny_read = [ "/Users/alice/.gitconfig", "/Users/alice/.ssh", "./managed-private/**/*.env", ] ``` Those entries are compiled into the effective filesystem policy as `access = none` rules, equivalent in shape to filesystem permission entries like: ```toml [permissions.workspace.filesystem] "/Users/alice/.gitconfig" = "none" "/Users/alice/.ssh" = "none" "/absolute/path/to/managed-private/**/*.env" = "none" ``` The important difference is that the managed entries come from requirements, so lower-precedence user config cannot remove them or make those paths readable again. Relative managed `deny_read` entries are resolved relative to the directory containing the managed requirements file. Glob entries keep their glob suffix after the non-glob prefix is normalized. ## Runtime behavior - Managed `deny_read` entries are appended to the effective `FileSystemSandboxPolicy` after the selected permission profile is resolved. - Exact paths become `FileSystemPath::Path { access: None }`; glob patterns become `FileSystemPath::GlobPattern { access: None }`. - When managed deny-read entries are present, `sandbox_mode` is constrained to `read-only` or `workspace-write`; `danger-full-access` and `external-sandbox` cannot silently bypass the managed read-deny policy. - On Windows, the managed deny-read policy is enforced for direct file tools, but shell subprocess reads are not sandboxed yet, so startup emits a warning for that platform. - `/debug-config` shows the effective managed requirement as `permissions.filesystem.deny_read` with its source. ## Stack 1. #15979 - glob deny-read policy/config/direct-tool support 2. #18096 - macOS and Linux sandbox enforcement 3. This PR - managed deny-read requirements --------- Co-authored-by: Codex <noreply@openai.com>viyatb-oai ·
2026-04-17 08:40:09 -07:00 -
fix(tui): use BEL for terminal title updates (#18261)
## Summary Fixes #18160. iTerm2 can append the current foreground process to tab titles, and Codex's terminal-title updates were causing that decoration to appear as `(codex")` with a stray trailing quote. Codex was writing OSC 0 title sequences terminated with ST (`ESC \`). Some terminal title integrations appear to accept that title update but still expose the ST terminator in their own process/title decoration. ## Changes - Update `codex-rs/tui/src/terminal_title.rs` to terminate OSC 0 title updates with BEL instead of ST. - Update the focused terminal-title encoding test to assert the BEL-terminated sequence. ## Compatibility This should be low risk: the title payload and update timing are unchanged, and BEL is the form already emitted by `crossterm::terminal::SetTitle` in the crossterm version used by this repository. BEL is also the widely supported xterm-family title terminator used by common terminals and multiplexers. The main theoretical risk would be a very old or unusual terminal that accepted only ST and not BEL for OSC title termination, but that is unlikely compared with the observed iTerm2 issue. ## Verification - `cargo test -p codex-tui terminal_title` - `cargo test -p codex-tui`
Eric Traut ·
2026-04-17 08:39:37 -07:00 -
Support Ctrl+P/Ctrl+N in resume picker (#18267)
Fixes #18179. ## Why The fullscreen `/resume` picker accepted Up/Down navigation but ignored Ctrl+P/Ctrl+N, which made it inconsistent with other TUI selection flows such as `ListSelectionView`-backed pickers and composer navigation. ## What Changed Updated `codex-rs/tui/src/resume_picker.rs` so the resume picker treats Ctrl+P/Ctrl+N as aliases for Up/Down, including the raw `^P`/`^N` control-character events some terminals emit without a CONTROL modifier.
Eric Traut ·
2026-04-17 08:38:47 -07:00 -
Add PermissionRequest hooks support (#17563)
## Why We need `PermissionRequest` hook support! Also addresses: - https://github.com/openai/codex/issues/16301 - run a script on Hook to do things like play a sound to draw attention but actually no-op so user can still approve - can omit the `decision` object from output or just have the script exit 0 and print nothing - https://github.com/openai/codex/issues/15311 - let the script approve/deny on its own - external UI what will run on Hook and relay decision back to codex ## Reviewer Note There's a lot of plumbing for the new hook, key files to review are: - New hook added in `codex-rs/hooks/src/events/permission_request.rs` - Wiring for network approvals `codex-rs/core/src/tools/network_approval.rs` - Wiring for tool orchestrator `codex-rs/core/src/tools/orchestrator.rs` - Wiring for execve `codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs` ## What - Wires shell, unified exec, and network approval prompts into the `PermissionRequest` hook flow. - Lets hooks allow or deny approval prompts; quiet or invalid hooks fall back to the normal approval path. - Uses `tool_input.description` for user-facing context when it helps: - shell / `exec_command`: the request justification, when present - network approvals: `network-access <domain>` - Uses `tool_name: Bash` for shell, unified exec, and network approval permission-request hooks. - For network approvals, passes the originating command in `tool_input.command` when there is a single owning call; otherwise falls back to the synthetic `network-access ...` command. <details> <summary>Example `PermissionRequest` hook input for a shell approval</summary> ```json { "session_id": "<session-id>", "turn_id": "<turn-id>", "transcript_path": "/path/to/transcript.jsonl", "cwd": "/path/to/cwd", "hook_event_name": "PermissionRequest", "model": "gpt-5", "permission_mode": "default", "tool_name": "Bash", "tool_input": { "command": "rm -f /tmp/example" } } ``` </details> <details> <summary>Example `PermissionRequest` hook input for an escalated `exec_command` request</summary> ```json { "session_id": "<session-id>", "turn_id": "<turn-id>", "transcript_path": "/path/to/transcript.jsonl", "cwd": "/path/to/cwd", "hook_event_name": "PermissionRequest", "model": "gpt-5", "permission_mode": "default", "tool_name": "Bash", "tool_input": { "command": "cp /tmp/source.json /Users/alice/export/source.json", "description": "Need to copy a generated file outside the workspace" } } ``` </details> <details> <summary>Example `PermissionRequest` hook input for a network approval</summary> ```json { "session_id": "<session-id>", "turn_id": "<turn-id>", "transcript_path": "/path/to/transcript.jsonl", "cwd": "/path/to/cwd", "hook_event_name": "PermissionRequest", "model": "gpt-5", "permission_mode": "default", "tool_name": "Bash", "tool_input": { "command": "curl http://codex-network-test.invalid", "description": "network-access http://codex-network-test.invalid" } } ``` </details> ## Follow-ups - Implement the `PermissionRequest` semantics for `updatedInput`, `updatedPermissions`, `interrupt`, and suggestions / `permission_suggestions` - Add `PermissionRequest` support for the `request_permissions` tool path --------- Co-authored-by: Codex <noreply@openai.com>
Abhinav ·
2026-04-17 14:45:47 +00:00 -
Sync local plugin imports, async remote imports, refresh caches after… (#18246)
… import ## Why `externalAgentConfig/import` used to spawn plugin imports in the background and return immediately. That meant local marketplace imports could still be in flight when the caller refreshed plugin state, so newly imported plugins would not show up right away. This change makes local marketplace imports complete before the RPC returns, while keeping remote marketplace imports asynchronous so we do not block on remote fetches. ## What changed - split plugin migration details into local and remote marketplace imports based on the external config source - import local marketplaces synchronously during `externalAgentConfig/import` - return pending remote plugin imports to the app-server so it can finish them in the background - clear the plugin and skills caches before responding to plugin imports, and again after background remote imports complete, so the next `plugin/list` reloads fresh state - keep marketplace source parsing encapsulated behind `is_local_marketplace_source(...)` instead of re-exporting the internal enum - add core and app-server coverage for the synchronous local import path and the pending remote import path ## Verification - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-core` (currently fails an existing unrelated test: `config_loader::tests::cli_override_can_update_project_local_mcp_server_when_project_is_trusted`) - `cargo test` (currently fails existing `codex-app-server` integration tests in MCP/skills/thread-start areas, plus the unrelated `codex-core` failure above)
alexsong-oai ·
2026-04-17 09:34:55 +00:00 -
[codex] Revoke ChatGPT tokens on logout (#17825)
## Summary This changes Codex logout so managed ChatGPT auth is revoked against AuthAPI before local auth state is removed. CLI logout, TUI `/logout`, and the app-server account logout path now use the token-revoking logout flow instead of only deleting `auth.json` / credential store state. ## Root Cause Logout previously cleared only local auth storage. That removed Codex's local credentials but did not ask the backend to invalidate the refresh/access token state associated with a managed ChatGPT login. ## Behavior For managed ChatGPT auth, logout sends the stored refresh token to `https://auth.openai.com/oauth/revoke` with `token_type_hint: refresh_token` and the Codex OAuth client id, then deletes all local auth stores after revocation succeeds. If only an access token is available, it falls back to revoking that access token. API key auth and externally supplied `chatgptAuthTokens` are still only cleared locally because Codex does not own a refresh token for those modes. Revocation failures are fail-closed: if Codex cannot load stored auth or the backend revoke call fails, logout returns an error and leaves local auth in place so the user can retry instead of silently clearing local state while backend tokens remain valid. ## Validation ran local version of `codex-cli` with staging overrides/harness for auth ran `codex login` then `codex logout`: saw auth.json clear and backend revocation endpoints were called ``` POST /oauth/revoke status: 200 revoking access token should clear auth session clearing auth session due to token revocation successfully revoked session and access token CANONICAL-API-LINE Response: status='200' method='POST' path='/oauth/revoke ``` --------- Co-authored-by: Codex <noreply@openai.com>
sashank-oai ·
2026-04-16 22:51:21 -07:00 -
Stream apply_patch changes (#17862)
Adds new events for streaming apply_patch changes from responses api. This is to enable clients to show progress during file writes. Caveat: This does not work with apply_patch in function call mode, since that required adding streaming json parsing.
Akshay Nathan ·
2026-04-16 18:12:19 -07:00