Claude Code Keybindings
Rebind any shortcut in Claude Code. Covers the 17 contexts, keystroke syntax, unbinding defaults, and keybindings.json example configs.
Your fingers expect Ctrl+K to pop a command palette. Claude Code has other ideas. Each wrong reflex costs a second of thought and a beat of flow.
The cost stacks up. A long Claude Code session runs on muscle memory, and bad defaults fight that muscle memory on every keystroke. Years of VS Code, Vim, or Emacs habits don't unlearn on command. Retraining your hands to match someone else's shortcut layout is wasted effort.
The fix is built in. One JSON file, organized by context, handles every shortcut you care about. You get chord sequences, modifier stacks, and the option to kill a default outright. Edits go live the moment you save. Here is how to wire it up so the tool feels like yours.
First Steps With Custom Keybindings
Type /keybindings inside Claude Code. That slash command creates or opens ~/.claude/keybindings.json for you. The file lives in the usual ~/.claude/ folder next to the rest of your settings.
The shape of the file is plain:
{
"$schema": "https://platform.claude.com/docs/schemas/claude-code/keybindings.json",
"$docs": "https://code.claude.com/docs/en/keybindings",
"bindings": [
{
"context": "Chat",
"bindings": {
"ctrl+e": "chat:externalEditor",
"ctrl+u": null
}
}
]
}Three top-level keys do all the work:
$schema- Optional. Pointing at the JSON Schema URL hands your editor free autocompletion and validation. Worth keeping.$docs- Optional. A docs link for quick lookups.bindings- The array where your shortcuts live. One entry per context.
That schema field is a quiet win. Any editor with JSON Schema support then suggests valid actions and context names as you type.
Saved files are picked up on the fly. Edit, hit save, and the new bindings work right away. No restart.
How Contexts Work
Each binding sits inside a context, and the context decides when the shortcut is live. A Chat binding only fires when the main chat input has focus. Reuse the same keys across contexts and they can each do something different.
There are 17 contexts in Claude Code:
| Context | When It's Active |
|---|---|
Global | Everywhere in the app |
Chat | Main chat input area |
Autocomplete | Autocomplete menu is open |
Settings | Settings menu is open |
Confirmation | Permission and confirmation dialogs |
Tabs | Tab navigation components |
Help | Help menu is visible |
Transcript | Transcript viewer |
HistorySearch | History search mode (Ctrl+R) |
Task | Background task is running |
ThemePicker | Theme picker dialog |
Attachments | Image/attachment bar navigation |
Footer | Footer indicator navigation |
MessageSelector | Rewind dialog message selection |
DiffDialog | Diff viewer navigation |
ModelPicker | Model picker effort level |
Select | Generic select/list components |
Plugin | Plugin dialog (browse, discover, manage) |
Global is the odd one. A shortcut here fires no matter what view you are in. Use it with care. A global Ctrl+K will trigger inside chat, inside autocomplete, and inside a diff review.
Every Action, Listed
Action names follow a namespace:action pattern. Below is every action in every context, with its default key.
Global Actions
These fire anywhere:
| Action | Default | What It Does |
|---|---|---|
app:interrupt | Ctrl+C | Cancel current operation |
app:exit | Ctrl+D | Exit Claude Code |
app:toggleTodos | Ctrl+T | Toggle task list visibility |
app:toggleTranscript | Ctrl+O | Toggle verbose transcript |
Heavy users of the task list hit app:toggleTodos all day. If Ctrl+T clashes with your terminal, move it somewhere friendlier.
Chat Actions
Where most of your keystrokes land:
| Action | Default | What It Does |
|---|---|---|
chat:cancel | Escape | Cancel current input |
chat:cycleMode | Shift+Tab | Cycle permission modes |
chat:modelPicker | Cmd+P / Meta+P | Open model picker |
chat:thinkingToggle | Cmd+T / Meta+T | Toggle extended thinking |
chat:submit | Enter | Submit message |
chat:undo | Ctrl+_ | Undo last action |
chat:externalEditor | Ctrl+G | Open in external editor |
chat:stash | Ctrl+S | Stash current prompt |
chat:imagePaste | Ctrl+V (Alt+V on Windows) | Paste image |
On Windows without VT mode, chat:cycleMode falls back to Meta+M. That applies to Node builds older than 24.2.0/22.17.0, and Bun older than 1.2.23. The shortcut controls permission modes, which gates what Claude is allowed to do.
History Actions
Walking back through past prompts:
| Action | Default | What It Does |
|---|---|---|
history:search | Ctrl+R | Open history search |
history:previous | Up | Previous history item |
history:next | Down | Next history item |
Autocomplete Actions
Active while the suggestions menu is open:
| Action | Default | What It Does |
|---|---|---|
autocomplete:accept | Tab | Accept suggestion |
autocomplete:dismiss | Escape | Dismiss menu |
autocomplete:previous | Up | Previous suggestion |
autocomplete:next | Down | Next suggestion |
Confirmation Actions
Bindings for permission and approval dialogs:
| Action | Default | What It Does |
|---|---|---|
confirm:yes | Y, Enter | Confirm action |
confirm:no | N, Escape | Decline action |
confirm:previous | Up | Previous option |
confirm:next | Down | Next option |
confirm:nextField | Tab | Next field |
confirm:previousField | (unbound) | Previous field |
confirm:cycleMode | Shift+Tab | Cycle permission modes |
confirm:toggleExplanation | Ctrl+E | Toggle permission explanation |
permission:toggleDebug | Ctrl+D | Toggle permission debug info |
Transcript Actions
| Action | Default | What It Does |
|---|---|---|
transcript:toggleShowAll | Ctrl+E | Toggle show all content |
transcript:exit | Ctrl+C, Escape | Exit transcript view |
History Search Actions
| Action | Default | What It Does |
|---|---|---|
historySearch:next | Ctrl+R | Next match |
historySearch:accept | Escape, Tab | Accept selection |
historySearch:cancel | Ctrl+C | Cancel search |
historySearch:execute | Enter | Execute selected command |
Task Actions
| Action | Default | What It Does |
|---|---|---|
task:background | Ctrl+B | Background current task |
Theme, Help, and Settings Actions
| Action | Context | Default | What It Does |
|---|---|---|---|
theme:toggleSyntaxHighlighting | ThemePicker | Ctrl+T | Toggle syntax highlighting |
help:dismiss | Help | Escape | Close help menu |
settings:search | Settings | / | Enter search mode |
settings:retry | Settings | R | Retry loading usage data |
Navigation Actions
Tabs, attachments, footer, diffs, model picker, selects, and the message selector all live here:
| Action | Context | Default | What It Does |
|---|---|---|---|
tabs:next | Tabs | Tab, Right | Next tab |
tabs:previous | Tabs | Shift+Tab, Left | Previous tab |
attachments:next | Attachments | Right | Next attachment |
attachments:previous | Attachments | Left | Previous attachment |
attachments:remove | Attachments | Backspace, Delete | Remove attachment |
attachments:exit | Attachments | Down, Escape | Exit attachment bar |
footer:next | Footer | Right | Next footer item |
footer:previous | Footer | Left | Previous footer item |
footer:openSelected | Footer | Enter | Open selected item |
footer:clearSelection | Footer | Escape | Clear selection |
messageSelector:up | MessageSelector | Up, K | Move up in list |
messageSelector:down | MessageSelector | Down, J | Move down in list |
messageSelector:top | MessageSelector | Ctrl+Up, Shift+Up | Jump to top |
messageSelector:bottom | MessageSelector | Ctrl+Down, Shift+Down | Jump to bottom |
messageSelector:select | MessageSelector | Enter | Select message |
diff:dismiss | DiffDialog | Escape | Close diff viewer |
diff:previousSource | DiffDialog | Left | Previous diff source |
diff:nextSource | DiffDialog | Right | Next diff source |
diff:previousFile | DiffDialog | Up | Previous file |
diff:nextFile | DiffDialog | Down | Next file |
diff:viewDetails | DiffDialog | Enter | View details |
modelPicker:decreaseEffort | ModelPicker | Left | Decrease effort level |
modelPicker:increaseEffort | ModelPicker | Right | Increase effort level |
select:next | Select | Down, J, Ctrl+N | Next option |
select:previous | Select | Up, K, Ctrl+P | Previous option |
select:accept | Select | Enter | Accept selection |
select:cancel | Select | Escape | Cancel selection |
plugin:toggle | Plugin | Space | Toggle plugin |
plugin:install | Plugin | I | Install plugins |
Keystroke Syntax
The syntax for defining key combinations is easy on the eyes.
Modifiers
Join modifier keys to the target key with +:
ctrlorcontrolfor the Control keyalt,opt, oroptionfor Alt/Optionshiftfor Shiftmeta,cmd, orcommandfor Meta/Command
A few examples:
ctrl+k Single modifier + key
shift+tab Shift + Tab
meta+p Command/Meta + P
ctrl+shift+c Multiple modifiersUppercase Letters and Shift
A bare uppercase letter already means Shift. So K in a binding is the same thing as shift+k. Handy for Vim-style layouts where j and J (or k and K) map to different actions.
One gotcha. Once a modifier is attached, case stops mattering. ctrl+K and ctrl+k are the same binding. With modifiers present, uppercase is only cosmetic.
Chord Sequences
Chords give you multi-key shortcuts. Put a space between the keystrokes:
ctrl+k ctrl+s Press Ctrl+K, release, then press Ctrl+S
That opens up far more room than single-key bindings. Running low on unused key combos? Chords add hundreds of fresh options without stepping on anything.
Special Keys
Non-character keys have their own names:
escapeorescenterorreturntabspaceup,down,left,rightbackspace,delete
Turning Off Default Shortcuts
Set the action to null and the default goes away:
{
"bindings": [
{
"context": "Chat",
"bindings": {
"ctrl+s": null
}
}
]
}Handy when a default steps on your terminal, your OS, or another tool running next to Claude Code. You can also null out a default and then give that same key a new action.
Reserved Shortcuts
Two keys are hardcoded. They cannot be rebound:
| Shortcut | Reason |
|---|---|
| Ctrl+C | Hardcoded interrupt/cancel |
| Ctrl+D | Hardcoded exit |
Claude Code will reject any attempt to remap these, and that is the right call. Every terminal user alive expects Ctrl+C to interrupt and Ctrl+D to exit. Those are Unix conventions.
Terminal Multiplexer Conflicts
Running Claude Code inside tmux, GNU screen, or a similar multiplexer? The prefix keys will bite you:
| Shortcut | Conflict |
|---|---|
| Ctrl+B | tmux prefix (press twice to send through) |
| Ctrl+A | GNU screen prefix |
| Ctrl+Z | Unix process suspend (SIGTSTP) |
task:background ships with Ctrl+B, which is exactly the tmux prefix. If you live in tmux, remap it on day one:
{
"bindings": [
{
"context": "Task",
"bindings": {
"ctrl+b": null,
"ctrl+shift+b": "task:background"
}
}
]
}That conflict trips up a lot of developers who run Claude Code inside multiplexed sessions.
Vim Mode Interaction
Turn on vim mode with /vim and it works on a separate layer from keybindings:
- Vim mode handles text editing. Cursor motion, INSERT and NORMAL modes, motions, text objects.
- Keybindings handle app-level actions. Toggling the task list, submitting a message, opening the model picker.
The Escape key is the clearest split. Inside vim mode, Escape leaves INSERT and drops to NORMAL. It does not call chat:cancel. Most Ctrl+key shortcuts cut straight through vim mode into the keybinding layer, so Ctrl+T still toggles the task list even from NORMAL mode.
In NORMAL mode, ? pulls up the vim-style help, not Claude Code's help screen.
Heavy thinking-mode users on vim mode should park chat:thinkingToggle behind a chord that stays clear of vim motions. The interactive mode guide covers how vim mode, slash commands, and the rest of the interactive features slot together.
Validation and Diagnostics
Claude Code checks your keybindings file on every save and flags:
- Parse errors in JSON syntax or structure
- Invalid context names that don't match the 17 supported contexts
- Reserved shortcut conflicts if you try to rebind Ctrl+C or Ctrl+D
- Terminal multiplexer conflicts for Ctrl+B, Ctrl+A, and Ctrl+Z
- Duplicate bindings in the same context
Hit /doctor to see every keybinding warning in one place. That is the fastest path to figuring out why a shortcut misbehaves.
Practical Configuration Examples
A few configurations pulled from real-world setups.
VS Code User Configuration
Coming from VS Code and want the usual shortcuts back:
{
"$schema": "https://platform.claude.com/docs/schemas/claude-code/keybindings.json",
"bindings": [
{
"context": "Chat",
"bindings": {
"ctrl+k ctrl+s": "chat:stash",
"ctrl+shift+p": "chat:modelPicker",
"ctrl+g": "chat:externalEditor"
}
},
{
"context": "Global",
"bindings": {
"ctrl+shift+t": "app:toggleTodos"
}
}
]
}tmux-Friendly Setup
Sidesteps the tmux prefix clash:
{
"$schema": "https://platform.claude.com/docs/schemas/claude-code/keybindings.json",
"bindings": [
{
"context": "Task",
"bindings": {
"ctrl+b": null,
"ctrl+shift+b": "task:background"
}
}
]
}Minimal Distraction Setup
Kill the shortcuts your fingers keep triggering by accident:
{
"$schema": "https://platform.claude.com/docs/schemas/claude-code/keybindings.json",
"bindings": [
{
"context": "Chat",
"bindings": {
"ctrl+s": null,
"ctrl+u": null
}
}
]
}Chord-Based Power User
Park rarer features behind chords so the single-key combos stay free:
{
"$schema": "https://platform.claude.com/docs/schemas/claude-code/keybindings.json",
"bindings": [
{
"context": "Chat",
"bindings": {
"ctrl+k ctrl+t": "chat:thinkingToggle",
"ctrl+k ctrl+m": "chat:modelPicker",
"ctrl+k ctrl+e": "chat:externalEditor"
}
}
]
}Your most-used actions keep their one-key bindings. Everything else is one chord away.
Building Your Own Configuration
Go slow. Remapping the entire app in one pass is a trap. Here is a saner approach:
- Run
/keybindingsto generate the config file - Pick your three worst pain points (shortcut clashes, missing bindings, accidental fires)
- Fix those three first with targeted entries
- Run
/doctorto validate the file - Spend a full Claude Code session on it and note what still snags
- Iterate by adding or tweaking bindings as friction shows up
Customizing every possible shortcut is not the goal. The goal is closing the gap between what your hands expect and what Claude Code does. Five to ten bindings is usually enough for the tool to feel native.
Keybindings handle the physical side. CLAUDE.md and custom slash commands handle the behavioral side. Wire them together and Claude Code starts to feel like it was built around your workflow.
Stop configuring. Start building.
AI SEO and GEO Optimization
A rundown of Generative Engine Optimization: how to get content cited inside ChatGPT, Claude, and Perplexity responses instead of just ranked on Google.
Claude Code Status Line Setup
How to wire up a custom Claude Code status line. Configuration, JSON input, ready-to-copy scripts in bash, Python, and Node.js.