Custom Keybindings for the Atuin TUI

One of the longest-standing feature requests for Atuin has finally landed: full custom keybinding support for the search TUI. No more being stuck with our defaults, no more wishing ctrl-d did something else. Your TUI, your rules.

One of the longest-standing feature requests for Atuin has finally landed: full custom keybinding support for the search TUI. No more being stuck with our defaults, no more wishing ctrl-d did something else. Your TUI, your rules.

Custom key bindings · Issue #193 · atuinsh/atuin
I’m using this and liking it. Thank you! Just for the record, I’d like to use different key bindings than the default arrows.

With the new [keymap] config system, you can now fully customize every keybinding in the TUI, with conditional execution.

# Simple binding: ctrl-c returns to your original command
[keymap.emacs]
"ctrl-c" = "return-original"

# Conditional binding: left arrow exits when cursor is at start
[keymap.emacs]
"left" = [
  { when = "cursor-at-start", action = "exit" },
  { action = "cursor-left" },
]

The first matching rule wins. No match? The key passes through.

Conditional Bindings

This is where it gets interesting. You can now express keybindings that depend on the current state of the app:

# ctrl-d: delete char, unless input is empty, then exit
[keymap.emacs]
"ctrl-d" = [
  { when = "cursor-at-start && input-empty", action = "return-original" },
  { action = "delete-char-after" },
]

The condition system supports boolean expressions with &&, ||, !, and parentheses. Available conditions include:

  • cursor-at-start / cursor-at-end
  • input-empty
  • vim-normal-mode / vim-insert-mode
  • And more in the docs

Accept vs Return Selection

We've split the old Accept action into two distinct behaviors:

  • accept: Execute the command immediately (what enter does by default)
  • return-selection: Place the command on your command line without executing (what tab does by default)

Previously, enter_accept toggled this behavior at runtime. Now you can bind whichever action you want to whichever key you want:

# Make enter insert for editing, tab execute immediately
[keymap.emacs]
"enter" = "return-selection"
"tab" = "accept"

There's also return-selection-1 through return-selection-9 for selecting numbered history entries without executing, as well as return-query for returning what you've typed in the search box.

See the docs for the full list of actions

Five Keymaps

The system supports five separate keymaps:

  • [keymap.emacs] - Default mode
  • [keymap.vim-normal] - Vim normal mode
  • [keymap.vim-insert] - Vim insert mode
  • [keymap.inspector] - The history inspector view
  • [keymap.prefix] - After pressing the prefix key (ctrl+a by default)

Each has sensible defaults, and you only need to override what you want to change.

Backward Compatibility

If you're using the old [keys] config (with scroll_exits, exit_past_line_start, etc.), it still works. The new [keymap] takes precedence when present, but your existing config won't break.

If you have both [keys] and [keymap] defined, Atuin will use [keymap] config only and log a warning.

Example: Recreating the Default Emacs Bindings

Want to see what the defaults look like? Here's a taste:

[keymap.emacs]
"ctrl-c" = "return-original"
"ctrl-g" = "return-original"
"ctrl-d" = [
  { when = "cursor-at-start && input-empty", action = "return-original" },
  { action = "delete-char-after" },
]
"esc" = "return-original"
"enter" = "accept"
"tab" = "return-selection"
"ctrl-r" = "cycle-filter-mode"
"ctrl-s" = "cycle-search-mode"
"ctrl-o" = "open-inspector"
"up" = [
  { when = "at-top", action = "exit" },
  { action = "history-prev" },
]
"down" = [
  { when = "no-selection", action = "return-query" },
  { action = "history-next" },
]
"left" = [
  { when = "cursor-at-start", action = "exit" },
  { action = "cursor-left" },
]
"right" = "cursor-right"
"ctrl-a" = "cursor-start"
"ctrl-e" = "cursor-end"
"ctrl-u" = "clear-input"
"ctrl-w" = "delete-word-before"
"backspace" = "delete-char-before"
"delete" = "delete-char-after"
"ctrl-y" = "copy-command"
"page-up" = "page-up"
"page-down" = "page-down"

The full list of actions and conditions is in the advanced keybinding docs.

Getting Started

Update to the latest Atuin and add a [keymap.emacs] section (or whichever mode you use) to your ~/.config/atuin/config.toml. Override just the keys you want to change.

The system is designed to be additive - you don't need to specify everything, just your customizations.


Thanks to everyone who's been asking for this over the years. Your keybindings are finally yours.

Check out the full documentation at docs.atuin.sh/cli/configuration/advanced-key-binding/