Keybindings
Press F1 inside Rove for the live, localized keymap, including your own
overrides. This page is the stable vocabulary and behavior reference.
How keys work
Two things decide what a key does:
- Where. A key is either Rove-wide, or owned by the focused pane.
- How. One press, or the prefix followed by a second key.
Which gives you three patterns:
| Pattern | Example | Used for |
|---|---|---|
| Bare letter | n, d, r | Actions in the focused pane |
| One press | ctrl+t, ctrl+w | Frequent Rove-wide actions |
| Prefix sequence | ctrl+a then i | Everything less frequent |
Inside the embedded engine terminal, unclaimed keys go straight to the engine;
Rove only reserves its explicit chords. The prefix still works there, so
the command menu is reachable from every pane. Press ctrl+q to leave the
terminal without opening it.
Tap the configured prefix once to open the command layer. By default, Rove opens the complete command guide and also shows shortcuts beside clickable controls already on screen, such as New task, Inbox, Kanban, Routines, Zen, Ask agent to create PR, and Settings. In Settings → Keybindings → Prefix tap, choose Complete guide only to hide the on-screen badges while keeping the guide.
Both the badges and guide read the live keymap. A rebound prefix or action changes immediately, and an unbound or currently unreachable action is not advertised. Clicking a guide row rechecks the current pane and modal scope before it runs. The setting changes only whether the pending command layer also marks controls in place. Both choices use the same prefix, second stroke, timeout, pane scope, and cancellation rules.
The prefix
The default first stroke is ctrl+a. Tap it, then press one more key within
5 seconds. A complete on-screen command map appears after a short pause and
shows only actions that can run right now.
| Sequence | Action |
|---|---|
ctrl+a f | New-conversation dialog, preset to "fork a child task": new managed worktree, branched off this Task's branch. Its ATTEMPTS row fans one prompt out to a round of up to 5 |
ctrl+a c | New-conversation dialog, preset to "continue this chat" in a new tab of the same Task directory |
ctrl+a i | Open the Inbox |
ctrl+a h / l | Move focus left / right across panes |
ctrl+a o | Open the Task directory in your editor |
ctrl+a m | Reorder sidebar rows (scope-aware: tab / task / project) |
ctrl+a n | New task |
ctrl+a w | Close the active split, otherwise the tab — the prefix twin of ctrl+w |
ctrl+a 1 / 2 / 3 | Kanban / Routines / Issues |
ctrl+a z | Toggle zen mode |
ctrl+a , | Open Settings |
ctrl+a p (P is the same key) | Create a PR — for the active task, or for the row under the cursor while the sidebar has focus (the focus rule) |
ctrl+a k | Pull the failing PR checks' logs into the task's engine (proposed — awaiting owner sign-off) |
ctrl+a u | Merge the base branch into the task's worktree (proposed — awaiting owner sign-off) |
ctrl+a r | Redraw the screen — erase and fully repaint. While the DAEMON OUT OF DATE banner is up it instead refreshes Rove onto the installed build: restarts the daemon and relaunches the TUI, after a confirm (proposed — awaiting owner sign-off) |
ctrl+a c picks an engine first. Claude and Codex can fork their own
conversations natively. Copilot and Kimi use a transcript handoff even for a
same-engine continuation; a built-in source can also hand off to a different
built-in or custom target. A custom source has no readable transcript, so its
continuation is refused. See Engines.
ctrl+a r is the escape hatch for a screen that has gone wrong: it erases
the display and repaints every cell, so leftover glyphs from a terminal that
reflowed, a resize Rove did not see, or another program writing over Rove all
clear in one frame. It touches nothing but pixels — no task, tab, or engine
state changes — so it is always safe to press. Rove already repaints itself
after a resize, so reach for this only when something slipped past that.
The same stroke changes meaning while the two builds differ (the amber DAEMON
OUT OF DATE banner): then ctrl+a r refreshes Rove onto the installed build
— it stops the daemon and relaunches the TUI, after one confirm — and the
redraw is not bound. Engine sessions live in the PTY host and survive the
relaunch; the tabs reattach to the same sessions. On a current Rove the
refresh is absent from the keymap and the command guide, and r redraws.
The sequence cancels on timeout, esc, an invalid second key, or a change of
focus or dialog.
Hold ctrl to reveal follow-up keys
Hold either Ctrl key for at least 400 ms to open a guide to the keys you can
press next. The guide includes each available direct ctrl+<key> shortcut and
the current prefix entry. Each row omits the ctrl+ prefix because Ctrl is
already held. Bare keys, F-row keys, multi-modifier chords, and individual
prefix commands stay out of this guide. The current Binding Stack determines
the rows, so changing focus or opening a page or dialog narrows the list to the
shortcuts that work there.
The guide also opens while an embedded engine terminal has focus. It does not take ownership of the next key. Releasing Ctrl or pressing any other key closes the guide, and that other key continues through normal shortcut or terminal dispatch.
This guide needs a terminal that reports modifier press and release events through the kitty keyboard protocol. Unsupported terminals ignore Rove's request, so the guide stays unavailable and existing typing and shortcuts keep their old behavior. See Troubleshooting for terminal support.
One-press keys
| Key | Action |
|---|---|
F1 | The live keymap; works from every pane, including inside the terminal (not while a dialog or a full-page view — Settings / Worktrees / Update — is open) |
ctrl+q | Focus the sidebar; pressed again there, quit immediately (q in the sidebar quits with a confirm) |
ctrl+t | New engine tab |
ctrl+e | New-conversation dialog with the engine/shell picker; inside it, ←/→ (or h/l) pick the engine and enter confirms, tab cycles the destination (new tab here → fork a child task → new Scratch task in $HOME) and ctrl+f the context (fresh ⇄ continue this chat). A Scratch destination starts the picked engine, or a bare shell when shell is picked |
ctrl+w | Close the active split, otherwise the tab — closing the last tab leaves the task open with no session |
enter | Reopen a session in a task whose tabs are all closed (only while that empty pane is showing; ctrl+e does the same there) |
ctrl+[ / ctrl+] | Previous / next tab (ctrl+[ needs kitty — see below) |
ctrl+1 … ctrl+9 | Tab N of the current task — the number the folded rail prints on it (needs kitty — see below) |
ctrl+\ | Split right |
ctrl+= | Split down |
F2 | Rename the active split, otherwise the tab |
F3 | Focus the next split |
F4 | Cycle focus forward |
F5 | Confirm and reset the active terminal |
F7 | Jump to the next Inbox item across all projects |
Overlap resolves by context: ctrl+w closes the innermost split when a tab
is split, otherwise the tab. F2 follows the same rule. enter is bound only
by the "no sessions here" pane, which has no input and no tab of its own —
everywhere else in the workspace it reaches the terminal as usual.
New task is ctrl+a n from anywhere (the sidebar also answers to bare
n). It is a prefix sequence, not a direct ctrl+n, so the embedded engine
and shell terminals keep ctrl+n for readline/emacs next-history.
Both split chords need a terminal speaking the kitty keyboard protocol
(legacy terminals can't encode ctrl+=, and ctrl+\ would be SIGQUIT);
reserving ctrl+\ also costs the embedded shell its SIGQUIT. If a split
chord does nothing, rove doctor says whether your terminal answers the
protocol query — that is the first thing to check.
ctrl+[ needs kitty for the same reason. Without the protocol it is not a
chord at all: it sends the same byte as Escape, so the terminal cannot
tell the two apart and Rove reads it as Escape — cycling backwards is
simply unavailable there, with no second binding to fall back on. ctrl+]
has its own byte and works everywhere. The consolation is that the ambiguity
resolves in favour of the engine: ctrl+[ keeps working as Escape inside
the embedded terminal, which is what vim and every CLI's cancel key need.
ctrl+<digit> needs kitty too. Legacy terminals send nothing for ctrl+1 and
ctrl+9, and ctrl+2…ctrl+8 arrive as control bytes that read as other
keys (ctrl+3 is Escape, ctrl+8 is Backspace), so those keep their old
meaning there and tab N is reached with ctrl+] instead.
Horizontal keys: h / l
Wherever ← / → move you sideways — a dialog's engine picker, effort or
status row, the new-task selector fields, the automation schedule segments, the
Kanban board's card cursor — h and l do the same thing, vim-style. They are
always an alternative, never a replacement: the arrow keys keep working.
h/l are live only where ←/→ already are, and only while nothing is
being typed. A focused text field, the composer, or the sidebar's / search
keeps h and l as ordinary letters. The one deliberate exception is the
sidebar itself: right focuses the engine pane, but l there already means
"open the row under the cursor", so the sidebar keeps right alone. In the
Files pane h/l already fold and unfold the tree, which is the same shape.
Sidebar and Files
Bare letters work only while that pane has focus and no dialog or text input is active.
Sidebar
| Key | Action | Key | Action | |
|---|---|---|---|---|
n | New task | r | Rename | |
enter | Open | b | Rename branch | |
l / space | Open the row under the cursor | v | Change engine | |
o | Open Task directory in your editor | s | Settings | |
u | Update page — version check + release notes | / | Search | |
d | Delete Task / forget project | x | Worktrees page | |
gg / shift+g | Top / bottom | |||
shift+p | Pin / unpin managed Task | right | Focus the current engine pane | |
shift+m | Enter reorder mode (scope-aware: tab / task / project) | t | Cycle task sort (default → recent → attention → name) |
Sidebar row verbs (b, v, o, d, r, shift+p, shift+m) act on the
row under the cursor — the highlight j/k moves, which may differ from the
active task until you press enter. Prefix chords (ctrl+a o, ctrl+a p)
are global and act on the active task, except while the sidebar has focus —
both of them then follow the row under the cursor.
In reorder mode, j/k moves the highlighted project and enter or esc
finishes. Project headings themselves aren't cursor rows; the move routes
through a Task row in that project.
Files
| Key | Action |
|---|---|
j / k (or arrows) | Move |
h / l (or ←/→) | Collapse / expand |
enter | Open in your configured editor; changed files use a Vim/Nvim diff when available, otherwise Rove falls back to its read-only preview |
d | Open a read-only diff in a workspace tab without moving focus. On a directory row it opens everything under it as one combined diff |
shift+D | Open the whole worktree's diff in one tab (proposed, awaiting sign-off — the Changes tab's [D] diff everything chip does the same with no chord) |
r | Refresh the current file tab |
b | On Changes, switch working-tree changes ⇄ branch vs base |
o | Open audio, video, or PDF files in the system application |
a | Insert an @path mention into the engine pane |
[ / ] | Switch file tabs |
h / l fold directories on both tabs — on Changes they also expand
and collapse untracked-directory rows.
The sidebar is a tree (project → Task → Terminal Tab) and it never folds, so
everything is always visible. Search (/) matches titles, repos, branches,
and live tab titles, and keeps matching rows' parents so a hit is never
orphaned.
Right-click any row for its context menu; j/k and ⏎ drive it, and a press
anywhere else, or esc, dismisses it. Common row actions also have direct
chords. A Task or tab row also offers New conversation (the ctrl+e
engine/shell picker) and New shell (a bare shell tab) for that worktree,
both enter the Task first, exactly as pressing the chord there would.
These entries have no chord of their own. Set status opens a picker over
the six Task statuses and writes the one you choose. Copy branch name and
Copy path put the Task's branch or recorded worktree path on the system
clipboard (local clipboard command plus OSC 52, so it also works over SSH);
copying never creates the worktree, and a project-main or directory row, whose
stored branch is empty, offers only Copy path. Run again re-fires the
Task's stored brief as a new Task, and appears only on a row that recorded
one. Land into base branch runs the same land the Worktrees page's l
does, and appears only on a managed Task row that has a branch — a
project-main or directory row owns no Rove branch to land. On a project
header, Field notes reads the repo's durable notes (rove api note).
Open in editor, Rename branch, and
Change engine are the o, b, and v chords for the row you clicked;
the engine entry opens a picker over your available engines instead of
cycling, and Rename branch follows the same empty-branch rule as Copy branch
name. (If right-click opens your terminal's menu
instead, see Troubleshooting.)
Terminal scrollback
These chords are trapped by Rove while the embedded terminal has focus; the engine or shell does not receive them.
| Key | Action |
|---|---|
ctrl+pageup | Scroll one page up through buffered terminal output |
ctrl+pagedown | Scroll one page down; reaching the bottom resumes following live output |
The mouse wheel uses the same scrollback. Buffer size is configured in Settings → General → Terminal and applies to newly opened terminals.
While scrolled back, click first beside the line count to jump to the earliest retained line, or latest to return to the bottom and follow new output. These buttons do not send input to the engine or shell.
Copying from it
Drag with the mouse to select, and the selection is copied when you release. The chords below copy the same selection without the mouse.
| Key | Action |
|---|---|
ctrl+c | Copy when text is selected; interrupt the engine or shell when nothing is |
cmd+c | Copy the selection (macOS) |
ctrl+shift+c | Copy the selection |
ctrl+c is selection-aware on every platform. Rove draws the selection
itself, so no terminal emulator knows it is there to claim the chord first —
without this, ctrl+c interrupted the engine while text sat highlighted.
Copying clears the selection, so the next ctrl+c is an interrupt again, and
ctrl+c with nothing selected is always an interrupt.
cmd+c and ctrl+shift+c only reach Rove on terminals that forward them.
Most emulators keep cmd+c for their own copy, which is equivalent; kitty,
Ghostty and iTerm2 can be configured to pass it through. ctrl+shift+c
requires a terminal that speaks the kitty keyboard protocol — without it a
terminal sends ctrl+shift+c and ctrl+c as the same byte, and the
selection-aware ctrl+c above is what answers.
Searching it
ctrl+a / opens a query row in the pane footer. Typing filters as you go,
and each new query parks on the newest occurrence — a scrollback is read
backwards, so the hit you want is nearly always the last one.
Pasting while the query row is focused adds to the query; it does not send input to the terminal child. Line breaks in pasted queries become spaces. Switching terminal sessions clears the query, selection and local scroll position. The session's process and buffered output stay available when you return. Resizing the same session keeps its query open.
| Key | Action |
|---|---|
ctrl+a / | Open the query row |
return or up | Walk to the older match (wraps at the top) |
down | Walk to the newer match |
escape | Close the row and return to the scroll position you opened it at |
Every hit on screen is highlighted; the one you are parked on is painted in
the accent colour. The search covers Rove's own scrollback only — while a
full-screen app (an engine, vim, less) is on the alternate screen it owns
its buffer, and the row says so instead of searching one screen of somebody
else's redraw.
Inbox
ctrl+a i opens it. What the sections mean and how items clear:
The TUI → Inbox.
| Key | Action |
|---|---|
j / k (or arrows) | Select |
enter | Open the target task and its exact tab when present, then clear the item |
d | Clear an ATTENTION item without navigating |
esc | Close |
Diff review
In the read-only diff tab, with the workspace focused:
| Key | Action |
|---|---|
j / k (or arrows) | Move the line cursor |
v | Anchor a range (v again cancels) |
c | Write a note |
x | Drop the note the cursor sits inside |
s | Send all unsent notes to the engine |
r | Reload the diff from disk |
These are fixed and can't be rebound. A send with no engine session in the Task leaves the notes unsent and says so. The workflow: The TUI → Diff review.
Workspace pages
All of these pages close with q, esc, or ctrl+c. Their bare letters are
active only while the page has focus.
| Page | Keys |
|---|---|
| Kanban | arrows (or h/l) move between cards; tab changes project; enter opens details; n creates; d deletes; r refreshes |
| Routines | j/k select; n creates; e pauses/resumes; s runs now; d deletes; r refreshes; enter opens the latest run's Task |
| GitHub Issues | j/k select; tab changes repo; a toggles "assigned to me"; r refreshes; enter starts a Task |
| Worktrees | j/k or arrows select; l lands; d starts removal; see Managing worktrees |
| Update | j/k selects an action; u updates; r opens the release page; enter runs the selected action |
In the Kanban story drawer, tab / shift+tab walks fields and ctrl+enter
activates its primary action: start an unlinked story or open the linked Task.
While creating a story, ctrl+s saves without starting and esc cancels.
In an existing story, esc saves edits and closes, while ctrl+c discards
them.
Customizing
Edit ~/.rove/settings/keybindings.yaml. Changes reload live, no restart.
prefix:
key: ctrl+a # or a list: [ctrl+a, ctrl+s]; null disables prefix bindings
timeoutMs: 5000
bindings:
chat.fork.new: f
bindings:
chat.tab.new: ctrl+t
chat.tab.chooseEngine: ctrl+e
sidebar.select: [enter]
files.createPR: null # null or [] unbinds
darwin: # platform overlays win per chord
bindings:
files.openExternal: cmd+o- A direct override replaces that binding's whole chord list.
prefix.keymay list several first strokes. Each opens the same command layer; hints and the guide print the first one.- Prefix overrides set second-stroke keys and keep the binding's pane scope.
- Uppercase is a distinct chord:
shift+p(or justP) can be bound apart fromp. Shift with another modifier on a letter (ctrl+shift+p) is invalid; legacy terminals send the same byte either way. - Unknown ids and invalid entries are ignored with a warning in Settings → Keybindings. A typo never breaks the default keymap.
Plugin chords
Rove ships none; every plugin chord is your own choice:
plugins:
ctrl+g: pane:examples.lazygit.git
f6: action:examples.notify.testSee design/plugins.md.
Why each chord sits where it does, and which ones are still open questions: design/keybinding-decisions.md.