Global config
View as markdownTwo files under ~/.shelbi/ hold hub-wide settings that apply across
every project on your machine, independent of any single project's
config mode: config.yaml (UI
preferences) and keys.yaml (keybindings). Both are optional: absent or
partial files fall back to built-in defaults, never an error.
Home resolution
~/.shelbi/ is the default base. It can be relocated via --root, then
$SHELBI_ROOT, then $SHELBI_HOME, then a default baked in at install time
(if any), before falling back to $HOME/.shelbi. Every path below joins a filename onto that base.
config.yaml
Per-user UI preferences. Distinct from shelbi.yaml (the per-project
last_launched index) so a future shelbi config reset can wipe UI
tweaks without touching hub bookkeeping. A file that omits a key or a
block resolves to that setting's default.
A new install starts from a self-documenting config.yaml that sets
theme: dark, desktop.contrast: 50, and a translucent desktop window
(desktop.window_opacity: 85 and desktop.window_blur: 30). Whichever
writes the file first (shelbi init, or a first settings change in either
client) writes those values, and with no file at all both clients show them.
An existing config.yaml is never rewritten: without these keys it keeps the
defaults in the tables below (auto, contrast 0, an opaque window).
Path: ~/.shelbi/config.yaml
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
keymap.zen_toggle | chord | no | alt-z | Legacy. Set the Zen Mode chord in keys.yaml (defaults.global.zen_toggle) instead: a non-default value here is moved into keys.yaml on the next start and reset here, with a one-time notice. |
theme | auto | dark | light | no | auto | Color theme for the TUI and the desktop app. See Theme. |
desktop | Desktop | no | — | Desktop app settings. Ignored by the CLI and the TUI (except app_icon, which the TUI's About draws and its Settings ▸ General picks). |
editor | command | { app: <path> } | no | $EDITOR, else vim | Editor Shelbi opens for "Edit in <editor>" (in the review interface and the workspace panel) and for the desktop app's external edits (an issue body, a workflow's Edit YAML). Hub-wide, so it follows you across projects. A command (hx, code --wait) runs in a pane; an app opens in the app. See Editor and diff tool. |
diff_tool | builtin | git | command | { app: <path> } | no | builtin | What View Diff shows over a branch's changes: Shelbi's own diff view, git's difftool, a command in a pane, or an app. A project's review.diff_command takes precedence. See Editor and diff tool. |
# ~/.shelbi/config.yaml
editor: code --wait
theme: light
desktop:
contrast: 50
window_opacity: 85
window_blur: 30Editor and diff tool
editor and diff_tool each take one of two forms. The rule is the same for
both: a command-line tool opens as a pane (a terminal in the worktree, beside
the agent), and an app opens in the app.
# ~/.shelbi/config.yaml
# A command: a program on your login PATH, with flags if you like.
editor: hx
diff_tool: difft
# An app: the path to its .app bundle.
editor: { app: /Applications/Zed.app }
diff_tool:
app: /Applications/Kaleidoscope.appA plain string is a command, so a config.yaml written before apps were
supported keeps working unchanged.
Editor. A command runs in a pane in the worktree (exec <command>). An app
opens the worktree with open -a <app> <worktree>, and "Edit in" leaves the
current view selected rather than switching to a pane. Unset, Shelbi runs
$EDITOR, then vim. A pane can't host an app, so anything that needs a
terminal editor falls back past an app setting to $EDITOR, then vim.
Diff tool. View Diff compares the branch with its base
(merge-base(<base branch>, HEAD)..HEAD). In precedence order it shows:
- the project's
review.diff_command, when it sets one, diff_tool, when set to a tool,- Shelbi's own diff view, which is what
diff_tool: builtinasks for and what an unset setting means.
diff_tool: git runs git's own difftool (diff.guitool, else diff.tool). Any
other diff_tool command runs in a pane through git difftool, one file at a
time, with the two files appended (nvim -d, vimdiff). A command that names
$LOCAL and $REMOTE itself is run as written. difft
(difftastic) runs as git's external diff
through less -R.
A diff_tool app opens the diff in the app through its own command-line helper,
found on your login PATH or inside the app bundle:
| App | Helper | Shows |
|---|---|---|
| FileMerge | opendiff | the whole change (folders) |
| Kaleidoscope | ksdiff | the whole change (folders) |
| Beyond Compare | bcomp | the whole change (folders) |
| Visual Studio Code | code --diff | one file at a time |
| Sublime Merge | smerge | the repository |
| P4Merge | launchp4merge | one file at a time |
| Araxis Merge | compare | one file at a time |
| DeltaWalker | DeltaWalker | one file at a time |
Any other app gets the two folders with open -W -a <app>. If a listed app's
helper isn't installed, View Diff says so on the status line.
Remote workspaces. Shelbi's own diff view reads a worktree on any machine, in both clients. A workspace on another machine also offers Edit, and an external diff tool, as panes that run on that machine. An app can't open a worktree on another machine. A review slot on another machine offers no Edit, and offers View Diff only for Shelbi's own view.
Labels. "Edit in <name>" uses the tool's name: Edit in Neovim for
nvim, Edit in Helix for hx, Edit in Visual Studio Code for
code --wait or the app, and the bundle's name for any other app. A command
Shelbi doesn't know shows its program name with the first letter upper-cased.
Settings. Settings ▸ General has an Editor picker and a Diff tool picker
in both clients. Each lists the default (no setting, so the fallback applies),
the command-line tools and the apps Shelbi finds installed, Browse… (an app or
a program on disk), and Other command… (a command line with its flags, saved
when you press Enter). A pick saves at once, and the page shows what Shelbi
runs and where it comes from (this key, $EDITOR, or the vim default). In
the TUI, Browse asks for a path, with Tab completion.
Theme
theme picks the color theme both clients use. The two themes share one
set of named colors, so the TUI and the desktop app look like the same
product.
| Value | TUI | Desktop app |
|---|---|---|
auto (default) | dark (a terminal doesn't report whether it's light or dark) | follows the system appearance, and switches live when the system switches |
dark | dark | dark |
light | light, for a terminal with a light background | light |
Both clients set it in Settings ▸ General. In the TUI a change saves at
once and repaints every surface on the next frame, with no restart and no
effect on running sessions. The TUI also reads config.yaml again whenever
its Settings opens, so an edit made in a text editor or in the desktop app
shows there. A missing key is auto (a new install's file sets dark). The dark theme follows your terminal's own palette for
its status colors; the light theme pins every color, so it reads the same in
any light terminal.
Desktop
The desktop: block holds the desktop app's settings. Its Settings ▸ General
and Settings ▸ Terminal pages write these keys for you; every one is optional.
| Field | Type | Default | Description |
|---|---|---|---|
cli_path | path | discovered | The shelbi CLI the app runs, overriding its discovery (the login-shell PATH, then the Homebrew prefixes and ~/.cargo/bin). A leading ~/ is expanded. |
terminal_font_family | string | Geist Mono | Font family for the app's terminals. |
terminal_font_size | integer (points) | app default | Font size for the app's terminals. |
option_as_meta | false | true | left | right | false | Whether Option acts as Meta in the terminals (Option+B sends ESC b) instead of typing the layout's Option characters. left / right make only that Option key Meta. |
terminal_scrollbar | auto | scrolling | always | auto | When the terminals show a scrollbar: auto follows macOS's "Show scroll bars", scrolling only while scrolling, always whenever there is scrollback. |
notifications.workspace_blocked | bool | true | Notify when a workspace's agent stops for you (waiting for input, or a permission dialog). |
notifications.review_ready | bool | true | Notify when a task reaches the review column. |
notifications.orchestrator_waiting | bool | true | Notify when the orchestrator waits for an answer or shows a permission dialog. |
terminal_colors.<color>.regular / .bold | #rrggbb | theme palette | Terminal ANSI colors you changed, per color (black, red, green, yellow, blue, magenta, cyan, white). Unset colors follow the app's palette. |
window_opacity | percent | 100 | Window opacity. Values below the floor of 30 are clamped up; a fraction like 0.85 reads as 85. A new install's file sets 85. |
window_blur | 0 to 50 | 0 | Blur radius, in points, for what shows through a translucent window. A new install's file sets 30. |
contrast | percent | 0 | How far apart surfaces and their text sit; 100 is the strongest step. A new install's file sets 50. |
app_icon | command-grille | retro | racing-s | retro-racing-s | command-grille | The icon in the Dock and in About: Command Grille, Retro, Racing S or Retro Racing S. Any case, and _ for -; an unknown value is ignored. |
zen_toggle chords
The accepted values for the Zen toggle chord:
| Value | Key |
|---|---|
alt-z | Alt+Z (default) |
ctrl-backslash | Ctrl+\ |
ctrl-g | Ctrl+G |
ctrl-shift-z | Ctrl+Shift+Z |
none | disabled — no chord toggles Zen Mode |
keys.yaml
Overrides for Shelbi's keybindings, shared by the TUI and the desktop app.
Both clients edit this file in Settings ▸ Keybindings (in the TUI press , in
the sidebar, then 2; in the desktop app, ⌘2 while Settings is open). Built-in
chords apply out of the box;
this file layers on top of them, either globally (defaults) or per
project (projects.<name>). Parse errors never fail the load. A
mistyped entry is skipped and that action keeps its built-in chord.
Path: ~/.shelbi/keys.yaml
Shape
# ~/.shelbi/keys.yaml
defaults: # applies to every project
<mode>:
<action>: <chord | [chords] | null>
projects: # per-project overrides, keyed by project name
<project-name>:
<mode>:
<action>: <chord | [chords] | null>Bindings resolve in three layers, each overriding the last: built-in
defaults → defaults.<mode>.<action> → projects.<name>.<mode>.<action>.
| Block | Type | Required | Default | Description |
|---|---|---|---|---|
defaults | map of mode → action → chord(s) | no | — | Overrides applied to every project. |
projects | map of project name → (mode → action → chord(s)) | no | — | Overrides scoped to one project; win over defaults. |
Leaf values
The value under each action is untyped so one bad entry only affects itself:
| Form | Meaning |
|---|---|
scalar string (alt-z) | Bind the action to a single chord. |
list ([k, up]) | Bind the action to several chords. |
[] (empty list) | Deliberately unbind the action. |
null | No override — fall through to the layer below. |
In the diff mode a chord can be two keys, separated by a space ('g g',
'z C', '] h'). Quote them: a bare ] isn't YAML. A key can't both do
something by itself and start a two-key binding.
Modes
The valid top-level keys under defaults and each projects.<name>:
global, sidebar, kanban, popover, activity, diff, palette.
global bindings apply everywhere; the rest scope to their pane.
Actions
The action names accepted under each mode, with their built-in chords:
| Mode | Action | Built-in |
|---|---|---|
global | quit | ctrl-c |
global | zen_toggle | alt-z |
global | open_palette | ctrl-p |
global | focus_sidebar / focus_main | ctrl-h / ctrl-l |
sidebar | quit | q,ctrl-c |
sidebar | nav_up / nav_down | k,up / j,down |
sidebar | activate | enter,space |
sidebar | refresh | r |
sidebar | open_settings | ',' (quoted: a bare comma isn't YAML) |
kanban | nav_left / nav_right | h,left / l,right |
kanban | nav_up / nav_down | k,up / j,down |
kanban | move_card_left / move_card_right | H / L |
kanban | reorder_up / reorder_down | K,shift-up / J,shift-down |
kanban | open_popover | enter,space |
kanban | cycle_workflow_filter | tab |
kanban | open_workspace | o |
popover | close | esc,enter,space,q |
popover | scroll_up / scroll_down | k,up / j,down |
popover | page_up / page_down | page-up,u / page-down,d |
popover | move_left / move_right | H,shift-left / L,shift-right |
popover | open_workspace | o |
popover | open_pr | p |
activity | scroll_up / scroll_down | k,up / j,down |
activity | scroll_end | G,end |
activity | reset_filter | a |
activity | toggle_zen_filter | z |
activity | toggle_workspaces_filter | w |
diff | cursor_down / cursor_up | j,down / k,up |
diff | next_file / prev_file | l,ctrl-n,right / h,left |
diff | page_down / page_up | space,ctrl-f,page-down / b,page-up |
diff | half_page_down / half_page_up | ctrl-d / ctrl-u |
diff | top / bottom | 'g g' / G |
diff | center_viewport / center_cursor | 'z z' / M |
diff | next_change / prev_change | '] h' / '[ h' |
diff | next_comment / prev_comment | '] c' / '[ c' |
diff | next_empty_line / prev_empty_line | '}' / '{' |
diff | find_forward / find_backward | f / F |
diff | till_forward / till_backward | t / T |
diff | repeat_find | ';' |
diff | search / next_match / prev_match | / / n / N |
diff | file_palette / command_palette / help | ctrl-p / ':' / '?' |
diff | toggle_split / toggle_blame / toggle_file_list | s / B / ctrl-b,\ |
diff | next_hunk_filter / prev_hunk_filter | tab / back-tab |
diff | toggle_hunk_fold / close_hunk_fold / open_hunk_fold | 'z a' / 'z c' / 'z o' |
diff | close_file_fold / open_file_fold | 'z C' / 'z O' |
diff | close_all_folds / open_all_folds | 'z M' / 'z R' |
diff | visual_select | v,V |
diff | comment / reply_or_refresh / toggle_thread | enter / r / o |
diff | delete_comment / clear_comments | d / D |
diff | yank / yank_all / send_to_agent | y / Y / 'g Y' |
diff | send_to_reviewer | 'g A' |
diff | revert_hunk / revert_file | 'g r' / 'g R' |
diff | toggle_resolved / toggle_comment_target | x / C |
diff | submit_review / pr_info | R / i |
diff | open_in_editor | ctrl-g |
diff | toggle_viewed / pick_commit | m / c |
palette | close | esc,ctrl-c,ctrl-p |
palette | activate | enter |
palette | nav_up / nav_down | up / down |
palette | backspace | backspace |
Most modes also carry refresh (r) and scroll-navigation actions
(page_up/page_down, scroll_home). For the full list with the chords in
effect after your keys.yaml, run
shelbi config list-actions. shelbi config dump-keybindings prints the whole default keymap as a starting keys.yaml, and
shelbi config check validates the file and reports errors and warnings.
A mode binding that reuses a global chord is dead in the sidebar, kanban,
and activity modes: global bindings fire first. shelbi config check warns
about it. The diff mode is the other way around: its bindings win while the
diff view has focus, so ctrl-p opens its file palette there.
# rebind the palette opener globally, and add a second chord in one project
defaults:
global:
open_palette: ctrl-k
projects:
myapp:
kanban:
move_card_left: [H, alt-h]Sibling files
Two more files live under ~/.shelbi/ but are managed by Shelbi rather
than hand-edited:
shelbi.yaml— hub-wide bookkeeping: a per-projectlast_launchedindex used by the project picker. Written when you launch a project.events.log— the cross-project events log. Append-only state, not config.
See also
- Config modes — per-project config, which these hub-wide files sit above.
- Project config — the per-project YAML.