Skip to content

Config Reference

Lshika edited this page Aug 2, 2026 · 18 revisions

Config Reference

Your config lives at ~/.config/tuicc/config.toml. If it's missing, tuicc creates it by copying the packaged default the first time it runs — you always have a real, editable file with sensible defaults, never a hidden in-memory fallback.

If you add or edit sections here and tuicc throws a KeyError on startup, your existing config is probably out of date with a newer packaged default (a new section was added since your config was generated). Delete ~/.config/tuicc/config.toml and run tuicc again to regenerate it with the current defaults, then reapply your customizations. There's no automatic migration yet — this is a known, not-yet-solved gap.


[layout]

[layout]
preset = 1
Key Type Description
preset integer Which layout preset to use. Live-switchable — change this any time, not just on first run.

Where a preset actually lives: ~/.config/tuicc/presets/<N>.toml is the real, editable file tuicc reads — copied there from the packaged template (src/tuicc/presets/<N>.toml) the first time that number is requested, and never touched again after that unless you edit it yourself (or tuicc's own resize mode saves a new one — see below). If you edit a preset and want to reset it back to the packaged version, delete ~/.config/tuicc/presets/<N>.toml and it'll be recopied next time that number is used.

Preset box fields

A preset is a list of [[box]] entries, each needing a name plus x, y, w, h — all four required, all plain ratios (0.0–1.0) of the terminal's width (x, w) or height (y, h):

[[box]]
name = "sidebar"
x = 0.0
y = 0.0
w = 0.26
h = 0.6

Boxes are completely independent — there's no right_of/below/above/bottom/cols/rows/fill_to system anymore (an earlier version of tuicc had one; it was removed once interactive resize mode made "fix it when you see it" cheap enough that the auto-coordination it existed for stopped earning its cost — see Architecture for the full reasoning). Changing one box's position or size never moves or resizes another. If a box looks wrong on a terminal size very different from the one you set it up on, that's expected, not a bug — fix it with resize mode (below) rather than hand-computing ratios.

Editing a layout from inside tuicc (resize mode)

You don't have to hand-edit preset TOML at all — press resize (F2 by default) on the currently active module to enter resize mode:

  • Arrow keys change the box's size (w/h) by default; press move_toggle (m) to switch to changing its position (x/y) instead, and again to switch back.
  • delete_box (Delete) asks y/n before removing the box from the layout entirely.
  • confirm (Enter) keeps whatever you changed — in memory only, nothing written to disk yet — and returns to normal navigation, so you can resize/move as many other modules as you like before saving anything.
  • Escape reverts the box to how it was when you entered resize mode on it. On a box you just spawned (below) with no "before" state to revert to, Escape removes it instead.
  • spawn_box (F6), save_layout (F3), cycle_preset (F4), and help (F1, described below) all work even while resize mode is active on some other box — pressing one first commits your in-progress change (same as confirm would), then does its own thing.

spawn_box (F6) lists every module not currently placed in your layout (numbered), and adding one via a digit key spawns it centered on screen, dropped straight into move mode so you can immediately position it.

save_layout (F3) writes your entire in-memory layout as a new preset — never overwriting an existing one, since round-tripping an existing preset through the TOML writer would silently strip any comments in it — and switches [layout] preset in config.toml over to that new number for you (see set_active_preset() in config.py: it patches just that one line by hand, not a full rewrite, so the rest of your hand-edited config.toml — comments, formatting, everything — survives untouched).

cycle_preset (F4) switches through every preset number that actually exists (packaged or yours), live — each press changes what's on screen and updates config.toml to match, same as save_layout does.

help (F1) isn't part of resize mode itself, but is worth knowing about here too — it opens an in-app reference covering all of this (plus your current keybinds and a live [theme] color editor) without needing this wiki open. See Keybindings: Help menu for the full page-by-page rundown.


[navigation]

[navigation]
tab_order = "columns_first"
vim_mode = false
Key Type Description
tab_order "columns_first" | "rows_first" Order Tab cycles through items within a module. columns_first: top-to-bottom within a column, then next column. rows_first: left-to-right within a row, then next row.
vim_mode bool If true, ambient typing no longer opens the launcher — you have to press the insert key (see [navigation.keys] below) first. This exists so vim-style bindings like h/j/k/l don't collide with typing search text.

[wm]

[wm]
provider = "sway"
total_workspaces = 10
Key Type Description
provider string Which WM provider to use. Built in: sway, i3. See Writing a WM Provider to add your own — once registered in providers/registry.py, its name becomes valid here.
total_workspaces integer How many workspace slots the sidebar always shows, regardless of how many are actually in use. Empty slots render thin; occupied ones grow to list every window.

Not a config.toml key, but a required setup step: tuicc needs to run floating, not tiled, or it'll still reserve its slot in your tiling split even after it filters itself out of its own window list (see Architecture). Add a rule to your WM config — for sway/i3:

for_window [app_id="tuicc"] floating enable

If you also want it fullscreen, floating enable must come before fullscreen enable in the same rule, not after — applying fullscreen to a still-tiled window behaves differently than fullscreen on a floating one:

for_window [app_id="tuicc"] floating enable, fullscreen enable

This also means launching tuicc via a plain python main.py in whatever terminal you happen to have open won't get the app_id this rule matches against — you'll want something like kitty --class=tuicc -e /path/to/.venv/bin/python main.py (adjust for your terminal/venv), so the window actually reports app_id="tuicc" for the rule to catch. main.py currently resolves its own src/ import path relative to wherever it's launched from, so a --directory (or equivalent, for other terminals) pointing at the tuicc checkout is worth adding to the same command if you're not launching from inside that folder already.


[theme]

[theme]
background = "inherit"
border = "white"
border_selected = "white"
text = "white"
accent = "cyan"
selected = "blue"
warning = "yellow"
urgent = "red"

Every role accepts one of four formats:

Format Example Notes
"inherit" "inherit" Use the terminal's own color for this role — curses's default color (-1). Typically used for background.
Named color "cyan" One of: black, red, green, yellow, blue, magenta, cyan, white.
Hex string "#7dd3fc" Approximated to the nearest color in curses's 256-color cube — not exact true-color, since curses doesn't support that directly.
RGB list [125, 211, 252] Same approximation as hex, different input format. "#7dd3fc" and [125, 211, 252] resolve to the identical color.

Note: a named color and its hex/RGB equivalent don't necessarily resolve to the same internal color number — named colors map directly to curses's base 8, while hex/RGB always goes through the 256-color cube approximation. "red" and "#ff0000" are different numbers internally, even though they look the same.

You don't have to hand-edit this section either — the Help menu's Colors page (help, F1, then 3) edits and previews all 8 roles live from inside tuicc, and writes the result back here for you. It only accepts a named color, #hex, or "inherit" through that UI though — an [R, G, B] list still needs hand-editing.

Roles

Role Used for
background Overall background. Almost always "inherit".
border Default box outline color for modules and items.
border_selected Outline color for the currently active module (the one Shift+Tab last landed on) — see Keybindings.
text Default, unselected text.
accent Highlight color — currently used for floating window boxes in the preview.
selected Text/border color for the currently selected item within a module.
warning Reserved for non-critical alerts. Not yet used by any built-in module.
urgent Critical/destructive emphasis — used for confirm prompts on destructive actions (power menu, quick actions) and for confirm = true entries in the list before they're even selected.

[navigation.keys]

[navigation.keys]
left = "Left"
right = "Right"
up = "Up"
down = "Down"
tab = "Tab"
switch_module = "Shift+Tab"
confirm = "Enter"
confirm_yes = "y"
confirm_no = "n"
help = "F1"
resize = "F2"
save_layout = "F3"
cycle_preset = "F4"
spawn_box = "F6"
move_toggle = "m"
delete_box = "Delete"
Key Description
left, right, up, down Move selection within the active module (predictable left-to-right order for preview windows), or between modules when there's nowhere further to go in the current one.
tab Cycle through items in the currently active module.
switch_module Switch which module is "active" (cycles through the modules in your current layout preset).
confirm Activate the selected item — switch workspace, focus a window, connect/disconnect wifi or bluetooth, launch an app, or run a power-menu/quick action (prompting first if the action has confirm = true).
confirm_yes, confirm_no Answer a Y/N confirmation dialog. The on-screen hint always reflects whatever you bind here — rebind these and the dialog's text updates to match, no separate step needed.
insert Only used when [navigation].vim_mode = true — press this to start typing into the launcher, since ambient typing is disabled in vim mode.
help Opens the in-app help menu — keybinds/FAQ, a resize-mode reference, and a live [theme] color editor. See Keybindings: Help menu.
spawn_box, resize, save_layout, cycle_preset, move_toggle, delete_box Interactive layout editing (resize mode) — see Config Reference: Editing a layout from inside tuicc above and Keybindings for the full behavior. move_toggle/delete_box only do anything while resize mode is already active on some box; the other four (including help) also work from normal navigation.

Accepted values: named specials (Left, Right, Up, Down, Tab, Shift+Tab, Enter, Escape, Space, Delete, F1F12), any single character (e.g. "h", "j", "k", "l" for vim-style bindings), or Ctrl+<letter> (e.g. "Ctrl+L"). Uppercase letters work as an implicit Shift — curses reports "A" and "a" as different key codes on their own. Ctrl+<letter> combos work reliably (a plain ASCII control code); general Shift+<key> combos other than Shift+Tab aren't attempted, since curses can't report them reliably across terminals. F-keys are their own separate namespace — deliberately used for resize mode's and the help menu's entry points instead of Ctrl+<letter> (already spoken for by power-menu-style global shortcuts) or a bare character (already spoken for by the launcher's "start typing from anywhere" fallback).

There's no dedicated quit key yet. Ctrl+C (an ordinary terminal interrupt, not a tuicc keybind) is the only way to exit without doing anything, for now — see Keybindings for the current state of this gap.


[[quick_actions.action]]

[[quick_actions.action]]
label = "Lock"
icon = ""
command = "swaylock"
confirm = false
shell_true = false

[[quick_actions.action]]
label = "Shutdown"
icon = ""
command = "systemctl poweroff"
confirm = true
shell_true = false

Add as many [[quick_actions.action]] blocks as you want — each one is a separate entry in the quick-actions module. Not shown in the default layout preset — the module exists and works, but is reserved for something more open-ended later. Editing this section won't visibly change anything unless your preset actually places quick_actions somewhere.

Key Type Required Description
label string yes Shown in the UI.
command string yes Command run (via subprocess.Popen) when you select the action and press confirm.
icon string no (defaults to "") Shown before the label, if set.
confirm bool no (defaults to false) If true, pressing confirm shows a Y/N prompt in place of the action list instead of running the command immediately. Use this for anything destructive.
shell_true bool no (defaults to false) If false (the default), command runs as plain arguments — no shell involved, so nothing in the string is ever interpreted as shell syntax. Set to true only if the command genuinely needs shell syntax (pipes, ;, &&, $VARS) — see SECURITY for why this is opt-in rather than the default.

tuicc doesn't wait for or report on the command's success/failure; it exits immediately after launching it.


[[power_menu.action]]

[[power_menu.action]]
label = "Lock"
shortcut = "Ctrl+L"
icon = ""
command = "swaylock"
confirm = false
shell_true = false

[[power_menu.action]]
label = "Shutdown"
shortcut = "Ctrl+P"
icon = ""
command = "systemctl poweroff"
confirm = true
confirm_text = "Shut down now?"
shell_true = false

The module actually shown in the default layout — a vertical list, not capped at any fixed number of entries (the old 4-slot grid design was replaced with a plain list, so add as many as you like, limited only by how tall the box is). Same base fields as quick_actions.action, plus two more:

Key Type Required Description
label string yes Shown in the UI, and used in the confirm question if confirm_text isn't set.
command string yes Same as quick_actions.action.
icon string no Currently unused by the list-style rendering — kept for a possible future icon mode.
confirm bool no (defaults to false) Same as quick_actions.action.
shell_true bool no (defaults to false) Same as quick_actions.action — see that section above for the full explanation.
confirm_text string no A custom confirmation question (e.g. "Reboot now?"), shown above the Y/N prompt. Only meaningful when confirm = true — otherwise never shown. If omitted (with confirm = true), just the plain Y/N prompt shows, no question line.
shortcut string no A key (same format as [navigation.keys], typically "Ctrl+<letter>") that runs this action from anywhere in the running app, not just when this entry happens to be selected — and shows automatically as a [^X]-style prefix next to the label. Omit this entirely if you don't want a shortcut for that action; it's never forced on you.

Collision checking: every shortcut across every action, plus every [navigation.keys] binding, is checked against every other one at startup. Two things bound to the same key raise a KeyError naming both, rather than one silently winning — see Keybindings for more on how this works.


[clock]

[clock]
time_format = "%H:%M:%S"
date_format = "%a %d.%m."
Key Type Description
time_format string strftime-style format string for the time.
date_format string strftime-style format string for the date.

Not shown in the default layout preset — the clock module exists and works, but isn't placed anywhere by the current preset.


[title_condense]

[title_condense]
terminal_apps = ["kitty", "alacritty", "foot", "wezterm", "st", "urxvt", "xterm", "ghostty"]
browser_apps = ["librewolf", "firefox", "chromium", "chrome", "google-chrome"]
browser_title_names = ["librewolf", "mozilla firefox", "firefox", "chromium"]

Controls how the sidebar condenses a window's title down to just the useful part, keyed by app ID (lowercase):

Key Type Description
terminal_apps list of strings App IDs shown with their full window title — usually the running command or working directory, which is genuinely useful for a terminal.
browser_apps list of strings App IDs shown with just the site/page name, not the browser's own name repeated in every title.
browser_title_names list of strings Words filtered out of a browser title when picking the site name (e.g. so "GitHub — Mozilla Firefox" shows "GitHub", not "Mozilla Firefox").

Anything not in either list falls back to a generic heuristic: the first segment of the title, or nothing if that segment just repeats the app's own name.


[network]

[network]
wifi_backend = "iwd"
bluetooth_backend = "bluez"
Key Type Description
wifi_backend string Which wifi backend to use. Built in: iwd.
bluetooth_backend string Which bluetooth backend to use. Built in: bluez.

iwd is talked to directly over D-Bus (not by parsing iwctl's text output — its signal-strength display uses ANSI color to encode strength, not something safely text-parseable). bluez is driven via bluetoothctl CLI text, which doesn't have that problem. Connection requests run on a background thread — the render loop only ever reads cached state, never blocks waiting for a connect/disconnect to finish.

Clone this wiki locally