Every keyboard shortcut is a named command, and the [keybindings] table maps
command ids to the keys you want them on:
[keybindings]
"hunk.app.quit" = "ctrl+x" # one chord
"hunk.review.nextHunk" = ["]", "ctrl+n"] # several chords for one command
"hunk.review.focusFilter" = "/" # takes "/" back from content search
"hunk.view.toggleMenuBar" = false # unbind it entirely
"myext.toggle" = "ctrl+g" # extension commands tooEvery id starts with the name of whoever owns the command: Hunk's own commands
live under hunk., and an extension's live under its extension id. That split
is structural — hunk is a reserved extension id, so an extension can never
mint a command id that shadows a built-in, whatever Hunk adds later. Extension commands currently
run on review surfaces; history resolves its built-in command set without claiming review-only extension chords.
Rules worth knowing:
- User bindings replace defaults. Listing chords for a command is the complete set of keys it answers to, not an addition to the shipped ones.
- A key you bind is yours. Any command that held the same chord only as a
default gives it up, keeping its other keys. Above,
hunk.search.findhands/to the filter whilen/Nstill step search matches. false(or[]) unbinds a command, leaving its keys doing nothing.- Unbound commands are one line away. The file filter ships without a key
(Tab and the File menu reach it), as do
hunk.review.nextNote/previousNote(}/{step through annotated hunks); one[keybindings]line gives any of them a chord. - Two entries claiming one chord is a conflict: the first in the file wins and the session reports the other. Unknown command ids and unusable chords are reported the same way, and the rest of the table still applies.
- Escape clears an active visual selection contextually after overlays and extension modes have had their normal ownership. Without a selection, Escape remains available to extension commands because clear-selection is unbound.
Chords are ctrl, alt/option, cmd/meta, and shift joined with +
around a base key: a character ("y", "["), an uppercase letter for its
shifted form ("G"), or a named key ("tab", "pageup", "left", "f2").
shift applies to letters and named keys only — for a shifted symbol or digit,
write the character the shift produces ("!", not "shift+1"), since that is
what terminals report. ctrl+<letter> also matches an unnamed bare control
byte; named Tab and Enter events stay distinct. alt/option matches both
explicit Alt events and the Escape-prefixed form used by legacy terminals. A
legacy terminal cannot distinguish Alt from Meta, so alt+n and meta+n may
overlap there; Kitty keyboard events keep them distinct.
Inline saved notes also expose clickable Edit, Reply, and (for reply-free user notes)
Delete actions. E edits the first editable user note in the selected hunk and R replies
to its first visible stored note. Replies inherit the code anchor and may be nested without a
product depth limit. Static sidecar annotations are not reply targets, and a parent cannot be
deleted until its replies are removed.
The built-in commands and the keys they ship with:
On a terminal, hunk log opens its read-only history browser automatically. Its hunk.history.*
commands use the same configurable keybinding resolver as review while retaining history-specific effects.
Shared application commands such as hunk.app.quit, hunk.app.toggleHelp, and
hunk.view.openThemeSelector keep the same ids on both surfaces. F10 opens File, View, Navigate, Commit, and Help menus;
View includes Hunk's shared theme selector and an optional Graph view that replaces the default
day-grouped timeline with commit-topology lanes. It uses Up/Down or j/k to move; press v first to
extend a contiguous commit selection with those same keys. Shift+Up/Shift+Down or uppercase K/J extend
directly, and Escape collapses the selection. PageUp/PageDown, b/f, or Shift+Space/Space page
through history; u/d or Ctrl-U/Ctrl-D move by half a page; g/G or Home/End jump,
/ to search, n/N for matches, t to choose a theme, r to refresh, y to copy the focused commit's full id,
Enter to open the selection in normal Hunk review, and q or Ctrl-C to quit. With a mouse, Shift-click a row to extend the
selection when the terminal forwards modifiers, click a commit id to open it immediately, click the adjacent copy
icon to copy its full immutable id, click elsewhere on a row to select it, or double-click a row to open it.
Range selection is unavailable with --all or author, message, date, and path filters because those traversals
can interleave unrelated commits or hide intermediate commits. Quitting the opened review returns to the retained history selection and viewport. The Commit menu's
Compare with first parent and Compare with parent… actions compare the selected commit against
an ordered provider-owned parent; they do not navigate the history selection to that parent.
History-specific commands:
| Command id | Does | Default keys |
|---|---|---|
hunk.history.openSelection |
Open the selected commit(s) | enter |
hunk.history.copyRevision |
Copy the focused commit id | y |
hunk.history.refresh |
Refresh repository history | r |
hunk.history.previousCommit |
Move to the previous commit | up, k |
hunk.history.nextCommit |
Move to the next commit | down, j |
hunk.history.startVisualSelection |
Start visual selection | v |
hunk.history.clearSelection |
Clear visual selection | escape |
hunk.history.extendPrevious |
Extend selection upward | shift+up, K |
hunk.history.extendNext |
Extend selection downward | shift+down, J |
hunk.history.pageUp |
Move up one page | pageup, b, shift+space |
hunk.history.pageDown |
Move down one page | pagedown, space, f |
hunk.history.halfPageUp |
Move up half a page | u, ctrl+u |
hunk.history.halfPageDown |
Move down half a page | d, ctrl+d |
hunk.history.jumpToFirst |
Jump to the first commit | home, g |
hunk.history.jumpToLast |
Jump to the last commit | end, G |
hunk.history.search |
Search history | / |
hunk.history.nextMatch |
Select the next match | n |
hunk.history.previousMatch |
Select the previous match | N |
hunk.history.toggleGraph |
Toggle graph presentation | (none) |
hunk.history.toggleUnicode |
Toggle Unicode graph lines | (none) |
hunk.history.toggleAuthor |
Toggle author metadata | (none) |
hunk.history.toggleDate |
Toggle date metadata | (none) |
hunk.history.toggleDecorations |
Toggle ref decorations | (none) |
hunk.history.openFirstParent |
Compare with first parent | (none) |
hunk.history.openParent |
Choose a parent to compare | (none) |
hunk.history.showAbout |
Show application information | (none) |
Review and shared commands:
| Command id | Does | Default keys |
|---|---|---|
hunk.app.openAgentSkill |
Show agent skill | (none) |
hunk.app.quit |
Quit | q |
hunk.app.refresh |
Refresh the review | r |
hunk.app.toggleFocusArea |
Switch focus between files and filter | tab |
hunk.app.toggleHelp |
Toggle help | ? |
hunk.review.alignCurrentLineBottom |
Align current line to viewport bottom | (none) |
hunk.review.alignCurrentLineCenter |
Center current line in viewport | (none) |
hunk.review.alignCurrentLineTop |
Align current line to viewport top | (none) |
hunk.review.clearSelection |
Clear the active visual selection | (none) |
hunk.review.copySelection |
Copy the active visual selection | y |
hunk.review.deleteActiveNote |
Delete active review note | D |
hunk.review.editActiveNote |
Edit active review note | E |
hunk.review.editSelectedFile |
Open the selected file in your editor | e |
hunk.review.focusFilter |
Focus the file filter | (none) |
hunk.review.halfPageDown |
Scroll down half a page | d, ctrl+d |
hunk.review.halfPageUp |
Scroll up half a page | u, ctrl+u |
hunk.review.jumpToBottom |
Jump to end | G, end |
hunk.review.jumpToTop |
Jump to start | g, home |
hunk.review.nextAnnotatedFile |
Next annotated file | (none) |
hunk.review.nextAnnotatedHunk |
Next annotated hunk | } |
hunk.review.nextFile |
Next file | . |
hunk.review.nextHunk |
Next hunk | ] |
hunk.review.nextNote |
Next review note | (none) |
hunk.review.pageDown |
Scroll down one page | pagedown, space, f |
hunk.review.pageUp |
Scroll up one page | pageup, b, shift+space |
hunk.review.previousAnnotatedFile |
Previous annotated file | (none) |
hunk.review.previousAnnotatedHunk |
Previous annotated hunk | { |
hunk.review.previousFile |
Previous file | , |
hunk.review.previousHunk |
Previous hunk | [ |
hunk.review.previousNote |
Previous review note | (none) |
hunk.review.replyToActiveNote |
Reply to active review note | R |
hunk.review.saveNote |
Save a draft review note | ctrl+s |
hunk.review.scrollCodeLeft |
Scroll code left (shifted scrolls fast) | left, shift+left |
hunk.review.scrollCodeRight |
Scroll code right (shifted scrolls fast) | right, shift+right |
hunk.review.startNote |
Add a review note | c |
hunk.review.startVisualSelection |
Start visual line selection | v |
hunk.review.stepDown |
Move down one line or note | down, j |
hunk.review.stepUp |
Move up one line or note | up, k |
hunk.review.toggleHunkGap |
Expand or collapse the selected context | z |
hunk.search.find |
Search diff content | / |
hunk.search.next |
Next search match | n |
hunk.search.previous |
Previous search match | N |
hunk.view.applyFilePresentationToAllMatching |
Apply current file presentation to all matches | (none) |
hunk.view.cursorLineNumber |
Mark the current line number | (none) |
hunk.view.cursorLineOff |
Hide the current-line marker | (none) |
hunk.view.cursorLineRow |
Highlight the current row | (none) |
hunk.view.layoutAuto |
Auto layout | 0 |
hunk.view.layoutSplit |
Split layout | 2 |
hunk.view.layoutUnified |
Unified layout | 1 |
hunk.view.openThemeSelector |
Choose theme | t |
hunk.view.toggleAgentNotes |
Toggle agent notes | a |
hunk.view.toggleCopyDecorations |
Toggle copy decorations | (none) |
hunk.view.toggleFilesPane |
Toggle files pane | s |
hunk.view.toggleHunkHeaders |
Toggle hunk headers | m |
hunk.view.toggleLineNumbers |
Toggle line numbers | l |
hunk.view.toggleLineWrap |
Toggle line wrapping | w |
hunk.view.toggleMenuBar |
Toggle menu bar | M |
The files-pane command follows the named hunk:files role. If an extension
replaces that role, the command and View → Files pane toggle the resolved
replacement on any terminal edge without changing unrelated panes. Remapping or
unbinding hunk.view.toggleFilesPane changes that role-aware action, not an
extension pane's own commands. The former hunk.view.toggleSidebar id remains a
compatibility alias; prefer the files-pane name in new config and extension
code. Likewise, hunk.view.layoutStack remains a deprecated alias for
hunk.view.layoutUnified, so existing keybindings and extension command calls
continue to select the canonical unified layout.
Commands marked (none) ship without a key: they remain callable by command id
and can be assigned a shortcut through [keybindings]. Some also appear in a
menu, while semantic commands such as current-line alignment do not need a menu
entry.
The menus and the controls help dialog (?) show the keys for the commands they
present, so remapping something changes what they advertise. Unbinding a menu
command keeps its menu item and simply stops showing a key.
Extension commands are named <extensionId>.<commandId> and remap the same way
(see docs/extensions.md). An explicitly activated extension
keyboard mode is a routing layer rather than a second command table: it may
consume a key, pass it to these resolved bindings, or consume it and exit. Its
multi-key grammar and counts are extension-owned, but resolved actions should
invoke these same public hunk.* commands.
Routing precedence is host prompts and dialogs, menus/overlays, focused text
inputs, an interactive file-view mode, a session extension keyboard mode, then
the command table and focused review widget. Keys that belong to a dialog,
menu, or focused text input — Esc, Enter — are part of those widgets rather
than commands, and are not remappable. The note composer's save shortcut is the
command hunk.review.saveNote (default ctrl+s) and is remappable; while the
composer is focused it still wins over the command table, using the resolved
chord. Escape is also the reserved exit from each active extension mode, so an
extension cannot trap the keyboard.
[keybindings]
"hunk.review.saveNote" = "ctrl+enter" # Zellij-friendly; default is ctrl+s[keybindings] is read from your user config only — never from a repository's
.hunk/config.toml. Which keys do what is a property of your keyboard and your
habits, so a checkout you review cannot rearrange them.