Keyboard shortcuts
A terminal agent’s input line looks like a text box and behaves like a readline-descended line editor. Ctrl+A doesn’t select all, it moves to the start of the line. Ctrl+X doesn’t cut. Nothing errors - you just get a different feature, silently.
Everything below was read from each tool’s own source, binary or docs, and is dated. 489 bindings, 6 tools, 8 surfaces.
The test: if you keep reaching for the same familiar key and the agent does something else, look up the binding by intent before changing your terminal or editor.
Everything on this page - the tables, the collisions, the full reference - filters to what you pick above.
The tasks you’ll actually do
Section titled “The tasks you’ll actually do”| Task | Claude Code | Codex | OpenCode | Pi | CursorIDE | Cursor | CopilotIDE | Copilot |
|---|---|---|---|---|---|---|---|---|
| Stop the agent | Esc | Esc | Esc | Esc | - | - | - | Esc |
| Newline without submitting | Ctrl+J | Ctrl+J | Ctrl+J | Ctrl+J | - | Ctrl+J | - | - |
| Newline (alternative) | - | Shift+Enter | Shift+Enter | Shift+Enter | - | Shift+Enter | - | Shift+Enter |
| Paste an image | Ctrl+V | Ctrl+V | - | Ctrl+V | - | - | - | - |
| Delete to line start | Ctrl+U | Ctrl+U | Ctrl+U | Ctrl+U | - | - | - | Ctrl+U |
| Delete to line end | Ctrl+K | Ctrl+K | Ctrl+K | Ctrl+K | Ctrl+K | - | - | Ctrl+K |
| Delete previous word | Ctrl+W | Ctrl+W | Ctrl+W | Ctrl+W | Ctrl+W | - | - | Ctrl+W |
| Paste back what you deleted | Ctrl+Y | Ctrl+Y | - | Ctrl+Y | - | - | - | - |
| Jump to line start | Ctrl+A | Ctrl+A | Ctrl+A | Ctrl+A | - | - | - | Ctrl+A |
| Jump to line end | Ctrl+E | Ctrl+E | Ctrl+E | Ctrl+E | Ctrl+E | - | - | Ctrl+E |
| Search past prompts | Ctrl+R | Ctrl+R | - | - | - | - | - | Ctrl+R |
| Open $EDITOR | - | Ctrl+G | - | Ctrl+G | - | - | - | Ctrl+X then e |
| Cycle mode | Shift+Tab | Shift+Tab | Shift+Tab | Shift+Tab | Shift+Tab | Shift+Tab | - | Shift+Tab |
| Quit | Ctrl+D | Ctrl+D | Ctrl+D | Ctrl+D | - | Ctrl+D | - | Ctrl+D |
| Suspend to shell | Ctrl+Z | Ctrl+Z | Ctrl+Z | Ctrl+Z | - | - | - | Ctrl+Z |
Three things worth pulling out of that table, if you turn all six on:
Escis the stop key in the terminal agents here. NotCtrl+C. This is the strongest convergence in the set - but it holds for the CLI surfaces, not the editor ones. Inside an IDE,Escis already spoken for: in Cursor it can accept a suggested terminal command, and in VS Code it dismisses an inline suggestion. Check which surface you are actually typing into.Shift+Tabcycles a mode everywhere, but not the same mode - permission modes in Claude Code, collaboration mode in Codex, the agent in OpenCode, thinking level in Pi, agent modes in Cursor, session modes in Copilot CLI.Ctrl+Jinserts a newline in every TUI agent here;Shift+Entersometimes can’t.Shift+Enterdepends on your terminal being able to transmit it.Ctrl+Jis the newline character, so it survives the trip. In Cursor and Copilot the newline is the host editor’s to define, not the agent’s. IfShift+Enterkeeps submitting, that’s your terminal, not the agent.
Keys that don’t mean what you think
Section titled “Keys that don’t mean what you think”| Key | You expect | What it actually does |
|---|---|---|
| ctrl+kcan lose work | In stock VS Code, Cmd/Ctrl+K is a chord prefix (e.g. Cmd+K Cmd+S for Keyboard Shortcuts, Cmd+K Cmd+C to comment a block, Cmd+K Cmd+F to format selection, etc.) - pressing it alone does nothing visible, it just arms the second key. |
|
| ctrl+asilently different | Select all text in the current field |
|
| ctrl+ccan lose work | Copy the current selection to the clipboard |
|
| ctrl+dcan lose work | No universal GUI meaning; closest common expectation is 'do nothing' or, in a browser, 'bookmark this page' |
|
| ctrl+rsilently different | Reload the page, or redo the last undone action, in most GUI apps and browsers |
|
| ctrl+wcan lose work | close tab/window (browsers, many GUI apps) |
|
| ctrl+zcan lose work | Undo the last action |
|
| ctrl+vsilently different | Paste clipboard contents as plain text at the cursor |
|
| ctrl+xsilently different | Cut the current selection to the clipboard |
|
| tabsilently different | Inside any text input/textarea (including VS Code's own webview panels), Tab conventionally either inserts a tab character or moves focus to the next control - it does not change which message is displayed. |
|
| ctrl+bsilently different | toggle the browser's bookmarks bar (most browsers) |
|
| ctrl+isilently different | Cmd/Ctrl+I has no default binding in stock VS Code, but is widely muscle-memorized by GitHub Copilot users as 'open Copilot Inline Chat' (an inline, in-editor AI prompt at the cursor position). |
|
| ctrl+osilently different | open a file |
|
| ctrl+tsilently different | new tab (browser) |
|
| ctrl+ysilently different | In the classic emacs/readline convention this CLI otherwise follows for Ctrl+A/E/U/K/W/B/F/H, Ctrl+Y is 'yank' - paste back the text most recently deleted by Ctrl+U, Ctrl+K, or Ctrl+W |
|
| escapesilently different | Escape is a near-universal 'cancel/dismiss' convention across all editors and OSes - including elsewhere in this same Cursor shortcuts table, where Escape means 'Unfocus field' (Chat) and is commonly used to dismiss dialogs. |
|
Ctrl+Z is the one that generates panic. It is not a crash and your session isn’t gone - the process is stopped in the background. Type fg to bring it back.
Explore it
Section titled “Explore it”Pick a tool, hold a modifier, click a key. Or search by what you’re trying to do - including the key you’d wrongly reach for, so typing ctrl+x or “select all and delete” lands on the correction.
Three things that explain most surprises
Section titled “Three things that explain most surprises”The kill ring is not your clipboard. Ctrl+U and Ctrl+Y are a matched pair inside the editor. Text moved that way cannot be pasted into your browser. To get text out, use your terminal emulator’s own selection and copy. Some tools bind their own key for it: Pi copies the last assistant message with Ctrl+X, Codex copies the last response with Ctrl+O.
Context decides, not the key. In OpenCode, Ctrl+A, Ctrl+D, Ctrl+F and the arrows each appear against several actions and don’t conflict: a managed text-area layer is active only while the prompt has focus and wins there, and the history handler declines the keystroke unless the cursor is already at the buffer edge. When a shortcut “doesn’t work,” focus is usually somewhere you didn’t think it was.
You can rebind almost all of it, by action id. Four tools ship a remappable keymap: Claude Code (~/.claude/keybindings.json), Codex (tui.keymap.*, with an in-app /keymap picker), OpenCode (tui.json, ~140 actions plus a leader key), Pi (~/.pi/agent/keybindings.json). Default keys move between releases; action names rarely do, so write down the action. This also reveals capability no shortcut list shows: Codex ships toggle_vim_mode and toggle_fast_mode as real actions with no default key.
Full reference
Section titled “Full reference”Every binding we have, grouped by where it applies. rl marks bindings inherited from readline rather than implemented by the tool. The last column is how the fact was established: source (read from the implementation), first-hand (run locally), docs.
Claude Codeterminal
Input line
| Keys | Does | Src |
|---|---|---|
| ctrl+l | Force a full terminal redraw, preserving input. In fullscreen rendering, press twice within two seconds to run /clear.chat:clearInput | source |
| ctrl+r | Open reverse history search over previous prompts.rlhistory:search | source |
| ctrl+s | Stash the current prompt text and clear the input. Pressed again on an empty prompt, restores the stashed text, cursor position, and pasted content.chat:stash | source |
| ctrl+vctrl+v (or cmd+v in iTerm2) macOS | Paste an image from the clipboard, inserting a `[Image #N]` chip at the cursor.chat:imagePaste | source |
| esc esc | Double-tap: if the prompt has text, clears it and saves the draft to history (Up recalls it). If the prompt is empty, opens the rewind menu to restore/summarize code and conversation from an earlier point. | docs |
| shift+tab | Cycle permission modes (default/Manual -> acceptEdits -> plan -> any custom modes like auto/bypassPermissions).chat:cycleMode | source |
| option+p (mac) / alt+p (win/linux)option+p / meta+p macOS | Open the model picker.chat:modelPicker | source |
| option+t (mac) / alt+t (win/linux)option+t / meta+t macOS | Toggle extended thinking mode. No effect on Fable 5, which always uses extended thinking.chat:thinkingToggle | source |
| option+o (mac) / alt+o (win/linux)option+o / meta+o macOS | Toggle fast mode.chat:fastMode | source |
| enter | Submit the message.chat:submit | source |
| ctrl+j | Insert a newline without submitting. Works in any terminal without configuration.chat:newline | source |
| ctrl+_ / ctrl+shift+- | Undo last input edit - restores the previous input text and cursor position.rlchat:undo | source |
| ctrl+g / ctrl+x ctrl+e | Open the current prompt in your default text editor ($VISUAL/$EDITOR).rlchat:externalEditor | source |
| ctrl+x ctrl+k | Stop all running background subagents in this session. Press twice within 3 seconds to confirm.chat:killAgents | source |
| ctrl+a | Move cursor to the start of the current logical line (in multiline input).rl | docs |
| ctrl+e | Move cursor to the end of the current logical line (in multiline input).rl | docs |
| ctrl+k | Delete from cursor to end of line. Stores deleted text for pasting (yank buffer).rl | docs |
| ctrl+u | Delete from cursor to line start. Stores deleted text for pasting; repeat to clear across lines in multiline input.rl | docs |
| ctrl+w | Delete the previous word. Stores deleted text for pasting.rl | docs |
| ctrl+y | Paste (yank) text previously deleted with Ctrl+K, Ctrl+U, or Ctrl+W.rl | docs |
| alt+y (after ctrl+y)option+y (after ctrl+y, requires Option-as-Meta) macOS | Cycle through previously deleted (killed) text after a yank.rl | docs |
| alt+boption+b (requires Option-as-Meta) macOS | Move cursor back one word.rl | docs |
| alt+foption+f (requires Option-as-Meta) macOS | Move cursor forward one word.rl | docs |
| up / down (or ctrl+p / ctrl+n) | Move cursor within a multi-row prompt first; once the cursor is on the first/last visual row, navigates command history instead.history:previoushistory:next | source |
| ? | On an empty prompt, toggles the shortcut help panel. With text already in the input, types a literal '?' instead. | docs |
| tab | Accept the current autocomplete suggestion (or place a prompt suggestion into the input).autocomplete:accept | source |
| / | At the start of input, opens the command/skill menu. | docs |
| ! | At the start of input, enters shell mode - runs a command directly and adds its output to context. | docs |
| @ | Trigger file path autocomplete/mention. | docs |
| :name: | Type a full :shortcode: to insert an emoji, or 2+ chars for a suggestion popup. | docs |
| space (hold or tap)space macOS | Voice dictation push-to-talk (hold to record, or /voice tap for tap-to-toggle).voice:pushToTalk | docs |
| esc | In vim editing mode: switch from INSERT or VISUAL back to NORMAL mode. | docs |
| i / I / a / A / o / O / v / V | Vim NORMAL-mode entry points into INSERT or VISUAL modes (insert before/at-line-start/after/at-line-end cursor, open line below/above, char-wise/line-wise visual select). | docs |
| h j k l, w e b, 0 $ ^, gg G, f/F/t/T{char}, ; ,same macOS | Vim NORMAL-mode navigation motions (left/down/up/right, word/end/back-word, line start/end/first-non-blank, buffer start/end, find-char motions, repeat motion). | docs |
| x, dd, D, dw/de/db, cc, C, cw/ce/cb, s, S, yy/Y, yw/ye/yb, p, P, >>, <<, J, u, .same macOS | Vim NORMAL-mode editing operators (delete char/line/to-end/word variants, change line/to-end/word variants, substitute char/line, yank line/word variants, paste after/before, indent/dedent, join lines, undo, repeat last change). | docs |
| iw/aw, iW/aW, i"/a", i'/a', i(/a(, i[/a[, i{/a{same macOS | Vim text objects (inner/around word, WORD, quotes, brackets) usable with d/c/y operators. | docs |
Anywhere
| Keys | Does | Src |
|---|---|---|
| ctrl+c | Interrupt a running operation. If nothing is running, first press clears the prompt input; a second press exits Claude Code.app:interrupt | source |
| ctrl+d | Exit Claude Code. First press shows a confirmation hint, second press within 800ms exits. When the prompt has text, deletes the character after the cursor instead (classic readline forward-delete).app:exit | source |
| ctrl+o | Toggle the verbose transcript viewer (detailed tool usage/execution with timestamps and model per message).app:toggleTranscript | source |
| ctrl+t | Toggle visibility of Claude's to-do checklist (not the /tasks background-task view).app:toggleTodos | source |
| ctrl+b | Background the currently running Bash command/agent task.task:background | docs |
| ctrl+z | Suspend Claude Code to the shell (Unix only). Run `fg` to resume. | docs |
| esc | Interrupt Claude mid-turn (stop the current response/tool call, keeping work done so far), or close an open dialog (e.g. permission prompt) without interrupting.chat:cancel | source |
Transcript / pager
| Keys | Does | Src |
|---|---|---|
| q / ctrl+c / esc | Exit the transcript viewer.transcript:exit | source |
| { / } | Jump to the previous/next user prompt in the transcript, like vim paragraph motion. | docs |
| [ | Write the full conversation to the terminal's native scrollback so Cmd+F/tmux copy mode can search it. | docs |
| v | Write the conversation to a temp file and open it in $VISUAL/$EDITOR. | docs |
| ? | Show the full shortcut reference panel inside the transcript viewer. | docs |
| ctrl+home / ctrl+endctrl+home / ctrl+end (cmd+up / cmd+down conventionally on mac, but docs specify Ctrl+Home/End) macOS | Jump to start/latest message of the conversation (fullscreen rendering).scroll:topscroll:bottom | docs |
| pageup / pagedownpageup / pagedown (fn+up/down on mac laptop keyboards) macOS | Scroll up/down half the viewport height in the transcript or diff viewer.scroll:pageUpscroll:pageDown | docs |
| ctrl+shift+c / cmd+ccmd+c macOS | Copy the selected transcript text to the clipboard (fullscreen rendering text selection).selection:copy | docs |
Dialogs and pickers
| Keys | Does | Src |
|---|---|---|
| left / right | Cycle through dialog tabs (navigate between tabs in permission dialogs and menus).tabs:previoustabs:next | docs |
| up/down/left/right, ctrl+n/ctrl+p, j/ksame macOS | Move selection up/down in generic select lists and the rewind/summarize message selector.rlselect:nextselect:previous | source |
| space | Toggle a checkbox/selection in confirmation dialogs, plugin dialogs, or settings.confirm:toggle | source |
| / | Enter search mode in the Settings menu.settings:search | docs |
Permission prompts
| Keys | Does | Src |
|---|---|---|
| y / n | Confirm (Y) or decline (N) a permission/confirmation dialog.confirm:yesconfirm:no | source |
| ctrl+e | Toggle a model-generated explanation of the command on Bash/PowerShell permission prompts.confirm:toggleExplanation | source |
Codexterminal
Input line
| Keys | Does | Src |
|---|---|---|
| enterreturn macOS | Submit the current composer draft.tui.keymap.composer.submit | source |
| tab | Queue the draft while a task is running.tui.keymap.composer.queue | source |
| ? or shift+? | Show or hide the composer shortcut overlay.tui.keymap.composer.toggle_shortcuts | source |
| ctrl+r | Open reverse history search, or move to the previous match.rltui.keymap.composer.history_search_previous | source |
| ctrl+s | Move to the next match in reverse history search.tui.keymap.composer.history_search_next | source |
| ctrl+j / ctrl+m / shift+enter / alt+enterctrl+j / ctrl+m / shift+return / option+return macOS | Insert a newline in the editor.tui.keymap.editor.insert_newline | source |
| left / ctrl+b | Move the cursor left.rltui.keymap.editor.move_left | source |
| right / ctrl+f | Move the cursor right.rltui.keymap.editor.move_right | source |
| up / ctrl+p | Move the cursor up.rltui.keymap.editor.move_up | source |
| down / ctrl+n | Move the cursor down.rltui.keymap.editor.move_down | source |
| alt+b / alt+left / ctrl+leftoption+b / option+left / ctrl+left macOS | Move to the beginning of the previous word.rltui.keymap.editor.move_word_left | source |
| alt+f / alt+right / ctrl+rightoption+f / option+right / ctrl+right macOS | Move to the end of the next word.rltui.keymap.editor.move_word_right | source |
| home / ctrl+a | Move to the beginning of the line.rltui.keymap.editor.move_line_start | source |
| end / ctrl+e | Move to the end of the line.rltui.keymap.editor.move_line_end | source |
| backspace / shift+backspace / ctrl+hdelete / shift+delete / ctrl+h macOS | Delete one grapheme to the left.rltui.keymap.editor.delete_backward | source |
| delete / shift+delete / ctrl+dfn+delete / shift+fn+delete / ctrl+d macOS | Delete one grapheme to the right.rltui.keymap.editor.delete_forward | source |
| alt+backspace / ctrl+backspace / ctrl+shift+backspace / ctrl+w / ctrl+alt+hoption+delete / ctrl+delete / ctrl+shift+delete / ctrl+w / ctrl+option+h macOS | Delete the previous word.rltui.keymap.editor.delete_backward_word | source |
| alt+delete / ctrl+delete / ctrl+shift+delete / alt+doption+fn+delete / ctrl+fn+delete / ctrl+shift+fn+delete / option+d macOS | Delete the next word.rltui.keymap.editor.delete_forward_word | source |
| ctrl+u | Delete from cursor to line start.rltui.keymap.editor.kill_line_start | source |
| ctrl+k | Delete from cursor to line end.rltui.keymap.editor.kill_line_end | source |
| ctrl+y | Paste the kill buffer (yank).rltui.keymap.editor.yank | source |
| ctrl+vcmd+v is NOT wired; use ctrl+v macOS | Paste an image from the clipboard as an attachment. | source |
| / | Trigger the slash-command popup (only at the start of an empty draft). | source |
| ! | Trigger shell-command mode (only at the start of an empty draft). | source |
| @ | Trigger the file-path mention popup. | source |
| $ | Trigger the connector-mentions popup. | source |
| esc (backtrack step 1, main view, empty composer, no running turn)esc macOS | Prime edit-previous-message (backtrack) mode. | source |
| i / insert | Enter insert mode at the cursor.tui.keymap.vim_normal.enter_insert | source |
| a | Enter insert mode after the cursor.tui.keymap.vim_normal.append_after_cursor | source |
| shift+a / A | Enter insert mode at end of line.tui.keymap.vim_normal.append_line_end | source |
| shift+i / I | Enter insert mode at the first non-blank character.tui.keymap.vim_normal.insert_line_start | source |
| o | Open a new line below and enter insert mode.tui.keymap.vim_normal.open_line_below | source |
| shift+o / O | Open a new line above and enter insert mode.tui.keymap.vim_normal.open_line_above | source |
| h / left | Move left in Vim normal mode.tui.keymap.vim_normal.move_left | source |
| l / right | Move right in Vim normal mode.tui.keymap.vim_normal.move_right | source |
| k / up | Move up or recall older history in Vim normal mode.tui.keymap.vim_normal.move_up | source |
| j / down | Move down or recall newer history in Vim normal mode.tui.keymap.vim_normal.move_down | source |
| w | Move to the start of the next word.tui.keymap.vim_normal.move_word_forward | source |
| b | Move to the start of the previous word.tui.keymap.vim_normal.move_word_backward | source |
| e | Move to the end of the current or next word.tui.keymap.vim_normal.move_word_end | source |
| 0 | Move to the start of the line.tui.keymap.vim_normal.move_line_start | source |
| $ / shift+$ | Move to the end of the line.tui.keymap.vim_normal.move_line_end | source |
| x | Delete the character under the cursor.tui.keymap.vim_normal.delete_char | source |
| s | Delete the character under the cursor and enter insert mode.tui.keymap.vim_normal.substitute_char | source |
| shift+d / D | Delete from cursor to end of line.tui.keymap.vim_normal.delete_to_line_end | source |
| shift+c / C | Change from cursor to end of line and enter insert mode.tui.keymap.vim_normal.change_to_line_end | source |
| shift+y / Y | Yank the entire line.tui.keymap.vim_normal.yank_line | source |
| p | Paste after the cursor.tui.keymap.vim_normal.paste_after | source |
| d | Begin a delete operator and wait for a motion.tui.keymap.vim_normal.start_delete_operator | source |
| y | Begin a yank operator and wait for a motion.tui.keymap.vim_normal.start_yank_operator | source |
| c | Begin a change operator and wait for a text object.tui.keymap.vim_normal.start_change_operator | source |
| esc | Cancel a pending Vim operator.tui.keymap.vim_normal.cancel_operator | source |
| d | Repeat delete operator to delete the whole line.tui.keymap.vim_operator.delete_line | source |
| y | Repeat yank operator to yank the whole line.tui.keymap.vim_operator.yank_line | source |
| h | Operator motion left.tui.keymap.vim_operator.motion_left | source |
| l | Operator motion right.tui.keymap.vim_operator.motion_right | source |
| k | Operator motion up.tui.keymap.vim_operator.motion_up | source |
| j | Operator motion down.tui.keymap.vim_operator.motion_down | source |
| w | Operator motion to start of next word.tui.keymap.vim_operator.motion_word_forward | source |
| b | Operator motion to start of previous word.tui.keymap.vim_operator.motion_word_backward | source |
| e | Operator motion to end of word.tui.keymap.vim_operator.motion_word_end | source |
| 0 | Operator motion to line start.tui.keymap.vim_operator.motion_line_start | source |
| $ / shift+$ | Operator motion to line end.tui.keymap.vim_operator.motion_line_end | source |
| i | Select an inner text object.tui.keymap.vim_operator.select_inner_text_object | source |
| a | Select an around text object.tui.keymap.vim_operator.select_around_text_object | source |
| esc | Cancel the pending operator.tui.keymap.vim_operator.cancel | source |
| w | Target the current word.tui.keymap.vim_text_object.word | source |
| shift+w / W | Target the current WORD.tui.keymap.vim_text_object.big_word | source |
| ( / shift+( / ) / shift+) / b | Target enclosing parentheses.tui.keymap.vim_text_object.parentheses | source |
| [ / ] | Target enclosing brackets.tui.keymap.vim_text_object.brackets | source |
| { / shift+{ / } / shift+} / shift+b / B | Target enclosing braces.tui.keymap.vim_text_object.braces | source |
| " / shift+" | Target enclosing double quotes.tui.keymap.vim_text_object.double_quote | source |
| ' | Target enclosing single quotes.tui.keymap.vim_text_object.single_quote | source |
| ` | Target enclosing backticks.tui.keymap.vim_text_object.backtick | source |
| esc | Cancel the pending text object.tui.keymap.vim_text_object.cancel | source |
Anywhere
| Keys | Does | Src |
|---|---|---|
| ctrl+t | Open the transcript overlay.tui.keymap.global.open_transcript | source |
| ctrl+g | Open the current draft in an external editor ($EDITOR).tui.keymap.global.open_external_editor | source |
| ctrl+o | Copy the last agent response to the clipboard.tui.keymap.global.copy | source |
| ctrl+l | Clear the terminal UI.rltui.keymap.global.clear_terminal | source |
| alt+roption+r macOS | Toggle raw scrollback mode for copy-friendly transcript selection.tui.keymap.global.toggle_raw_output | source |
| ctrl+/ | Switch between a side conversation and its parent without closing either.tui.keymap.global.toggle_side_conversation | source |
| esc | Interrupt the active turn.tui.keymap.chat.interrupt_turn | source |
| alt+, or shift+downoption+, or shift+down macOS | Decrease reasoning effort.tui.keymap.chat.decrease_reasoning_effort | source |
| alt+. or shift+upoption+. or shift+up macOS | Increase reasoning effort.tui.keymap.chat.increase_reasoning_effort | source |
| alt+up or shift+leftoption+up or shift+left macOS | Edit the most recently queued message.tui.keymap.chat.edit_queued_message | source |
| ctrl+c (first press) | Interrupt the active turn if one is running. | source |
| ctrl+c (idle, second/only press) | Quit Codex. | source |
| ctrl+d (composer empty) | Quit Codex.rl | source |
| shift+tab | Cycle the collaboration mode. | source |
| alt+leftoption+left macOS | Switch to the previous agent. | source |
| alt+rightoption+right macOS | Switch to the next agent. | source |
| ctrl+z | Suspend Codex (SIGTSTP); resume with `fg` in the shell. | source |
Transcript / pager
| Keys | Does | Src |
|---|---|---|
| esc (backtrack step 2)esc macOS | Open the transcript overlay with the last user message highlighted for editing. | source |
| left / esc | Select the previous (older) prior user message to edit. | source |
| right | Select the next (newer) prior user message to edit. | source |
| enterreturn macOS | Fork the thread before the selected prior message and reopen it for editing. | source |
| up / k | Scroll up by one row (pager/transcript overlay).tui.keymap.pager.scroll_up | source |
| down / j | Scroll down by one row (pager/transcript overlay).tui.keymap.pager.scroll_down | source |
| pageup / shift+space / ctrl+b | Scroll up by one page (pager/transcript overlay).tui.keymap.pager.page_up | source |
| pagedown / space / ctrl+f | Scroll down by one page (pager/transcript overlay).tui.keymap.pager.page_down | source |
| ctrl+u | Scroll up by half a page (pager/transcript overlay).tui.keymap.pager.half_page_up | source |
| ctrl+d | Scroll down by half a page (pager/transcript overlay).tui.keymap.pager.half_page_down | source |
| home | Jump to the beginning (pager/transcript overlay).tui.keymap.pager.jump_top | source |
| end | Jump to the end (pager/transcript overlay).tui.keymap.pager.jump_bottom | source |
| q / ctrl+c | Close the pager overlay.tui.keymap.pager.close | source |
| ctrl+t | Close the transcript overlay.tui.keymap.pager.close_transcript | source |
Dialogs and pickers
| Keys | Does | Src |
|---|---|---|
| up / ctrl+p / ctrl+k / k | Move list selection up (popup pickers).tui.keymap.list.move_up | source |
| down / ctrl+n / ctrl+j / j | Move list selection down (popup pickers).tui.keymap.list.move_down | source |
| left / ctrl+h | Move horizontally left in list pickers (tabs/toolbars).tui.keymap.list.move_left | source |
| right / ctrl+l | Move horizontally right in list pickers (tabs/toolbars).tui.keymap.list.move_right | source |
| pageup / ctrl+b | Move list selection up by one page.tui.keymap.list.page_up | source |
| pagedown / ctrl+f | Move list selection down by one page.tui.keymap.list.page_down | source |
| home | Jump to the first list item.tui.keymap.list.jump_top | source |
| end | Jump to the last list item.tui.keymap.list.jump_bottom | source |
| enterreturn macOS | Accept the current list selection.tui.keymap.list.accept | source |
| esc | Cancel and close selection views.tui.keymap.list.cancel | source |
| ctrl+c | Cancel the open list picker (resume picker etc.), does not quit Codex. | source |
| ctrl+t | Toggle transcript preview inside the resume/session picker. | source |
| ctrl+e | Toggle expansion inside the resume/session picker. | source |
| ctrl+o | Toggle density inside the resume/session picker. | source |
Approval prompts
| Keys | Does | Src |
|---|---|---|
| ctrl+a / ctrl+shift+a | Open approval details fullscreen.tui.keymap.approval.open_fullscreen | source |
| o | Open the approval's source thread, when available.tui.keymap.approval.open_thread | source |
| y | Approve the primary option.tui.keymap.approval.approve | source |
| a | Approve for the rest of the session, when available.tui.keymap.approval.approve_for_session | source |
| p | Approve with an exec-policy prefix, when available.tui.keymap.approval.approve_for_prefix | source |
| d | Choose the explicit deny option, when available.tui.keymap.approval.deny | source |
| esc / n | Decline and provide corrective guidance.tui.keymap.approval.decline | source |
| c | Cancel an elicitation request.tui.keymap.approval.cancel | source |
OpenCodeterminal
Input line
| Keys | Does | Src |
|---|---|---|
| <leader>e | editor_open - open the external $EDITOR to compose the current message.editor_open | source |
| ctrl+c | input_clear - clear the input box.input_clear | source |
| ctrl+v | input_paste - paste clipboard contents into the input box.input_paste | source |
| return | input_submit - submit the current message.input_submit | source |
| shift+return,ctrl+return,alt+return,ctrl+j | input_newline - insert a newline in the input box without submitting.input_newline | source |
| left,ctrl+b | input_move_left - move cursor left one character.rlinput_move_left | source |
| right,ctrl+f | input_move_right - move cursor right one character.rlinput_move_right | source |
| up | input_move_up - move cursor up a line in a multi-line input.input_move_up | source |
| down | input_move_down - move cursor down a line in a multi-line input.input_move_down | source |
| shift+left | input_select_left - extend selection left one character.input_select_left | source |
| shift+right | input_select_right - extend selection right one character.input_select_right | source |
| shift+up | input_select_up - extend selection up one line.input_select_up | source |
| shift+down | input_select_down - extend selection down one line.input_select_down | source |
| ctrl+a | input_line_home - move cursor to the start of the current line.rlinput_line_home | source |
| ctrl+e | input_line_end - move cursor to the end of the current line.rlinput_line_end | source |
| ctrl+shift+a | input_select_line_home - select from cursor to start of line.input_select_line_home | source |
| ctrl+shift+e | input_select_line_end - select from cursor to end of line.input_select_line_end | source |
| alt+a | input_visual_line_home - move to start of the visual (wrapped) line.input_visual_line_home | source |
| alt+e | input_visual_line_end - move to end of the visual (wrapped) line.input_visual_line_end | source |
| alt+shift+a | input_select_visual_line_home - select to start of the visual line.input_select_visual_line_home | source |
| alt+shift+e | input_select_visual_line_end - select to end of the visual line.input_select_visual_line_end | source |
| home | input_buffer_home - move cursor to the very start of the whole input buffer.input_buffer_home | source |
| end | input_buffer_end - move cursor to the very end of the whole input buffer.input_buffer_end | source |
| shift+home | input_select_buffer_home - select to the start of the whole buffer.input_select_buffer_home | source |
| shift+end | input_select_buffer_end - select to the end of the whole buffer.input_select_buffer_end | source |
| ctrl+shift+d | input_delete_line - delete the entire current line.input_delete_line | source |
| ctrl+k | input_delete_to_line_end - delete from cursor to end of line (kill-line).rlinput_delete_to_line_end | source |
| ctrl+u | input_delete_to_line_start - delete from cursor to start of line (unix-line-discard).rlinput_delete_to_line_start | source |
| backspace,shift+backspace | input_backspace - delete character before cursor.input_backspace | source |
| ctrl+d,delete,shift+delete | input_delete - delete character after cursor (forward delete).rlinput_delete | source |
| ctrl+-,super+zcmd+z (super+z),ctrl+- macOS | input_undo - undo the last text edit in the input box.input_undo | source |
| ctrl+.,super+shift+zcmd+shift+z,ctrl+. macOS | input_redo - redo the last undone text edit in the input box.input_redo | source |
| alt+f,alt+right,ctrl+right | input_word_forward - move cursor forward one word.rlinput_word_forward | source |
| alt+b,alt+left,ctrl+left | input_word_backward - move cursor backward one word.rlinput_word_backward | source |
| alt+shift+f,alt+shift+right | input_select_word_forward - extend selection forward one word.input_select_word_forward | source |
| alt+shift+b,alt+shift+left | input_select_word_backward - extend selection backward one word.input_select_word_backward | source |
| alt+d,alt+delete,ctrl+delete | input_delete_word_forward - delete word after cursor (kill-word).rlinput_delete_word_forward | source |
| ctrl+w,ctrl+backspace,alt+backspace | input_delete_word_backward - delete word before cursor (unix-word-rubout).rlinput_delete_word_backward | source |
| super+acmd+a macOS | input_select_all - select all text in the input box.input_select_all | source |
| up | history_previous - recall the previous submitted prompt from history.history_previous | source |
| down | history_next - recall the next submitted prompt from history.history_next | source |
| up,ctrl+p | prompt.autocomplete.prev - move to previous autocomplete suggestion (e.g. @file references).rlprompt.autocomplete.prev | source |
| down,ctrl+n | prompt.autocomplete.next - move to next autocomplete suggestion.rlprompt.autocomplete.next | source |
| escape | prompt.autocomplete.hide - dismiss the autocomplete popup.prompt.autocomplete.hide | source |
| return | prompt.autocomplete.select - accept the highlighted autocomplete suggestion.prompt.autocomplete.select | source |
| tab | prompt.autocomplete.complete - complete/accept via Tab.prompt.autocomplete.complete | source |
Anywhere
| Keys | Does | Src |
|---|---|---|
| ctrl+x | Leader key. Activates leader mode for leader_timeout ms (default 2000); the next key pressed is interpreted as a leader combo, e.g. ctrl+x then n = new session.leader | source |
| ctrl+c,ctrl+d,<leader>q | app_exit - quit OpenCode.app_exit | source |
| ctrl+p | command_list - open the command palette.command_list | source |
| <leader>t | theme_list - open theme picker.theme_list | source |
| <leader>b | sidebar_toggle - show/hide the sidebar.sidebar_toggle | source |
| <leader>s | status_view - open status view.status_view | source |
| <leader>x | session_export - export current conversation to Markdown and open in $EDITOR.session_export | source |
| <leader>n | session_new - start a new session.session_new | source |
| <leader>l | session_list - list and switch between saved sessions.session_list | source |
| <leader>g | session_timeline - open session timeline view.session_timeline | source |
| ctrl+r | session_rename - rename the current session.session_rename | source |
| ctrl+d | session_delete - delete the currently selected/open session.session_delete | source |
| escape | session_interrupt - interrupt/cancel the model's in-flight response.session_interrupt | source |
| <leader>c | session_compact - compact/summarize the current session.session_compact | source |
| <leader>down | session_child_first - jump to the first child (subagent) session.session_child_first | source |
| right | session_child_cycle - cycle to the next child/subagent session.session_child_cycle | source |
| left | session_child_cycle_reverse - cycle to the previous child/subagent session.session_child_cycle_reverse | source |
| up | session_parent - go to the parent session.session_parent | source |
| ctrl+d | stash_delete - delete a stashed prompt.stash_delete | source |
| <leader>m | model_list - list/switch available models.model_list | source |
| f2 | model_cycle_recent - cycle to the next recently-used model.model_cycle_recent | source |
| shift+f2 | model_cycle_recent_reverse - cycle to the previous recently-used model.model_cycle_recent_reverse | source |
| <leader>a | agent_list - list/switch agents.agent_list | source |
| tab | agent_cycle - cycle to the next agent.agent_cycle | source |
| shift+tab | agent_cycle_reverse - cycle to the previous agent.agent_cycle_reverse | source |
| ctrl+t | variant_cycle - cycle the active model's reasoning/thinking variant (e.g. effort level).variant_cycle | source |
| ctrl+z | terminal_suspend - suspend OpenCode to the background (POSIX SIGTSTP, like any terminal job-control suspend; resume with `fg` in the shell).terminal_suspend | source |
| <leader>h | tips_toggle - toggle the tips panel.tips_toggle | source |
| ctrl+alt+k | which_key_toggle - toggle the 'which-key' style help overlay listing available leader combos.which_key_toggle | source |
| ctrl+alt+shift+k | which_key_layout_toggle - toggle the which-key overlay's layout.which_key_layout_toggle | source |
| ctrl+alt+shift+p | which_key_pending_toggle - toggle showing only pending/available combos in the which-key overlay.which_key_pending_toggle | source |
| ctrl+alt+left,ctrl+alt+[ | which_key_group_previous - previous group in the which-key overlay.which_key_group_previous | source |
| ctrl+alt+right,ctrl+alt+] | which_key_group_next - next group in the which-key overlay.which_key_group_next | source |
| ctrl+alt+up,ctrl+alt+p | which_key_scroll_up - scroll the which-key overlay up.which_key_scroll_up | source |
| ctrl+alt+down,ctrl+alt+n | which_key_scroll_down - scroll the which-key overlay down.which_key_scroll_down | source |
| ctrl+alt+pageup | which_key_page_up - page up in the which-key overlay.which_key_page_up | source |
| ctrl+alt+pagedown | which_key_page_down - page down in the which-key overlay.which_key_page_down | source |
| ctrl+alt+home | which_key_home - jump to top of the which-key overlay.which_key_home | source |
| ctrl+alt+end | which_key_end - jump to bottom of the which-key overlay.which_key_end | source |
| ctrl+b | session_background - background running synchronous subagents.session_background | source |
| <leader>1 | session_quick_switch_1 - switch to the session pinned in quick slot 1.session_quick_switch_1 | source |
| <leader>2 | session_quick_switch_2 - switch to the session pinned in quick slot 2.session_quick_switch_2 | source |
| <leader>3 | session_quick_switch_3 - switch to the session pinned in quick slot 3.session_quick_switch_3 | source |
| <leader>4 | session_quick_switch_4 - switch to the session pinned in quick slot 4.session_quick_switch_4 | source |
| <leader>5 | session_quick_switch_5 - switch to the session pinned in quick slot 5.session_quick_switch_5 | source |
| <leader>6 | session_quick_switch_6 - switch to the session pinned in quick slot 6.session_quick_switch_6 | source |
| <leader>7 | session_quick_switch_7 - switch to the session pinned in quick slot 7.session_quick_switch_7 | source |
| <leader>8 | session_quick_switch_8 - switch to the session pinned in quick slot 8.session_quick_switch_8 | source |
| <leader>9 | session_quick_switch_9 - switch to the session pinned in quick slot 9.session_quick_switch_9 | source |
Transcript / pager
| Keys | Does | Src |
|---|---|---|
| pageup,ctrl+alt+b | messages_page_up - scroll transcript up one page.messages_page_up | source |
| pagedown,ctrl+alt+f | messages_page_down - scroll transcript down one page.messages_page_down | source |
| ctrl+alt+y | messages_line_up - scroll transcript up one line.messages_line_up | source |
| ctrl+alt+e | messages_line_down - scroll transcript down one line.messages_line_down | source |
| ctrl+alt+u | messages_half_page_up - scroll transcript up half a page.messages_half_page_up | source |
| ctrl+alt+d | messages_half_page_down - scroll transcript down half a page.messages_half_page_down | source |
| ctrl+g,home | messages_first - jump to the first message in the transcript.messages_first | source |
| ctrl+alt+g,end | messages_last - jump to the last message in the transcript.messages_last | source |
| <leader>y | messages_copy - copy message(s) from the transcript.messages_copy | source |
| <leader>u | messages_undo - undo the last conversation turn (git-based; reverts file changes too). Requires the project to be a git repo.messages_undo | source |
| <leader>r | messages_redo - redo a previously undone turn.messages_redo | source |
| <leader>h | messages_toggle_conceal - toggle concealment of message content.messages_toggle_conceal | source |
Dialogs and pickers
| Keys | Does | Src |
|---|---|---|
| ctrl+a | model_provider_list - open the model provider list.model_provider_list | source |
| ctrl+f | model_favorite_toggle - toggle a model as favorite.model_favorite_toggle | source |
| up,ctrl+p | dialog.select.prev - move selection up in an open dialog/list.rldialog.select.prev | source |
| down,ctrl+n | dialog.select.next - move selection down in an open dialog/list.rldialog.select.next | source |
| pageup | dialog.select.page_up - page up within an open dialog/list.dialog.select.page_up | source |
| pagedown | dialog.select.page_down - page down within an open dialog/list.dialog.select.page_down | source |
| home | dialog.select.home - jump to first item in an open dialog/list.dialog.select.home | source |
| end | dialog.select.end - jump to last item in an open dialog/list.dialog.select.end | source |
| return | dialog.select.submit - confirm the selected item in an open dialog/list.dialog.select.submit | source |
| return | dialog.prompt.submit - submit a text-entry dialog/prompt.dialog.prompt.submit | source |
| space | dialog.mcp.toggle - toggle an item in the MCP server dialog.dialog.mcp.toggle | source |
| space | plugins.toggle - toggle a plugin on/off in the plugins dialog.plugins.toggle | source |
| shift+i | dialog.plugins.install - install the selected plugin.dialog.plugins.install | source |
| escape,q | diff_close - close the diff viewer.diff_close | source |
| enter,space | diff_toggle - toggle the selected diff viewer item (e.g. expand/collapse or check off a file).diff_toggle | source |
| right | diff_expand - expand the selected diff viewer item.diff_expand | source |
| E | diff_expand_all - expand all folders in the diff viewer file tree.diff_expand_all | source |
| left | diff_collapse - collapse the selected diff viewer item.diff_collapse | source |
| tab | diff_switch_focus - switch focus between diff viewer panes (e.g. file tree vs diff body).diff_switch_focus | source |
| ] | diff_next_hunk - jump to the next diff hunk.diff_next_hunk | source |
| [ | diff_previous_hunk - jump to the previous diff hunk.diff_previous_hunk | source |
| n | diff_next_file - jump to the next file in the diff viewer.diff_next_file | source |
| p | diff_previous_file - jump to the previous file in the diff viewer.diff_previous_file | source |
| b | diff_toggle_file_tree - show/hide the diff viewer's file tree pane.diff_toggle_file_tree | source |
| s | diff_single_patch - toggle single-patch view in the diff viewer.diff_single_patch | source |
| d | diff_switch_source - switch the diff viewer's source.diff_switch_source | source |
| v | diff_toggle_view - toggle diff viewer split vs unified view.diff_toggle_view | source |
| ? | diff_help - show more diff viewer shortcuts.diff_help | source |
| ctrl+f | session_pin_toggle - pin or unpin a session inside the session-list dialog.session_pin_toggle | source |
| ctrl+m | dialog.move_session.new - create a new project copy from the move-session dialog.dialog.move_session.new | source |
| ctrl+d | dialog.move_session.delete - delete a project copy from the move-session dialog.dialog.move_session.delete | source |
| ctrl+r | dialog.move_session.refresh - refresh project copies in the move-session dialog.dialog.move_session.refresh | source |
Permission prompts
| Keys | Does | Src |
|---|---|---|
| ctrl+f | permission.prompt.fullscreen - expand the permission prompt to fullscreen.permission.prompt.fullscreen | source |
Piterminal
Input line
| Keys | Does | Src |
|---|---|---|
| up | Move cursor uptui.editor.cursorUp | first-hand |
| down | Move cursor downtui.editor.cursorDown | first-hand |
| left, ctrl+b | Move cursor leftrltui.editor.cursorLeft | first-hand |
| right, ctrl+f | Move cursor rightrltui.editor.cursorRight | first-hand |
| alt+left, ctrl+left, alt+boption+left, ctrl+left, option+b (terminal-dependent Alt/Option mapping) macOS | Move cursor one word leftrltui.editor.cursorWordLeft | first-hand |
| alt+right, ctrl+right, alt+foption+right, ctrl+right, option+f (terminal-dependent) macOS | Move cursor one word rightrltui.editor.cursorWordRight | first-hand |
| home, ctrl+a | Move to line startrltui.editor.cursorLineStart | first-hand |
| end, ctrl+e | Move to line endrltui.editor.cursorLineEnd | first-hand |
| ctrl+] | Jump forward to charactertui.editor.jumpForward | first-hand |
| ctrl+alt+]ctrl+option+] macOS | Jump backward to charactertui.editor.jumpBackward | first-hand |
| pageUpfn+up (pageUp, terminal-dependent) macOS | Scroll up by page (editor)tui.editor.pageUp | first-hand |
| pageDownfn+down (pageDown, terminal-dependent) macOS | Scroll down by page (editor)tui.editor.pageDown | first-hand |
| backspacedelete (backspace) macOS | Delete character backwardrltui.editor.deleteCharBackward | first-hand |
| delete, ctrl+dfn+delete (forward delete), ctrl+d macOS | Delete character forwardrltui.editor.deleteCharForward | first-hand |
| ctrl+w, alt+backspacectrl+w, option+delete macOS | Delete word backwardrltui.editor.deleteWordBackward | first-hand |
| alt+d, alt+deleteoption+d, option+fn+delete macOS | Delete word forwardrltui.editor.deleteWordForward | first-hand |
| ctrl+u | Delete to line startrltui.editor.deleteToLineStart | first-hand |
| ctrl+k | Delete to line endrltui.editor.deleteToLineEnd | first-hand |
| shift+enter, ctrl+jshift+return, ctrl+j macOS | Insert new line (multiline input)tui.input.newLine | first-hand |
| enterreturn macOS | Submit input; when the agent is already running, Enter instead queues a steering message delivered after the current tool-call turn finishestui.input.submit | first-hand |
| tab | Tab / autocompletetui.input.tab | first-hand |
| ctrl+y | Paste (yank) most recently deleted textrltui.editor.yank | first-hand |
| alt+yoption+y macOS | Cycle through deleted text after yank (yank-pop)rltui.editor.yankPop | first-hand |
| ctrl+- | Undo last editrltui.editor.undo | first-hand |
| ctrl+c | Copy selection; if no selection, clears the editortui.input.copyapp.clear | first-hand |
| ctrl+d | Exit pi when the editor is empty (EOF-style exit)rlapp.exit | first-hand |
| ctrl+g | Open current input in an external editor ($VISUAL, $EDITOR, Notepad on Windows, or nano elsewhere)app.editor.external | first-hand |
| ctrl+vcmd+v (native paste)/ctrl+v; alt+v on Windows macOS | Paste image from clipboardapp.clipboard.pasteImage | first-hand |
| ctrl+p | Cycle to next model (when --models patterns configured); also toggles path display in the session list, and toggles all models for the current provider in the scoped-models selectorapp.model.cycleForwardapp.session.togglePathapp.models.toggleProvider | first-hand |
| shift+ctrl+p | Cycle to previous modelapp.model.cycleBackward | first-hand |
| ctrl+l | Open model selectorapp.model.selectapp.tree.filter.labeledOnly | first-hand |
| shift+tab | Cycle thinking level (off/minimal/low/medium/high/xhigh/max)app.thinking.cycle | first-hand |
| alt+enteroption+return macOS | Queue a follow-up message, delivered after the agent finishes all current workapp.message.followUp | first-hand |
| alt+upoption+up macOS | Restore queued messages back to the editorapp.message.dequeueapp.models.reorderUp | first-hand |
| ctrl+home | Move cursor to line start / editor top (fullscreen mode)tui.editor.cursorLineStart | docs |
| ctrl+end | Move cursor to editor end (fullscreen mode)tui.editor.cursorLineEnd | docs |
Anywhere
| Keys | Does | Src |
|---|---|---|
| escapeesc macOS | Cancel / abort current agent turn; in dialogs/selectors, cancels the selectionapp.interrupttui.select.cancel | first-hand |
| ctrl+z | Suspend to background (job control)rlapp.suspend | first-hand |
Transcript / pager
| Keys | Does | Src |
|---|---|---|
| ctrl+t | Collapse or expand thinking blocksapp.thinking.toggleapp.tree.filter.noTools | first-hand |
| ctrl+o | Collapse or expand tool outputapp.tools.expandapp.tree.filter.cycleForward | first-hand |
| ctrl+x | Copy the last assistant message (or the selected message in /tree)app.message.copyapp.models.clearAll | first-hand |
| home (unmodified)home macOS | Scroll transcript to top (fullscreen mode only; controls editor in default mode)tui.altScreen.top | docs |
| end (unmodified)end macOS | Scroll transcript to bottom and follow new output (fullscreen mode only)tui.altScreen.bottom | docs |
| ctrl+shift+up | Jump to the previous marked message in the transcript (fullscreen mode)tui.altScreen.previousPrompt | docs |
| ctrl+shift+down | Jump to the next marked message in the transcript (fullscreen mode)tui.altScreen.nextPrompt | docs |
Dialogs and pickers
| Keys | Does | Src |
|---|---|---|
| ctrl+left, alt+leftctrl+left, option+left macOS | Fold current tree branch segment, or jump to previous segment startapp.tree.foldOrUp | first-hand |
| ctrl+right, alt+rightctrl+right, option+right macOS | Unfold current tree branch segment, or jump to next segment/branch endapp.tree.unfoldOrDown | first-hand |
| shift+l | Edit the label on the selected tree nodeapp.tree.editLabel | first-hand |
| shift+t | Toggle label timestamps in the treeapp.tree.toggleLabelTimestamp | first-hand |
| ctrl+a | Toggle tree filter that shows all entries (inside /tree); also enables all models in the scoped-models selectorapp.tree.filter.allapp.models.enableAll | first-hand |
| ctrl+s | Toggle sort mode in the session list; saves current model selection in the scoped-models selectorapp.session.toggleSortapp.models.save | first-hand |
| ctrl+n | Toggle named-only filter in the session listapp.session.toggleNamedFilter | first-hand |
| ctrl+r | Rename sessionapp.session.rename | first-hand |
| ctrl+backspacectrl+delete (backspace) macOS | Delete session when the session-list query is emptyapp.session.deleteNoninvasive | first-hand |
| shift+ctrl+o | Cycle tree filter backwardapp.tree.filter.cycleBackward | first-hand |
| alt+downoption+down macOS | Move the selected model down in the cycle order (scoped-models selector)app.models.reorderDown | first-hand |
Cursoreditor extension
Anywhere
| Keys | Does | Src |
|---|---|---|
| ctrl+icmd+i macOS | Toggle Sidepanel (opens the Chat/Agent panel) - unless bound to a specific mode | docs |
| ctrl+lcmd+l macOS | Toggle Sidepanel (opens the Chat/Agent panel) - unless bound to a specific mode | docs |
| ctrl+.cmd+. macOS | Mode Menu (open the Agent/Ask/Plan mode selector) | docs |
| ctrl+/cmd+/ macOS | Loop between AI models | docs |
| ctrl+shift+jcmd+shift+j macOS | Cursor settings | docs |
| ctrl+shift+spacecmd+shift+space macOS | Toggle Voice Mode | docs |
| ctrl+,cmd+, macOS | General settings | docs |
| ctrl+shift+pcmd+shift+p macOS | Command palette | docs |
agent
| Keys | Does | Src |
|---|---|---|
| ctrl+ecmd+e macOS | Toggle Agent layout | docs |
chat
| Keys | Does | Src |
|---|---|---|
| enter | Nudge (default) - send/submit the chat message | docs |
| ctrl+enter | Queue message | docs |
| ctrl+entercmd+enter macOS | Force send message (when typing) | docs |
| ctrl+shift+backspacecmd+shift+backspace macOS | Cancel generation | docs |
| ctrl+shift+lcmd+shift+l macOS | Add selected code as context (with code selected) | docs |
| ctrl+vcmd+v macOS | Add clipboard as context (with code or log in clipboard) | docs |
| ctrl+shift+vcmd+shift+v macOS | Add clipboard to input box (with code or log in clipboard) | docs |
| ctrl+entercmd+enter macOS | Accept all changes (with suggested changes pending) | docs |
| ctrl+backspacecmd+backspace macOS | Reject all changes | docs |
| tab | Cycle to next message | docs |
| shift+tab | Rotate between Agent modes | docs |
| ctrl+alt+/cmd+opt+/ macOS | Model toggle | docs |
| ctrl+ncmd+n macOS | New chat | docs |
| ctrl+rcmd+r macOS | New chat | docs |
| ctrl+tcmd+t macOS | New chat tab | docs |
| ctrl+[cmd+[ macOS | Previous chat | docs |
| ctrl+]cmd+] macOS | Next chat | docs |
| ctrl+wcmd+w macOS | Close chat | docs |
| esc | Unfocus field | docs |
| @ | @-mentions - trigger the context-attachment picker (files, docs, symbols, etc.) | docs |
| / | Shortcut Commands - trigger the slash-command menu in chat/agent input | docs |
| ctrl+entercmd+enter macOS | Search codebase in chat | docs |
| ctrl+c then ctrl+vcmd+c then cmd+v macOS | Add copied reference code as context | docs |
| ctrl+c then ctrl+shift+vcmd+c then cmd+shift+v macOS | Add copied code as text context | docs |
editor
| Keys | Does | Src |
|---|---|---|
| ctrl+kcmd+k macOS | Open (Inline Edit prompt) | docs |
| ctrl+shift+kcmd+shift+k macOS | Toggle input focus (Inline Edit) | docs |
| enter | Submit (Inline Edit) | docs |
| ctrl+shift+backspacecmd+shift+backspace macOS | Cancel (Inline Edit) | docs |
| alt+enteropt+enter macOS | Ask quick question (Inline Edit) | docs |
| ctrl+shift+lcmd+shift+l macOS | Add selection to Chat | docs |
| ctrl+shift+kcmd+shift+k macOS | Add selection to Edit | docs |
| ctrl+lcmd+l macOS | Add selection to new chat | docs |
| ctrl+mcmd+m macOS | Toggle file reading strategies | docs |
| ctrl+rightcmd+right macOS | Accept next word of suggestion | docs |
| tab | Accept suggestion (Tab completion) | docs |
| ctrl+rightcmd+right macOS | Accept next word (Tab completion, partial accept) | docs |
terminal
| Keys | Does | Src |
|---|---|---|
| ctrl+kcmd+k macOS | Open terminal prompt bar (natural-language -> shell command) | docs |
| ctrl+entercmd+enter macOS | Run generated command | docs |
| esc | Accept command | docs |
Cursorterminal
Anywhere
| Keys | Does | Src |
|---|---|---|
| shift+tab | Rotate between modes (Agent, Plan, Ask) | docs |
| shift+enter | Insert a newline instead of submitting (multi-line prompts) | docs |
| ctrl+d | Exit the CLI | docs |
| ctrl+j | Insert a newline (universal alternative that works in all terminals) | docs |
| ctrl+r | Review changes | docs |
| i | Add follow-up instructions (while in the review flow) | docs |
| up/down | Cycle through previous messages (Navigation) / scroll (during review) | docs |
| left/right | Switch files (during the review flow) | docs |
| @ | Select files/folders to include in context | docs |
Copilotvscode extension
chat
| Keys | Does | Src |
|---|---|---|
| ctrl+alt+ictrl+cmd+i macOS | Open/focus the Copilot Chat view (side panel)workbench.action.chat.open | docs |
| ctrl+shift+alt+lcmd+opt+shift+l macOS | Open Quick Chat (transient inline chat popover, not the full panel)workbench.action.quickchat.toggle | docs |
| ctrl+ncmd+n macOS | Start a new chat session (clears current Chat view thread) | docs |
| ctrl+shift+i (win) / ctrl+shift+alt+i (linux)cmd+shift+i macOS | Switch the Chat view into Agent mode | docs |
| ctrl+alt+.option+cmd+. macOS | Open the model picker in the Chat view | docs |
| ctrl+alt+upopt+cmd+up macOS | Go to the previous prompt in the current chat session | docs |
| ctrl+alt+downopt+cmd+down macOS | Go to the next prompt in the current chat session | docs |
| ctrl+alt+pageupopt+cmd+pageup macOS | Go to the previous code block in the chat session | docs |
| ctrl+alt+pagedownopt+cmd+pagedown macOS | Go to the next code block in the chat session | docs |
completion
| Keys | Does | Src |
|---|---|---|
| tab | Accept the full ghost-text inline suggestion (or its first line if multi-line)editor.action.inlineSuggest.commit | docs |
| escape | Dismiss the current inline suggestioneditor.action.inlineSuggest.hide | docs |
| alt+]option+] macOS | Show next inline suggestion (cycle forward)editor.action.inlineSuggest.showNext | docs |
| alt+[option+[ macOS | Show previous inline suggestion (cycle backward)editor.action.inlineSuggest.showPrevious | docs |
| alt+\option+\ macOS | Manually trigger an inline suggestioneditor.action.inlineSuggest.trigger | docs |
| ctrl+rightcmd+right macOS | Accept the suggestion word-by-wordeditor.action.inlineSuggest.acceptNextWord | docs |
| none (no default) | Accept the suggestion one line at a timeeditor.action.inlineSuggest.acceptNextLine | docs |
| ctrl+entercmd+enter macOS | Open the Copilot completions panel showing multiple suggestions in a new editor tab | docs |
inline-chat
| Keys | Does | Src |
|---|---|---|
| ctrl+icmd+i macOS | Open inline chat at the cursor position in the editorinlineChat.start | docs |
terminal
| Keys | Does | Src |
|---|---|---|
| ctrl+icmd+i macOS | Open inline chat in the integrated terminalworkbench.action.terminal.chat.start | docs |
Copilotterminal
Anywhere
| Keys | Does | Src |
|---|---|---|
| shift+tab | Cycle between Standard, Plan, and Autopilot session modes | docs |
| esc | Cancel the current operation; press twice to interrupt the running turn, or to stop background agents when the main agent is idle | docs |
| ctrl+c | Cancel operation / clear input. Press twice to exitrl | docs |
| ctrl+d | Shutdownrl | docs |
| ctrl+l | Clear the screenrl | docs |
| ctrl+enter or ctrl+qcmd+enter or ctrl+q macOS | Queue a message to send while the agent is busy | docs |
| ctrl+r | Reverse search through command historyrl | docs |
| up / down | Navigate the command historyrl | docs |
| ctrl+a | Move to beginning of the line (when typing)rl | docs |
| ctrl+e | Move to end of the line (when typing); when the prompt input is empty instead, this same key expands all items in the response timelinerl | docs |
| ctrl+b | Move to the previous characterrl | docs |
| ctrl+f | Move to the next character (when typing); when the prompt input is empty instead, this same key opens timeline searchrl | docs |
| ctrl+h | Delete the previous characterrl | docs |
| ctrl+k | Delete from cursor to end of the line. If the cursor is at the end of the line, delete the line breakrl | docs |
| ctrl+u | Delete from cursor to beginning of the linerl | docs |
| ctrl+w | Delete the previous wordrl | docs |
| ctrl+vcmd+v macOS | Paste from clipboard as an attachment | docs |
| ctrl+z | Suspend the process to the background (Unix)rl | docs |
| ctrl+x then / | Run a slash command after you have already started typing a prompt | docs |
| ctrl+x then e | Edit the prompt in an external editor ($EDITOR) | docs |
| ctrl+x then b | Promote the running task or shell command to the background | docs |
| ctrl+x then o | Open the most recent link from the response timeline | docs |
| ctrl+g | Edit the prompt in an external editor ($EDITOR) | docs |
| ctrl+o | With an empty prompt input, expand the most recent item in the response timeline to show more detail | docs |
| ctrl+t | Expand/collapse the display of the model's reasoning in responses | docs |
| shift+enter or alt+entershift+enter or option+enter macOS | Insert a newline in the prompt input without submitting | docs |
| @ then filename | Include a file's contents as context (input prefix, not a modifier-key binding) | docs |
| # then number | Include a GitHub issue or pull request as context | docs |
| ! then command | Execute a shell command directly, bypassing Copilot; '!' alone on an empty prompt enters shell mode for running multiple shell commands in sequence, exited via Esc or Ctrl+C | docs |
| $ | Hand the terminal over to a real interactive shell ($SHELL on Unix, %COMSPEC% on Windows), suspending the CLI UI entirely so job control, full-screen apps, tab completion, and colors work natively | docs |
| ? | Open quick help, when the prompt input is empty; press again to dismiss and insert a literal '?' | docs |
completion
| Keys | Does | Src |
|---|---|---|
| tab or ctrl+y | Accept the current inline completion suggestion | docs |
How it works in each tool
Section titled “How it works in each tool”Verified against 2.1.222 on 2026-08-07. Bindings below were read from the official keybindings reference and cross-checked against action strings in the installed binary.
The input line is readline-based. Ctrl+A / Ctrl+E move to line start and end, Ctrl+U and Ctrl+K kill backwards and forwards, Ctrl+W deletes the previous word, and Ctrl+Y yanks the last killed text back. None of these touch your system clipboard.
Ctrl+X is a chord prefix. Pressed alone it does nothing visible - it arms a two-key sequence (Ctrl+X Ctrl+K, and others). If a keystroke seems to vanish, this is usually why.
Stopping the agent: press Esc. It interrupts mid-turn and keeps the work done so far. Double-tapping Esc does one of two things depending on the prompt: with text in it, it clears the prompt and saves the draft to history (Up recalls it); with the prompt empty, it opens the rewind menu to restore or summarize from an earlier point. Ctrl+C also interrupts a running operation, or clears the input when nothing is running, but Esc is the one that transfers to every other terminal agent here.
Session control: Ctrl+D on an empty input exits, requiring a double press. Ctrl+Z suspends the process to the shell - fg brings it back.
Images: Ctrl+V pastes an image from the clipboard, inserting an [Image #N] chip into the prompt.
Views: Ctrl+O toggles the verbose transcript, Ctrl+T toggles the to-do checklist, Ctrl+B backgrounds a running Bash task, Ctrl+R opens reverse history search over your previous prompts.
Multi-line: Ctrl+J inserts a newline without submitting.
Modes: Shift+Tab cycles permission modes - default → acceptEdits → plan, plus any additional modes you have enabled, such as auto or bypassPermissions.
Rebinding: ~/.claude/keybindings.json maps keys to action ids such as chat:submit, app:interrupt, app:exit. The action id is the stable identifier; defaults move between releases. Eleven documented actions ship with no default key at all, so they are only reachable if you bind them yourself.
A vim mode exists for the input line, with its own normal/insert bindings.
Verified against 0.146.0 on 2026-08-07, read from the keymap source rather than documentation - Codex has no prose docs for its keymap, but it ships a complete action table in source that also backs the in-app /keymap picker.
Esc is the interrupt key, not Ctrl+C. Esc also drives a distinctive two-stage backtrack: press once to prime, again to open the transcript, then Left/Right to pick an earlier prompt and Enter to fork the conversation from there.
Ctrl+C when idle quits immediately, with no confirmation prompt. The double-press-to-quit guard exists in the code but is compiled off (DOUBLE_PRESS_QUIT_SHORTCUT_ENABLED = false). While a turn is running it interrupts instead. Ctrl+D behaves the same way when the composer is empty, and deletes the character under the cursor when it isn’t.
Line editing is readline-style: Ctrl+A/Ctrl+E, Ctrl+U/Ctrl+K, Ctrl+W, Ctrl+Y, plus Alt+B/Alt+F for word movement.
Useful non-obvious ones: Ctrl+G opens the current draft in $EDITOR. Ctrl+O copies the last agent response to the clipboard - not “open.” Ctrl+R opens reverse history search. Ctrl+V pastes an image from the clipboard as an attachment; pasting text is a separate path.
Multi-line: Ctrl+J, Shift+Enter and Alt+Enter all insert a newline. Shift+Tab cycles the collaboration mode.
Rebinding: the whole keymap is user-remappable under tui.keymap.*, and /keymap opens a picker in-app. Twenty-two bindings are reserved and cannot be remapped, including Ctrl+C, Ctrl+D, Ctrl+V, Shift+Tab and Esc.
Two actions ship with no default key: toggle_vim_mode and toggle_fast_mode. They are real and bindable, just invisible until you bind them.
Verified against v1.18.13 on 2026-08-07, read from the keybind definitions and dispatcher source. OpenCode has by far the largest keymap here - roughly 140 named actions, around 40 of which ship unbound.
Ctrl+X is the leader key. It arms a two-second window in which a second key selects from a whole command vocabulary (<leader>m for the model list, and so on). This is a broader mechanism than a chord prefix, and it means Ctrl+X never cuts anything.
Esc interrupts the model’s in-flight response (session_interrupt). Ctrl+C clears the input box (input_clear) rather than copying or cancelling.
Ctrl+R renames the session. It is not reverse history search - OpenCode has no reverse-search binding. If you have muscle memory from Claude Code or Codex, this is the most surprising divergence in the set.
Ctrl+D is context-scoped and can be destructive. In the input line it forward-deletes a character; in dialogs it resolves to session_delete, stash_delete or dialog.move_session.delete depending on what has focus.
Keys are resolved by focus layer, not by a precedence table. Several keys appear against multiple actions in the config and do not actually conflict: a managed text-area layer is active only while the prompt has focus and wins there, and the history-recall handler declines the keystroke unless the cursor is already at the buffer edge, falling through to plain cursor movement otherwise.
Multi-line: Shift+Enter, Ctrl+Enter, Alt+Enter and Ctrl+J all insert a newline.
Rebinding: every binding is user-configurable through tui.json, which also sets the leader key and its timeout, supports disabling a binding, and merges with the defaults rather than replacing them.
No modal/vim editing was found in the TUI source as of the commit checked. Unverified: a third-party claim of a personal implementation exists; treat it as neither confirmed nor supported by the source checked.
Two separate surfaces, two unrelated keymaps. Cursor is a VS Code fork whose headline shortcuts are editor commands, and it also ships cursor-agent, a terminal agent with its own small binding set. Nothing transfers between them.
Sourced from Cursor’s official shortcut reference and checked on 2026-08-07. Cursor does not version-stamp its docs, and its defaults have shifted between releases more than once, so a lot of third-party shortcut content is stale.
In the editor.
Cmd/Ctrl+K opens Inline Edit at the cursor. In stock VS Code that combination is a chord prefix - it waits for a second key - so this is a silent override of one of the most-used bindings in the editor.
Cmd/Ctrl+L opens the chat panel, overriding the near-universal terminal convention where Ctrl+L clears the screen.
Cmd/Ctrl+I opens the agent/composer surface. Anyone arriving from Copilot has this in their fingers for a different panel.
Shift+Tab rotates agent modes. Tab in the chat input cycles to the next message rather than indenting.
In cursor-agent (terminal).
Shift+Enter inserts a newline, Shift+Tab rotates between Agent, Plan and Ask, Ctrl+D exits, Ctrl+R opens review, and @ attaches context. There is no dedicated shortcuts reference page for the CLI - these are scattered across the CLI docs.
Unverified: Cursor’s documentation indicates that Esc accepts - that is, runs - an AI-generated terminal command rather than cancelling it. That inverts the near-universal cancel convention and we have not been able to confirm it first-hand. Check before relying on it.
Rebinding: everything goes through VS Code’s own keybindings UI and keybindings.json. Cursor does not publish command ids for most of its AI features, so rebinding them means finding the command in the keyboard-shortcuts UI rather than looking up an identifier.
Two separate surfaces. The VS Code extension and the Copilot CLI have completely different keymaps, and the CLI’s is the larger of the two.
In VS Code.
Tab accepts the ghost-text suggestion. This is the single most consequential rebinding in any tool here, because Tab already meant “indent” to every developer alive. When a suggestion is showing, indentation is not what you get.
Esc dismisses the active suggestion rather than doing nothing. Alt+] / Alt+[ cycle through alternative suggestions. Ctrl/Cmd+Enter opens a side-by-side panel of full completions instead of inserting a newline. Ctrl/Cmd+→ accepts the suggestion one word at a time, hijacking word-navigation while ghost text is visible.
Ctrl/Cmd+I opens inline chat, in the editor or the terminal.
Most of these are contributed keybindings and are rebindable through VS Code’s keyboard-shortcuts UI. Several have no officially published command id, which makes those the ones most likely to drift silently between releases.
In the Copilot CLI.
The input line is readline-based - Ctrl+A, Ctrl+E, Ctrl+B, Ctrl+F, Ctrl+K, Ctrl+U, Ctrl+W all behave as standard Unix line editing.
Ctrl+Y breaks that pattern. Instead of yanking back killed text, it accepts the current inline completion - the same action as Tab. If you have just killed a line with Ctrl+U, the key you would reach for to undo it does something else entirely.
Esc cancels the current operation. Ctrl+C cancels or clears the prompt on the first press, and exits on a second. Ctrl+X is a chord prefix - Ctrl+X E opens $EDITOR. Ctrl+R opens reverse search over the CLI’s own history. Shift+Tab cycles between Standard, Plan and Autopilot modes.
Unverified: treat Ctrl+D with care. The documentation lists it as bare “Shutdown,” with no press-count qualifier or confirmation language - unlike Ctrl+C, which explicitly says press twice. The docs also say nothing about whether an in-flight turn is recoverable.
Rebinding: no configuration mechanism for the CLI’s keys is documented. Assume they are fixed.
Verified first-hand against an installed 0.82.1 on 2026-08-07, cross-checked against Pi’s own keybindings documentation and compiled source. Despite being the most minimal harness in this set, Pi ships a full keymap - roughly a third of it inherited readline editing, the rest its own.
Esc cancels the current agent turn. In dialogs and selectors it closes or backs out instead.
Clipboard keys behave unusually here, more so than in any other tool:
Ctrl+Ccopies the selection if one exists, and otherwise clears the editor. It does not send SIGINT.Ctrl+Vpastes an image from the clipboard, with a text fallback.Ctrl+Xcopies the last assistant message. It does not cut.
Ctrl+R renames the current session, matching OpenCode rather than Claude Code or Codex. No reverse history search was found.
Line editing is readline-style: Ctrl+A/Ctrl+E, Ctrl+B/Ctrl+F, Ctrl+W, Ctrl+K, Ctrl+U, Ctrl+Y, with Alt+B/Alt+F/Alt+D for word operations. Ctrl+Z suspends the process to the shell.
Useful ones: Ctrl+G opens the current input in $VISUAL or $EDITOR. Ctrl+P cycles the active model when model patterns are configured. Shift+Enter and Ctrl+J insert a newline.
Rebinding: ~/.pi/agent/keybindings.json maps keys onto namespaced action ids (tui.editor.*, app.*), and every default is remappable.
Known gaps, stated honestly. No prompt-history recall was found - Up/Down move the cursor within the multiline buffer rather than stepping through previous submissions. Unverified: approval-prompt bindings may reuse the generic list-select keys. A further set of fullscreen-mode bindings exists only on the unreleased main branch and is deliberately excluded here.
Comparison
Section titled “Comparison”| Task | Claude Code | Codex | OpenCode | Cursor | Copilot | Pi |
|---|---|---|---|---|---|---|
| Stop the current run | Esc | Esc | Esc | Esc | Esc | Esc |
| Insert a newline | Ctrl+J | Ctrl+J | Ctrl+J | Host editor/terminal | Host editor/terminal | Ctrl+J |
| Rebind defaults | ~/.claude/keybindings.json | TUI keymap settings | tui.json | VS Code keybindings | VS Code keybindings | ~/.pi/agent/keybindings.json |
| Main caveat | readline and Claude chords share a line editor | TUI actions vary by mode | leader/chord prefixes change context | IDE and terminal layers overlap | surface-specific keymaps | extensions can add bindings |
Name collisions
Section titled “Name collisions”- “Keybindings” means a user config file of action ids in Claude Code and Pi; in Cursor and Copilot it means VS Code’s keybindings UI, a different system with different precedence.
Ctrl+Xis a leader key in OpenCode and a chord prefix in Claude Code and Copilot CLI. A leader arms a timed window for a whole command vocabulary; a chord prefix waits for one specific completion. Neither cuts.Ctrl+Rsplits the field: reverse history search in Claude Code, Codex and Copilot CLI; rename the session in OpenCode and Pi.- “Vim mode” is not one feature. Claude Code ships one. Codex has the action but no default key. Nothing equivalent was found in OpenCode’s source.