Configuration

Every knob Thurbox reads, where it lives, and how it behaves. One file per audience/lifecycle: hand-edited registries are TOML, the machine-written keybindings are JSON, and concurrently-written runtime state lives in SQLite.

Dev builds (version 0.0.0-dev ) use thurbox-dev in place of thurbox in every path below, plus a thurbox-dev tmux socket, so a development checkout never touches your real setup. All paths respect $XDG_CONFIG_HOME / $XDG_DATA_HOME .

Files at a glance #

File Format Edited by Read Purpose
~/.config/thurbox/agents.toml TOML you live (mtime poll) coding-agent CLI definitions
~/.config/thurbox/hosts.toml TOML you startup remote SSH hosts
~/.config/thurbox/settings.toml TOML you / Settings panel live (mtime poll) tuning knobs + feature flags
~/.config/thurbox/themes.toml TOML you startup custom theme palettes
~/.config/thurbox/keybindings.json JSON F1 editor (or you) live (mtime poll) key chord overrides
~/.config/thurbox/extensions/<name>.toml TOML extension install startup + tick extension manifests (self-healed resources)
~/.local/share/thurbox/thurbox.db SQLite thurbox live sessions, automations, tasks, theme, editor command
~/.local/share/thurbox/thurbox.log text thurbox logs (incl. config warnings)

agents.toml , keybindings.json , and settings.toml reload live : the TUI polls their mtime (~1/s) and applies edits with a confirmation toast — no restart. For settings.toml the UI-panel feature flags apply immediately; the [notifications] knobs, the automations/mouse/notifications/version_check/auto_update feature flags, and the write-once scalars take effect on the next launch and the toast says so. hosts.toml and themes.toml need a restart.

Config problems are not silent : parse errors, unknown fields, invalid chords, and chord conflicts surface as a status-bar toast on startup (and in the log file). Unknown TOML keys are tolerated and reported by name, while syntax/type errors fall back to built-ins (agents), zero hosts, or defaults (settings). Check everything from the command line:

bash
thurbox-cli config validate   # strict parse of every file; exit 1 on problems
thurbox-cli config show       # effective config + where each value came from

Which file do I edit?

A task-to-file map so you don't have to scan every section to find the right knob. None of these files need to exist on a fresh install — every one is seeded (commented-out where applicable) on first run, and absent files fall back to built-in defaults.

I want to… Edit
Add a coding agent, pin a model, change resume/fork flags agents.toml
Run sessions on a remote machine over SSH hosts.toml
Turn a whole TUI feature on/off (tasks, mouse, notifications…) settings.toml [features]
Tune scrollback, panel breakpoints, audit retention settings.toml
Change when/how OS notifications fire settings.toml [notifications]
Add or recolour a TUI theme themes.toml
Rebind a key keybindings.json (or the F1 editor)
Set the Ctrl+O editor, pick a theme runtime — SQLite

agents.toml #

Declares the launchable coding agents. Seeded with the built-ins ( claude , codex , antigravity , opencode , aider , copilot , vibe , pi , omp ) on first run; edit or add [[agents]] entries to support any CLI — no recompile. A malformed file falls back to the built-ins and shows the error.

agents.toml
config_version = 1
default = "claude"          # agent preselected in the picker / headless spawns

[[agents]]
name = "claude"             # display + lookup name (unique)
command = "claude"          # executable
args = []                   # always passed; bake a model here if you want one
resume_args = ["--resume", "{id}"]            # emitted when resuming
fork_args = ["--resume", "{id}", "--fork-session"]
new_session_args = ["--session-id", "{id}"]   # emitted on a fresh spawn
resume_latest = false       # true = id-less "resume last session in cwd"

{id} is substituted with the thurbox-generated session UUID. Groups are emitted only when their driving value exists; precedence is fork > resume > new-session.

For each built-in's recommended configuration and runtime behavior — resume/fork semantics, whether it pins a session id, and how it reports status — see Built-in agents.

hosts.toml #

Declares remote SSH hosts; each [[hosts]] entry registers a session backend named ssh:<name> . Seeded fully commented-out (fresh installs are local-only). A malformed file means zero remote hosts and shows the error.

Field Required Default Purpose
name yes backend id ssh:<name>; what --host expects
destination yes ssh target (user@host or ~/.ssh/config alias)
ssh_opts no [] extra ssh flags, one token per element
socket no thurbox remote tmux -L socket
session no thurbox remote tmux session name
worktrees_dir no remote $HOME/.local/share/thurbox/worktrees absolute remote worktrees dir

Auth comes entirely from your ~/.ssh/config ; thurbox never handles credentials. Host changes require a restart.

settings.toml #

Scalar tuning knobs plus the [features] switches, seeded fully commented-out (defaults apply when absent). Only knobs a user plausibly wants are exposed; internals stay hardcoded. The file is live-reloaded via mtime poll: the UI-panel feature flags apply immediately, while the [notifications] knobs, the automations/mouse/notifications/version_check/auto_update feature flags, and the write-once scalars take effect on the next launch.

