# keybinding.kdl (/docs/v0.1/configuration/keybinding-kdl)



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](/docs/v0.1/configuration#where-the-files-go).

<Callout type="warn">
  Any error drops the whole file. Run `koshi keys conflicts` after editing, and
  `koshi keys list` to see what is actually active.
</Callout>

## Top-level settings [#top-level-settings]

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

| Key                  | Value                                                                                                     | Default | Since   |
| -------------------- | --------------------------------------------------------------------------------------------------------- | ------- | ------- |
| `chord-timeout-ms`   | integer — ambiguity delay when one sequence is both a complete binding and the prefix of a longer binding | `500`   | ≥ 0.1.0 |
| `which-key-delay-ms` | integer — ms before the hint bar appears                                                                  | `300`   | ≥ 0.1.0 |
| `max-chord-depth`    | integer — most keys one shortcut may chain (≥ 1)                                                          | `4`     | ≥ 0.1.0 |
| `leader`             | string — what `<leader>` stands for: a modifier run like `"C-"`, or a single chord like `"<Space>"`       | `"C-"`  | ≥ 0.1.0 |
| `unlock-alternative` | string — an extra chord that leaves locked mode                                                           | none    | ≥ 0.1.0 |

## Key grammar [#key-grammar]

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

| Written                       | Means                                              |
| ----------------------------- | -------------------------------------------------- |
| `<C-t>`                       | Ctrl+t. Modifiers are `C` Ctrl, `A` Alt, `S` Shift |
| `<Tab>` `<CR>` `<Esc>` `<BS>` | Named keys                                         |
| `<leader>p`                   | The leader, then `p`                               |

<Callout type="warn">
  Always bracket named keys. A bare word like `Tab` is read as one chord **per
  character** — `T`, then `a`, then `b`.
</Callout>

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 [#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.

| Node                         | Meaning                                                           |
| ---------------------------- | ----------------------------------------------------------------- |
| `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.

## The complete default keymap [#the-complete-default-keymap]

```kdl title="keybinding.kdl"
// keybinding.kdl — the complete default keymap.
version 1

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>"    // optional extra unlock chord; off by default

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 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>g" "core:mouse-select"
}
```

## Checking your work [#checking-your-work]

```bash
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
```
