Rove

Configuration

Most settings are written for you by the Settings dialog — press ctrl+a, then ,. This page is for when you want to edit them by hand.

Where things live

PathWhatWritten by
~/.config/rove/state.jsonAll your preferences, as flat JSONRove (Settings, CLI); yours to hand-edit
~/.rove/themes/*.jsonInstalled themesrove theme add, or drop files in
~/.rove/settings/keybindings.yamlKeybinding overridesYou only
<repo>/.rove/init.sh + init-prompt.mdPer-repo worktree setupYou (committed to the repo)
<repo>/.rove/pr-instructions.mdPer-repo PR action promptYou (committed to the repo)

Setting ROVE_HOME_DIR changes the home beneath these paths. KOBE_HOME_DIR remains a supported fallback; when both are set, ROVE_HOME_DIR wins. On first launch, Rove copies missing client-owned data from .kobe and .config/kobe; daemon-owned stores are copied when the new daemon starts, after the old writer has stopped. Neither phase overwrites or deletes old files. Existing worktrees stay where they are; daemon/PTY runtime files and plugins retain their compatibility paths.

Editing settings

rove config          # open state.json in your editor
rove config --path   # just print the path

rove picks your editor in this order: $VISUAL / $EDITOR → your configured editor (editor.kind below) → the first installed of nvim, vim, emacs, nano.

Restart Rove to apply a hand edit everywhere.

Hand-editing is safe. Unknown keys are ignored and bad values fall back to defaults, so a typo can't wedge the app — worst case a preference resets. If the file becomes invalid JSON, Rove renames it to state.json.corrupt-<timestamp> and starts fresh rather than deleting it. Concurrent Rove processes re-read before writing, so they don't clobber each other.

Settings reference

Keys not listed here are internal UI state (saved repos, tab layouts) that happen to share the file.

Appearance

KeyTypeDefaultWhat it does
activeThemetheme name"claude"See Themes
transparentBackgroundbooleantrueLet the terminal background show through
focusAccentprimary | success | infoprimaryColor of the focused-pane indicator
appearance.splitStylebox | lineboxbox frames each split; line is the minimal tmux-style look
localeen | zhenUI language
hints.keyboard.enabledbooleantrueKeyboard discoverability hints

Turning keyboard hints back on relights the first-use pane hints you'd already dismissed.

Editor

editor.kind and editor.customCommand control the file tree's enter action and rove config. Opening an entire worktree (o in the sidebar or ctrl+a o) uses the separate GUI/workspace opener described below.

KeyTypeDefaultWhat it does
editor.kindauto | vim | nvim | nano | emacs | customautoauto honors $VISUAL/$EDITOR, then auto-detects
editor.customCommandstringunsetCommand for custom, e.g. code -w

In editor.customCommand, {file} is replaced by the quoted file path. Without it, the path is appended.

Set ROVE_OPEN_EDITOR to choose the GUI editor for a whole worktree, for example ROVE_OPEN_EDITOR=zed. KOBE_OPEN_EDITOR remains a compatibility fallback; when both are set, ROVE_OPEN_EDITOR wins. Without either variable, Rove tries the code, cursor, windsurf, and zed CLIs in that order, then the platform opener. These variables do not change the file tree's per-file TTY editor.

Engines

KeyTypeDefaultWhat it does
defaultVendorengine id"claude"Default engine for new tasks
engineCommand.<id>stringbuilt-inLaunch command, e.g. "engineCommand.claude": "claude --model opus"
engineName.<id>stringbuilt-inDisplay name
customEngineIdsstring[][]Your own engines — see Custom engines
lastActiveVendor.<repo>engine idunsetPer-project last used; outranks defaultVendor. Written by Rove

Launch commands are parsed shell-ish — quotes group arguments. Clear both engineName.<id> and engineCommand.<id> to reset an engine to its default.

Terminal and tabs

KeyTypeDefaultWhat it does
terminal.scrollbackRowsnumber1000History per embedded terminal. Clamped 100–100,000
chat.tabStrip.modealways | multipleOnly | neverneverHorizontal chat tab strip

The tab strip is off by default because the sidebar tree already lists every tab. multipleOnly shows it once a task has more than one. (An older chat.tabStrip.hideSingle boolean still works if you set it before chat.tabStrip.mode existed; writing the new key retires it.)

Scrollback changes apply to terminals started after the change; live ones keep the buffer they were born with.

Notifications

All three default to on.

KeyTypeWhat it does
notifications.toast.enabledbooleanIn-TUI completion toasts
notifications.sound.enabledbooleanChime when a background tab finishes
notifications.crossTask.enabledbooleanToasts for tasks you aren't looking at

Error toasts always show, even with toasts off. See Notifications for how they're delivered.

Zen mode

Zen hides the Files pane so the active workspace gets the freed width. The engine or shell in the workspace remains visible. Toggle with ctrl+a z.

KeyTypeDefaultWhat it does
zen.activebooleanfalseOn/off. Persisted, so switching projects keeps you in zen

The current PureTUI always keeps the Tasks rail visible in zen mode because the rail also contains the exit affordance. zen.keepTasks is a legacy value: Settings can still write it, but it currently has no layout effect.

Worktree location

By default new worktrees land under ~/.rove/worktrees/<repo-key>/<slug>.

KeyTypeDefaultWhat it does
worktree.basePathstring~/.rove/worktreesWhere new worktrees go
worktree.basePath.customstringunsetRemembers your last custom path in the TUI

worktree.basePath takes an absolute path, or one starting with the $project_dir token, which expands to each task's project root — one setting that gives you a per-project layout. $project_dir/.. puts worktrees next to each repo. The token only counts as the first segment.

Only new tasks move. Existing tasks keep the path they were created with, including legacy global and repo-local roots. New remote (SSH) worktrees use <basePath>/.rove/worktrees; their existing .kobe/worktrees remain discoverable. No restart needed.

The current tree sidebar follows persisted project/task order and supports manual project reordering with shift+m. Older state files may contain activeSortMode and tasksPane.projectFilter; the daemon still mirrors those compatibility values, but the current PureTUI tree does not consume them.

Experimental

Off by default. These can change without notice.

KeyWhat it enables
experimental.remoteProjectsProjects over SSH
experimental.autoStatusTasks move to in_progress and self-report in_review
experimental.dispatcherPer-repo routing of field notes between sessions
experimental.archivedHistoryPreviewReserved legacy toggle; the current PureTUI has no archived-history viewer

Themes

rove bundles three themes — claude, conductor, and tokyonight — and ten more are one command away:

rove theme list
rove theme add https://rove.sma1lboy.me/themes/gruvbox.json
rove theme remove gruvbox

Available hosted: catppuccin, dracula, everforest, gruvbox, kanagawa, nord, opencode, osaka-jade, rose-pine, solarized. Preview them at https://rove.sma1lboy.me/themes.

You can also drop your own <name>.json into ~/.rove/themes/ — no recompile, loaded at boot, and a user theme wins over a bundled one with the same name. Writing one: Themes.

Keybindings

Full vocabulary: Keybindings. The configuration surface:

  • Edit ~/.rove/settings/keybindings.yaml by hand. Rove never writes it.
  • Changes reload live — no restart. Problems show up as warnings in Settings → Keybindings.
  • A direct override replaces that binding's whole chord list; null or [] unbinds it. Prefix overrides set second-stroke keys and keep the original pane scope. Platform overlays (darwin:, …) win per chord.
  • A plugins: section binds chords to installed plugin panes and actions. Rove ships no default plugin chords.
  • Unknown ids are ignored with a warning — a typo never breaks the keymap.

Notifications and sound

Three kinds: done (green), needs_input (yellow), error (red). Yellow and red outrank green when both fire for the same tab. Three delivery channels:

  • Toasts — in-TUI, 4.5 seconds. Error toasts always show, even with toasts disabled: a failure shouldn't vanish because you turned off completion popups.
  • Desktop notification — Rove emits an OSC 9 escape that iTerm2, kitty, WezTerm, and Ghostty turn into a real OS notification; other terminals ignore it. Because it travels down the terminal stream, it reaches you over SSH. No separate switch.
  • Sound — a short chime when a background tab finishes. Rove uses the first player it finds on PATH (afplay, ffplay, mpv, play, aplay, …). With none installed it's silent and the terminal bell is the fallback.

Custom engines

Built-in engines are claude, codex, copilot, and kimi. You can register any other CLI from Settings → Engines, or by hand:

{
  "customEngineIds": ["aider"],
  "engineCommand.aider": "aider --model sonnet",
  "engineName.aider": "Aider"
}

Being in customEngineIds is the registration — there's no other step. Ids must match ^[a-z][a-z0-9_-]{0,47}$ and can't collide with a built-in; invalid ones are dropped on read.

A custom engine launches and runs like any other, but Rove deliberately doesn't guess at its internals: no history reader, no account detection, no activity hooks, no session resume. More in Engines.

Per-repo init

A repo can ship two files in its own .rove/ directory:

  • .rove/init.sh — runs in each new task worktree before the engine starts, once per worktree. Use it for bun install, direnv, codegen.
  • .rove/init-prompt.md — sent as the engine's first message.

Files committed in the repo win over any per-user override you set with rove repo set. Legacy .kobe/init.sh and .kobe/init-prompt.md remain field-by-field fallbacks; a .rove file wins when both spellings exist.

The PR action also reads .rove/pr-instructions.md as its prompt template. It falls back to .kobe/pr-instructions.md; when both files are present, the non-empty .rove file wins.

On this page