gwm-cli 1.0.0

git worktree manager — TUI + CLI, native libgit2, per-repo bootstrap
Documentation
---
title: Keybindings
description: Every key the TUI listens to — list, sidebar, filter, confirm overlay, link prompts.
---

# Keybindings

The full key map for `gwm`'s ratatui interface. Press `?` at any time for the same table as an in-app overlay.

> **The keymap is fully configurable.** Every binding below is a
> **default** — the `[tui.keys]` block in `.gwm.toml` rebinds any
> list-view action, including multi-key chords like `g g`. The `?`
> help overlay is keymap-driven, so it always renders the bindings you
> actually resolved, not these defaults. See [Keymap & command
> palette](/tui/keymap-and-palette) and
> [Configuration → `[tui.keys]`]/configuration/gwm-toml#tuikeys.
>
> **Modal keys are rebindable too.** The keys inside each overlay below are
> defaults of typed verbs under `[tui.keys.modal.<context>]`
> ([#219]https://github.com/kbrdn1/gwm-cli/issues/219). The same physical key
> can mean different things per modal (`Enter` is `submit` in the create form
> but `activate` in the delete-confirm modal). `Ctrl+C`, the list view's
> contextual `Esc` / `Enter`, and the PTY overlay's emergency `Esc` stay
> hard-coded by design. See [Keymap & command
> palette](/tui/keymap-and-palette#rebindable-modal-keys).

> **Keymap redesign (v0.10)**[#290]https://github.com/kbrdn1/gwm-cli/issues/290
> reshuffled the list-view bindings into logical chords and added several
> verbs (pull / push, rename, exit-to-worktree, branch / worktree-name yanks,
> mux pane, user macros). The table below is the resolved default set printed by
> `gwm tui keys`. Pre-#290 `[tui.keys]` slugs (`git_tui`, `review`, `yank`,
> `open`, `open_menu`, …) still load through backward-compat aliases, so an
> existing override keeps working.

## list view (default)

| Key         | Action (slug)                                                                                     |
|:------------|:--------------------------------------------------------------------------------------------------|
| `` / `k`   | previous worktree (`up`) — scrolls the sidebar when it has focus                                  |
| `` / `j`   | next worktree (`down`) — scrolls the sidebar when it has focus                                    |
| `gg`        | jump to the first worktree (`top`)                                                                |
| `G` / `End` | jump to the last worktree (`bottom`)                                                              |
| `n`         | new worktree (`create`; form: type → issue → description) · gated by the [TOFU trust ledger]/configuration/trust-ledger — refuses with a status-bar hint on untrusted `.gwm.toml` |
| `c`         | rename the selected worktree (`edit_worktree`; form pre-filled from the current branch) — renames the local branch, the remote branch if it exists, and moves the worktree directory, all off-thread |
| `d`         | delete selected (`delete`; confirm `y` · countdown when `D` is armed — see [confirm-overlay]/tui/confirm-countdown) |
| `D`         | toggle "delete branch on remove" (`delete_branch`)                                                |
| `b`         | re-run bootstrap on the selected worktree (`bootstrap`), off-thread (the statusbar spinner animates while it runs; the Report view opens when it finishes) · same [trust gate]/configuration/trust-ledger as `n` |
| `s`         | sync the selected worktree onto its upstream (`sync`) — fetch + rebase, off-thread (statusbar spinner); refuses a dirty tree / missing upstream / conflicts |
| `p`         | git pull the selected worktree's branch (`pull`), off-thread (progress in the status bar)         |
| `P`         | git push the selected worktree's branch (`push`), off-thread                                      |
| `f`         | refresh the worktree list (`refresh`)                                                             |
| `F`         | refresh the GitHub issue / PR status (`fetch_github`) — off-thread `gh` fetch, statusbar spinner  |
| `e`         | quit the TUI and print the selected path to stdout (`exit_to_worktree`) — enables `cd "$(gwm)"` shell patterns |
| `o`         | open a native `$SHELL` in an embedded [PTY overlay]/tui/open-dispatch at the worktree (`terminal_pty`) |
| `O`         | open a native `$SHELL` fullscreen, suspending the TUI (`terminal_fullscreen`)                     |
| `l`         | launch the configured [`[git_tui]`]/tui/launchers command in an embedded [PTY overlay]/tui/launchers#the-embedded-pty-overlay-l--r (`lazygit_pty`) |
| `L`         | launch the configured [`[git_tui]`]/tui/launchers command fullscreen (`lazygit_fullscreen`)     |
| `r`         | launch the configured [`[review]`]/tui/launchers command in a [PTY overlay]/tui/launchers#the-embedded-pty-overlay-l--r (`review_pty`) — AI / web reviewer over `git diff base..head` |
| `R`         | launch the configured [`[review]`]/tui/launchers command fullscreen (`review_fullscreen`)       |
| `t`         | open the selected worktree in a new tmux / zellij pane (`mux_pane`) — falls back to a status-bar hint when no multiplexer is detected |
| `h`         | run the user-configured [`[tui.macro1]`]/configuration/gwm-toml#tuimacro1-and-tuimacro2 command (`macro_one`) |
| `H`         | run the user-configured [`[tui.macro2]`]/configuration/gwm-toml#tuimacro1-and-tuimacro2 command (`macro_two`) |
| `y`         | yank the selected worktree's **branch name** to the clipboard (`yank_branch_name`)                |
| `Y`         | yank the selected worktree's **path** to the clipboard (`yank_path`) — pbcopy / wl-copy / xclip / xsel / clip |
| `w`         | yank the selected worktree's **slug / name** to the clipboard (`yank_worktree_name`)              |
| `B`         | open menu for the linked issue / PR (`browse_links`; `i` issue, `p` pr → spawns browser)          |
| `.`         | open the gwm documentation in the default browser (`open_docs`)                                   |
| `i`         | link prompt (`link`) — choose `i` or `p`, then digits, to attach an issue / PR                    |
| `V`         | toggle the details sidebar (`toggle_sidebar`) — on a narrow terminal it stacks under the table instead of hiding |
| `S`         | toggle the sidebar Details mode (`toggle_sidebar_mode`) — `commits``stashes` — see [stashes mode]/tui/sidebar#stashes-mode |
| `Space`     | cycle the sidebar layout (`cycle_sidebar_layout`) — `auto` (width-driven) → `side-by-side``stacked` |
| `v`         | toggle the sidebar position left ↔ right (`toggle_sidebar_position`; side-by-side layout only)    |
| `Tab`       | swap focus between the worktree list and the sidebar (`focus_swap`)                               |
| `1`         | focus the worktrees pane (`focus_worktrees`)                                                      |
| `2`         | open (if hidden) and focus the status pane (`focus_status`)                                       |
| `3`         | open the Command Logs overlay (`command_logs`) — scrollable transcript of the commands gwm ran    |
| `4`         | open the [Settings panel]#settings-panel-4 (`config_panel`) — edit theme / worktree / TUI knobs and **all keymaps**, with a per-row source column |
| `x`         | open the [exec picker overlay]#exec-picker-overlay-x (`exec_overlay`) — pick a [`[exec.profiles]`]/configuration/gwm-toml#exec profile and run it in a [PTY overlay]/tui/launchers#the-embedded-pty-overlay-l--r on the selected worktree |
| `X`         | open the [clean overlay]#clean-overlay-x (`clean_overlay`) — preview and reclaim build artifacts in the selected worktree (safety countdown before deleting) |
| `/`         | open the [fuzzy filter]/tui/filter bar (`filter`; `Enter` confirms · `Esc` clears)              |
| `:`         | open the [command palette]/tui/keymap-and-palette#command-palette (`command_palette`)           |
| `Enter`     | show selected path in status bar                                                                  |
| `?`         | help overlay (`help`)                                                                             |
| `q`         | quit (`quit`)                                                                                     |
| `Esc`       | clear a sticky filter if any, otherwise quit                                                      |

## confirm-delete overlay

The overlay shows two selectable buttons, `[ Confirm ]` / `[ Cancel ]`,
with focus defaulting to **Cancel** — the safe choice for a destructive
action, so a stray `Enter` cancels rather than deletes. The classic
`y` / `n` shortcuts still work regardless of focus.

| Key                  | Verb (`[tui.keys.modal.confirm]`)                                               |
|:---------------------|:--------------------------------------------------------------------------------|
| `` / `h`            | focus `[ Confirm ]` (`focus_confirm`)                                           |
| `` / `l`            | focus `[ Cancel ]` (`focus_cancel`)                                             |
| `Tab`                | toggle focus between the two buttons (`toggle_focus`; defaults to Cancel)       |
| `Enter`              | activate the focused button (`activate`; Confirm → delete · Cancel → dismiss)   |
| `y`                  | confirm (`confirm`; classic) or arm the countdown (when `D` is armed — see [countdown]/tui/confirm-countdown) |
| `y` again            | during an armed countdown, **disarms** it without firing                        |
| `n` / `Esc`          | cancel (`cancel`)                                                               |

While the safety countdown is armed an animated spinner sits beside the
progress bar as a live loader.

## create / rename overlay

Both the New Worktree form (`n`) and the rename form (`c`) share the same
`[tui.keys.modal.create]` verbs:

| Key                       | Verb (`[tui.keys.modal.create]`)                        |
|:--------------------------|:--------------------------------------------------------|
| `Tab`                     | next field (`next_field`)                               |
| `BackTab` (`Shift+Tab`)   | previous field (`prev_field`)                           |
| `` / `` / `h`           | previous worktree type (`prev_type`; on the type field) |
| `` / `` / `l`           | next worktree type (`next_type`; on the type field)     |
| `Enter`                   | submit and bootstrap / rename (`submit`; subject to the [TOFU trust gate]/configuration/trust-ledger) |
| `Esc`                     | cancel (`cancel`)                                       |

If the repo's `.gwm.toml` isn't trusted, `Enter` lands the form's status bar on a refuse message instead of running the bootstrap — the worktree directory is **not** created in that case, so you can fix the trust state in another terminal (`gwm bootstrap` from CLI, or set `GWM_ALLOW_BOOTSTRAP=1` and relaunch) and retry. See [Configuration → TOFU trust ledger](/configuration/trust-ledger#tui-behaviour) for the exact wording and full decision tree.

## settings panel (`4`)

`4` opens the in-TUI Settings panel. Tabs (`Tab` / `Shift+Tab`) split it into
`Theme`, `Worktree`, `TUI`, `Keys` and the read-only `All` resolved-config
view. `L` flips the edit layer between the project `.gwm.toml` and the
user-global config; the layer selector decides which file an edit writes.

| Key            | Action                                                              |
|:---------------|:-------------------------------------------------------------------|
| `Tab` / `BackTab` | next / previous tab                                             |
| `` / ``      | select a field / binding (scrolls on the `All` tab)                |
| `L`            | toggle the edit layer (project ↔ global)                           |
| `Space` / `Enter` | activate: cycle a choice, edit a value, or **rebind a key**     |
| `Esc` / `q`    | close                                                              |

### Keys tab — live keymap editor

The `Keys` tab lists **every** rebindable binding: the global list-view
actions (`[global]`) and every modal verb grouped by context
(`[modal.<context>]`), each with its current key(s) and a `default` / `user` /
`repo` source badge. Select a binding and press the activate key (`Space` /
`Enter`) to capture a new key — the key column becomes a `[ … ]` input:

| Key             | Action                                                            |
|:----------------|:-----------------------------------------------------------------|
| any key         | record it into the binding                                       |
| `Enter`         | commit a multi-stroke global chord (modal verbs auto-commit on the first key) |
| `Backspace`     | drop the last captured stroke (global chord)                     |
| `Esc`           | cancel the capture, leaving the binding unchanged                |

The capture writes the binding as a TOML array to the targeted layer
(`[tui.keys]` for a global action, `[tui.keys.modal.<context>]` for a modal
verb), validates it (a conflict / prefix-collision aborts the write and leaves
the previous binding live), and reloads the keymap so the new key works
immediately. An empty capture (`Enter` with nothing recorded — global only)
unbinds the action. `Esc`, `Enter`, `Backspace` and `Ctrl+C` can't themselves
be assigned via capture — hand-edit `.gwm.toml` for those (see
[`[tui.keys]`](/configuration/gwm-toml#tuikeys)).

## issue / PR link prompt (`i`)

The first stage (`[tui.keys.modal.link.choose_target]`) is a navigable
issue-or-PR chooser; the second (`[tui.keys.modal.link.input_number]`) takes the
number.

| Stage              | Key            | Verb                              |
|:-------------------|:---------------|:----------------------------------|
| target choice      | `j` / ``      | next target (`next`)              |
| target choice      | `k` / ``      | previous target (`prev`)          |
| target choice      | `i`            | select issue (`issue`)            |
| target choice      | `p`            | select PR (`pr`)                  |
| target choice      | `Enter`        | confirm the target (`accept`)     |
| target choice      | `Esc`          | cancel (`cancel`)                 |
| number input       | digits         | type the issue / PR number        |
| number input       | `Enter`        | commit the link (`submit`)        |
| number input       | `Esc`          | cancel (`cancel`)                 |

## issue / PR open menu (`B`)

| Key       | Verb (`[tui.keys.modal.open_menu]`)   |
|:----------|:--------------------------------------|
| `j` / `k` / `` / `` | move between issue and PR (`toggle`) |
| `i`       | open the linked issue in the browser (`issue`) |
| `p`       | open the linked PR in the browser (`pr`) |
| `Enter`   | open the highlighted target (`accept`)|
| `Esc` / `q` | dismiss (`close`)                   |

## exec picker overlay (`x`)

Lists the `[exec.profiles.*]` names; `Enter` resolves the highlight to its
`command` array and runs it — **with no shell** — in an embedded PTY overlay
rooted at the selected worktree (the same overlay `l` / `r` use). Refuses to
open with a status-bar hint when no `[exec.profiles]` are configured. Unlike
the CLI `gwm exec --workspace`, the overlay runs the profile in the **single**
selected worktree (one PTY cannot fan out).

| Key            | Verb (`[tui.keys.modal.exec]`)        |
|:---------------|:--------------------------------------|
| `j` / ``      | next profile (`next`)                 |
| `k` / ``      | previous profile (`prev`)             |
| `Enter`        | run the highlighted profile (`accept`)|
| `Esc`          | cancel (`cancel`)                     |

## clean overlay (`X`)

Previews the reclaimable build artifacts in the selected worktree and deletes
them on confirmation. The scan is gated by the **exact** safety check
`gwm clean --yes` uses — only directories git treats as ignored **and** holding
no tracked files are counted; anything else is listed as *skipped* and never
touched. The picker always opens on a `(default)` choice — the set `gwm clean`
resolves with no `--profile` (the built-in `target` / `node_modules` / `dist` /
`build`, or `[clean.profiles.default]` when defined) — followed by any
configured `[clean.profiles]`; `j` / `k` cycle them, re-scanning each time. The
confirm key arms the same safety countdown as
the [delete-confirm overlay](/tui/confirm-countdown) (driven by
`[tui] confirm_countdown_secs`); a second confirm or `Esc` disarms it, and the
reclaim fires automatically when the countdown elapses.

> The scan runs **synchronously** when the overlay opens, so opening it on a
> very large `target/` can briefly block the UI while the sizes are computed.
> Moving the scan onto the off-thread spine (#231) is a follow-up.

| Key            | Verb (`[tui.keys.modal.clean]`)       |
|:---------------|:--------------------------------------|
| `j` / ``      | next profile (`next`)                 |
| `k` / ``      | previous profile (`prev`)             |
| `y` / `Enter`  | arm / fire the reclaim (`confirm`)    |
| `n` / `Esc`    | cancel / disarm (`cancel`)            |

## help overlay (`?`)

Keys render as coloured **badges** (the same chip style as the bottom
statusline) with themed section headers, so a binding stands out from
its description. All colours follow the resolved `[theme]`.

| Key                          | Action               |
|:-----------------------------|:---------------------|
| `Esc` / `q` / `?` / `Enter`  | dismiss              |

## v0.10 rebind summary

The [#290](https://github.com/kbrdn1/gwm-cli/issues/290) keymap redesign moved
several keys to make room for the new verbs. The biggest changes to relearn:

| Pre-v0.10 | v0.10+ | Why                                                                     |
|:----------|:-------|:------------------------------------------------------------------------|
| `L` (link) | `i`   | `L` now launches lazygit fullscreen; `i` is the issue/PR link prompt    |
| `S` (sync) | `s`   | lowercase mutating verb; `S` now toggles the sidebar Commits ↔ Stashes  |
| `p` (toggle delete-branch) | `D` | `p` is now `pull`; `D` arms "delete branch on remove"     |
| `O` (open menu) | `B` | `O` now opens a fullscreen terminal; `B` browses the issue/PR links     |
| `o` (open dispatch) | `o` (terminal PTY) | `o` now opens an embedded `$SHELL` PTY overlay   |
| `v` / `V` (sidebar toggle / layout) | `V` / `Space` | `V` toggles the sidebar, `Space` cycles layout |
| `y` (yank path) | `Y`  | `y` now yanks the **branch name**; `Y` yanks the path; `w` yanks the slug |
| `R` (review) | `r` / `R` | `r` runs the review in a PTY overlay, `R` runs it fullscreen        |
| _(none)_  | `c`    | rename the selected worktree (`edit_worktree`)                          |
| _(none)_  | `e`    | exit the TUI to the selected path (`exit_to_worktree`)                  |
| _(none)_  | `t`    | open the worktree in a new tmux / zellij pane (`mux_pane`)              |
| _(none)_  | `h` / `H` | run `[tui.macro1]` / `[tui.macro2]`                                  |

Existing `[tui.keys]` overrides written with the old slugs (`git_tui`,
`review`, `yank`, `open`, `open_menu`, …) keep working through backward-compat
aliases — only the physical defaults moved.

## v0.6 rebind summary

Three keys moved when [#75 (configurable launchers)](https://github.com/kbrdn1/gwm-cli/issues/75) landed. Update muscle memory accordingly:

| Pre-v0.6 | v0.6+ | Why                                                                                       |
|:---------|:------|:------------------------------------------------------------------------------------------|
| `r`      | `f`   | `r` kept as **alias** for muscle memory, but the documented mnemonic is now `f`           |
| `R`      | `F`   | freed `R` for the new review launcher; `F` does the GitHub refresh `R` used to do         |
| _(none)_ | `R`   | launch the configured `[review]` command (lumen / claude / codex / aider / gh / custom)   |

If you wired any of these into a custom script (unlikely — they're TUI-only), nothing breaks; this is purely about the in-app overlay.