keybindings.json
Where the key map lives, and how to add, change or remove a binding by hand.
Every shortcut in Overterm is a command with an id, and the key on it is
whatever keybindings.json says last. Settings ▸ Keyboard Shortcuts writes
that file for you; editing it by hand works just as well and takes effect
immediately.
~/Library/Application Support/Overterm/keybindings.json
The format
VS Code’s: a list of objects, each with a key and a command.
// Overterm keybindings (Settings ▸ Keyboard Shortcuts writes this file; editing it by hand works too).
// { "key": "cmd+shift+d", "command": "splits.down" } binds a key; "-splits.down" removes that key from it.
[
{ "key": "cmd+j", "command": "palette.show" },
{ "key": "ctrl+cmd+t", "command": "tasks.new" }
]
It is read as JSON5, so comments and trailing commas are fine. A file that does not parse leaves the shortcuts exactly as they were, and Settings says why.
Each entry adds a key to a command. A command holds one key — a menu item can only carry one — so if several entries name the same command, the last one wins.
Writing a key
Modifiers joined to the key with +, in any order:
| Modifier | Spellings |
|---|---|
| ⌘ | cmd, command, super |
| ⇧ | shift |
| ⌥ | alt, opt, option |
| ⌃ | ctrl, control |
The key itself is a single character (d, [, =, ,) or one of these
names:
enter tab space escape backspace delete
up down left right home end pageup pagedown
f1 … f12
cmd++ binds ⌘+, if you want it.
Keys are written by position on a US layout, which is why they survive a
keyboard change. ⌘, is cmd+, even on a Turkish Q layout, where
AppKit shows it as ⌘Ö.
Removing a binding
Prefix the command with -. The entry says “this key is no longer this
command’s”, and it only takes effect when the key matches the one the command
currently has:
[{ "key": "cmd+l", "command": "-agents.askSelection" }]
That leaves Ask an Agent About the Selection with no key at all, and frees ⌘L for the terminal.
Worked examples
Move the palette to ⌘J. One entry is enough; the old ⌘K goes with it, because a command holds one key.
[{ "key": "cmd+j", "command": "palette.show" }]
Put Tab Info back on ⌘I, and move the inbox. Two commands cannot share a key, so move the inbox first — or rather, in the same file:
[
{ "key": "shift+cmd+i", "command": "inbox.show" },
{ "key": "cmd+i", "command": "tabs.info" }
]
Give the editor’s delete-line its own key. editor.deleteLine is
⇧⌘K by default, which is also Clear the Screen in the terminal.
They do not clash — the editor’s commands are a scope of their own — but you
may still want them apart:
[{ "key": "ctrl+shift+k", "command": "editor.deleteLine" }]
Unbind a terminal command entirely.
[{ "key": "shift+cmd+k", "command": "-terminal.clear" }]
How it reaches the terminal
Ghostty sees keys in the terminal before the menu does, so a key Ghostty holds would be a menu item that silently does nothing. Overterm therefore writes extra lines into its Ghostty overrides file for whatever differs from the defaults:
- for a menu command, an
unbindof Ghostty’s old key and of the new one, so the menu gets the key; - for a terminal command, an
unbindof the old key and the new one bound to Ghostty’s action.
You do not have to do any of this, and you should not put keybind lines in
your own Ghostty config to work around it — Overterm’s overrides are loaded
after yours and would win anyway.
Two keys are deliberately left shared: ⌘F is the editor’s find bar and the terminal’s search, and Settings does not report that as a conflict. Only a key you chose that collides with another command is called a clash.
Command ids
Every id, with its default key and what it does, is in Keyboard shortcuts. Settings ▸ Keyboard Shortcuts is searchable and shows the key in force, which is the quickest way to find an id you half remember.
An entry naming a command Overterm does not know, or a key it cannot bind, is listed as a problem in Settings and otherwise ignored — the rest of the file still applies.
Resetting
Settings ▸ Keyboard Shortcuts can reset one command or all of them. By hand, an empty list is the factory default:
[]