Settings panel. You don't have to hand-edit the file: the TUI has a Settings modal opened with Ctrl+, (or F6 ) that views and edits all of settings.toml — the [features] toggles, [notifications] knobs, and scalars. It edits a working copy and applies only on Ctrl+S (Esc discards); the panel writes back through the same file, preserving its documentation comments.

Key Default Purpose
scrollback_lines 1000 terminal scrollback kept per session
two_panel_min_cols 80 width below which only the terminal renders
three_panel_min_cols 120 width unlocking the optional third column
audit_retention_days 90 audit-log history kept (pruned on startup)

A complete settings.toml showing every knob at its default — copy this and uncomment what you want to change (the UI-panel feature flags apply live; the [notifications] knobs, the automations/mouse/notifications/version_check/auto_update flags, and the write-once scalars take effect on the next launch):

settings.toml
config_version = 1

# Scalar tuning knobs (top level)
scrollback_lines      = 1000   # terminal scrollback kept per session
two_panel_min_cols    = 80     # width below which only the terminal renders
three_panel_min_cols  = 120    # width unlocking the optional third column
audit_retention_days  = 90     # audit-log history kept (pruned on startup)

[features]
tasks         = true
automations   = true
file_viewer   = true
global_search = true
info_panel    = true
shell_pane    = true
code_review   = true           # native diff-review pane (F7)
mouse         = true
notifications = true
soft_delete   = true           # Ctrl+D soft-deletes (Ctrl+Z undo); false = hard-delete
version_check = false          # opt-in: makes a network call
auto_update   = false          # opt-in: downloads + replaces binaries

[notifications]
backend             = "auto"   # auto / dbus / windows / off
also_on_waiting     = false    # also fire on Busy → Waiting (no bell)
suppress_for_active = true     # skip the session you're currently viewing
sound               = true     # play the OS default notification sound
min_interval_secs   = 5        # per-session floor between notifications

[features] — whole-feature switches

Turn major TUI features off entirely. All default to true except version_check and auto_update, which default to false (both reach the network, so they are opt-in). The UI-panel feature flags (tasks, file_viewer, info_panel, global_search, shell_pane, code_review, soft_delete) are live-reloaded — they take effect immediately, no restart. The rest (automations, mouse, notifications, version_check, auto_update) and the write-once scalars wait for the next launch. A disabled feature's pane never renders, its keybinding shows a status toast instead of acting, and its global-search scope returns no results. Data is never touched, so re-enabling a flag is lossless.

Key Default Controls
tasks true tasks panel (F5/Ctrl+W) and task search results
automations true automations pane, Ctrl+P, TUI schedule firing, heartbeat arming
file_viewer true file viewer column (F3) and file search results
global_search true global search strip (Ctrl+/)
info_panel true info panel column (F2)
shell_pane true per-session shell toggle (Ctrl+T)
code_review true native code-review view (diff + comments, Ctrl+X)
mouse true mouse capture: clicks, wheel, drag-select, hover, scrollbars
notifications true OS desktop notifications when a session needs attention
soft_delete true TUI Ctrl+D soft-deletes (with a Ctrl+Z undo window); false makes it a hard delete behind a confirmation modal. Never affects thurbox-cli session delete (soft unless --force).
version_check false GitHub update check: TUI header “update available” badge + thurbox-cli version --check
auto_update false silent self-update: download + verify + replace the binaries on startup + thurbox-cli update

automations = false is the one flag with teeth beyond the UI: it also stops the TUI from firing due schedules and arming the tmux heartbeat at startup (explicit thurbox-cli automation commands still work). mouse = false skips terminal mouse capture entirely, so the terminal keeps its native mouse behavior. notifications = false keeps the background dispatcher thread from ever starting (zero overhead) and silently no-ops every transition; the session status display itself is unaffected.

version_check = true enables the update check. On launch the TUI reads a cached result (~/.local/share/thurbox/version-check.json) and, if it is older than 24 h, fires a single best-effort background fetch of GitHub's latest release (via curl/wget); a newer release shows a ↑ vX.Y.Z available badge next to the version in the header. The fetch never blocks startup and failures are silent. Dev builds (0.0.0-dev) never show the badge. The same flag enables thurbox-cli version --check (thurbox-cli version with no flag always prints the current version).

auto_update = true goes a step further than version_check: instead of just showing a badge, the TUI silently updates itself on startup. After the same 24 h cache check, if a newer release exists it downloads that release's tarball + checksums from GitHub Releases (curl/wget), verifies the SHA256 (sha256sum/shasum), extracts it (tar), and atomically replaces the installed thurbox/thurbox-cli binaries in place — mirroring scripts/install.sh. The download is verified before any installed file is touched, so a failed download leaves the current binaries untouched; the step runs before the TUI takes the terminal and is best-effort. The replaced binary takes effect on the next launch, so the TUI shows an “Updated to vX.Y.Z — restart to apply” status line. thurbox-cli update performs the same update on demand (--force bypasses the up-to-date and dev-build guards); dev builds (0.0.0-dev) never auto-update. version_check and auto_update are independent — enable either or both.

