mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
9271e84b79ddd02eb5f7be91b894febb66fe384a
1865 Commits
-
tui: add named permission profile picker (#21559)
## Why Users who opt into named permission profiles through `default_permissions` or `[permissions.*]` should stay in named-profile semantics when they open `/permissions`. The legacy picker rewrites those users into anonymous preset state, which loses the active profile identity and hides custom configured profiles. ## What changed - Switch `/permissions` to a profile-aware picker when profile mode is active. - Show friendly built-in labels instead of raw `:` profile syntax. - Include configured custom profiles and their descriptions in the picker. - Route selections through the split TUI profile-selection flow below this PR. - Add TUI snapshots and regression coverage for built-ins, custom profiles, and conflicting legacy runtime overrides. ## Stack 1. [#22931](https://github.com/openai/codex/pull/22931): runtime/session/network propagation for active permission profiles. 2. [#23708](https://github.com/openai/codex/pull/23708): TUI selection plumbing and guardrail flow. 3. **This PR**: profile-aware `/permissions` menu and custom profile display. ## UX impact In profile mode, `/permissions` shows the same human-facing built-ins users already know: ```text Default Auto-review Full Access Read Only locked-down web-enabled ``` Selecting `locked-down` keeps `active_permission_profile = Some("locked-down")`; selecting a built-in keeps the friendly label while switching to its named built-in profile. ## Screenshots Live `$test-tui` smoke screenshots uploaded through GitHub attachments: **Profile mode with built-ins and custom profiles** <img width="832" alt="Profile mode permissions picker with custom profiles" src="https://github.com/user-attachments/assets/58b72431-418c-4839-9e39-575076db4c8f" /> **Legacy mode remains anonymous preset picker** <img width="1232" alt="Legacy permissions picker" src="https://github.com/user-attachments/assets/95f413ab-4cee-411c-9afb-92580a885c97" /> <img width="1296" height="906" alt="image" src="https://github.com/user-attachments/assets/ea381a78-9904-4aa2-828f-b7f2e43f60f2" /> <img width="705" height="207" alt="Screenshot 2026-05-18 at 2 58 00 PM" src="https://github.com/user-attachments/assets/2fa6dd71-0296-449e-a6de-a72d78a1cb70" /> ## Validation - `git diff --cached --check` before commit. - Full test run skipped at the user request while pushing the split stack.
viyatb-oai ·
2026-05-26 16:39:55 +00:00 -
tui: include exec sessions in resume list (#24503)
## Why Fixes #24502. `codex resume --include-non-interactive` should include sessions created by `codex exec`, but the TUI was sending no `sourceKinds` filter to `thread/list` for that mode. `thread/list` treats omitted or empty `sourceKinds` as interactive-only (`cli`, `vscode`), so exec sessions were still filtered out. ## What Changed - Added a shared TUI `resume_source_kinds` helper so both resume lookup paths always pass explicit `sourceKinds` to `thread/list`. - Kept the default resume behavior scoped to `cli` and `vscode`. - Made `--include-non-interactive` include `exec` and `appServer` sessions, while continuing to exclude subagent and unknown sources. ## Verification Added focused coverage for both affected TUI request builders: - `latest_session_lookup_params_can_include_non_interactive_sources` - `remote_thread_list_params_can_include_non_interactive_sources`
Eric Traut ·
2026-05-26 08:27:10 -07:00 -
Use thread config for TUI MCP inventory (#24532)
## Summary `/mcp` in the TUI should reflect the current loaded thread, including project-local MCP servers from that thread config. Before this change, `mcpServerStatus/list` only read the latest global MCP config, so the active chat could miss project-local servers. This adds optional `threadId` to `mcpServerStatus/list`. When present, app-server resolves the loaded thread and lists MCP status from the refreshed effective config for that thread; when omitted, existing global config behavior stays unchanged. The TUI now sends the active chat thread id for `/mcp` and `/mcp verbose`, carries that origin through the async inventory result, and ignores stale completions if the user has switched threads before the fetch returns. The app-server schemas were regenerated. ## Follow-up Once this app-server API change lands, the desktop app should make the same `threadId` plumbing so its MCP inventory also uses the current thread config. Fixes #23874
Eric Traut ·
2026-05-26 07:44:04 -07:00 -
fix(tui): prevent macos stderr from corrupting composer (#24459)
## Why Fixes #17139. On macOS, runtime diagnostics such as `MallocStackLogging` messages can be written directly to process stderr while the inline TUI owns the terminal. Those bytes paint into the same viewport as the composer without passing through the renderer or composer state, making diagnostic output appear to leak into the input area. ## What Changed - Add a macOS terminal stderr guard while the inline TUI owns the viewport. - Restore stderr when Codex returns terminal ownership for external interactive programs, suspend/resume, panic handling, and normal shutdown. - Add an fd-level regression test that verifies output is suppressed only while terminal ownership is held and restored at each handoff boundary. ## How to Test 1. On macOS, launch the interactive TUI and leave the composer visible. 2. Exercise the workflow that triggers an allocator/runtime stderr diagnostic during an active session, as reported in #17139. 3. Confirm the diagnostic no longer overwrites the active composer region. 4. Suspend or exit the TUI and confirm subsequent terminal stderr output remains visible. The platform diagnostic is environment-dependent, so the deterministic regression check is the new fd-lifecycle test in `tui::terminal_stderr::tests::suppresses_stderr_only_while_terminal_is_owned`. Targeted validation: - `just argument-comment-lint-from-source -p codex-tui` passed. - `just test -p codex-tui` exercised and passed the new stderr-guard regression test. The full invocation currently fails in two unrelated guardian-policy tests, `update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default` and `update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`, which reproduce when rerun in isolation.
Felipe Coury ·
2026-05-25 19:53:40 +00:00 -
fix(tui): improve multiline markdown list readability (#24351)
## Why Numbered Markdown findings become hard to scan when long items visually run together or when wrapped explanatory paragraphs lose their list indentation. This is especially visible in review output: the next number can look attached to the previous finding, and paragraph continuation rows can jump back toward the left margin instead of staying grouped beneath their item. <table><tr><td> <center>Before</center> <img width="1718" height="836" alt="CleanShot 2026-05-24 at 14 00 49" src="https://github.com/user-attachments/assets/f1ee0023-50fa-4f81-a641-ae08b17b99bd" /> </td></tr> <tr><td> <center>After</center> <img width="1714" height="906" alt="image" src="https://github.com/user-attachments/assets/b123a5e0-a232-47bf-96d5-c935295f7c0a" /> </td></tr> </table> ## What Changed - Insert a blank separator before a sibling list item when the previous item occupies more than one rendered line. - Preserve compact rendering for lists whose sibling items each render on one line. - Preserve list-body leading whitespace when transient streamed assistant rows require another wrapping pass for history display, so wrapped paragraphs stay aligned beneath their item. - Share the existing leading-whitespace prefix logic used by history insertion instead of introducing a second indentation rule. - Keep streamed Markdown output aligned with completed rendering and add snapshots for findings-style spacing and streamed paragraph indentation. ## How to Test 1. Start Codex from this branch and open the recorded repro session `019e563f-7d58-7ff2-8ec7-828f20fa61ca`. 2. Inspect the numbered `Findings` list whose items contain explanatory paragraphs. 3. Confirm each multiline finding is separated from the next numbered finding by one blank line. 4. Confirm wrapped rows of each indented paragraph remain aligned beneath the finding body, rather than returning to the left edge. 5. Render a short one-line numbered or unordered list and confirm its items remain compact without added blank rows. Targeted tests: - `just test -p codex-tui history_cell insert_history markdown_render markdown_stream streaming::controller` - `just argument-comment-lint-from-source -p codex-tui` ## Related Work PR #24346 changes Markdown table column allocation in parallel. This PR is intentionally limited to list-item readability and history wrapping; both branches touch `codex-rs/tui/src/markdown_render.rs`, so a small merge conflict may need resolution depending on merge order.
Felipe Coury ·
2026-05-25 15:42:28 -03:00 -
fix(tui): improve markdown table column allocation (#24346)
## Why Markdown tables with a long path-heavy column could allocate almost all available width to that column and collapse neighboring prose columns to only a few characters. In rollout summaries this made `Unit` and `What It Adds` difficult to read, even though the long `Files` values were the content best suited to wrapping. The affected example also specified `Files` as right aligned in its markdown delimiter (`---:`). This change preserves that requested alignment while improving how width is distributed. | Before | After | |---|---| | <img width="1709" height="764" alt="image" src="https://github.com/user-attachments/assets/932ab21c-b72d-48a2-9aad-b69da87a0968" /> | <img width="1711" height="855" alt="image" src="https://github.com/user-attachments/assets/4028bd20-2228-4c2f-be8a-1866325b7f62" /> | ## What Changed - Classify table columns as narrative, token-heavy, or compact during width allocation. - Shrink token-heavy path and URL columns before shrinking narrative prose, while preserving compact counts and short labels longest. - Use readable soft floors for narrative and token-heavy content before falling back to tighter layouts. - Add snapshot coverage for a rollout-shaped table containing right-aligned file paths and prose columns. ## How to Test 1. Render a markdown table with `Unit`, right-aligned `Files`, `Adds`, `Removes`, and `What It Adds` columns at a constrained terminal width. 2. Put long repository paths in `Files` and sentence-length content in `Unit` and `What It Adds`. 3. Confirm that `Files` remains right aligned but wraps before the narrative columns become unreadable. 4. Confirm that the compact numeric columns remain easy to scan. Targeted tests: - `just test -p codex-tui markdown_render` Validation note: `just test -p codex-tui` was also attempted and reached two existing unrelated failures in `app::tests::update_feature_flags_disabling_guardian_*`; the markdown rendering regression test passes in the targeted run.
Felipe Coury ·
2026-05-25 15:09:17 -03:00 -
TUI config cleanup: MCP inventory (#24265)
## Summary The TUI `/mcp` inventory flow should reflect the app server’s MCP status response. It was also joining those results with the TUI process’s local `config.mcp_servers`, which can diverge once MCP state is owned by a remote app server and cause stale local command, URL, status, or empty-state details to render. This change removes the local config join from the app-server-backed inventory renderer. The TUI now renders directly from the existing `mcpServerStatus/list` payload and treats an empty status response as the empty MCP inventory state. ## Known limitation The existing `mcpServerStatus/list` payload does not include disabled-state or disabled-reason fields. To preserve the current app-server API, this PR does not try to infer that state from client-local config. If remote `/mcp` needs to show disabled/reason details again, that should come from app-server-owned status data in a follow-up. Related to #22914, #22915, and #22916.
Eric Traut ·
2026-05-25 09:56:21 -07:00 -
TUI config cleanup: trusted projects (#24255)
## Why TUI onboarding trusted-project persistence should go through the same app-server config write path as other config mutations. Writing `config.toml` directly from the trust widget bypasses that layer and can let onboarding proceed even when the trust decision was not actually persisted. ## What changed - Added a TUI config helper that writes the existing project trust structure through `config/batchWrite`. - Persists trust decisions as `projects.<project>.trust_level = "trusted"` using the existing project trust key helper. - Changed the trust directory widget to only record the user selection; onboarding performs the app-server write before reporting success. - Keeps the user on the trust screen and shows an error if app-server persistence fails. ## Verification - `cargo test -p codex-tui --lib trust_persistence_failure_keeps_trust_step_in_progress` - `cargo test -p codex-tui --lib trusted_project_edit_targets_project_trust_level` - Manual: built the local `codex-cli`, accepted the trust prompt in a temp project, confirmed `projects.<project>.trust_level = "trusted"`, and simulated an unwritable config to verify onboarding stays on the trust screen without writing trust.
Eric Traut ·
2026-05-25 09:54:05 -07:00 -
TUI config cleanup: oss_provider (#24254)
## Summary Manual provider selection during `codex --oss` startup was still persisting `oss_provider` through the legacy local `config.toml` writer. That bypasses the app-server-owned config mutation path used by the TUI, so this routes the write through the app server config API instead. The net behavior is intentionally narrow: only an interactive picker selection is persisted. Auto-detected single-running-provider startup and explicit `--local-provider` startup remain ephemeral, so merely having one backend running does not make that provider sticky for future runs. ## What Changed - Removed the TUI picker’s direct dependency on `set_default_oss_provider`. - Had `oss_selection` report whether the returned provider came from the interactive picker. - Carried only manually selected providers into startup persistence. - Wrote `oss_provider` via `config/batchWrite` once the app server session is available. - Logged a warning and continued startup if the app-server config write fails. ## Verification Manually smoke-tested the real `codex-tui` binary with a temporary `CODEX_HOME`, pseudo-terminal input, and a fake LM Studio HTTP server: - Interactive picker selection persisted `oss_provider = "lmstudio"`. - Non-picker `--local-provider lmstudio` startup did not persist `oss_provider`.
Eric Traut ·
2026-05-25 09:53:39 -07:00 -
Respect hook trust bypass during TUI startup (#24317)
Fixes #24093. ## Why `--dangerously-bypass-hook-trust` is a supported CLI flag intended for headless or automated runs where enabled hooks should be allowed to run without requiring persisted trust. In the TUI, startup hook review still opened whenever hooks looked untrusted, so a launch using the bypass could block on the interactive "Hooks need review" prompt. The tricky case is persistent app-server resume: a resume may attach to an already-running thread, where resume config overrides are ignored. In that path, hiding the startup review would be wrong because the existing hook engine may still filter untrusted hooks. ## What Changed - Startup hook review now skips the prompt only when hook trust bypass is actually safe for that launch. - The TUI forwards `bypass_hook_trust` through the app-server request config for fresh thread start/resume/fork paths, and the app-server applies it as a runtime-only `ConfigOverrides` value rather than treating it like a `config.toml` setting. - Persistent app-server resumes keep the startup review prompt so users still have a chance to trust hooks when the running thread cannot receive the bypass override. ## Verification - Added focused coverage for startup hook review with and without `bypass_hook_trust`. - Extended existing TUI/app-server config override tests to cover forwarding and applying `bypass_hook_trust`.
Eric Traut ·
2026-05-25 09:44:21 -07:00 -
Show remote connection details in /status (#24420)
## Summary Fixes #24411. `/status` currently has no way to show when the TUI is talking to Codex through a remote transport. That makes embedded local sessions, local daemon sessions, and true remote sessions look the same, and it hides the remote server version when debugging connection-specific behavior. This PR adds a single `Remote` row for non-embedded connections only. The row shows the sanitized connection address and a dimmed version parenthetical, preserving the existing status output for embedded local sessions. <img width="791" height="144" alt="image" src="https://github.com/user-attachments/assets/529d7940-1c45-4586-8b06-f20a1f04b771" /> ## Verification - Manually validated when connecting remotely (either implicitly to local daemon or explicitly)
Eric Traut ·
2026-05-25 09:42:42 -07:00 -
tui: label compact rate-limit percentages (#24314)
## Summary The compact TUI status line already renders rate-limit percentages as remaining capacity, but the text did not say so. That made high-usage red indicators ambiguous because values like `weekly 6%` could be read as either used or remaining. This PR labels the compact rate-limit values explicitly as `left` across the status line, terminal title, and setup previews. Addresses #24274
Eric Traut ·
2026-05-25 09:41:32 -07:00 -
fix(tui): restore Windows VT before TUI renders (#24082)
## Why Older Git for Windows versions can leave the Windows console output mode without virtual terminal processing after Codex runs git metadata commands in a repository. When the TUI later emits ANSI control sequences for redraws, restore, or image rendering, Windows Terminal can show raw escape bytes or leave the prompt/status area corrupted. This is a targeted mitigation for the repo-conditioned Windows rendering corruption reported in #23888 and related reports #23512 and #23628. Updating Git avoids the trigger for affected users, but Codex should also reassert the terminal mode before it writes TUI control sequences. | Before | After | |---|---| | <img width="2100" height="1359" alt="CleanShot 2026-05-22 at 11 23 21" src="https://github.com/user-attachments/assets/3218c379-5f97-4c71-ab25-805c9d20578a" /> | <img width="2100" height="1359" alt="CleanShot 2026-05-22 at 11 23 58" src="https://github.com/user-attachments/assets/55ac72bb-37d0-400e-99bc-12dd5ea4092d" /> | ## What Changed - Re-enable Windows virtual terminal processing for stdout and stderr before TUI mode setup, restore, redraw, resume, and pet image render paths. - Treat invalid, null, or non-console handles as no-ops so redirected or non-console output is unaffected. - Keep the helper as a no-op on non-Windows platforms. ## How to Test 1. On Windows Terminal with a Git 2.28.0 for Windows install, start Codex inside a valid Git repository. 2. Start a new Codex CLI session. 3. Confirm the prompt, working indicator, and bottom status line remain readable instead of showing raw ANSI escape sequences. 4. Repeat outside a Git repository to confirm the ordinary non-repo startup path is unchanged. Targeted tests: - Not run locally; the behavior depends on Windows console mode APIs and the current worktree is on macOS.
Felipe Coury ·
2026-05-22 16:20:09 -03:00 -
docs: update README.md to mention curl-based installer (#24106)
Now that users can install via `curl` (or `irm`), we should tell them about it so they no longer need to use `npm`! Note that on one Windows machine I tested on, when I ran: ``` irm https://chatgpt.com/codex/install.ps1 | iex ``` I got this error: ``` iex : The property 'OSArchitecture' cannot be found on this object. Verify that the property exists. At line:1 char:45 + irm https://chatgpt.com/codex/install.ps1 | iex + ~~~ + CategoryInfo : NotSpecified: (:) [Invoke-Expression], PropertyNotFoundException + FullyQualifiedErrorId : PropertyNotFoundStrict,Microsoft.PowerShell.Commands.InvokeExpressionCommand ``` so we'll recommend the following that works from both `cmd.exe` and PowerShell: ``` powershell -ExecutionPolicy ByPass -c "irm https://chatgpt.com/codex/install.ps1 | iex" ``` This PR makes a slight update to `codex-rs/tui/src/update_action.rs` to match.
Michael Bolin ·
2026-05-22 18:39:08 +00:00 -
Add new enterprise requirement gate (#23736)
Add new enterprise requirement gate. Validation: - `cargo test -p codex-config --lib` - `cargo test -p codex-app-server-protocol --lib` - `cargo test -p codex-tui --lib debug_config` - `cargo test -p codex-app-server --lib` *(fails: stack overflow in `in_process::tests::in_process_start_initializes_and_handles_typed_v2_request`; reproduces when run alone)*
adams-oai ·
2026-05-22 11:33:44 -07:00 -
tui: make
codex-tui.logopt-in (#24081)## Why The TUI currently creates a shared plaintext `codex-tui.log` under the default log directory. That append-only file can keep growing across runs even though the TUI already records diagnostics in bounded local stores. Make the plaintext file log an explicit troubleshooting choice instead of a default side effect. This is possible because logs are also stored in the DB with proper rotation ## What changed - Only install the TUI file logging layer when `log_dir` is explicitly set. - Remove the prior `codex-tui.log` at startup before an opt-in file layer is created. - Clarify the `log_dir` config/schema text and `docs/install.md` example so users opt in with `codex -c log_dir=...` when they need a plaintext log.
jif-oai ·
2026-05-22 17:19:51 +00:00 -
config: remove legacy profile write paths (#24055)
## Why [#23883](https://github.com/openai/codex/pull/23883) moved the user-facing `--profile` flag onto profile v2 and [#23886](https://github.com/openai/codex/pull/23886) removed CLI forwarding for the legacy profile-v1 path. Core and TUI config persistence still carried `active_profile` and `ConfigEditsBuilder::with_profile`, which let later writes continue targeting legacy `[profiles.<name>]` tables after profile selection moved to profile-v2 config files. ## What - Remove legacy profile routing from [`ConfigEditsBuilder`](https://github.com/openai/codex/blob/4b38e9c22e762261d7f7eef49d8a21792e241a06/codex-rs/core/src/config/edit.rs#L1064-L1294), so core config edits no longer carry `with_profile` or infer `[profiles.*]` write targets from a `profile` key. - Drop `active_profile` plumbing from runtime `Config`, TUI startup/state, app-server config override forwarding, and Windows sandbox setup persistence. - Make app-server-backed TUI config edits use unscoped model, service-tier, feature, Auto-review, plan-mode, and Windows sandbox paths through [`tui/src/config_update.rs`](https://github.com/openai/codex/blob/4b38e9c22e762261d7f7eef49d8a21792e241a06/codex-rs/tui/src/config_update.rs#L43-L112). - Update config edit coverage so legacy `profile` state stays untouched by direct model writes, and remove tests whose only contract was the deleted profile-scoped persistence path. ## Testing - Not run locally.
jif-oai ·
2026-05-22 12:50:42 +02:00 -
config: remove legacy profile v1 resolution (#24051)
## Why [#23883](https://github.com/openai/codex/pull/23883) moved user-facing `--profile` selection onto profile v2, and [#23886](https://github.com/openai/codex/pull/23886) removed the old CLI `config_profile` override path. Core still had a second legacy path: `profile = "..."` could select `[profiles.*]` values while runtime config was built. Keeping that resolver alive preserves the old precedence model and profile-carrying surfaces even though profile selection now points at `$CODEX_HOME/<name>.config.toml`. ## What - Reject legacy top-level `profile = "..."` config while loading runtime config, with an error that points callers at `--profile <name>` and `<name>.config.toml` in the [core load path](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/mod.rs#L2524-L2531). - Remove the remaining profile-v1 merge points from runtime config resolution, including features, permissions, model/provider selection, web search, Windows sandbox settings, TUI settings, role reloads, and OSS provider lookup. - Drop the leftover profile override surface from [`ConfigOverrides`](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/mod.rs#L2118-L2148) and from the MCP server `codex` tool schema. - Prune profile-precedence tests that only exercised the removed resolver and replace them with rejection coverage for the legacy selector. ## Testing - Not run in this metadata pass. - Added [`legacy_profile_selection_is_rejected`](https://github.com/openai/codex/blob/3d923366eca10a29143623124c6c6e538f058269/codex-rs/core/src/config/config_tests.rs#L7942-L7965) coverage for the new runtime guard.
jif-oai ·
2026-05-22 12:13:52 +02:00 -
Fix auto-review permission profile override (#23956)
## Summary The auto-review runtime sync path was assigning a raw `PermissionProfile` into `runtime_permission_profile_override`, whose field now expects `RuntimePermissionProfileOverride`. That broke the TUI Bazel build. This changes the assignment to store `RuntimePermissionProfileOverride::from_config(&self.config)`, matching the other runtime override paths and preserving the active profile and network metadata with the permission profile.
Eric Traut ·
2026-05-21 16:52:36 -07:00 -
[3 of 4] tui: route feature and memory toggles through app server (#22915)
## Why Experimental feature toggles and memory settings can update several related config values in one interaction. Keeping those writes local in a remote TUI session is especially dangerous because the UI can diverge from the app-server config while also leaving behind partially stale supporting keys. This is **[3 of 4]** in a stacked series that moves TUI-owned config mutations onto app-server APIs. ## What changed - Routed feature flag persistence through app-server batch writes, including the supporting reviewer and permission updates used by guardian approval. - Routed Windows sandbox mode persistence and legacy Windows feature cleanup through app-server writes. - Routed memory settings through app-server batch writes and updated the TUI tests to exercise the embedded app-server path. ## Config keys affected - `features.<feature_key>` - `profiles.<profile>.features.<feature_key>` - `approval_policy` - `sandbox_mode` - `approvals_reviewer` - `windows.sandbox` - `features.experimental_windows_sandbox` - `features.elevated_windows_sandbox` - `features.enable_experimental_windows_sandbox` - Profile-scoped Windows legacy feature variants under `profiles.<profile>.features.*` - `memories.use_memories` - `memories.generate_memories` - Profile-scoped memory variants under `profiles.<profile>.memories.*` ## Suggested manual validation - Connect the TUI to a remote app server, toggle guardian approval on and off, and confirm the remote config updates `features.guardian_approval`, reviewer state, approval policy, and sandbox mode coherently. - Toggle a default-false experimental feature at the root level, disable it again, and confirm the key clears instead of lingering as an unnecessary explicit `false`. - Change memory settings and confirm the remote config updates both memory keys while the running TUI reflects the new state. - On Windows, switch sandbox mode through the TUI and confirm `windows.sandbox` is updated while the legacy Windows feature keys are cleared. ## Stack 1. [#22913](https://github.com/openai/codex/pull/22913) `[1 of 4]` primary settings writes 2. [#22914](https://github.com/openai/codex/pull/22914) `[2 of 4]` app and skill enablement 3. [#22915](https://github.com/openai/codex/pull/22915) `[3 of 4]` feature and memory toggles 4. [#22916](https://github.com/openai/codex/pull/22916) `[4 of 4]` startup and onboarding bookkeeping
Eric Traut ·
2026-05-21 16:03:11 -07:00 -
TUI: skip goal replace prompt for completed goals (#23792)
## Why Users reported that the replacement confirmation feels unnecessary when the current thread goal is already complete. In that state, `/goal <objective>` is starting fresh rather than interrupting active work. ## What changed `/goal <objective>` now skips the replace confirmation when the existing goal has `complete` status and uses the existing fresh replacement path. Goals that are active, paused, blocked, usage-limited, or budget-limited still require confirmation before being replaced.
Eric Traut ·
2026-05-21 10:45:43 -07:00 -
Improve
/goalerror messages for ephemeral sessions (#23796)## Why When a user runs `/goal` in a temporary session, the TUI can currently surface an internal app-server failure such as `thread/goal/get failed in TUI`. That message is technically true, but it does not explain the actual constraint: goals require a saved session because goal state is persisted with the thread. This is especially confusing when `codex doctor` reports the background app-server as running in ephemeral mode, since that wording is easy to conflate with ephemeral thread/session behavior. ## What changed - Added a TUI-side formatter for thread-goal RPC failures in `codex-rs/tui/src/app/thread_goal_actions.rs`. - Detects app-server/core errors that indicate goals are unsupported for an ephemeral thread/session. - Replaces the internal RPC failure with a user-facing explanation: ```text Goals need a saved session. This session is temporary. Run `codex` to start a saved session, or `codex resume` / `/resume` to reopen one. ``` - Preserves the existing generic failure wording for non-ephemeral goal errors. ## Verification - `cargo test -p codex-tui thread_goal_error_message --lib` I also tried `cargo test -p codex-tui`; it built successfully but the test runner aborted in an unrelated side-thread stack overflow (`app::tests::discard_side_thread_removes_agent_navigation_entry`), which reproduced when run by itself.
Eric Traut ·
2026-05-21 09:33:17 -07:00 -
tui: plumb permission profile selection (#23708)
## Why The named-profile `/permissions` picker needs a small TUI action path that can select permission profiles without folding the menu UI and profile metadata into the same review. ## What changed - Carry permission-profile selections through the TUI app event flow. - Persist selected profiles while preserving the existing approval settings and guardrail prompts. - Keep the legacy `/permissions` picker behavior in this layer; the profile-mode menu stays in the follow-up PR. ## Stack 1. [#22931](https://github.com/openai/codex/pull/22931): runtime/session/network propagation for active permission profiles. 2. **This PR**: TUI selection plumbing and guardrail flow. 3. [#21559](https://github.com/openai/codex/pull/21559): profile-aware `/permissions` menu and custom profile display. <img width="1632" height="1186" alt="image" src="https://github.com/user-attachments/assets/69ddcd5e-b57c-468d-8c1d-246916323c15" /> ## Validation - `git diff --cached --check` before commit. - Full test run skipped at the user request while pushing the split stack.
viyatb-oai ·
2026-05-21 12:26:36 -03:00 -
cli: remove legacy profile v1 plumbing (#23886)
## Why [#23883](https://github.com/openai/codex/pull/23883) moved the user-facing `--profile` flag onto profile v2. The shared CLI option layer still carried the old `config_profile` slot and several CLI entrypoints still copied that value into legacy config overrides. Leaving that path around makes the CLI surface look like it still selects legacy `[profiles.*]` state even though `--profile` now means `$CODEX_HOME/<name>.config.toml`. ## What - Remove the legacy `config_profile` field and merge/copy path from [`SharedCliOptions`](https://github.com/openai/codex/blob/95baaf72920c8db22097df8d15a0bb76c84528b6/codex-rs/utils/cli/src/shared_options.rs#L8-L177). - Stop forwarding profile-v1 overrides from CLI, exec, TUI, doctor, debug, feature, and exec-server paths; runtime profile selection remains on `config_profile_v2` through [`loader_overrides_for_profile`](https://github.com/openai/codex/blob/95baaf72920c8db22097df8d15a0bb76c84528b6/codex-rs/cli/src/main.rs#L1606-L1619). - Resolve local OSS provider selection from the base config in exec and TUI now that the legacy profile argument is gone. ## Testing - Not run (cleanup-only follow-up to #23883).
jif-oai ·
2026-05-21 17:21:37 +02:00 -
feat: support managed permission profiles in requirements.toml (#23433)
## Why Cloud-managed `requirements.toml` should be able to define the managed permission profiles a client may select and constrain that selectable set without requiring local user config to recreate the profile catalog. This keeps requirements focused on restrictions. The selected default remains a config or session choice, while requirements contribute the managed profile bodies and `allowed_permissions` allowlist that the config-loading boundary validates before a resolved runtime `PermissionProfile` is installed. ## What changed - Add `requirements.toml` support for a managed permission-profile catalog plus its allowlist: ```toml allowed_permissions = ["review", "build"] [permissions.review] extends = ":read-only" [permissions.build] extends = ":workspace" ``` - Merge requirements-defined profile bodies into the effective permission catalog and reject profile ids that collide with config-defined profiles. - Validate that every `allowed_permissions` entry resolves to a built-in or catalog profile before selection uses it. - Preserve allowed configured named-profile selections. When a configured named profile is disallowed, fall back to the first allowed requirements profile with a startup warning. - Keep built-in selections and the stock trust-based `:read-only` / `:workspace` fallback path intact when no permission profile is explicitly selected. - Centralize the managed catalog and allowlist selection path in `EffectivePermissionSelection` so the requirements boundary is visible in config loading. - Surface `allowedPermissions` through `configRequirements/read`, and update the generated app-server schema fixtures plus the app-server README. ## Validation - `cargo test -p codex-config` - `cargo test -p codex-core system_requirements_` - `cargo test -p codex-core system_allowed_permissions_` - `cargo test -p codex-app-server-protocol` - `just write-app-server-schema` ## Related work - Uses merged permission-profile inheritance support from #22270 and #23705. - Kept separate from the in-flight permission profile listing API in #23412.
viyatb-oai ·
2026-05-20 17:33:01 -07:00 -
[codex] Add plugin id to MCP tool call items (#23737)
Add owning plugin id to MCP tool call items so we can better filter them at plugin level. ## Summary - add optional `plugin_id` to MCP tool-call items and legacy begin/end events - propagate plugin metadata into emitted core items and app-server v2 `ThreadItem::McpToolCall` - preserve plugin ids through app-server replay/redaction paths and regenerate v2 schema fixtures ## Testing - `just write-app-server-schema` - `just fmt` - `just fix -p codex-core` - `cargo test -p codex-protocol -p codex-app-server-protocol` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-core mcp_tool_call_item_includes_plugin_id --lib` - `cargo check -p codex-tui --tests` - `cargo check -p codex-app-server --tests` - `git diff --check` ## Notes - `just fix -p codex-core` completed with two non-fatal `too_many_arguments` warnings on the touched MCP notification helpers. - A broader `cargo test -p codex-core` run passed core unit tests, then hit shell/sandbox/snapshot failures in the integration target. - A broader app-server downstream run hit the existing `in_process::tests::in_process_start_clamps_zero_channel_capacity` stack overflow; `cargo test -p codex-exec` also hit the existing sandbox expectation mismatch in `thread_lifecycle_params_include_legacy_sandbox_when_no_active_profile`.
Matthew Zeng ·
2026-05-20 17:02:10 -07:00 -
Honor client-resolved service tier defaults (#23537)
## Why Model catalog responses can now advertise a nullable `default_service_tier` for each model. Codex needs to preserve three distinct states all the way from config/app-server inputs to inference: - no explicit service tier, so the client may apply the current model catalog default when FastMode is enabled - explicit `default`, meaning the user intentionally wants standard routing - explicit catalog tier ids such as `priority`, `flex`, or future tiers Keeping those states distinct prevents the UI from showing one tier while core sends another, especially after model switches or app-server `thread/start` / `turn/start` updates. ## What Changed - Plumbed `default_service_tier` through model catalog protocol types, app-server model responses, generated schemas, model cache fixtures, and provider/model-manager conversions. - Added the request-only `default` service tier sentinel and normalized legacy config spelling so `fast` in `config.toml` still materializes as the runtime/request id `priority`. - Moved catalog default resolution to the TUI/client side, including recomputing the effective service tier when model/FastMode-dependent surfaces change. - Updated app-server thread lifecycle config construction so `serviceTier: null` preserves explicit standard-routing intent by mapping to `default` instead of internal `None`. - Kept core responsible for validating explicit tiers against the current model and stripping `default` before `/v1/responses`, without applying catalog defaults itself. ## Validation - `CARGO_INCREMENTAL=0 cargo build -p codex-cli` - `CARGO_INCREMENTAL=0 cargo test -p codex-app-server model_list` - `cargo test -p codex-tui service_tier` - `cargo test -p codex-protocol service_tier_for_request` - `cargo test -p codex-core get_service_tier` - `RUST_MIN_STACK=8388608 CARGO_INCREMENTAL=0 cargo test -p codex-core service_tier`
Shijie Rao ·
2026-05-20 15:57:50 -07:00 -
Add SubagentStop hook (#22873)
# What <img width="1792" height="1024" alt="image" src="https://github.com/user-attachments/assets/8f81d232-5813-4994-a61d-e42a05a93a3e" /> `SubagentStop` runs when a thread-spawned subagent turn is about to finish. Thread-spawned subagents use `SubagentStop` instead of the normal root-agent `Stop` hook. Configured handlers match on `agent_type`. Hook input includes the normal stop fields plus: - `agent_id`: the child thread id. - `agent_type`: the resolved subagent type. - `agent_transcript_path`: the child subagent transcript path. - `transcript_path`: the parent thread transcript path. - `last_assistant_message`: the final assistant message from the child turn, when available. - `stop_hook_active`: `true` when the child is already continuing because an earlier stop-like hook blocked completion. `SubagentStop` shares the same completion-control semantics as `Stop`, scoped to the child turn: - No decision allows the child turn to finish. - `decision: "block"` with a non-empty `reason` records that reason as hook feedback and continues the child with that prompt. - `continue: false` stops the child turn. If `stopReason` is present, Codex surfaces it as the stop reason. # Lifecycle Scope Only thread-spawned subagents run `SubagentStop`. Internal/system subagents such as Review, Compact, MemoryConsolidation, and Other do not run normal `Stop` hooks and do not run `SubagentStop`. This avoids exposing synthetic matcher labels for internal implementation paths. # Stack 1. #22782: add `SubagentStart`. 2. This PR: add `SubagentStop`. 3. #22882: add subagent identity to normal hook inputs.
Abhinav ·
2026-05-20 14:59:41 -07:00 -
core: refresh active permission profiles at runtime (#22931)
## Why Once a named permission profile is selected, runtime state has to keep that profile identity intact instead of collapsing back to anonymous effective permissions. The session refresh path also needs to rebuild profile-derived network proxy state so active profile switches take effect consistently. ## What changed - Preserve the active permission profile through session updates. - Rebuild profile-derived runtime/network configuration when the active profile changes. - Keep the runtime path aligned with the current session configuration APIs. - Tighten the affected tests, including the Windows delete-pending memory-file case that was intermittently tripping CI. ## Stack 1. **This PR**: runtime/session/network propagation for active permission profiles. 2. [#23708](https://github.com/openai/codex/pull/23708): TUI selection plumbing and guardrail flow. 3. [#21559](https://github.com/openai/codex/pull/21559): profile-aware `/permissions` menu and custom profile display. <img width="1296" height="906" alt="image" src="https://github.com/user-attachments/assets/077fa3a7-80cb-4925-80b1-d2395018d90a" />
viyatb-oai ·
2026-05-20 21:55:21 +00:00 -
Fix thread settings clippy failure (#23724)
## Why `main` picked up two small Rust build failures after nearby merges: - #23507 added a real handler for `ServerNotification::ThreadSettingsUpdated`, but the same variant was still listed in the ignored-notification match arm. Full Clippy runs treat the resulting unreachable-pattern warning as an error. - #23666 added `turn_id` and `truncation_policy` to `codex_tools::ToolCall`, while the goal extension backend test fixtures from the goal-extension work still used the old shape. That left `codex-goal-extension` tests unable to compile once the branches met on `main`. ## What changed Removed the duplicate `ThreadSettingsUpdated` match pattern from `tui/src/chatwidget/protocol.rs`. Updated the goal extension test `tool_call` helper to populate the new `ToolCall` fields, and reused that helper for the one direct literal that still had the old field list. ## Verification - `just fix -p codex-tui` - `cargo test -p codex-goal-extension`
Eric Traut ·
2026-05-20 11:58:23 -07:00 -
Sync TUI thread settings through app server (#23507)
Builds on #23502. ## Why #23502 adds the app-server `thread/settings/update` API and matching `thread/settings/updated` notification. The TUI already lets users change thread-scoped settings such as model, reasoning effort, service tier, approvals, permissions, personality, and collaboration mode, but those updates need to flow through the app server so embedded and connected clients observe the same thread state. This is a rework (simplification) of PR https://github.com/openai/codex/pull/22510. It has the same functionality, but the underlying `thread/settings/update` api is now simpler in that it no longer returns the effective settings as a response. Now, clients receive the effective settings only through the `thread/settings/updated` notification. ## What Changed This updates the TUI to send `thread/settings/update` whenever those thread-scoped settings change and to treat the RPC response as the authoritative acknowledgement. It also routes `thread/settings/updated` notifications back into cached session state and the visible chat widget so active and inactive threads stay in sync after app-server-originated changes. The implementation is kept to the TUI layer: settings conversion and merge logic live under `codex-rs/tui/src/app/thread_settings.rs`, with dispatch/routing hooks in the existing app and chat widget paths. ## Verification I manually tested using `codex app-server --listen unix://` and then launching two copies of the TUI that use the same local app server. I then resumed the same thread on both and verified that changes like plan mode, fast mode, model, reasoning effort, etc. are reflected "live" in the second client when modified in the first and vice versa.
Eric Traut ·
2026-05-20 11:05:14 -07:00 -
Add thread/settings/update app-server API (#23502)
## Why App-server clients need a way to update a thread's next-turn settings without starting a turn, adding transcript content, or waiting for turn lifecycle events. This gives settings UI a direct path for durable thread settings while clients observe the eventual effective state through a notification. This is a simplified rework of PR https://github.com/openai/codex/pull/22509. In particular, it changes the `thread/settings/update` api to return immediately rather than waiting and returning the effective (updated) thread settings. This makes the new api consistent with `turn/start` and greatly reduces the complexity of the implementation relative to the earlier attempt. ## What Changed - Adds experimental `thread/settings/update` with partial-update request fields and an empty acknowledgment response. - Adds experimental `thread/settings/updated`, carrying full effective `ThreadSettings` and scoped by `threadId` to subscribed clients for the affected thread. - Shares durable settings validation with `turn/start`, including `sandboxPolicy` plus `permissions` rejection and `serviceTier: null` clearing. - Emits the same settings notification when `turn/start` overrides change the stored effective thread settings. - Regenerates app-server protocol schema fixtures and updates `app-server/README.md`.
Eric Traut ·
2026-05-20 11:03:20 -07:00 -
[2 of 2] Start fresh TUI thread in background (#23176)
## Why After the terminal-probe work in #23175, fresh-session startup still waits for `thread/start` before the chat input can become usable. The chat widget already has the machinery to hold early submissions until a session is configured, so fresh `thread/start` does not need to stay on the input-ready hot path. Refs #16335. ## What This PR starts fresh app-server threads in a background task, reports completion through a startup app event, and attaches the primary session once `thread/start` returns. Resume and fork startup paths remain synchronous. ## Benchmark In the local pty startup benchmark, this PR's pre-optimization base branch, #23175, measured about 152ms median from launch to accepted chat input. The stacked result measured about 66ms median, for an approximate additional savings of 85-95ms. For broader context, the original `main` baseline before either startup optimization was about 250.5ms median. We also measured Codex 0.117.0 on the same machine at about 64.6ms median, so the stacked branch is back in the old-startup-time range. ## Stack 1. [#23175: [1 of 2] Optimize TUI startup terminal probes](https://github.com/openai/codex/pull/23175) — base PR 2. [#23176: [2 of 2] Start fresh TUI thread in background](https://github.com/openai/codex/pull/23176) — this PR ## Verification - `cargo test -p codex-tui`
Eric Traut ·
2026-05-20 10:00:33 -07:00 -
anp-oai ·
2026-05-20 15:49:35 +00:00 -
runtime: detect Codex package layout (#23596)
## Why The package-builder stack now creates a canonical Codex package directory where the entrypoint lives under `bin/`, bundled helper resources live under `codex-resources/`, and bundled PATH-style tools live under `codex-path/`. That layout is not specific to the standalone installer: npm, brew, install scripts, and manually unpacked artifacts should all be able to use the same package shape. The Rust runtime still only knew about the legacy standalone release layout, where resources sit next to the executable. A packaged binary therefore would not identify its package root or prefer the bundled `rg` from `codex-path/`. ## What changed - Adds `CodexPackageLayout` to `codex-install-context` and detects it from an executable path shaped like `<package>/bin/<entrypoint>` when `<package>/codex-package.json` is present. - Splits `InstallContext` into an install `method` plus an optional package layout so the layout is shared across npm, bun, brew, standalone, and other launch contexts. - Stores package-layout paths as `AbsolutePathBuf` values. - Keeps `codex-resources/` and `codex-path/` optional so Codex can still run with degraded behavior if sidecar directories are missing. - Updates `InstallContext::rg_command()` to prefer bundled `codex-path/rg` or `rg.exe`, then fall back to the legacy standalone resources location, then system `rg`. - Updates `codex doctor` reporting so package installs show package, bin, resources, and path directories, and so bundled search detection recognizes `codex-path/` for any install method. ## Test plan - `cargo test -p codex-install-context` - `cargo test -p codex-cli` - `cargo test -p codex-tui update_action::tests::maps_install_context_to_update_action` - `just bazel-lock-check`
Michael Bolin ·
2026-05-19 23:13:49 -07:00 -
Fix stale background terminal poll events (#23231)
## Why Issue #23214 reports `/ps` showing no background terminals while the status line still says it is waiting for a background terminal. The race is in core: `write_stdin` can poll a process that exits before the response returns. The process manager correctly returns `process_id: None`, but the handler still emitted a `TerminalInteraction` event using the requested session id, causing clients to believe a dead process was still being polled. Fixes #23214. ## What changed - Suppress `TerminalInteraction` events for empty `write_stdin` polls once `response.process_id` is `None`. - Continue emitting interactions for non-empty stdin, even if that input causes the process to exit before the response returns. - Extend the unified exec integration test to assert completed empty polls do not emit terminal interactions. ## Verification - `cargo test -p codex-core --test all unified_exec_emits_one_begin_and_one_end_event` - `cargo test -p codex-core --test all unified_exec_emits_terminal_interaction_for_write_stdin` `cargo test -p codex-core` currently aborts in unrelated `agent::control::tests::resume_agent_from_rollout_uses_edge_data_when_descendant_metadata_source_is_stale` with a reproducible stack overflow.
Eric Traut ·
2026-05-19 20:48:37 -07:00 -
Fix: TUI starting in wrong CWD (#23538)
This fixes a regression wher codex could start in the wrong directory when a live local app-server socket was present. The issue was that implicit local socket reuse was being treated like an explicit remote workspace session, which dropped the invoking cwd unless --cd was passed. The change separates local socket transport from true remote workspace semantics. - Plain local startup keeps local cwd, trust, resume, picker, and config-refresh behavior. - Explicit --remote keeps the existing remote cwd behavior. - Added coverage for launch target selection and local-session filtering/cwd behavior. Steps to test: - Start a local app-server from a different directory than the repo you want to use. - Launch codex from a project/worktree without --cd. - Confirm the session starts in the invoking directory, not the app-server process directory. - Confirm explicit codex --remote ... still preserves existing remote behavior.
canvrno-oai ·
2026-05-19 15:48:40 -07:00 -
Add CUA requirements subsection for locked computer use (#23555)
Adds a new top-level section for "CUA" requirements that can allow for disablement of specific features as needed for enterprises.
adams-oai ·
2026-05-19 15:41:44 -07:00 -
fix(tui): preserve modified enter in plan questions (#23536)
## Why Plan mode questionnaires reuse the shared composer for free-form answers, but the surrounding `request_user_input` overlay still treated every `KeyCode::Enter` as “advance to the next question.” That made `Shift+Enter` insert a newline in the composer and then immediately advance the questionnaire anyway. Fixes #23448. ## What Changed - pass the live `RuntimeKeymap` into `RequestUserInputOverlay` so its embedded composer honors existing `/keymap` composer/editor remaps - advance free-form questions only on the configured composer submit binding, instead of any Enter-shaped key event - add regressions for `Shift+Enter` newline behavior and configured composer submit bindings inside the questionnaire UI ## How to Test 1. Start Codex in Plan mode and trigger a `request_user_input` questionnaire with a free-form answer field. 2. Focus the free-form field, type a line, then press `Shift+Enter`. 3. Confirm the answer gains a newline and the questionnaire stays on the same question. 4. Press the configured submit binding, or plain `Enter` with the default keymap, and confirm the questionnaire advances as before. Targeted tests: - `cargo test -p codex-tui bottom_pane::request_user_input::tests::freeform_ -- --nocapture` ## Notes - `cargo test -p codex-tui` still reaches an unrelated existing stack overflow in `app::tests::discard_side_thread_removes_agent_navigation_entry` on this checkout. - `just argument-comment-lint` is locally blocked by Bazel analysis failing in external `compiler-rt` before the lint runs.
Felipe Coury ·
2026-05-19 18:01:38 -03:00 -
Make local environment optional in EnvironmentManager (#23369)
## Summary - make `EnvironmentManager` local environment/runtime paths optional - simplify constructor surface around snapshot materialization - rename local env accessors to `require_local_environment` / `try_local_environment` ## Validation - devbox Bazel build for touched crate surfaces - `//codex-rs/exec-server:exec-server-unit-tests` - `//codex-rs/app-server-client:app-server-client-unit-tests` - filtered touched `//codex-rs/core:core-unit-tests` cases
starr-openai ·
2026-05-19 12:55:34 -07:00 -
Add SubagentStart hook (#22782)
# What `SubagentStart` runs once when Codex creates a thread-spawned subagent, before that child sends its first model request. Thread-spawned subagents use `SubagentStart` instead of the normal root-agent `SessionStart` hook. Configured handlers match on the subagent `agent_type`, using the same value passed to `spawn_agent`. When no agent type is specified, Codex uses the default agent type. Hook input includes the normal session-start fields plus: - `agent_id`: the child thread id. - `agent_type`: the resolved subagent type. `SubagentStart` may return `hookSpecificOutput.additionalContext`. That context is added to the child conversation before the first model request. # Lifecycle Scope Only thread-spawned subagents run `SubagentStart`. Internal/system subagents such as Review, Compact, MemoryConsolidation, and Other do not run normal `SessionStart` hooks and do not run `SubagentStart`. This avoids exposing synthetic matcher labels for internal implementation paths. Also the `SessionStart` hook no longer fires for subagents, this matches behavior with other coding agents' implementation # Stack 1. This PR: add `SubagentStart`. 2. #22873: add `SubagentStop`. 3. #22882: add subagent identity to normal hook inputs.
Abhinav ·
2026-05-19 12:45:08 -07:00 -
Harden CLI rate limit window labels (#22929)
## Context The CLI rate-limit surfaces previously described usage windows as fixed 5-hour and weekly limits. We want the CLI to display whatever supported rate-limit period the server returns instead of assuming a 5-hour/1-week pair. This supports generalized Codex rate-limit periods. ## Summary - Formats CLI rate-limit warning/status labels only for the supported returned window durations: approximate 5h, daily, weekly, monthly, and annual. - Uses generic fallback copy when a primary or secondary window has no duration, so missing secondary protection data does not produce stale weekly copy. - Uses generic fallback copy for unsupported window durations instead of adding arbitrary hourly, multi-day, multi-week, or multi-year labels. - Updates status line and terminal title setup descriptions/previews to talk about primary/secondary usage limits rather than fixed 5h/weekly limits. - Adds rendered insta snapshot coverage for the updated rate-limit status surfaces and `/status` fallback labels. ## Tests Tested locally: - one primary window - one secondary window - primary and secondary window
Arun Eswara ·
2026-05-19 11:22:00 -07:00 -
Make
denycanonical for filesystem permission entries (#23493)## Why Filesystem permission profiles used `none` for deny-read entries, which is less direct than the action the entry actually represents. This change makes `deny` the canonical filesystem permission spelling while preserving compatibility for older configs that still send `none`. ## What changed - rename `FileSystemAccessMode::None` to `Deny` - serialize and generate schemas with `deny` as the canonical value - retain `none` only as a legacy input alias for temporary config compatibility - update filesystem glob diagnostics and regression coverage to use the canonical spelling - refresh config and app-server schema fixtures to match the new wire shape ## Validation - `cargo test -p codex-protocol` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-core config_toml_deserializes_permission_profiles --lib` - `cargo test -p codex-core read_write_glob_patterns_still_reject_non_subpath_globs --lib` Earlier in the session, a broad `cargo test -p codex-core` run reached unrelated pre-existing failures in timing/snapshot/git-info tests under this environment; the targeted surfaces touched by this PR passed cleanly.
viyatb-oai ·
2026-05-19 11:03:47 -07:00 -
[2 of 4] tui: route app and skill enablement through app server (#22914)
## Why App and skill toggles are user config mutations too. When the TUI is attached to a remote app server, writing those toggles into the local `config.toml` makes the UI report success without updating the server that actually owns the session. This is **[2 of 4]** in a stacked series that moves TUI-owned config mutations onto app-server APIs. ## What changed - Routed app enable/disable persistence through app-server config batch writes. - Routed skill enable/disable persistence through `skills/config/write`. - Avoided refreshing local config from disk after these writes when the TUI is connected to a remote app server. ## Config keys affected - `apps.<app_id>.enabled` - `apps.<app_id>.disabled_reason` - `[[skills.config]]` entries keyed by `path`, with `enabled = false` used for persisted disables ## Suggested manual validation - Connect the TUI to a remote app server, disable an app, reconnect, and confirm the app remains disabled from remote config rather than local disk state. - Re-enable the same app and confirm both `apps.<app_id>.enabled` and `apps.<app_id>.disabled_reason` are cleared remotely. - Disable a skill in the manage-skills UI and confirm a remote `[[skills.config]]` disable entry appears. - Re-enable that skill and confirm the disable entry is removed and the effective enabled state updates without relying on local config reloads. ## Stack 1. [#22913](https://github.com/openai/codex/pull/22913) `[1 of 4]` primary settings writes 2. [#22914](https://github.com/openai/codex/pull/22914) `[2 of 4]` app and skill enablement 3. [#22915](https://github.com/openai/codex/pull/22915) `[3 of 4]` feature and memory toggles 4. [#22916](https://github.com/openai/codex/pull/22916) `[4 of 4]` startup and onboarding bookkeeping
Eric Traut ·
2026-05-19 10:21:07 -07:00 -
app-server: use profile ids in v2 permission params (#23360)
## Why The v2 app-server permission profile fields are experimental, but the previous migration kept a legacy object payload for profile selection. That made clients aware of server-owned `activePermissionProfile` metadata such as `extends`, and it kept a `legacy_additional_writable_roots` path even though `runtimeWorkspaceRoots` now owns runtime workspace-root selection. This PR makes the client contract match the intended model: clients select a permission profile by id, and the server resolves and reports active profile provenance in response payloads. Follow-up to #22611. ## What Changed - Changed `thread/start`, `thread/resume`, `thread/fork`, and `turn/start` permission profile selection to plain profile id strings. - Changed `command/exec.permissionProfile` to a plain profile id string for the same client/server ownership split. - Removed `PermissionProfileSelectionParams` and the legacy `{ type: "profile", modifications: [...] }` compatibility deserializer. - Updated app-server, TUI, and `codex exec` call sites to send only ids, while keeping `activePermissionProfile` as server response metadata. - Updated app-server docs and schema fixtures for the revised `command/exec.permissionProfile` shape. ## Verification - `cargo test -p codex-app-server-protocol` - `RUST_MIN_STACK=8388608 cargo test -p codex-app-server` - `cargo test -p codex-exec` - `RUST_MIN_STACK=8388608 cargo test -p codex-tui` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/23360). * #23368 * __->__ #23360
Michael Bolin ·
2026-05-18 17:28:50 -07:00 -
fix(tui): warn on unsupported iTerm2 pet versions (#23371)
## Why Older iTerm2 builds can be detected as supporting the image transport that terminal pets use, but in practice they fail to render the pet flow correctly. Instead of silently attempting image rendering, Codex should tell the user that their iTerm2 version is too old and that upgrading is the fix. ## What Changed - gate iTerm2 pet auto-detection on version `3.6.0` or newer - show a dedicated upgrade message for older or unknown iTerm2 versions instead of the generic unsupported-terminal warning - keep the existing generic unsupported-terminal path for non-iTerm terminals - add regression coverage for iTerm2 version parsing and the old-iTerm warning path ## How to Test 1. Start Codex in iTerm2 3.6 or newer. 2. Run `/pets`. 3. Confirm the pets picker opens instead of showing a warning. 4. Start Codex in an older iTerm2 build, or exercise the equivalent test path. 5. Run `/pets`. 6. Confirm Codex warns that pets require iTerm2 3.6 or newer and tells the user to upgrade. 7. Also verify that a non-iTerm unsupported terminal still shows the generic unsupported-terminal message. Targeted tests: - `cargo test -p codex-terminal-detection` - `cargo test -p codex-tui pets::` - `cargo test -p codex-tui slash_pets_on_unsupported_terminal` - `cargo test -p codex-tui slash_pets_on_old_iterm2`
Felipe Coury ·
2026-05-18 20:24:09 -03:00 -
feat(tui): handle paste in session picker (#23338)
## Why The session picker already supports typed search, but it ignored bracketed paste events entirely. On macOS terminals this makes pasted text look like a no-op on the resume screen, which is especially noticeable when a user wants to paste part of a thread name, branch, or path into the search field. ## What Changed - route `TuiEvent::Paste(String)` into the session picker instead of dropping it - normalize pasted search text into a single-line query by collapsing whitespace - ignore whitespace-only pastes - reuse the existing `set_query(...)` path so pasted searches keep the same filtering and pagination behavior as typed input - add focused tests for append behavior, whitespace normalization, whitespace-only paste, and the existing search-loading path This PR is stacked on top of #23234 and contains only the net change relative to `etraut/clarify-resume-hints`. ## How to Test 1. Start Codex in a terminal that emits bracketed paste, for example iTerm2 on macOS. 2. Open the resume picker so the search UI is visible. 3. Copy a term that should match one of the visible sessions, then paste it into the picker. 4. Confirm the query updates immediately and the list filters as if the text had been typed. 5. Also verify that pasting text with newlines or tabs still produces a usable single-line search query. 6. Also verify that normal typed search still works and that `Esc` still clears the query / exits as before. Targeted tests: - `cargo test -p codex-tui` --------- Co-authored-by: Eric Traut <etraut@openai.com>
Felipe Coury ·
2026-05-18 19:04:41 +00:00 -
TUI: replay in-progress MCP calls as started (#23236)
Fixes #22300. ## Summary MCP tool calls can appear in thread history while still in progress. During replay, `handle_thread_item` routed every `ThreadItem::McpToolCall` to the completion handler, so an in-progress item with no result or error was rendered as `MCP tool call completed without a result`. This updates replay handling to mirror command executions: `InProgress` MCP calls go through `on_mcp_tool_call_started`, while completed and failed calls continue through the completion path. ## Validation - `cargo test -p codex-tui replayed_in_progress_mcp_tool_call_stays_active`
Eric Traut ·
2026-05-18 11:34:31 -07:00 -
TUI: route elicitation responses to request thread (#23241)
## Why Fixes #21894. When the TUI handles an MCP elicitation, the request payload already includes the thread that generated the elicitation. `ChatWidget::handle_elicitation_request_now` was ignoring that value and using the currently visible chat thread instead. In a multi-session TUI, that can send `resolve_elicitation` to an older visible thread rather than the session that owns the pending elicitation, producing `elicitation request not found` and leaving the prompt unresolved. ## What changed - Parse `McpServerElicitationRequestParams.thread_id` in the ChatWidget elicitation handler and use it for app-link, form, fallback approval, and auto-decline resolution paths. - Keep the existing visible-thread fallback only for malformed request payloads with an invalid thread id. - Update the invalid URL elicitation regression test so the visible thread and request thread intentionally differ.
Eric Traut ·
2026-05-18 11:33:13 -07:00 -
Clarify resume hints for renamed threads (#23234)
Addresses #23181 ## Why Renamed threads can share names, so hints that suggest resuming directly by name are ambiguous. Issue #23181 asks for the picker hint to include the thread name and thread ID in parens so users can disambiguate safely. ## What - Adds a shared resume hint formatter for named threads: run `codex resume`, then select `<name> (<thread-id>)`. - Uses that hint for /rename confirmations, TUI session summaries, and CLI/TUI exit messages. - Keeps direct `codex resume <thread-id>` guidance for unnamed threads. ## Verification Manually verified that message after `/rename` and after `/exit` include session ID in parens. --------- Co-authored-by: Felipe Coury <felipe.coury@openai.com>
Eric Traut ·
2026-05-18 11:32:02 -07:00