Skip to content

Configuration reference

This reference comes from config.example.toml. Active values are defaults. Commented settings are optional examples. All settings are optional.

See Configuration for the file path and reload steps.

config.example.toml
# Thurm example configuration.
# Copy this file to ~/.config/thurm/config.toml, or use `thurm config-path`
# to find the active path. Run `thurm reload` after you make changes.
# All settings are optional. Active values below match the defaults.
# Optional overrides and custom entries are commented out. Remove the leading
# "# " from an example setting to use it.
# The updates Thurm has made to this file: it turns on features that came after the file was
# written, then raises this. Leave it as it is.
config_version = 9
[font]
# Use a font family or face name. Sizes and spacing are in points.
family = "JetBrains Mono"
# A face of the family for regular text; bold and italic follow its width.
# style = "Semi-Condensed"
size = 16.0
# These faces are selected from the font family when not set.
# family_bold = "JetBrains Mono Bold"
# family_italic = "JetBrains Mono Italic"
# family_bold_italic = "JetBrains Mono Bold Italic"
ligatures = true
# OpenType features, for example ["ss01", "zero", "-dlig"].
# A leading minus sign disables a feature.
features = []
# Multiply the font line height by this value.
line_height = 1.0
letter_spacing = 0.0
# Use CoreText font smoothing. Strength: 0 to 255.
thicken = true
thicken_strength = 255
fallback = ["SF Mono", "Menlo"]
# Use the included Symbols Nerd Font Mono for missing icons.
nerd_font_symbols = true
[window]
# Padding and sidebar width are in points.
padding_x = 8.0
padding_y = 6.0
# Opacity: 0.0 to 1.0. Blur needs opacity below 1.0.
opacity = 1.0
# Any value above 0 enables blur.
blur = 0
# Backdrop of the chrome when opacity is below 1: "theme", "system", "blend" or "modern".
material = "theme"
# Treat the Option key as Alt: "none", "left", "right", or "both".
option_as_alt = "none"
# Initial window size in terminal cells.
columns = 110
rows = 32
confirm_close = true
quit_after_last_window = false
# Dim panes without focus: 0.0 disables dimming; 1.0 gives full dimming.
unfocused_split_dim = 0.25
# Draw an accent-colored border around the focused pane while a tab shows several.
active_pane_border = false
# Even out a tab's splits when a pane opens or closes. A dragged divider holds until then.
auto_balance = true
pane_headers = true
# Space between split panes (and around them) when pane headers show, in points.
pane_gap = 6.0
# Animation speed for panes and the chrome: "normal", "slow" or "slower".
animation_speed = "normal"
# Tab location: "native" or "sidebar".
tab_style = "sidebar"
sidebar_width = 240.0
# Group the sidebar's tabs by repository; or list every workspace's tabs; or only what is
# going on: every agent that isn't idle, by status, and the tabs with progress.
sidebar_group_by_repo = true
sidebar_all_workspaces = false
sidebar_active_only = false
# What is left of the Claude Code / Codex subscription limits, at the bottom of the sidebar.
sidebar_usage_claude = false
sidebar_usage_codex = false
# The mouse's back and forward buttons go back and forward through the tabs visited
# (Window > Back / Forward). Off, they reach the program as mouse buttons.
mouse_navigation_buttons = true
[cursor]
# Shape: "block", "beam", or "underline".
style = "block"
blink = false
# Beam and underline thickness in points.
thickness = 2.0
[colors]
# Use a theme name or a path to a theme file. `thurm theme` lists names.
# To follow system appearance, use "light:NAME,dark:NAME".
# theme = "light:catppuccin-latte,dark:catppuccin-mocha"
# Colors use hexadecimal RGB values. Unset colors come from the theme.
# foreground = "#d8dee9"
# background = "#0e1116"
# cursor = "#d8dee9"
# cursor_text = "#0e1116"
# selection_foreground = "#ffffff"
# selection_background = "#434c5e"
# Override up to 16 ANSI colors, starting at index 0.
# For example: palette = ["#1b2029", "#e06c75"].
palette = []
bold_is_bright = false
improve_contrast = false
theme_palette = false
blend_backgrounds = false
display_p3 = false
[terminal]
# Scrollback lines kept in memory per pane.
scrollback = 10000
# Use the login shell when no shell command is set.
# shell = ["/bin/zsh", "-l"]
term = "xterm-256color"
# Add prompt marks and working directory tracking for zsh, bash, and fish.
shell_integration = true
# Clipboard access through OSC 52: "disabled", "copy", "paste", or "copy-paste".
osc52 = "copy"
kitty_keyboard = true
kitty_graphics = true
# Maximum memory for kitty graphics per pane, in MiB.
image_memory_mib = 320
# Characters that end a word during selection with a double click.
word_separators = ",│`|:\"' ()[]{}<>\t"
copy_on_select = false
# Lines moved per line of wheel or trackpad input.
scroll_multiplier = 3.0
smooth_scroll = true
# Show completion choices at a shell prompt. Requires shell integration.
tab_completion = true
[terminal.env]
# Set environment variables for shell processes.
# EDITOR = "nvim"
[session]
# Save the layout, working directories, and agents to disk. Scrollback stays in memory.
persist = true
snapshot_interval_secs = 15
# "detach" keeps shells running when the app quits.
# "terminate" stops shells when the app quits.
quit = "detach"
# Run configured agent resume commands when a saved session is restored.
resume_agents = true
# Exit the daemon this many seconds after the last pane closes. 0 disables this.
daemon_idle_exit_secs = 0
[security]
# Enable Secure Keyboard Entry when a password prompt is detected.
auto_secure_input = true
secure_input_indicator = true
# Ask before a paste with multiple lines outside bracketed paste mode.
confirm_multiline_paste = true
[notifications]
enabled = true
# Notify when a command takes at least this many seconds and ends without focus.
# Set to 0 to disable these command notifications.
command_finished_secs = 15
# Allow OSC 9, OSC 99, and OSC 777 notifications from programs.
program_notifications = true
bell_badge = true
# What an agent does in each state: a tab indicator, a desktop notification (in a pane without
# focus), a Dock badge (until seen) and a sound ("default", "none", or a sound file's name).
# States: working, waiting (needs input), blocked (asks for a permission), finished (ended a
# turn; needs agent hooks), failed, idle.
working = { tab_indicator = true, notify = false, badge = false, sound = "none" }
waiting = { tab_indicator = true, notify = true, badge = true, sound = "default" }
blocked = { tab_indicator = true, notify = true, badge = true, sound = "default" }
finished = { tab_indicator = true, notify = true, badge = true, sound = "default" }
failed = { tab_indicator = true, notify = true, badge = true, sound = "default" }
idle = { tab_indicator = true, notify = false, badge = false, sound = "none" }
[agents]
detect = true
# Mark a working agent as idle after this many milliseconds without output.
idle_after_ms = 1500
# Use agent session titles for tabs. Requires agent hooks.
session_titles = true
# Install the agent hooks (see `thurm hooks install`) when an agent launches without them.
install_hooks = true
# Empty presets use the installed built-in agents.
# Replace [] with entries that each contain a name and command, for example:
# [{ name = "My Bot", command = ["mybot"] }]
presets = []
# Add an agent definition, or use an existing kind to override it.
# Remove the comment prefix from the full block to enable this example.
# Replace the commands and matching text with values for your agent.
# The default list of custom definitions is empty.
# [[agents.define]]
# kind = "mybot"
# name = "My Bot"
# processes = ["mybot"]
# argv = ["mybot/cli"]
# working = ["Working"]
# attention = ["Approve?"]
# launch = ["mybot"]
# resume = ["mybot", "--continue"]
# resume_session = ["mybot", "--resume", "{session}"]
# fork_session = ["mybot", "--fork", "{session}"]
# processes matches executable names; argv matches parts of process arguments.
# working and attention match text on the screen.
# launch, resume, resume_session, and fork_session are optional commands.
# {session} is replaced with the session ID reported by agent hooks.
[programs]
# Show known programs (Neovim, Node, htop) with an icon for their kind in headers and the sidebar.
detect = true
# Show the program's name in place of its process name in titles ("Neovim" for "nvim").
names = true
# Add a program definition, or use an existing id to override it.
# Remove the comment prefix from the full block to enable this example.
# The default list of custom definitions is empty.
# [[programs.define]]
# id = "mytool"
# name = "My Tool"
# processes = ["mytool"]
# argv = ["mytool/cli.js"]
# icon = "build"
# color = "#3776ab"
# ink = "#ffffff"
# processes matches executable names, and a trailing * matches any suffix.
# argv matches parts of an interpreter's arguments.
# icon is a kind of program (editor, runtime, git, build, container, cluster, database,
# monitor, multiplexer, remote, files, docs), a mark (neovim, vim, sofka), or an SF Symbol
# name on macOS. color and ink are optional.
[ai]
# Use the on-device Apple Intelligence model. Requires macOS 26 or later, Apple silicon,
# and Apple Intelligence turned on in System Settings. Text never leaves the Mac.
# The features below take effect only when enabled is true.
enabled = false
# Name agent tabs after the task when the agent does not provide a session title.
titles = true
# Detect agents waiting for an answer when no attention pattern matches.
# Applies to agents without hooks.
status = true
# Describe agent requests and summarize finished turns in notifications
# and the agent switcher.
notifications = true
# Allow Edit > Explain Last Command and `thurm explain`.
explain = true
[plugins]
# Run plugins: init.lua next to this file, and the plugins in plugins/.
enabled = true
# Plugins not to start, by name.
disabled = []
# Settings for one plugin, passed to it as they are.
# [plugins.settings]
# git-tools = { remote = "origin" }
[updates]
# "auto" follows the installed build's channel: "release" or "tip".
# Use "release" or "tip" to select a fixed channel.
channel = "auto"
# Check for updates in the background.
check_automatically = true
# Download updates in the background and install them when Thurm quits.
download_automatically = false
[quick_terminal]
# A terminal that slides in from a screen edge on a global shortcut, from
# any app or Space. Its shell keeps running while it is hidden. You can also
# use Window > Quick Terminal.
# Modifiers are cmd, ctrl, alt and shift. An empty value sets no shortcut.
hotkey = ""
# hotkey = "ctrl+grave"
# "top", "bottom", "left", "right" or "center".
position = "top"
# The fraction of the screen that it takes.
size = 0.4
# Hide it when another app or another Thurm window takes focus.
autohide = true
# "mouse" uses the screen with the pointer. "main" uses the menu bar screen.
screen = "mouse"
# The slide animation length in seconds. Use 0 for no animation.
animation_duration = 0.2
# Background opacity from 0 to 1. When not set, window.opacity is used.
# opacity = 0.9
[keybindings]
# Map a key combination to an action name.
# "cmd+shift+d" = "split_down"
# "cmd+d" = "split_right"
# A command of your own, in the command palette and on an optional key. The daemon
# runs it through your login shell in the focused pane's directory, with
# THURM_PANE_ID and THURM_SOCKET set.
# [[commands]]
# name = "Dev layout"
# exec = ["~/bin/dev-layout", "--branch", "main"]
# key = "cmd+shift+l"
# For more than running a command, use init.lua next to this file, or a
# plugin in plugins/.
# A command the daemon runs on an event, with the event as JSON on stdin.
# Events: agent_working, agent_waiting, agent_blocked, agent_finished,
# agent_failed, agent_idle, command_finished and pane_exited.
# [[on]]
# event = "agent_finished"
# exec = ["~/bin/agent-done"]
# min_secs = 0 # command_finished only
[tailscale]
# Serve the daemon over Tailscale as a device of its own, so your phone and other
# devices reach it at wss://HOSTNAME.YOUR-TAILNET.ts.net/v1/connect without ssh.
# The first time, sign in with the link in Settings or `thurm tailscale status`.
enabled = false
# The device's name on the tailnet: one DNS label.
hostname = "thurm"
# Admit every tailnet member, not only the account that signed the device in.
allow_tailnet_members = false
# ACL tags to enroll with, such as ["tag:thurm"]. Needs allow_tailnet_members.
advertise_tags = []
# A file with a Tailscale auth key, to enroll without a browser.
auth_key_file = ""
# Also listen on this machine's tailnet addresses through its own Tailscale.
host_listen = ""
# host_listen = ":7297"
# A coordination server other than Tailscale's, such as a headscale.
# control_url = "https://headscale.example.com"
# Without HTTPS (no MagicDNS or certificates, as on headscale), listen on a tailnet address
# without TLS.
# plain_listen = ":7297"
# With host_listen: admit every identified caller, not only this machine's owner.
host_allow_identified = false
# A socket for `tailscale serve` to proxy to.
serve_socket = false
# Serve the browser client on the node's HTTPS address, at https://HOSTNAME.YOUR-TAILNET.ts.net/.
# Needs enabled.
web = false
# Remote workspaces: thurmd on another machine, reached with the system ssh, or over
# Tailscale when `tailnet` is set (ssh still installs, checks and hands off).
# `thurm remote add devbox devbox` checks the connection and writes an entry.
# [[remote]]
# name = "devbox"
# host = "devbox" # an ssh Host alias, user@host, or ssh://user@host:port
# socket = "/run/user/1000/thurm-1000/thurmd.sock" # discovered when unset
# enabled = true
# clipboard_read = "ask" # "ask", "always" or "never"
# tailnet = "wss://devbox.YOUR-TAILNET.ts.net/v1/connect" # over Tailscale instead of ssh