[notifications] — OS notification settings

Surfaces an OS notification when a session crosses into a state that needs the user's attention (the agent rang the terminal bell or emitted an OSC 9 / OSC 777 message — usually because it's waiting on an answer or has finished a task). Linux dispatches via dbus and supports click-to-focus: clicking the banner writes a focus request that the running TUI reads on its next tick and switches to that session. macOS shows the banner but ignores clicks (the modern UNUserNotificationCenter API requires a signed app bundle, which thurbox is not). The notification body is the agent's last OSC message when present, otherwise Waiting for input. Only fires while the TUI is open — the agent terminal parser is what sees the bell, and it doesn't run when thurbox isn't. Gated by the notifications feature flag above.

Key Default Purpose
backend auto delivery backend (auto / dbus / windows / off): auto picks dbus on a Linux desktop, the WSL Windows-toast fallback, or the macOS native banner; off drops every notification (a soft switch distinct from the feature flag)
also_on_waiting false also fire on Busy → Waiting (no explicit bell from the agent)
suppress_for_active true skip the notification for the session you're currently viewing
sound true play the OS default notification sound
min_interval_secs 5 per-session floor between two notifications (dedup)

The default-on Attention trigger is the right knob for any agent that respects the terminal bell / OSC 9 / OSC 777 conventions (Claude Code out of the box, for example). For agents that only go quiet without ringing a bell, set also_on_waiting = true — note this fires once each time the agent goes idle after activity, so it can be chatty.

themes.toml #

User-defined themes, offered in the Ctrl+Y picker alongside the nine built-in presets and persisted by name like any preset. Each [[themes]] entry starts from a built-in base and overrides only the colours it names:

themes.toml
[[themes]]
name = "my-mocha"            # stable id; must not shadow a built-in
display_name = "My Mocha"    # picker label (default: name)
base = "catppuccin-mocha"    # starting palette (default: default)
accent = "#fab387"
app_bg = "reset"             # keep the terminal's native background

Colours accept anything ratatui parses: #rrggbb , ANSI names ( red , lightcyan ), indexed ( 14 ), or reset . Bad colours and built-in name collisions degrade to startup warnings.

keybindings.json #

Maps Action names to one or more chord strings:

keybindings.json
{ "QuitApp": ["ctrl+a"], "OpenThemePicker": ["ctrl+y", "f4"] }
  • The preferred editing path is the F1 panel (live capture, conflict stealing, immediate persistence). Hand-edits are read at startup and live via mtime poll.
  • Chord syntax: [ctrl+][alt+][shift+][cmd+]<key> where <key> is a letter, f1f12 , or a named key ( enter , esc , tab , arrows, home , end , pageup , pagedown , backspace , delete , insert ). Case-insensitive. cmd (aliases super , command , win ) is the macOS Command key, delivered only by kitty-keyboard-protocol terminals.
  • Unknown action names, invalid chords, and the same chord bound to two actions in overlapping contexts are reported at startup (the file still loads; bad entries fall back to defaults).

See the Keybindings page for the full default chord table.

Extensions #

Each opt-in extension is described by a single extension.toml manifest. thurbox-cli extension install writes the home-resolved copy to ~/.config/thurbox/extensions/<name>.toml (thurbox never seeds this dir). The manifest has an install spec and a runtime spec; see the Extensions page for the full manifest format, lifecycle commands, and versioning.

bash
thurbox-cli extension install flow         # fetch + lay files + agents + activate
thurbox-cli extension list                 # installed + active/healthy + version/stale
thurbox-cli extension update --all         # re-fetch every installed extension
thurbox-cli extension activate <name>      # (re)create resources + mark active
thurbox-cli extension deactivate <name>    # tear down + stop self-heal
thurbox-cli extension status [<name>]      # per-resource presence + version/stale

SQLite-backed settings #

Live in the metadata table and apply immediately (no restart):

Key Set via Purpose
active_theme Ctrl+Y / F4 picker TUI palette (nine built-ins)
editor_command thurbox-cli editor set "<cmd>" what Ctrl+O runs
active_extensions extension activate/deactivate JSON array of active extensions to self-heal

These are in the DB rather than a file because they are written concurrently by multiple thurbox processes (TUI, CLI, MCP) and picked up live via PRAGMA data_version polling.

Environment variables #

Variable Used for
XDG_CONFIG_HOME, XDG_DATA_HOME config/data roots
VISUAL, then EDITOR Ctrl+O editor when editor_command is unset
SHELL the Ctrl+T companion shell pane (fallback /bin/sh)
RUST_LOG log filter for thurbox.log

Editor resolution order: DB editor_command$VISUAL$EDITOR → error toast.

Versioning #

The SQLite schema migrates automatically ( schema_version in metadata ). The TOML files carry a config_version = 1 marker so a future format change can migrate them too; current files are version 1 and the field is optional.