## Why
Starting a side chat waits for fork and setup requests. Keep the workspace responsive during those requests and let users return to an existing side chat through the sidebar chooser.
## What changed
- Add a clickable `Side chat` tab and `+` chooser, plus the configurable `focus_sidebar_tabs` action bound to `leader t` by default.
- Create workspace side chats in the background, showing loading and failure states with `Enter` to retry and `Esc` to go back. Preserve opening prompts and avoid taking focus when the user has moved away.
- Retain inherited permission profiles and defer startup notifications until the side chat is registered on its owning backend.
- Quiet the parent composer while the chooser has focus and prevent completion popups or repeated activation keys from consuming chooser input.
## Testing
Extend tests and snapshots for loading and failure states, returning to an existing chat, draft preservation, inherited permissions, focus transitions, and deferred MCP startup notifications.
GitOrigin-RevId: 244bcd3f170819e2260f21dc1041cf8899fe048c
## What changed
Add configurable pane actions with default leader shortcuts:
- `leader z` zooms or restores the focused conversation pane.
- `leader ,`, `leader .`, and `leader =` minimize, maximize, or equalize pane widths within layout limits.
- `leader shift-h` and `leader shift-l` move the divider while the side pane has focus.
- `leader r` enters resize mode, highlighting the divider and showing keyboard hints. Arrow keys or `h`/`l` move it one column; Shift+Left/Right move it ten columns. Enter or Esc saves the width to `tui.sidebar_width_percent`.
Discard resize previews when terminal focus is lost or the split layout becomes unavailable. Preserve exact column widths at the current terminal size for presets and completed keyboard resizing, avoiding percentage-rounding drift.
## Testing
Extend TUI tests and snapshots to cover zoom and restore, width presets, divider movement, resize previews and persistence, and interrupted resizing. Extend keymap tests to cover zoom binding conflicts and custom chords.
GitOrigin-RevId: 7dd823fd8c2a0c90368c66f254c4fdd7c863c8a8
## What changed
- Add configurable `focus_pane_left` and `focus_pane_right` actions, defaulting to `leader left` / `leader h` and `leader right` / `leader l`.
- Move focus to the parent or open side conversation without reopening a hidden pane. Preserve the current interaction when no neighbor is available, and accept fresh typing after a no-op shortcut while suppressing reported key repeats.
- Expose the actions in the keymap picker and configuration schema, and prevent workspace-only pane bindings from claiming keys in classic mode.
## Testing
Add regression coverage for pane navigation, preserved transcript selection and search, fresh typing after a no-op, key capture, and binding conflicts and limits.
GitOrigin-RevId: 7f7629d15cffcd35d1353b36c5c9208dbb1034e8
## What changed
- Add configurable `focus_main_composer` and `focus_sidebar_content` actions, with default `leader c` and `leader s` bindings in workspace mode.
- Let users return to the main composer while keeping the side pane open, or focus the side conversation and hide it when already focused.
- Clear transcript search, selection, and activity focus when returning to the main composer, including when hiding the side pane.
## Testing
Extend tests for focus switching, blocked thread switches, offline composer focus, key capture, and binding conflicts.
GitOrigin-RevId: da624ce7e00a63c4f13870e55c4bc95f09b32cc4
## What changed
Add `tui.keymap.global.hide_pane`, defaulting to `leader -` in workspace mode. Hiding a focused side conversation returns to its parent while retaining the conversation, drafts, and view state for reopening.
Expose the action in the workspace keymap picker, validate binding conflicts, and suppress held shortcut keys after switching focus.
## Testing
Add coverage for hiding and reopening at split-pane and narrow widths, preserving conversation state, shortcut availability, key capture, and repeat/release handling.
GitOrigin-RevId: 6897c34b208041e6f90ae0e18c781eebd62566bd
## What changed
- With multi-backend support enabled, show the current host before the first submission and use `leader b` to cycle through available connections. Expose the shortcut as `tui.keymap.global.change_host`.
- Preserve the conversation name and composer draft, including cursor position, attachments, pending pastes, and literal versus shell-command interpretation of `!`.
- Save explicit host choices in user-only `tui.default_hosts`, scoped to the local project and user identity. Use the saved host for new conversations, falling back to the first available connection when it is unavailable.
- Prepare the destination and check directory trust before replacing the current conversation. Block switching during voice calls and active turns, and remove replaced blank conversations from the session overview.
## Testing
Add coverage for shortcut visibility and remapping, draft and name preservation, project/user preference isolation, unavailable-host fallback, destination trust and startup failures, and voice-call guards.
GitOrigin-RevId: def7b088951336bec8fe3962954fba9b861f91c6
## Why
The agent command center previously required a shared background server, preventing embedded sessions from opening it and rejecting `codex agents --no-daemon`.
## What changed
- Allow `codex agents --no-daemon` to use an embedded app server and open the command center without a shared server.
- Route `codex agents` through the normal daemon startup, eligibility, and compatibility checks, including embedded fallback where applicable.
- Return embedded sessions to the command center when canceling directory trust or archived-session confirmation.
## Testing
Add CLI coverage for `--no-daemon` before and after `agents`, plus an integration test that verifies embedded mode is used even when a daemon is running. Update archived-session tests to expect cancellation to return to the command center.
GitOrigin-RevId: 3bdf18a00456eae2e4d38103d12126e039d44119
## Why
The `Cwd` session filter included sessions from linked worktrees, leaving no way to restrict the picker to the current directory. Project grouping also combined tasks across linked worktrees.
## What changed
- Keep `Cwd` filtering and directory-scoped `resume --last` and `fork --last` lookups limited to the current directory.
- Add an explicit `Repo` picker filter when multiple local worktrees are available, including sessions from corresponding directories across linked worktrees. Cycle between `Cwd`, `Repo`, and `All` in either direction.
- Add `Directory` grouping to the agent command center alongside `Project`, `Status`, and `Model`. Keep this choice in memory without writing a configuration value older clients cannot read.
## Testing
Extend coverage for directory and repository filtering, pagination scope, linked-worktree grouping, directory aliases, grouping persistence, and adjacent selection after task removal. Update picker and command center snapshots.
GitOrigin-RevId: 59603c9c5136db43124102b3277d1d1dab36bb87
## What changed
Replace the `/presets` recall picker with a responsive menu above the composer. Press `0`–`9` to run a saved preset or create one in an empty slot; use `n`, `s`, `e`, and `d` to create, start from current settings, edit, and delete presets.
Add `tui.keymap.chat.open_presets` with an implicit `leader p` shortcut that yields to existing bindings and explicit configuration. Show the action in `/keymap` and add a shortcut tooltip.
Preserve the composer draft, respect popup ownership, and consume held-key repeats after menu actions.
## Testing
Add snapshots for empty, populated, and narrow preset menus, plus coverage for draft preservation, cancellation, held-key handling, transcript search precedence, and default shortcut conflicts.
GitOrigin-RevId: f438c7015dbd416c90cdeb479d2a15d9d6d24954
## Why
The `/keymap` action catalog and root-config binding lookup duplicated the same action inventory, requiring both to be maintained together.
## What changed
Use `define_keymap_actions!` to generate `KEYMAP_ACTIONS` and `binding_slot` from a single declaration grouped by context. Preserve the existing action order, descriptions, feature gates, and binding mappings.
GitOrigin-RevId: 182e937d9642a8b5a4aa787691da793712f29010
## What changed
- Group preferences into Appearance, Notifications, Input, Sessions, and Text selection tabs, with search and links to existing theme, status line, terminal title, and keyboard editors.
- Persist preference changes to the selected local configuration file, apply supported changes immediately, and show save errors, configuration overrides, and restart requirements in the panel.
- Add a delayed notification test and controls for notification timing while preserving custom event filters.
- Add `tui.copy_on_select_clear_selection`, disabled by default, to clear transcript selection highlights only after confirmed automatic clipboard delivery.
- Keep local configuration editors usable while disconnected and prevent held activation keys or buffered input from triggering actions across editor and reconnect transitions.
## Testing
Add regression tests and rendering snapshots for panel navigation, search, dependency states, editor handoffs, offline persistence, notification timers, custom filter preservation, and confirmed-copy deselection.
GitOrigin-RevId: a16d218046060fcb6e61705a803fcd9297266e6e
## What changed
- Add `tui.keymap.global.leader`, defaulting to `ctrl-x`, and symbolic bindings such as `leader c` that follow the configured prefix. The default prefix yields to existing custom shortcuts and chord prefixes.
- Keep leader shortcut hints open until completion or cancellation, while ordinary chords retain their one-second timeout. Pressing `esc` or repeating the leader cancels the pending shortcut.
- Add leader configuration and a `Use leader...` capture option to `/keymap`, with resolved shortcut labels and conflict validation.
- Cancel pending chords when input targets change, on paste or focus loss, and on mouse actions other than movement.
- Move the default voice mute shortcut from `ctrl-x` to `f9` and update its tests and displayed hints.
GitOrigin-RevId: 35b964cccd2812c73200f0c26b0f19506821df92
## What changed
- Fork the selected conversation and open the new session with `f`, configurable through `agents.fork` in the TUI keymap.
- Move the default search shortcuts to `F3` and `/`, preserving unshadowed defaults when custom bindings conflict.
- Keep queued input on the source conversation while attaching and forking, and require closing an open side conversation before forking another task.
- Expose the fork action in command-center help and the keymap picker.
## Testing
Add regression coverage for queued-input preservation, side-conversation protection, configurable fork shortcuts, metadata editing, disconnected actions, and search fallback bindings. Update help and keymap snapshots.
GitOrigin-RevId: b11ae21ef6a2053609b31ce97c646104f18806a3
## Why
Queued-message edit hints could vary by terminal instead of showing the first configured shortcut. Use the keymap consistently for queued messages and async question navigation.
## What changed
- Make `Shift+Left` the primary shortcut for advancing through questions and editing the last queued message, and `Shift+Right` for navigating back toward the composer. Keep `Alt+Up` and `Alt+Down` as alternatives.
- Remove terminal-specific hint selection and derive hints from the configured keymap, including custom chords and unbound actions.
- Update question footers, queued-input previews, and keymap picker snapshots to reflect the preferred shortcuts.
## Testing
Extend tests to cover both default shortcut pairs, configured shortcut ordering, custom chord hints, and hiding the queued-message edit hint when the action is unbound.
GitOrigin-RevId: e0f60860ef1e81c71ca0fc32369b8cbd12582b47
## What changed
- Handle voice toggle and mute shortcuts in `App`, and route `/voice`, `/voice stop`, and `/voice mute` through thread-scoped events that ignore requests for a different current thread.
- Allow function-key voice toggle bindings and chords beyond chat, including transcript browsing and search, while preserving existing surface bindings and raw key capture.
- Exit transcript browsing when toggling voice, avoid matching completed chords again, and preserve startup submission handling before dispatch.
## Testing
Add regression coverage for voice chords outside chat, binding conflicts, key capture, transcript browsing, mute dispatch, and startup submission cancellation with draft preservation.
GitOrigin-RevId: c4d110ca8a2e1840247a7fe84cd69c6b7cdb36d7
## What changed
Remove trailing periods from concise built-in option descriptions and disabled-option explanations, and simplify wording across TUI menus. Share the built-in permission preset descriptions between permission pickers.
Document the convention in `codex-rs/tui/styles.md`, including normal punctuation for descriptions with multiple sentences and preservation of externally supplied descriptions.
## Testing
Update menu assertions and rendering snapshots for the revised copy and line wrapping.
GitOrigin-RevId: 3231d25484178452ab001af5ddc982460d14f94a
## Why
Keep diagnostics accessible without adding warning rows to the live conversation or changing the composer layout.
## What changed
- Show a deduplicated warning count in the passive footer, yielding to interactive hints.
- Open warning details with `F2`, `/warnings`, or a click on the warning notice. Support navigation, scrolling, and copying individual diagnostics while preserving the draft.
- Retain startup, runtime, MCP, and deprecation diagnostics in the full transcript. Group MCP details by server and preserve warnings during replay.
- Respect existing custom bindings and chord prefixes when enabling `F2`.
- Show an immediate explanation when `/pets` is unavailable.
## Testing
Add regression tests and snapshots for warning counts, draft preservation, viewer navigation and copying, narrow layouts, terminal scrollback, and keybinding conflicts.
GitOrigin-RevId: 2bc586430da60347cfbaa5bf128bc48f7f9dc777
## Why
Composer suggestions and transient hints should preserve the draft and transcript context. Submitting a local command while reading older history should reveal its output.
## What changed
- Separate persistent status from transient footer hints in the owned transcript, sharing layout calculations for rendering, measurement, and cursor placement.
- Overlay command and mention suggestions on history without moving the composer; hide retained suggestions while transcript interactions own input.
- Show responsive, grouped shortcut help above the composer and let `Esc` dismiss it before interrupting a task or navigating history.
- Resume transcript following for submissions, slash commands, and last-response copy results while preserving the reading position during background updates.
- Reset transcript interaction state after prompt reverts and refresh retained usage information without rewriting terminal history.
## Testing
Add regression tests and snapshots for popup placement, clipped layouts, footer focus, shortcut dismissal, local-command scrolling, prompt reverts, and pagination while browsing prompts.
GitOrigin-RevId: 890147313d53f050503165a57610c381ffb93ef5
## What changed
- Add incremental, case-insensitive literal search across transcript details, loading older history as needed. Use `F3` to start Find, or `/` in the transcript pager, and navigate matches in either direction. Closing Find restores the previous presentation and reading position.
- Add clickable activity detail controls and `F4` keyboard focus for inspecting individual activity groups in the owned transcript. Preserve expansion state as live activity becomes history.
- Expose configurable `global.find_transcript`, `global.focus_activity`, and `pager.find` bindings under `tui.keymap`. Let new defaults yield to existing custom bindings and show available completions for pending chords.
## Testing
Add regression coverage for Unicode matching, bounded scanning, paginated and changing history, selection during search, composer input isolation, activity controls, and custom shortcut conflicts.
GitOrigin-RevId: 5bcbcdfbca7c5c296c635ec9b079ccd7a908e336
## What changed
- Remove the legacy selection-list appearance and use shared full-width selection, filled tabs, wrapped hints, and separate overflow rows throughout.
- Give resume and fork pickers separate toolbar and search rows. Collapse spacing on short screens, keep the focused toolbar control visible on narrow screens, and prioritize labeled primary actions in the footer.
- Apply shared selection styling and contrast-aware text colors to session rows and metadata. Clear inherited selection colors and reversal from the transcript loading overlay.
- Preserve clipped-header notices alongside results in small approval dialogs.
## Testing
Add rendering assertions and snapshots for session selection contrast, reversed selection, loading overlay styles, compact metadata and action labels, and keyboard-focused toolbar visibility. Extend approval clipping snapshots to shorter terminal heights.
GitOrigin-RevId: 6e34b14f5528baf33e97ff6cf746107a1bbe69ab
## Why
Menu layouts and hints vary across TUI flows, and mismatched measurement and rendering widths can clip subsequent choices when descriptions wrap.
## What changed
- Apply shared picker styling across selection menus, with stable columns, descriptions hidden when space is tight, and compact hints derived from configured key bindings.
- Measure rows at their actual rendering width, including caller insets, so wrapped options receive enough space.
- Wrap model menu headers and shortcut capture content, and use the shared panel surface for shortcut capture.
- Indicate clipped headers in non-searchable menus and show the configured `view all` shortcut only when the view supplies one.
## Testing
Add regression tests and snapshots for wrapping boundaries, narrow picker layouts, configured selection and cancellation keys, and clipped approval headers. Verify that copy/export actions retain complete payloads and composer drafts.
GitOrigin-RevId: 8416bcd3c66b6cd15db3f9c1804f5f005b7964c1
## Why
Theme colors and dimmed text can lose contrast against terminal and shaded backgrounds. Pickers also need to keep controls and the selected result visible when space is limited.
## What changed
- Add shared blue accents and contrast-aware foregrounds that account for painted backgrounds and terminal color depth, with terminal-default fallbacks for limited palettes.
- Apply readable colors to footer text, status lines, prompt attachment labels, and diff content. Remove dimming from syntax-highlighted diff text so it does not undo contrast correction.
- Use compact shortcut labels such as `ctrl+c`, emphasize complete key combinations, and separate composer footer actions with ` · `.
- Add an opt-in picker presentation with full-width selection, filled tabs, separate overflow indicators, and navigation based on visible rows. Enable it for `/keymap`, reserving result space to keep controls stable across filtering and tab changes.
## Testing
Add regression tests and snapshots for contrast after palette conversion, shaded diff backgrounds, shortcut typography, picker resizing and pagination, Unicode tab truncation, and stable `/keymap` geometry.
GitOrigin-RevId: f3c71879d3bcc4e3b29d70e63cf377dea5914916
## What changed
- Bind `F8` to start or stop a voice conversation through the existing voice toggle handler, preserving its start guards and the composer draft.
- Expose `tui.keymap.chat.toggle_voice` in the configuration schema and keymap picker, with support for remapping, unbinding, and key chords.
- Let the default yield to existing `F8` bindings and overlapping chord prefixes, and validate explicit bindings against shortcut conflicts and reserved text input.
- Handle the shortcut only on key presses when no modal or popup is active.
## Testing
Add tests for default and custom bindings, conflicts, chord dispatch, live remapping and unbinding, draft preservation, start guards, and popup and key-event handling. Add a snapshot for the voice shortcut editor.
GitOrigin-RevId: e5e373e8eefa89bec4d5cbdca801616e312134b5
## What changed
- Add a configurable `new_worktree` action, bound to `w`, for local sessions with worktree support enabled.
- Create the worktree from the cached project default branch, preferring remote `HEAD` and falling back to conventional `main` or `master` refs without fetching. Preserve the selected subdirectory and source checkout edits.
- Start and bind a blank session in the new worktree, preserving the selected approval reviewer without sending an initial turn.
- Show creation progress, pause conflicting actions, clean up unclaimed clean worktrees, and report retained checkout paths when session startup fails. Clear pending creation state on reconnect.
## Testing
Add coverage for default-branch selection, source checkout preservation, session ownership and approval settings, cleanup, startup failures, reconnect state, and busy-state rendering. Extend Git environment isolation coverage and test unrelated non-UTF-8 refs.
GitOrigin-RevId: 771ddc12d04dbf0d12e77e9c96c8386cf31e67c5
## What changed
- Replace the inline task composer with a session list: `n` opens a blank session in the selected checkout without sending an initial turn or interrupting running agents.
- Use single-letter action shortcuts and `Enter` to open a session. `Esc` cancels search or rename without closing the list; `Ctrl+C` quits from the list.
- Load destination settings for new sessions while carrying over explicit permission choices. Retain blank sessions and their drafts across navigation until the first turn.
## Testing
Update tests and snapshots for command center navigation, shortcuts, blank draft restoration, destination defaults, permission carryover, and directory trust.
GitOrigin-RevId: bddd04fdbe6ac2f5b7bd70293fd04f673b97ba02
## What changed
- Cycle task grouping through project, status, and model with `Ctrl+S`, and show the active grouping in the footer.
- Group tasks by model with the most recently updated tasks first within each group. Use `Unknown` for missing or empty model names.
- Display the model in task details and refresh it when thread settings change.
- In model grouping, dispatch new tasks without inheriting the selected task's working directory, matching status grouping.
## Testing
Add coverage for model grouping, selection preservation, navigation, and new-task dispatch across grouping modes. Update snapshots for model details and grouping hints.
GitOrigin-RevId: 429cf61c1e7438ba3b2f989d3ed14e12545856f7
## What changed
- Add `Ctrl+E` to archive the selected task and its child agents, and `Delete` to permanently delete their history. Both actions require confirmation, with Cancel selected by default.
- Expose `agents.archive` and `agents.delete` in keymap configuration and the shortcut picker. Default bindings yield to existing custom bindings and chords.
- Show progress while requests run, keeping rendering responsive and blocking task switching. Refresh overview state afterward and keep the dashboard open when the current task is removed.
- Report failures and preserve the current attachment and draft when a rejected operation leaves the task loaded.
## Testing
Add coverage for confirmation and cancellation, active and background task removal, child-agent attachments, stale refresh invalidation, failure recovery, and draft preservation. Add progress input-isolation tests, shortcut conflict tests, and snapshots for confirmation, errors, progress, and keymap rendering.
GitOrigin-RevId: b327bb8834699d0058f9ffb903ace525ae270500
## What changed
- Add `Ctrl+W` to hide the selected task without stopping it. Hidden tasks stay hidden through activity and metadata refreshes until explicitly resumed or the TUI restarts.
- Expose `agents.hide` in keymap configuration and the shortcut picker, and let the default binding yield to existing custom shortcuts.
- Wrap overview footer hints while keeping shortcuts and their labels together when they fit.
## Testing
Add coverage for hiding filtered tasks across statuses, visibility through activity and refreshes, explicit resume, existing keybinding compatibility, and custom chord footer rendering at narrow widths.
GitOrigin-RevId: 980726e1095b8d5bad8901be919decdde8c0f925
## Why
Voice mute used a hard-coded `Ctrl+X` shortcut and footer hint, so keymap customization could not change or disable it.
## What changed
- Wire `tui.keymap.chat.toggle_voice_mute` into runtime keybindings and the keymap picker, supporting custom keys, chords, and unbinding.
- Keep `Ctrl+X` as the default, but let existing configured shortcuts and overlapping chord prefixes take precedence. Validate explicitly configured mute bindings for conflicts.
- Activate voice chords only when the microphone shortcut is available, excluding pagers and overlays.
- Refresh the voice footer when bindings change, showing the configured shortcut or `/voice mute` when unbound.
## Testing
Add regression tests for binding resolution, conflicts, voice chord context, and live keymap updates. Add footer snapshots covering custom keys, chords, and unbinding in muted and listening states at wide and narrow widths.
GitOrigin-RevId: ec9385f3956aa268bba34dcf2cc2b0c92a31bfec
## What changed
- Display questions from live agent messages with a collapsed question count and an expandable answer editor.
- Support navigating, answering, queueing, and skipping questions while preserving the main composer draft. Expose question navigation and skip actions in the keymap picker.
- Route answers through existing input delivery and consume them only after an accepted send or queue operation. Keep questions editable while disconnected, with delivery and skipping disabled.
## Testing
Add tests for answer delivery, queued answers, retained drafts, disconnected editing, Vim undo, buffered input, constrained layouts, and question shortcut descriptions.
GitOrigin-RevId: 084b54dceb8c0100aefbf9f0b7897bf8d26eac47
## What changed
- Introduce an async-question editor component with per-question drafts, navigation, replay deduplication, and submit or queue handling using the shared composer.
- Add bounded `AnsweredQuestion` framing that truncates question text at a UTF-8 boundary and flattens line breaks before prepending it to an answer.
- Add `prompt_stack_back` and `skip_question` keybinding actions and the `tui.question_esc_back` setting. Normalize `Ctrl+]` and `Ctrl+5` for key matching and conflict detection, and let default question shortcuts yield to explicit bindings.
- Flush buffered typing in both the main composer and the covering view so background input cannot keep the draw loop waiting.
The async-question component is not yet connected to the TUI event flow.
## Testing
Add regression coverage for bounded Unicode question framing, question-shortcut conflicts, and paste-buffer flushing in background and covering editors.
GitOrigin-RevId: 4098043cf588ddafc05c27505645495edd690cb9
## What changed
- Add a configurable `agents.resume` action, bound to `Ctrl+O` by default, that opens the session resume picker from the agent command center.
- Preserve command-center state when the picker is cancelled, and preserve per-thread composer and queued-input state when switching sessions.
- Keep resume failures within the command-center flow and wrap footer shortcuts on narrow terminals.
## Testing
- Add coverage for picker cancellation, active-session selection, resume failures, per-thread input restoration, custom keybindings, and narrow footer layout.
GitOrigin-RevId: 59159f838a0c642200cd164e3af45b0971d29bf8
## What changed
- Add Vim Replace mode, entered with `R`, which overwrites graphemes and appends at the end of a line.
- Restore overwritten text with Backspace and record replace edits for undo and dot-repeat.
- Preserve composer behavior for attachments, completions, paste bursts, history previews, and external editor imports while replacing text.
- Expose `vim_normal.enter_replace_mode` in the configurable TUI keymap.
## Testing
- Add coverage for grapheme replacement, Backspace recovery, dot-repeat, custom bindings, atomic attachments, completions, paste handling, and history interactions.
GitOrigin-RevId: cb04e3adcce013c1eb7b82c994b00e944310c481
## What changed
- Add a bounded redo stack for complete composer drafts, including paste payloads and image attachments. `Ctrl+R` now reapplies the last undone edit in Vim normal mode, while new edits clear stale redo history.
- Add the configurable `vim_normal.redo` action to the keymap schema and picker. Preserve reverse prompt-history search in Vim insert mode and non-Vim mode, and honor explicitly configured bindings.
- Keep pending edit snapshots outside the shared undo/redo byte budget so canceled commands cannot evict committed history.
## Testing
- Cover grouped edits, Vim searches, direct draft changes, history limits, empty redo stacks, and custom or unbound shortcuts.
GitOrigin-RevId: 0cf5bb376ff865ddc0a77705dcb322ef6b57b3a3
## Why
Composer drafts include attachments, mention targets, and deferred paste payloads in addition to visible text. Vim undo needs to restore that complete state as a single edit.
## What changed
- Add bounded, draft-level Vim undo history, with `u` as the configurable default binding in normal mode.
- Group complete Vim commands and insert sessions into undo steps, including direct composer changes such as pastes and attachments.
- Preserve undo, repeat, and search state when a reverse-history preview is canceled, and start fresh history when another prompt is accepted.
## Testing
- Cover grouped edits, custom bindings, history and search interactions, attachments, and large paste payloads.
GitOrigin-RevId: 12ecdb3c34a2d66f5d856aa2f82dc15bd91b230b
## What changed
- Add draft-local forward and backward literal search with `/` and `?`, plus
wrapped repeat navigation with `n` and `N`.
- Support search motions after delete, change, and yank operators, while keeping
queries separate from the draft and skipping atomic elements and partial
grapheme matches.
- Render and edit the query in the composer footer, highlight matches, and add
configurable `tui.keymap.vim_search` bindings to the keymap picker and schema.
## Testing
- Cover navigation, wrapping, operator composition, repeat behavior, Unicode
graphemes, atomic elements, query editing, paste handling, and rendering.
GitOrigin-RevId: 087b080ff8fd74e48456c6b899c07ea5eed38e0c
## What changed
- Add `gg` and `G` motions to jump to the first and last buffer lines.
- Support the motions with delete, change, and yank operators, including dot-repeat for edits.
- Expose normal-mode and operator-motion bindings in the configurable keymap while preserving conflicting user bindings.
## Testing
- Cover buffer jumps, operator combinations, repeat behavior, chord routing, and custom remapping.
GitOrigin-RevId: 24a9178cf7964053aaf9a8cd268c5434dda0778e
## What changed
- Add line-local `f`, `F`, `t`, and `T` motions to Vim normal mode.
- Support the motions with `c`, `d`, and `y`, including dot-repeat for changes.
- Expose separate configurable normal-mode and operator-motion bindings, while preserving existing custom keymaps that use the new defaults.
- Keep character targeting aligned to extended grapheme boundaries and skip embedded composer elements.
## Testing
- Cover forward and backward motion and operator ranges, missing and adjacent targets, cancellation, dot-repeat, custom bindings, shifted terminal key events, grapheme clusters, and embedded elements.
GitOrigin-RevId: 2610cf9a13538d9ae9b890c01417ca25316c1d60
## What changed
- Bind `.` in Vim normal mode to repeat the last complete edit.
- Record semantic delete, change, replace, paste, and insert-mode actions so repeats preserve motions, text objects, inserted text, and editor actions across keymap changes.
- Expose `vim_normal.repeat_last_change` in the configurable keymap and keymap picker, including conflict handling for existing custom bindings.
## Testing
- Add coverage for repeating deletes, replacements, complete changes, pasted and literal text, insert-mode editor actions, custom bindings, unavailable motions, and cleared buffers.
GitOrigin-RevId: 3213df964811e7902377ff1d93641e59f4037914
## What changed
- Add unbound `previous_permission_mode` and `next_permission_mode` actions to
`tui.keymap.chat` so users can configure shortcuts that cycle through the
available built-in permission modes.
- Apply shortcut selections only to the active session, without writing them
to `config.toml`, and report update failures in the transcript.
- Exclude modes disallowed by managed requirements or platform safety checks,
reject printable-key bindings, and ignore these bindings in project config.
## Testing
- Cover mode cycling, unavailable modes, session-only updates, server errors,
stale threads, keymap validation, and project-config sanitization.
GitOrigin-RevId: c3cfdf1e732b7b7bfe8f53fcac19a37e593bbfab
## What changed
- Add the configurable `vim_normal.replace_char` action, bound to `r` by default, to replace the grapheme under the cursor while remaining in normal mode.
- Support change-operator motions such as `cw`, `c$`, `cj`, and `ck`, plus the repeated `cc` command for changing the current line.
- Let `Esc` cancel a pending replacement before it reaches composer-level handling.
- Preserve existing custom Vim bindings and chord prefixes when introducing the new default.
## Testing
- Cover replacement, grapheme boundaries, remapping and unbinding, change motions, cancellation, keymap conflicts, and keymap picker snapshots.
GitOrigin-RevId: 98feb4eeb57142c37adb73abfe58d1f703b9270d
## What changed
- Add `tui.keymap.global.open_agents`, defaulting to `alt-a`, to open the shared agents overview.
- Add an `agents` keymap context for search, new task, rename, stop, and grouping actions.
- Expose the new actions in the keymap picker and render dashboard hints from the resolved bindings.
- Preserve existing custom `alt-a` bindings by disabling the new default when it would conflict.
## Testing
- Cover remapping, reserved keys, conflicts, and compatibility with existing bindings.
- Verify that configured dashboard shortcuts act on the selected filtered task.
GitOrigin-RevId: 98c48a332e06cb96dbf0e59647ce7959d45b9988
## What changed
- Accept two-stroke bindings such as `ctrl-x ctrl-s` in TUI keymap configuration while preserving arrays as alternative bindings.
- Route chords through the active TUI context, show pending and configured chord hints, and cancel pending chords on `esc`, context changes, or a one-second timeout.
- Extend `/keymap` to capture, add, replace, and display key chords.
- Reject chords that conflict with active single-key bindings, overlapping-context chords, or reserved terminal shortcuts.
## Testing
- Add coverage for chord parsing, validation, matching, timeout and cancellation behavior, context dispatch, key capture, and rendered shortcut hints.
GitOrigin-RevId: dfdede03f518d4936ad8621ebf5537026f2b282e
## What changed
- Add a configurable `toggle_side_conversation` TUI action, bound to `ctrl-/` by default, to switch between a side conversation and its parent without closing either.
- Show the active binding in the footer and distinguish switching from closing with `ctrl-c`.
- Allow starting a replacement side conversation from the parent, while cleaning up the previous side thread and preserving it if cleanup fails.
- Clean up retained side conversations when shutting down the current thread.
## Testing
- Cover shortcut remapping, conflicts, and compatibility with existing `ctrl-/` and `ctrl-7` bindings.
- Cover side-thread replacement and footer states for both the parent and side conversation.
GitOrigin-RevId: a621c21e1c45ba73197d59750b2e05efa5ee1081
## Summary
- add Vim normal-mode `s` support to substitute the character under the
cursor and enter insert mode
- fix Vim normal-mode `o` so opening below the final line moves the
cursor onto the new blank line
- update keymap config/schema and keymap picker snapshots for the new
action
## Validation
- `just fmt`
- `just write-config-schema`
- `just test -p codex-config`
- focused `just test -p codex-tui` coverage for the Vim `s` and `o`
behavior, keymap conflict handling, and keymap picker snapshots
- `cargo insta pending-snapshots --manifest-path tui/Cargo.toml`
- `git diff --check`
## Notes
A full `just test -p codex-tui` run still has two unrelated Guardian
feature-flag failures in this checkout:
-
`app::tests::update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
-
`app::tests::update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`
## Why
Interrupting an active turn is currently fixed to `Esc`, which is easy
to hit accidentally and cannot be customized through `/keymap`. This
gives users a less accidental binding while preserving the existing
default.
## What Changed
- Adds `tui.keymap.chat.interrupt_turn` to `/keymap`, defaulting to
`esc` and supporting remapping or unbinding.
- Uses the configured interrupt binding for running-turn status, queued
steer interruption, and `request_user_input`, including the visible
hints.
- Preserves local `Esc` behavior for popups, Vim insert mode, and
`/agent` editing while validating conflicts with fixed/backtrack and
request-input navigation bindings.
- Adds behavior and snapshot coverage for remapped interruption paths.
## How to Test
1. Run Codex and open `/keymap`, then set **Interrupt Turn** to `f12`.
2. Start a turn and confirm `Esc` no longer interrupts it while `f12`
does; the running hint should display `f12 to interrupt`.
3. Queue a steer while a turn is running and confirm the preview
displays `f12`; pressing it should interrupt and submit the steer
immediately.
4. Trigger a `request_user_input` prompt and confirm its footer uses
`f12`; with notes open, `Esc` should still clear notes while `f12`
interrupts the turn.
5. Clear the Interrupt Turn binding and confirm the key-specific
interrupt hint is removed while `Ctrl+C` remains available.
Targeted validation:
- `just write-config-schema`
- `just fix -p codex-config`
- `just fix -p codex-tui`
- `just fmt`
- `just argument-comment-lint-from-source -p codex-config -p codex-tui`
- `just test -p codex-config`
- `cargo insta pending-snapshots --manifest-path tui/Cargo.toml`
- `just test -p codex-tui keymap_setup::tests`
- `just test -p codex-tui` (fails in two pre-existing guardian
feature-flag tests unrelated to this diff; the intentional picker
snapshot updates were reviewed and accepted)
## Why
Vim mode currently supports some normal-mode operators and motions, but
common text-object combinations like `ciw`, `daw`, `di(`, and
quote/bracket variants are still missing. That makes the composer feel
incomplete for users who expect operator + text object editing to work
inside prompts.
Closes#21383.
## What Changed
- Add Vim pending-state support for operator/text-object sequences.
- Add `c` as a normal-mode operator for text objects, so combinations
like `ciw` delete the object and enter insert mode.
- Support word, WORD, delimiter, and quote text objects:
- `iw`, `aw`, `iW`, `aW`
- `i(`, `a(`, `i)`, `a)`, `ib`, `ab`
- `i[`, `a[`, `i]`, `a]`
- `i{`, `a{`, `i}`, `a}`, `iB`, `aB`
- `i"`, `a"`, `i'`, `a'`, `i\``, `a\``
- Add configurable keymap entries and keymap picker coverage for the new
Vim text-object context.
- Regenerate the config schema and update keymap picker snapshots.
## How to Test
Manual smoke test:
1. Start Codex with Vim composer mode enabled.
2. Type a draft such as:
```text
alpha beta gamma
call(foo[bar], {"x": "hello world"})
say "one \"two\" three" now
```
3. Put the cursor on `beta`, press `ciw`, and confirm `beta` is removed
and the composer enters insert mode.
4. Escape back to normal mode, put the cursor on `gamma`, press `daw`,
and confirm `gamma` plus surrounding whitespace is removed.
5. Put the cursor inside `foo[bar]`, press `di[`, and confirm only `bar`
is removed.
6. Put the cursor inside `call(...)`, press `da(`, and confirm the whole
parenthesized section is removed.
7. Put the cursor inside the quoted text, press `ci"`, and confirm the
quote contents are removed and insert mode starts.
8. Verify cancellation does not edit text: press `d` then `Esc`, and
press `d` then `i` then `Esc`.
Targeted tests:
- `cargo test -p codex-tui --lib vim_`
- `cargo nextest run -p codex-tui keymap_setup::tests`
Additional local checks:
- `just write-config-schema`
- `just fmt`
- `just fix -p codex-tui`
- `git diff --check`
- `cargo insta pending-snapshots --manifest-path tui/Cargo.toml`
Local full-suite note: `just test -p codex-tui` ran to completion. The
keymap snapshot failures were expected and accepted. Two unrelated
guardian feature-flag tests still fail locally:
-
`app::tests::update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
-
`app::tests::update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`
`just argument-comment-lint` is currently blocked locally by Bazel
analysis before the lint runs because `compiler-rt` has an empty
`include/sanitizer/*.h` glob in the local Bazel cache. The touched Rust
diff was manually inspected for opaque positional literals.
## Why
The TUI Vim composer currently diverges from normal Vim editing in two
common workflows: pressing `e` repeatedly can remain stuck at an
existing word end, and normal mode does not support `C` for changing
through the end of the line. The existing `D` behavior also removes the
newline when the cursor is already at the line boundary, which makes the
new `C` action and existing deletion action surprising in multiline
prompts.
Closes#23926.
Closes#24238.
## What Changed
- Make normal-mode `e` advance from the current word end to the next
word end, including for operator motions such as `de`.
- Add configurable Vim normal-mode `change_to_line_end` behavior, bound
to `C` by default, which deletes to the end of the current line and
enters Insert mode.
- Keep the newline intact when `D` or `C` is pressed at the end-of-line
boundary.
- Add regression coverage for repeated `e`, `de`, `C`, and the multiline
`C`/`D` boundary behavior.
- Regenerate the config schema and update the keymap picker snapshots
for the new Vim action.
## How to Test
1. Run Codex with Vim composer mode enabled:
```bash
cd codex-rs
cargo run --bin codex -- -c tui.vim_mode_default=true
```
2. Enter `alpha beta gamma`, press `Esc`, `0`, then press `e`
repeatedly.
Confirm the cursor advances through the ends of `alpha`, `beta`, and
`gamma`.
3. Enter `hello world`, press `Esc`, `0`, `w`, then `C`.
Confirm `world` is deleted and the composer enters Insert mode.
4. Enter a multiline prompt with `hello` above `world`, press `Esc`,
`k`, `$`, and then `D`.
Confirm the newline is preserved and the two lines do not join.
5. At the same boundary, press `C` and type `!`.
Confirm the composer enters Insert mode and yields `hello!` above
`world`, preserving the newline.
Targeted automated verification:
- `just fix -p codex-tui`
- `just argument-comment-lint-from-source -p codex-tui -p codex-config`
- `cargo insta pending-snapshots` reports no pending snapshots.
- `just test -p codex-tui` validates the new Vim and keymap snapshot
coverage, but the command remains red due to two reproducible unrelated
failures in `app::tests::update_feature_flags_disabling_guardian_*`.
## Validation Note
The workspace-wide `just argument-comment-lint` form is currently
blocked during Bazel analysis by the existing LLVM `compiler-rt` missing
`include/sanitizer/*.h` failure; package-scoped source linting for the
changed Rust crates passed.
## Why
Picker-style UI in the TUI has accumulated a mix of hardcoded navigation
keys. Some lists supported page movement, some did not; some accepted
Vim-like keys, while others only accepted arrows; and tabbed or
horizontally adjustable pickers had no shared keymap action for
left/right movement.
This PR makes picker/list navigation consistent and configurable so
users can rely on the same defaults across the TUI.
## What Changed
- Adds shared list keymap actions for:
- vertical movement: `move_up`, `move_down`
- horizontal movement: `move_left`, `move_right`
- paging and jumps: `page_up`, `page_down`, `jump_top`, `jump_bottom`
- Adds defaults:
- Up/down: arrows, `Ctrl+P/N`, `Ctrl+K/J`, and plain `k/j` where text
input is not active
- Page up/down: `PageUp/PageDown` and `Ctrl+B/F`
- First/last: `Home/End`
- Left/right: `Left/Right` and `Ctrl+H/L`
- Wires the shared list keymap through picker and list surfaces
including session resume, multi-select, tabbed selection lists,
settings-style lists, app-link selection, MCP elicitation,
request-user-input, and the OSS selection wizard.
- Keeps search behavior intact by reserving printable characters for
query text in searchable pickers.
- Updates keymap setup actions, config schema, snapshots, and focused
coverage for the new list actions.
## How to Test
1. Start Codex from this branch and open the session picker, for example
with an existing session history.
2. In the session list, verify that `Ctrl+J/K` moves the selection
down/up.
3. Verify that `Ctrl+F/B` pages down/up and `Home/End` jumps to the
first/last visible session.
4. Type printable search text such as `j` or `k` and confirm it updates
the query instead of navigating.
5. Focus a picker control that changes values horizontally, such as a
session picker toolbar control, and verify `Ctrl+H/L` changes the
focused value like left/right arrows.
Targeted tests run:
- `cargo test -p codex-tui keymap::tests::`
- `cargo test -p codex-tui keymap_setup::tests::`
- `cargo test -p codex-tui horizontal_list_keys`
- `cargo test -p codex-tui page_and_jump_navigation_use_list_keymap`
- `cargo test -p codex-tui ctrl_h_l_move_provider_selection`
- `cargo test -p codex-tui scroll_state::tests`
- `cargo test -p codex-tui
switching_tabs_changes_visible_items_and_clears_search`
- `cargo test -p codex-tui toggle_sort_key_reloads_with_new_sort`
Also ran `just write-config-schema`, `just fmt`, `just fix -p
codex-tui`, `just argument-comment-lint`, and `git diff --check`.
Note: `cargo test -p codex-tui` was attempted and still aborts in the
pre-existing
`tests::fork_last_filters_latest_session_by_cwd_unless_show_all` stack
overflow, which is unrelated to this branch.
## Why
On light terminal backgrounds, selected rows in several TUI pickers were
rendered with the same bright cyan accent used on dark themes. Against
the light menu surface, that made the current selection hard to
distinguish at a glance.
<table><tr>
<td>
<p align="center">Before</p>
<img width="1109" height="864" alt="SCR-20260509-nmtz"
src="https://github.com/user-attachments/assets/b31ce0d0-19c2-4bdd-a220-7acc77bd8e8e"
/>
</td>
<td>
<p align="center">After</p>
<img width="1164" height="844" alt="SCR-20260509-nmox"
src="https://github.com/user-attachments/assets/7b3fede0-4739-4a9f-a979-cdbb7451841f"
/>
</td>
</tr></table>
## What changed
- Added a shared background-aware accent style for active/selected TUI
controls.
- Use a darker cyan-family accent on light backgrounds while preserving
the existing bright cyan accent on dark or unknown backgrounds.
- Reused that accent across shared picker rows and the custom
selection-like surfaces that had drifted separately: picker tabs, hooks
browsing, external-agent migration choices, and /keymap affordances.
- Added focused tests for the light/dark accent rule and rendered
selected-row styling.
## How to Test
1. Start Codex in a terminal using a light background theme.
2. Type `/` to open the slash-command picker and move the selection
through a few rows.
3. Confirm that the selected row is visibly colored with strong contrast
instead of blending into the popup surface.
4. Open `/keymap` and confirm the active tab, selected rows, and picker
hint accents use the same light-theme accent treatment.
5. In a dark terminal theme, repeat the slash-picker check and confirm
the existing bright cyan selection styling is preserved.
Targeted tests:
- `cargo test -p codex-tui accent_style_uses_`
- `cargo test -p codex-tui selected_rows_use_the_shared_accent_style`
- `cargo test -p codex-tui
selected_event_rows_use_the_shared_accent_style`
Notes:
- A full `cargo test -p codex-tui` run reached the end of the suite but
hit an unrelated existing stack overflow in
`tests::fork_last_filters_latest_session_by_cwd_unless_show_all`.