Configuration Reference
Primary format: TOML (recommended)
Location: ~/.config/dumber/config.toml
Also supports: JSON (.json) and YAML (.yaml)
JSON Schema: ~/.config/dumber/config.schema.json (auto-generated for JSON format)
Why TOML?
TOML is the recommended format for dumber configuration because:
- Clear structure: Explicit sections make complex configs easy to read and modify
- No ambiguity: No whitespace sensitivity or type coercion issues
- Comments supported: Add documentation directly in your config
- Industry standard: Used by Cargo, Hugo, and many modern tools
You can still use JSON or YAML if you prefer - dumber automatically detects the format.
Database
| Key |
Type |
Default |
Description |
database.path |
string |
~/.local/share/dumber/dumber.db |
Database file path |
History
| Key |
Type |
Default |
Valid Values |
Description |
history.max_entries |
int |
10000 |
> 0 |
Maximum number of history entries |
history.retention_period_days |
int |
365 |
> 0 |
Days to keep history (1 year) |
history.cleanup_interval_days |
int |
1 |
> 0 |
How often to run cleanup |
Search Configuration
| Key |
Type |
Default |
Description |
default_search_engine |
string |
"https://duckduckgo.com/?q=%s" |
Default search engine URL template (must contain %s placeholder) |
search_shortcuts |
map |
See defaults |
Map of shortcut aliases to URLs |
Example:
# Default search engine - used when no shortcut is specified
default_search_engine = "https://duckduckgo.com/?q=%s"
# Alternative search engines:
# default_search_engine = "https://www.google.com/search?q=%s"
# default_search_engine = "https://www.startpage.com/search?q=%s"
# default_search_engine = "https://search.brave.com/search?q=%s"
Default shortcuts (usage: !shortcut query):
# Examples:
# !ddg golang → DuckDuckGo search for "golang"
# !g rust tutorial → Google search for "rust tutorial"
# !gi cats → Google Images search for "cats"
# !gh opencode → GitHub search for "opencode"
# !yt music video → YouTube search for "music video"
[search_shortcuts.ddg]
url = "https://duckduckgo.com/?q=%s"
description = "DuckDuckGo search"
[search_shortcuts.g]
url = "https://google.com/search?q=%s"
description = "Google Search"
[search_shortcuts.gi]
url = "https://google.com/search?tbm=isch&q=%s"
description = "Google Images"
[search_shortcuts.gh]
url = "https://github.com/search?q=%s"
description = "GitHub"
[search_shortcuts.yt]
url = "https://youtube.com/results?search_query=%s"
description = "YouTube"
These settings control the dumber dmenu CLI command for rofi/fuzzel integration.
| Key |
Type |
Default |
Description |
dmenu.max_history_items |
int |
20 |
Max items shown in launcher |
dmenu.show_visit_count |
bool |
true |
Show visit counts in output |
dmenu.show_last_visited |
bool |
true |
Show last visited dates in output |
dmenu.history_prefix |
string |
"🕒" |
Prefix for history items |
dmenu.shortcut_prefix |
string |
"🔍" |
Prefix for shortcuts |
dmenu.url_prefix |
string |
"🌐" |
Prefix for URLs |
dmenu.date_format |
string |
"2006-01-02 15:04" |
Go time format string |
dmenu.sort_by_visit_count |
bool |
true |
Sort by popularity |
CLI Usage:
# Pipe mode (default) - outputs history for rofi/fuzzel with favicons
dumber dmenu | rofi -dmenu -show-icons -p "Browse: " | dumber dmenu --select
dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select
# Interactive TUI mode
dumber dmenu --interactive
# Override max items via CLI flag
dumber dmenu --max 50
Omnibox
| Key |
Type |
Default |
Valid Values |
Description |
omnibox.initial_behavior |
string |
"recent" |
recent, most_visited, none |
Initial history display behavior |
Example:
[omnibox]
initial_behavior = "recent" # Show recent history when omnibox opens
# Alternative options:
# initial_behavior = "most_visited" # Show most visited sites
# initial_behavior = "none" # Show no initial suggestions
Logging
| Key |
Type |
Default |
Valid Values |
Description |
logging.level |
string |
"info" |
debug, info, warn, error |
Log level |
logging.format |
string |
"text" |
text, json |
Log format |
logging.max_age |
int |
7 |
>= 0 |
Days to keep logs |
logging.log_dir |
string |
~/.local/state/dumber/logs/ |
any |
Log directory |
logging.enable_file_log |
bool |
true |
- |
Enable file logging |
logging.capture_console |
bool |
false |
- |
Capture browser console to logs |
Appearance
| Key |
Type |
Default |
Description |
appearance.sans_font |
string |
"Fira Sans" |
Sans-serif font |
appearance.serif_font |
string |
"Fira Sans" |
Serif font |
appearance.monospace_font |
string |
"Fira Code" |
Monospace font |
appearance.default_font_size |
int |
16 |
Font size in points |
appearance.color_scheme |
string |
"default" |
prefer-dark, prefer-light, default |
Color Palettes
Light palette:
[appearance.light_palette]
background = "#f8f8f8"
surface = "#f2f2f2"
surface_variant = "#ececec"
text = "#1a1a1a"
muted = "#6e6e6e"
accent = "#404040"
border = "#d2d2d2"
Dark palette:
[appearance.dark_palette]
background = "#0e0e0e"
surface = "#1a1a1a"
surface_variant = "#141414"
text = "#e4e4e4"
muted = "#848484"
accent = "#a8a8a8"
border = "#363636"
Debug Options
| Key |
Type |
Default |
Description |
debug.enable_devtools |
bool |
true |
Enable browser developer tools (F12, Inspect Element) |
Rendering, UI Scale & Zoom
| Key |
Type |
Default |
Valid Values |
Description |
rendering.mode |
string |
"gpu" |
auto, gpu, cpu |
WebKit hardware acceleration policy |
rendering.disable_dmabuf_renderer |
bool |
false |
- |
Disable WebKit DMA-BUF renderer (may fix flicker on Wayland; slower) |
rendering.force_compositing_mode |
bool |
false |
- |
Force WebKit compositing mode (WEBKIT_FORCE_COMPOSITING_MODE) |
rendering.disable_compositing_mode |
bool |
false |
- |
Disable WebKit compositing mode (WEBKIT_DISABLE_COMPOSITING_MODE) |
rendering.gsk_renderer |
string |
"vulkan" |
auto, opengl, vulkan, cairo |
GTK renderer selection (GSK_RENDERER) |
rendering.disable_mipmaps |
bool |
false |
- |
Disable GTK mipmaps (GSK_GPU_DISABLE=mipmap) |
rendering.prefer_gl |
bool |
false |
- |
Prefer OpenGL over GLES (GDK_DEBUG=gl-prefer-gl) |
rendering.draw_compositing_indicators |
bool |
false |
- |
Draw WebKit compositing indicators (debug) |
rendering.show_fps |
bool |
false |
- |
Show WebKit FPS counter (WEBKIT_SHOW_FPS) |
rendering.sample_memory |
bool |
false |
- |
Enable WebKit memory sampling (WEBKIT_SAMPLE_MEMORY) |
rendering.debug_frames |
bool |
false |
- |
Enable GTK frame timing debug (GDK_DEBUG=frames) |
default_ui_scale |
float |
1.0 |
> 0 |
GTK widget UI scale (1.0=100%, 2.0=200%) |
default_webpage_zoom |
float |
1.2 |
> 0 |
Default page zoom (1.0=100%, 1.2=120%) |
Workspace Configuration
Pane Mode
| Key |
Type |
Default |
Description |
workspace.pane_mode.activation_shortcut |
string |
"ctrl+p" |
Pane mode activation key |
workspace.pane_mode.timeout_ms |
int |
3000 |
Pane mode timeout (ms) |
workspace.pane_mode.actions |
map |
See below |
Action→keys mappings |
Default pane mode actions:
[workspace.pane_mode.actions]
split-right = ["arrowright", "r"]
split-left = ["arrowleft", "l"]
split-up = ["arrowup", "u"]
split-down = ["arrowdown", "d"]
stack-pane = ["s"]
close-pane = ["x"]
focus-right = ["shift+arrowright", "shift+l"]
focus-left = ["shift+arrowleft", "shift+h"]
focus-up = ["shift+arrowup", "shift+k"]
focus-down = ["shift+arrowdown", "shift+j"]
confirm = ["enter"]
cancel = ["escape"]
Note: Actions are inverted to key→action map in memory for O(1) lookup performance during navigation.
Tab Mode
| Key |
Type |
Default |
Description |
workspace.tab_mode.activation_shortcut |
string |
"ctrl+t" |
Tab mode activation key |
workspace.tab_mode.timeout_ms |
int |
3000 |
Tab mode timeout (ms) |
workspace.tab_mode.actions |
map |
See below |
Action→keys mappings |
Default tab mode actions:
[workspace.tab_mode.actions]
new-tab = ["n", "c"]
close-tab = ["x"]
next-tab = ["l", "tab"]
previous-tab = ["h", "shift+tab"]
rename-tab = ["r"]
confirm = ["enter"]
cancel = ["escape"]
Note: Actions are inverted to key→action map in memory for O(1) lookup performance during navigation.
Global Shortcuts
| Key |
Type |
Default |
Description |
workspace.shortcuts.close_pane |
string |
"ctrl+w" |
Close active pane (closes tab if last pane) |
workspace.shortcuts.next_tab |
string |
"ctrl+tab" |
Next tab shortcut |
workspace.shortcuts.previous_tab |
string |
"ctrl+shift+tab" |
Previous tab shortcut |
Note: New tab creation uses modal tab mode (Ctrl+T then n/c). This follows the Zellij-style modal keyboard interface.
| Key |
Type |
Default |
Valid Values |
Description |
workspace.popups.behavior |
string |
"split" |
split, stacked, tabbed, windowed |
Popup opening mode |
workspace.popups.placement |
string |
"right" |
right, left, top, bottom |
Split direction |
workspace.popups.open_in_new_pane |
bool |
true |
- |
Open popups in workspace |
workspace.popups.follow_pane_context |
bool |
true |
- |
Follow parent pane context |
workspace.popups.blank_target_behavior |
string |
"pane" |
pane, tab |
_blank target handling |
workspace.popups.enable_smart_detection |
bool |
true |
- |
Use WindowProperties for detection |
workspace.popups.oauth_auto_close |
bool |
true |
- |
Auto-close OAuth popups |
Workspace Styling
| Key |
Type |
Default |
Description |
workspace.styling.border_width |
int |
1 |
Active pane border width (px) - overlay |
workspace.styling.border_color |
string |
"@theme_selected_bg_color" |
Active pane border color |
workspace.styling.pane_mode_border_width |
int |
4 |
Pane mode border width (px) - Ctrl+P N overlay |
workspace.styling.pane_mode_border_color |
string |
"#4A90E2" |
Pane mode border color (blue) |
workspace.styling.tab_mode_border_width |
int |
4 |
Tab mode border width (px) - Ctrl+P T overlay |
workspace.styling.tab_mode_border_color |
string |
"#FFA500" |
Tab mode border color (orange) |
workspace.styling.transition_duration |
int |
120 |
Border transition duration (ms) |
| Key |
Type |
Default |
Valid Values |
Description |
media.hardware_decoding |
string |
"auto" |
auto, force, disable |
Hardware video decoding mode |
media.prefer_av1 |
bool |
true |
- |
Prefer AV1 codec when available |
media.show_diagnostics |
bool |
true |
- |
Show media diagnostics warnings at startup |
media.force_vsync |
bool |
false |
- |
Force VSync for video playback (may help with tearing) |
media.gl_rendering_mode |
string |
"auto" |
auto, gles2, gl3, none |
OpenGL API selection for video rendering |
media.gstreamer_debug_level |
int |
0 |
0-5 |
GStreamer debug verbosity (0=off) |
media.video_buffer_size_mb |
int |
64 |
> 0 |
Video buffer size in MB for smoother streaming |
media.queue_buffer_time_sec |
int |
20 |
> 0 |
Queue prebuffer time in seconds |
Hardware decoding modes:
auto (recommended): Hardware preferred with software fallback - fixes Twitch Error #4000
force: Hardware only - fails if unavailable
disable: Software only - higher CPU usage
GL rendering modes:
auto (default): Let GStreamer choose the best OpenGL API
gles2: Force GLES2 (better for some mobile/embedded GPUs)
gl3: Force OpenGL 3.x desktop
none: Disable GL-based rendering
GPU auto-detection:
Dumber automatically detects your GPU vendor (AMD/Intel/NVIDIA) and sets optimal VA-API driver settings:
- AMD: Uses
radeonsi driver
- Intel: Uses
iHD driver (modern, for Broadwell+)
- NVIDIA: Uses
nvidia driver with EGL platform
Buffering settings:
video_buffer_size_mb: Controls GStreamer buffer size. Larger buffers reduce rebuffering on bursty streams (Twitch, YouTube). Uses more memory.
queue_buffer_time_sec: Controls prebuffer duration. Higher values allow more data to be buffered ahead of playback.
Example:
[media]
hardware_decoding = "auto" # HW preferred, SW fallback
prefer_av1 = true # AV1 is most efficient codec
show_diagnostics = true # Log warnings if HW accel unavailable
force_vsync = false # Let compositor handle VSync
gl_rendering_mode = "auto" # GStreamer picks best GL API
gstreamer_debug_level = 0 # Increase to 3-5 for debugging
video_buffer_size_mb = 64 # 64 MB buffer for smooth streaming
queue_buffer_time_sec = 20 # 20 seconds prebuffer
Diagnostics CLI:
# Check GStreamer plugins and VA-API status
dumber doctor --media
Runtime
| Key |
Type |
Default |
Description |
runtime.prefix |
string |
"" |
Optional runtime prefix (e.g., /opt/webkitgtk) used to locate newer GTK/WebKitGTK installs |
If set, dumber prepends prefix-derived paths to:
PKG_CONFIG_PATH (for version checks)
LD_LIBRARY_PATH (for runtime library loading)
GI_TYPELIB_PATH (GObject introspection)
XDG_DATA_DIRS (schemas/resources)
Example:
[runtime]
prefix = "/opt/webkitgtk"
Content Filtering
| Key |
Type |
Default |
Description |
content_filtering.enabled |
bool |
true |
Enable ad blocking |
content_filtering.auto_update |
bool |
true |
Automatically update filters |
Notes:
- Filter data is downloaded from
bnema/ublock-webkit-filters GitHub releases.
- Domain whitelist is managed via the database (
content_whitelist table), not the config file.
Environment Variables
All config values can be overridden via environment variables with the prefix DUMBER_:
# Database
DUMBER_DATABASE_PATH=/custom/path/db.sqlite
# Rendering (examples)
# Defaults: rendering.disable_dmabuf_renderer=false, rendering.gsk_renderer="vulkan"
DUMBER_RENDERING_MODE=cpu
# DUMBER_RENDERING_DISABLE_DMABUF_RENDERER=true
# DUMBER_RENDERING_GSK_RENDERER=opengl
DUMBER_DEFAULT_WEBPAGE_ZOOM=1.5
# Logging
DUMBER_LOG_LEVEL=debug
DUMBER_LOG_FORMAT=json
source
1# Configuration Reference
2
3**Primary format**: TOML (recommended)
4**Location**: `~/.config/dumber/config.toml`
5**Also supports**: JSON (`.json`) and YAML (`.yaml`)
6**JSON Schema**: `~/.config/dumber/config.schema.json` (auto-generated for JSON format)
7
8## Why TOML?
9
10TOML is the recommended format for dumber configuration because:
11- **Clear structure**: Explicit sections make complex configs easy to read and modify
12- **No ambiguity**: No whitespace sensitivity or type coercion issues
13- **Comments supported**: Add documentation directly in your config
14- **Industry standard**: Used by Cargo, Hugo, and many modern tools
15
16You can still use JSON or YAML if you prefer - dumber automatically detects the format.
17
18## Database
19
20| Key | Type | Default | Description |
21|-----|------|---------|-------------|
22| `database.path` | string | `~/.local/share/dumber/dumber.db` | Database file path |
23
24## History
25
26| Key | Type | Default | Valid Values | Description |
27|-----|------|---------|--------------|-------------|
28| `history.max_entries` | int | `10000` | > 0 | Maximum number of history entries |
29| `history.retention_period_days` | int | `365` | > 0 | Days to keep history (1 year) |
30| `history.cleanup_interval_days` | int | `1` | > 0 | How often to run cleanup |
31
32## Search Configuration
33
34| Key | Type | Default | Description |
35|-----|------|---------|-------------|
36| `default_search_engine` | string | `"https://duckduckgo.com/?q=%s"` | Default search engine URL template (must contain `%s` placeholder) |
37| `search_shortcuts` | map | See defaults | Map of shortcut aliases to URLs |
38
39**Example:**
40```toml
41# Default search engine - used when no shortcut is specified
42default_search_engine = "https://duckduckgo.com/?q=%s"
43
44# Alternative search engines:
45# default_search_engine = "https://www.google.com/search?q=%s"
46# default_search_engine = "https://www.startpage.com/search?q=%s"
47# default_search_engine = "https://search.brave.com/search?q=%s"
48```
49
50**Default shortcuts (usage: `!shortcut query`):**
51```toml
52# Examples:
53# !ddg golang → DuckDuckGo search for "golang"
54# !g rust tutorial → Google search for "rust tutorial"
55# !gi cats → Google Images search for "cats"
56# !gh opencode → GitHub search for "opencode"
57# !yt music video → YouTube search for "music video"
58
59[search_shortcuts.ddg]
60url = "https://duckduckgo.com/?q=%s"
61description = "DuckDuckGo search"
62
63[search_shortcuts.g]
64url = "https://google.com/search?q=%s"
65description = "Google Search"
66
67[search_shortcuts.gi]
68url = "https://google.com/search?tbm=isch&q=%s"
69description = "Google Images"
70
71[search_shortcuts.gh]
72url = "https://github.com/search?q=%s"
73description = "GitHub"
74
75[search_shortcuts.yt]
76url = "https://youtube.com/results?search_query=%s"
77description = "YouTube"
78```
79
80## Dmenu / Launcher
81
82These settings control the `dumber dmenu` CLI command for rofi/fuzzel integration.
83
84| Key | Type | Default | Description |
85|-----|------|---------|-------------|
86| `dmenu.max_history_items` | int | `20` | Max items shown in launcher |
87| `dmenu.show_visit_count` | bool | `true` | Show visit counts in output |
88| `dmenu.show_last_visited` | bool | `true` | Show last visited dates in output |
89| `dmenu.history_prefix` | string | `"🕒"` | Prefix for history items |
90| `dmenu.shortcut_prefix` | string | `"🔍"` | Prefix for shortcuts |
91| `dmenu.url_prefix` | string | `"🌐"` | Prefix for URLs |
92| `dmenu.date_format` | string | `"2006-01-02 15:04"` | Go time format string |
93| `dmenu.sort_by_visit_count` | bool | `true` | Sort by popularity |
94
95**CLI Usage:**
96```bash
97# Pipe mode (default) - outputs history for rofi/fuzzel with favicons
98dumber dmenu | rofi -dmenu -show-icons -p "Browse: " | dumber dmenu --select
99dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select
100
101# Interactive TUI mode
102dumber dmenu --interactive
103
104# Override max items via CLI flag
105dumber dmenu --max 50
106```
107
108## Omnibox
109
110| Key | Type | Default | Valid Values | Description |
111|-----|------|---------|--------------|-------------|
112| `omnibox.initial_behavior` | string | `"recent"` | `recent`, `most_visited`, `none` | Initial history display behavior |
113
114**Example:**
115```toml
116[omnibox]
117initial_behavior = "recent" # Show recent history when omnibox opens
118
119# Alternative options:
120# initial_behavior = "most_visited" # Show most visited sites
121# initial_behavior = "none" # Show no initial suggestions
122```
123
124## Logging
125
126| Key | Type | Default | Valid Values | Description |
127|-----|------|---------|--------------|-------------|
128| `logging.level` | string | `"info"` | `debug`, `info`, `warn`, `error` | Log level |
129| `logging.format` | string | `"text"` | `text`, `json` | Log format |
130| `logging.max_age` | int | `7` | >= 0 | Days to keep logs |
131| `logging.log_dir` | string | `~/.local/state/dumber/logs/` | any | Log directory |
132| `logging.enable_file_log` | bool | `true` | - | Enable file logging |
133| `logging.capture_console` | bool | `false` | - | Capture browser console to logs |
134
135## Appearance
136
137| Key | Type | Default | Description |
138|-----|------|---------|-------------|
139| `appearance.sans_font` | string | `"Fira Sans"` | Sans-serif font |
140| `appearance.serif_font` | string | `"Fira Sans"` | Serif font |
141| `appearance.monospace_font` | string | `"Fira Code"` | Monospace font |
142| `appearance.default_font_size` | int | `16` | Font size in points |
143| `appearance.color_scheme` | string | `"default"` | `prefer-dark`, `prefer-light`, `default` |
144
145### Color Palettes
146
147**Light palette:**
148```toml
149[appearance.light_palette]
150background = "#f8f8f8"
151surface = "#f2f2f2"
152surface_variant = "#ececec"
153text = "#1a1a1a"
154muted = "#6e6e6e"
155accent = "#404040"
156border = "#d2d2d2"
157```
158
159**Dark palette:**
160```toml
161[appearance.dark_palette]
162background = "#0e0e0e"
163surface = "#1a1a1a"
164surface_variant = "#141414"
165text = "#e4e4e4"
166muted = "#848484"
167accent = "#a8a8a8"
168border = "#363636"
169```
170
171## Debug Options
172
173| Key | Type | Default | Description |
174|-----|------|---------|-------------|
175| `debug.enable_devtools` | bool | `true` | Enable browser developer tools (F12, Inspect Element) |
176
177## Rendering, UI Scale & Zoom
178
179| Key | Type | Default | Valid Values | Description |
180|-----|------|---------|--------------|-------------|
181| `rendering.mode` | string | `"gpu"` | `auto`, `gpu`, `cpu` | WebKit hardware acceleration policy |
182| `rendering.disable_dmabuf_renderer` | bool | `false` | - | Disable WebKit DMA-BUF renderer (may fix flicker on Wayland; slower) |
183| `rendering.force_compositing_mode` | bool | `false` | - | Force WebKit compositing mode (`WEBKIT_FORCE_COMPOSITING_MODE`) |
184| `rendering.disable_compositing_mode` | bool | `false` | - | Disable WebKit compositing mode (`WEBKIT_DISABLE_COMPOSITING_MODE`) |
185| `rendering.gsk_renderer` | string | `"vulkan"` | `auto`, `opengl`, `vulkan`, `cairo` | GTK renderer selection (`GSK_RENDERER`) |
186| `rendering.disable_mipmaps` | bool | `false` | - | Disable GTK mipmaps (`GSK_GPU_DISABLE=mipmap`) |
187| `rendering.prefer_gl` | bool | `false` | - | Prefer OpenGL over GLES (`GDK_DEBUG=gl-prefer-gl`) |
188| `rendering.draw_compositing_indicators` | bool | `false` | - | Draw WebKit compositing indicators (debug) |
189| `rendering.show_fps` | bool | `false` | - | Show WebKit FPS counter (`WEBKIT_SHOW_FPS`) |
190| `rendering.sample_memory` | bool | `false` | - | Enable WebKit memory sampling (`WEBKIT_SAMPLE_MEMORY`) |
191| `rendering.debug_frames` | bool | `false` | - | Enable GTK frame timing debug (`GDK_DEBUG=frames`) |
192| `default_ui_scale` | float | `1.0` | > 0 | GTK widget UI scale (1.0=100%, 2.0=200%) |
193| `default_webpage_zoom` | float | `1.2` | > 0 | Default page zoom (1.0=100%, 1.2=120%) |
194
195## Workspace Configuration
196
197### Pane Mode
198
199| Key | Type | Default | Description |
200|-----|------|---------|-------------|
201| `workspace.pane_mode.activation_shortcut` | string | `"ctrl+p"` | Pane mode activation key |
202| `workspace.pane_mode.timeout_ms` | int | `3000` | Pane mode timeout (ms) |
203| `workspace.pane_mode.actions` | map | See below | Action→keys mappings |
204
205**Default pane mode actions:**
206```toml
207[workspace.pane_mode.actions]
208split-right = ["arrowright", "r"]
209split-left = ["arrowleft", "l"]
210split-up = ["arrowup", "u"]
211split-down = ["arrowdown", "d"]
212stack-pane = ["s"]
213close-pane = ["x"]
214focus-right = ["shift+arrowright", "shift+l"]
215focus-left = ["shift+arrowleft", "shift+h"]
216focus-up = ["shift+arrowup", "shift+k"]
217focus-down = ["shift+arrowdown", "shift+j"]
218confirm = ["enter"]
219cancel = ["escape"]
220```
221
222> **Note:** Actions are inverted to key→action map in memory for O(1) lookup performance during navigation.
223
224### Tab Mode
225
226| Key | Type | Default | Description |
227|-----|------|---------|-------------|
228| `workspace.tab_mode.activation_shortcut` | string | `"ctrl+t"` | Tab mode activation key |
229| `workspace.tab_mode.timeout_ms` | int | `3000` | Tab mode timeout (ms) |
230| `workspace.tab_mode.actions` | map | See below | Action→keys mappings |
231
232**Default tab mode actions:**
233```toml
234[workspace.tab_mode.actions]
235new-tab = ["n", "c"]
236close-tab = ["x"]
237next-tab = ["l", "tab"]
238previous-tab = ["h", "shift+tab"]
239rename-tab = ["r"]
240confirm = ["enter"]
241cancel = ["escape"]
242```
243
244> **Note:** Actions are inverted to key→action map in memory for O(1) lookup performance during navigation.
245
246### Global Shortcuts
247
248| Key | Type | Default | Description |
249|-----|------|---------|-------------|
250| `workspace.shortcuts.close_pane` | string | `"ctrl+w"` | Close active pane (closes tab if last pane) |
251| `workspace.shortcuts.next_tab` | string | `"ctrl+tab"` | Next tab shortcut |
252| `workspace.shortcuts.previous_tab` | string | `"ctrl+shift+tab"` | Previous tab shortcut |
253
254> **Note:** New tab creation uses modal tab mode (Ctrl+T then n/c). This follows the Zellij-style modal keyboard interface.
255
256### Popup Behavior
257
258| Key | Type | Default | Valid Values | Description |
259|-----|------|---------|--------------|-------------|
260| `workspace.popups.behavior` | string | `"split"` | `split`, `stacked`, `tabbed`, `windowed` | Popup opening mode |
261| `workspace.popups.placement` | string | `"right"` | `right`, `left`, `top`, `bottom` | Split direction |
262| `workspace.popups.open_in_new_pane` | bool | `true` | - | Open popups in workspace |
263| `workspace.popups.follow_pane_context` | bool | `true` | - | Follow parent pane context |
264| `workspace.popups.blank_target_behavior` | string | `"pane"` | `pane`, `tab` | `_blank` target handling |
265| `workspace.popups.enable_smart_detection` | bool | `true` | - | Use WindowProperties for detection |
266| `workspace.popups.oauth_auto_close` | bool | `true` | - | Auto-close OAuth popups |
267
268### Workspace Styling
269
270| Key | Type | Default | Description |
271|-----|------|---------|-------------|
272| `workspace.styling.border_width` | int | `1` | Active pane border width (px) - overlay |
273| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Active pane border color |
274| `workspace.styling.pane_mode_border_width` | int | `4` | Pane mode border width (px) - Ctrl+P N overlay |
275| `workspace.styling.pane_mode_border_color` | string | `"#4A90E2"` | Pane mode border color (blue) |
276| `workspace.styling.tab_mode_border_width` | int | `4` | Tab mode border width (px) - Ctrl+P T overlay |
277| `workspace.styling.tab_mode_border_color` | string | `"#FFA500"` | Tab mode border color (orange) |
278| `workspace.styling.transition_duration` | int | `120` | Border transition duration (ms) |
279
280## Media
281
282| Key | Type | Default | Valid Values | Description |
283|-----|------|---------|--------------|-------------|
284| `media.hardware_decoding` | string | `"auto"` | `auto`, `force`, `disable` | Hardware video decoding mode |
285| `media.prefer_av1` | bool | `true` | - | Prefer AV1 codec when available |
286| `media.show_diagnostics` | bool | `true` | - | Show media diagnostics warnings at startup |
287| `media.force_vsync` | bool | `false` | - | Force VSync for video playback (may help with tearing) |
288| `media.gl_rendering_mode` | string | `"auto"` | `auto`, `gles2`, `gl3`, `none` | OpenGL API selection for video rendering |
289| `media.gstreamer_debug_level` | int | `0` | `0-5` | GStreamer debug verbosity (0=off) |
290| `media.video_buffer_size_mb` | int | `64` | > 0 | Video buffer size in MB for smoother streaming |
291| `media.queue_buffer_time_sec` | int | `20` | > 0 | Queue prebuffer time in seconds |
292
293**Hardware decoding modes:**
294- `auto` (recommended): Hardware preferred with software fallback - fixes Twitch Error #4000
295- `force`: Hardware only - fails if unavailable
296- `disable`: Software only - higher CPU usage
297
298**GL rendering modes:**
299- `auto` (default): Let GStreamer choose the best OpenGL API
300- `gles2`: Force GLES2 (better for some mobile/embedded GPUs)
301- `gl3`: Force OpenGL 3.x desktop
302- `none`: Disable GL-based rendering
303
304**GPU auto-detection:**
305Dumber automatically detects your GPU vendor (AMD/Intel/NVIDIA) and sets optimal VA-API driver settings:
306- **AMD**: Uses `radeonsi` driver
307- **Intel**: Uses `iHD` driver (modern, for Broadwell+)
308- **NVIDIA**: Uses `nvidia` driver with EGL platform
309
310**Buffering settings:**
311- `video_buffer_size_mb`: Controls GStreamer buffer size. Larger buffers reduce rebuffering on bursty streams (Twitch, YouTube). Uses more memory.
312- `queue_buffer_time_sec`: Controls prebuffer duration. Higher values allow more data to be buffered ahead of playback.
313
314**Example:**
315```toml
316[media]
317hardware_decoding = "auto" # HW preferred, SW fallback
318prefer_av1 = true # AV1 is most efficient codec
319show_diagnostics = true # Log warnings if HW accel unavailable
320force_vsync = false # Let compositor handle VSync
321gl_rendering_mode = "auto" # GStreamer picks best GL API
322gstreamer_debug_level = 0 # Increase to 3-5 for debugging
323video_buffer_size_mb = 64 # 64 MB buffer for smooth streaming
324queue_buffer_time_sec = 20 # 20 seconds prebuffer
325```
326
327**Diagnostics CLI:**
328```bash
329# Check GStreamer plugins and VA-API status
330dumber doctor --media
331```
332
333## Runtime
334
335| Key | Type | Default | Description |
336|-----|------|---------|-------------|
337| `runtime.prefix` | string | `""` | Optional runtime prefix (e.g., `/opt/webkitgtk`) used to locate newer GTK/WebKitGTK installs |
338
339If set, dumber prepends prefix-derived paths to:
340- `PKG_CONFIG_PATH` (for version checks)
341- `LD_LIBRARY_PATH` (for runtime library loading)
342- `GI_TYPELIB_PATH` (GObject introspection)
343- `XDG_DATA_DIRS` (schemas/resources)
344
345**Example:**
346```toml
347[runtime]
348prefix = "/opt/webkitgtk"
349```
350
351## Content Filtering
352
353| Key | Type | Default | Description |
354|-----|------|---------|-------------|
355| `content_filtering.enabled` | bool | `true` | Enable ad blocking |
356| `content_filtering.auto_update` | bool | `true` | Automatically update filters |
357
358Notes:
359- Filter data is downloaded from `bnema/ublock-webkit-filters` GitHub releases.
360- Domain whitelist is managed via the database (`content_whitelist` table), not the config file.
361
362## Environment Variables
363
364All config values can be overridden via environment variables with the prefix `DUMBER_`:
365
366```bash
367# Database
368DUMBER_DATABASE_PATH=/custom/path/db.sqlite
369
370# Rendering (examples)
371# Defaults: rendering.disable_dmabuf_renderer=false, rendering.gsk_renderer="vulkan"
372DUMBER_RENDERING_MODE=cpu
373# DUMBER_RENDERING_DISABLE_DMABUF_RENDERER=true
374# DUMBER_RENDERING_GSK_RENDERER=opengl
375DUMBER_DEFAULT_WEBPAGE_ZOOM=1.5
376
377# Logging
378DUMBER_LOG_LEVEL=debug
379DUMBER_LOG_FORMAT=json
380```