KOSHI0.6.0
Configuration
v0.5configurationfield manual

keybinding.kdl

Rebind koshi's keys — leader, chord timeouts, key grammar, and the normal, locked, and pane-move mode blocks.

User bindings are applied over the built-in ones. A user binding wins for the same key; every key you do not mention keeps its built-in action.

The file sits directly in the config directory. Each terminal reads it for itself when it attaches, so two terminals on one session can use different shortcuts.

Any error drops the whole file. Run koshi keys conflicts after editing, and koshi keys list to see what is actually active.

Top-level settings

version is required. Every other setting is optional and may appear at most once, beside the mode blocks.

KeyValueDefaultSince
chord-timeout-msinteger — ambiguity delay when one sequence is both a complete binding and the prefix of a longer binding500≥ 0.1.0
which-key-delay-msinteger — accepted and validated, with no effect in this release: the hint bar shows the keys that continue a shortcut at once300≥ 0.1.0
max-chord-depthinteger 0–255 — most keys one shortcut may chain. A shortcut longer than this can never fire, and koshi keys conflicts reports it4≥ 0.1.0
leaderstring — what <leader> stands for: a modifier run like "C-", or a single chord like "<Space>""C-"≥ 0.1.0
unlock-alternativestring — the chord that leaves locked mode, in place of <C-l>none≥ 0.1.0

Key grammar

Keys use angle brackets. Spaces join keys into a sequence.

WrittenMeans
<C-t>Ctrl+t. Modifiers are C Ctrl, A Alt, S Shift, D Super
<A-S-n>Several modifiers on one key
<Tab> <CR> <Esc> <BS> <Space>Named keys. The others are <Del>, <Insert>, <Home>, <End>, <PageUp>, <PageDown>, <Left>, <Right>, <Up>, <Down>, and <F1> to <F24>
TAn uppercase letter is that letter with Shift: <S-t>
<leader>pThe leader, then p

Always bracket named keys. A bare word like Tab is read as one chord per character — T, then a, then b.

With leader "C-", <leader>p is <C-p>. With leader "<Space>" it becomes <Space> then p. Explicit keys such as <A-f> never move when the leader changes.

mode blocks

A mode block holds the bindings for one mode: "normal" is the usual one, "locked" passes keys straight to the program except the unlock chord, and "pane-placement" holds keys used while previewing a pane move.

NodeMeaning
bind "<key>" "core:action"Two strings: the key sequence and the full, namespaced action
remove "<key>"Void a key in this mode so lower layers no longer bind it

A bare action name like new-tab is rejected with a hint — write core:new-tab. A bind takes no arguments: a fixed choice lives in the action name (core:new-pane-left), an open value lives in the CLI. Run koshi actions list for every name you can bind to.

core:quit leaves the session; it does not end one. See Actions.

The complete default keymap

keybinding.kdl
// keybinding.kdl — the complete default keymap.
version 2

chord-timeout-ms 500
which-key-delay-ms 300
max-chord-depth 4
leader "C-"                      // the leader = the Ctrl modifier run (default)
// unlock-alternative "<A-u>"    // replaces <C-l>; also bind it to core:unlock in "locked"

mode "normal" {
    // reserved lock/unlock chord — explicit, never moves with the leader
    bind "<C-l>" "core:lock"

    // leader-relative — rebind `leader` and all of these move together
    bind "<leader>q" "core:quit"
    bind "<leader>g" "core:mouse-select"
    bind "<leader>p n" "core:new-pane"          // <C-p> n with the default leader
    bind "<leader>p h" "core:new-pane-left"
    bind "<leader>p j" "core:new-pane-down"
    bind "<leader>p k" "core:new-pane-up"
    bind "<leader>p l" "core:new-pane-right"
    bind "<leader>p s" "core:new-pane-stacked"
    bind "<leader>p m" "core:begin-pane-placement"
    bind "<leader>p x" "core:close-pane-tree"
    bind "<leader>p <Left>" "core:focus-pane-left"
    bind "<leader>p <Down>" "core:focus-pane-down"
    bind "<leader>p <Up>" "core:focus-pane-up"
    bind "<leader>p <Right>" "core:focus-pane-right"
    bind "<leader>s <Left>" "core:resize-pane-left"
    bind "<leader>s <Down>" "core:resize-pane-down"
    bind "<leader>s <Up>" "core:resize-pane-up"
    bind "<leader>s <Right>" "core:resize-pane-right"
    bind "<leader>t n" "core:new-tab"           // <C-t> n with the default leader
    bind "<leader>t x" "core:close-tab"

    // explicit chords — they never move with the leader
    bind "<A-f>" "core:toggle-pane-fullscreen"
    bind "<Tab>" "core:next-tab"
    bind "<S-Tab>" "core:previous-tab"
}

mode "locked" {
    // locked mode passes every other key straight to the program.
    bind "<C-l>" "core:unlock"
    bind "<leader>q" "core:quit"
    bind "<leader>p m" "core:begin-pane-placement"
    bind "<leader>g" "core:mouse-select"
}

mode "pane-placement" {
    bind "<Left>" "core:select-pane-target-left"
    bind "<Down>" "core:select-pane-target-down"
    bind "<Up>" "core:select-pane-target-up"
    bind "<Right>" "core:select-pane-target-right"
    bind "<S-Left>" "core:select-pane-insertion-left"
    bind "<S-Down>" "core:select-pane-insertion-down"
    bind "<S-Up>" "core:select-pane-insertion-up"
    bind "<S-Right>" "core:select-pane-insertion-right"
    bind "<Space>" "core:cycle-pane-placement-span"
    bind "<Tab>" "core:select-next-placement-tab"
    bind "<S-Tab>" "core:select-previous-placement-tab"
    bind "<CR>" "core:confirm-pane-placement"
    bind "<Esc>" "core:cancel-pane-placement"
}

Moving a pane

<leader>p m starts a move preview in the current client. The internal mode name is "pane-placement"; its keymap takes priority over the normal or locked map until the move is accepted or cancelled. The base mode is retained, so cancelling a move started from locked mode returns to locked mode.

Arrow keys choose a pane to swap with. Shift+Arrow chooses an edge to insert beside the selected pane or stack. Space cycles the available split spans. Tab and Shift+Tab preview another visible tab, where the same keys can choose a pane or insertion edge. Enter accepts the move; Escape cancels it. The pane-placement map must keep a live core:cancel-pane-placement binding.

Only the client that started the move sees the preview. After it is accepted, all clients see the new layout. By default the mode stays active after an accepted move; stay-in-pane-placement-mode-after-placement #false makes it end instead. Mouse drags can also preview and accept a move. To insert with a mouse, hold Shift when starting the drag.

Checking your work

koshi keys validate ~/.config/koshi/keybinding.kdl   # before adopting it
koshi keys conflicts                                 # clashes and dead shortcuts
koshi keys describe "<C-p> l"                        # what one sequence does
koshi keys list --scope user                         # only what you added

On this page