v0.29.0 21b3150

index.md RawHistoryFolder

Configuration Guide

Location: ~/.config/dumber/config.toml Formats: TOML (recommended), JSON, YAML

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"

Dmenu / Launcher

These settings control the dumber dmenu CLI command for rofi/fuzzel integration.

Key Type Default Description
dmenu.max_history_days int 30 Number of days of history to show (0 = all)
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 visit count instead of recency

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 history days via CLI flag (show last 7 days)
dumber dmenu --days 7

# Sort by most visited instead of recency
dumber dmenu --most-visited

# Combined: most visited from last 14 days
dumber dmenu --days 14 --most-visited

Omnibox

Key Type Default Valid Values Description
omnibox.initial_behavior string "recent" recent, most_visited, none Initial history display behavior
omnibox.most_visited_days int 30 >= 0 Days of history to consider when initial_behavior = "most_visited" (0 = all history)
omnibox.auto_open_on_new_pane bool false - Automatically open the omnibox after creating a new pane

Example:

[omnibox]
initial_behavior = "recent"  # Show recent history when omnibox opens
most_visited_days = 30        # Days of history used for most_visited
auto_open_on_new_pane = false

# 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" trace, debug, info, warn, error, fatal Log level
logging.format string "text" text, json, console Log format
logging.max_age int 7 >= 0 Days to keep logs
logging.max_files int 100 >= 0 Session log files to keep (0 disables count cleanup)
logging.log_dir string ~/.local/state/dumber/logs any path Log directory
logging.enable_file_log bool true - Enable file logging
logging.capture_console bool false - Capture browser console to logs
logging.capture_gtk_logs bool false - Capture GTK and WebKit logs for debugging.

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 "auto" 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)
engine.type string "cef" cef, webkit Browser engine. WebKit remains available as a fallback.
engine.cef.render_stack string "vulkan" vulkan, egl CEF GPU render stack
engine.cef.adaptive_windowless_frame_rate bool true - Enable adaptive CEF OSR FPS polling (only applies when windowless_frame_rate = 0)
engine.cef.windowless_frame_rate int32 0 >= 0 Explicit CEF OSR FPS cap; 0 uses adaptive mode if enabled, otherwise CEF default
engine.cef.windowless_frame_rate_max int32 240 >= 0 Hard cap for adaptive CEF OSR FPS; 0 falls back to the built-in default cap selected by Dumber/CEF
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

General

Key Type Default Description
workspace.new_pane_url string "about:blank" URL loaded for new panes/tabs (supports http(s)://, dumb://, file://, about:)
workspace.switch_to_tab_on_move bool true When moving a pane to another tab, automatically switch to the destination tab

Example:

[workspace]
new_pane_url = "dumb://history"

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"]
move-pane-to-tab = ["m"]
move-pane-to-next-tab = ["M", "shift+m"]

# Consume-or-expel (niri-style) - very alpha
consume-or-expel-left = ["["]
consume-or-expel-right = ["]"]
consume-or-expel-up = ["{"]
consume-or-expel-down = ["}"]

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.

Resize Mode

Key Type Default Description
workspace.resize_mode.activation_shortcut string "ctrl+n" Resize mode activation key
workspace.resize_mode.timeout_ms int 3000 Resize mode timeout (ms)
workspace.resize_mode.step_percent float 5.0 Split ratio step per keystroke (percent)
workspace.resize_mode.min_pane_percent float 10.0 Minimum pane size (percent)
workspace.resize_mode.actions map See below Action→keys mappings

Default resize mode actions:

[workspace.resize_mode.actions]
resize-increase-left = ["h", "arrowleft"]
resize-increase-down = ["j", "arrowdown"]
resize-increase-up = ["k", "arrowup"]
resize-increase-right = ["l", "arrowright"]
resize-decrease-left = ["H"]
resize-decrease-down = ["J"]
resize-decrease-up = ["K"]
resize-decrease-right = ["L"]
resize-increase = ["+", "="]
resize-decrease = ["-"]
confirm = ["enter"]
cancel = ["escape"]

Notes:

  • Directional actions (resize-increase-*/resize-decrease-*) move the split divider.
  • Smart actions (resize-increase / resize-decrease) grow/shrink the active pane (best-effort) by picking a direction automatically.
  • Timeout is refreshed on each resize keypress so you can keep adjusting without re-entering the mode.

Global Shortcuts

Global shortcuts are configured under workspace.shortcuts.actions using the same ActionBinding structure as modal keybindings:

Action Default Keys Description
toggle_floating_pane alt+f Toggle the workspace floating pane (persistent session)
close_pane ctrl+w Close active pane (or release floating pane when floating is active)
next_tab ctrl+tab Switch to next tab
previous_tab ctrl+shift+tab Switch to previous tab
consume_or_expel_left alt+[ Consume into left sibling stack, or expel left if stacked
consume_or_expel_right alt+] Consume into right sibling stack, or expel right if stacked
consume_or_expel_up alt+{ Consume into upper sibling stack, or expel up if stacked
consume_or_expel_down alt+} Consume into lower sibling stack, or expel down if stacked

Example:

[workspace.shortcuts.actions.close_pane]
  keys = ["ctrl+w"]
  desc = "Close active pane"

[workspace.shortcuts.actions.next_tab]
  keys = ["ctrl+tab", "alt+l"]
  desc = "Switch to next tab"

[workspace.shortcuts.actions.toggle_floating_pane]
  keys = ["alt+f"]
  desc = "Toggle floating pane"

Tip: Use dumb://config → Keybindings tab to edit shortcuts visually.

Note: New tab creation uses modal tab mode (Ctrl+T then n/c). This follows the Zellij-style modal keyboard interface.

Note: Consume-or-expel is experimental and may change behavior between releases.

Warning: Some Alt+<key> shortcuts may conflict with WebKit defaults, website handlers, or your desktop environment. If a binding does not fire, rebind it to a different key.

Floating Pane

The floating workspace pane is a persistent overlay session: hiding it does not destroy its web content.

  • Default behavior includes exactly one floating shortcut: Alt+F (toggle_floating_pane).
  • URL shortcuts (for example Alt+G) are user-defined via workspace.floating_pane.profiles and are empty by default.
  • Alt+F toggles visibility only and preserves floating state.
  • Ctrl+W on an active floating pane closes and releases that floating session for a fresh next open.
  • Floating profile keybindings support modifier combos with ctrl, shift, and alt (for example ctrl+shift+y or ctrl+alt+m).
Key Type Default Description
workspace.floating_pane.width_pct float 0.82 Floating pane width as fraction of workspace width ((0,1])
workspace.floating_pane.height_pct float 0.72 Floating pane height as fraction of workspace height ((0,1])
workspace.floating_pane.profiles map {} Named URL profiles, each with keys[], url, optional desc

Example:

[workspace.shortcuts.actions.toggle_floating_pane]
keys = ["alt+f"]
desc = "Toggle floating pane"

[workspace.floating_pane]
width_pct = 0.82
height_pct = 0.72

[workspace.floating_pane.profiles]
# Empty by default. Add as many entries as needed.

[workspace.floating_pane.profiles.google]
keys = ["alt+g"]
url = "https://google.com"
desc = "Open floating pane on Google"

[workspace.floating_pane.profiles.github]
keys = ["alt+h"]
url = "https://github.com"
desc = "Open floating pane on GitHub"

Browsing Context Behavior

Key Type Default Valid Values Description
workspace.browsing_contexts.behavior string "split" split, stacked, tabbed, windowed Placement mode for script-opened browsing contexts
workspace.browsing_contexts.placement string "right" right, left, top, bottom Split direction when behavior is split
workspace.browsing_contexts.open_in_new_pane bool true - Allow new browsing contexts to open in the workspace
workspace.browsing_contexts.follow_pane_context bool true - Keep new browsing contexts aligned with the parent pane context
workspace.browsing_contexts.blank_target_behavior string "stacked" split, stacked, tabbed Placement mode for _blank / new-page link contexts
workspace.browsing_contexts.enable_smart_detection bool true - Use window properties to refine browsing-context classification
workspace.browsing_contexts.oauth_auto_close bool true - Auto-close OAuth browsing contexts after success

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.mode_border_width int 4 Modal mode border width (px) - applies to all modes
workspace.styling.pane_mode_color string "#4A90E2" Pane mode color (blue) - used for border and toaster
workspace.styling.tab_mode_color string "#FFA500" Tab mode color (orange) - used for border and toaster
workspace.styling.session_mode_color string "#9B59B6" Session mode color (purple) - used for border and toaster
workspace.styling.resize_mode_color string "#00D4AA" Resize mode color (teal) - used for border and toaster
workspace.styling.mode_indicator_toaster_enabled bool true Show toaster notification when modal modes are active
workspace.styling.transition_duration int 120 Border transition duration (ms)

Example:

[workspace.styling]
border_width = 1
border_color = "@theme_selected_bg_color"
mode_border_width = 4
pane_mode_color = "#4A90E2"      # Blue for pane mode
tab_mode_color = "#FFA500"       # Orange for tab mode
session_mode_color = "#9B59B6"   # Purple for session mode
resize_mode_color = "#00D4AA"    # Teal for resize mode
mode_indicator_toaster_enabled = true
transition_duration = 120

Session

Key Type Default Description
session.auto_restore bool false Automatically restore the last session on startup
session.snapshot_interval_ms int 5000 Minimum interval between snapshots in milliseconds
session.max_exited_sessions int 50 Maximum number of exited sessions to keep
session.max_exited_session_age_days int 7 Maximum age in days for exited sessions (auto-deleted on startup)

Session Mode

Key Type Default Description
session.session_mode.activation_shortcut string "ctrl+o" Session mode activation key
session.session_mode.timeout_ms int 3000 Session mode timeout (ms)
session.session_mode.actions map See below Action to keys mappings

Default session mode actions:

[session.session_mode.actions]
session-manager = ["s", "w"]
confirm = ["enter"]
cancel = ["escape"]

Example:

[session]
auto_restore = false              # Don't auto-restore on startup
snapshot_interval_ms = 5000       # Save state every 5 seconds (debounced)
max_exited_sessions = 50          # Keep last 50 exited sessions
max_exited_session_age_days = 7   # Delete sessions older than 7 days on startup

Media

Key Type Default Valid Values Description
media.hardware_decoding string "auto" auto, force, disable Hardware video decoding mode
media.prefer_av1 bool false - Prefer AV1 codec when available
media.show_diagnostics bool false - 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)

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

Example:

[media]
hardware_decoding = "auto"    # HW preferred, SW fallback
prefer_av1 = false            # Let site choose codec
show_diagnostics = false      # Keep off for daily use
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

Diagnostic mode toggle path:

# ~/.config/dumber/config.toml
[media]
show_diagnostics = true
gstreamer_debug_level = 3

Set show_diagnostics = false and gstreamer_debug_level = 0 to return to normal mode.

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"

Clipboard

Key Type Default Description
clipboard.auto_copy_on_selection bool true Automatically copy selected text to clipboard (zellij/tmux-style)

When enabled, selecting text in a web page immediately copies it to the clipboard with a brief toast notification. Does not apply to text selection in input fields or textareas.

Example:

[clipboard]
auto_copy_on_selection = true  # Enabled by default

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.

Update

Key Type Default Description
update.enable_on_startup bool true Check for updates when browser starts
update.auto_download bool false Automatically download updates in background
update.notify_on_new_settings bool true Show toast notification when new config settings are available

Example:

[update]
enable_on_startup = true       # Check for updates on startup
auto_download = false          # Don't auto-download (prompt instead)
notify_on_new_settings = true  # Show toast when config migration available

CLI Commands:

# Check config status and available migrations
dumber config status

# Add missing settings with default values
dumber config migrate

# Skip confirmation prompt
dumber config migrate --yes

Performance Profiles

Performance profiles provide preset configurations for WebKitGTK tuning. These settings affect Skia rendering threads, memory pressure handling, and WebView pool behavior.

Note: Performance settings are applied at browser startup. Changes require a restart to take effect.

Key Type Default Valid Values Description
performance.profile string "default" default, lite, max, custom Performance profile selection

Profiles

Profile Description Use Case
default No tuning, uses WebKit defaults Compatibility baseline, troubleshooting
lite Reduced resource usage Low-RAM systems (< 4GB), battery saving
max Maximum responsiveness Heavy pages (GitHub PRs, complex SPAs), high-end systems
custom Manual control over all settings Advanced users who want fine-grained control

Profile Settings Matrix

Setting default lite max
Skia CPU threads unset 2 NumCPU()/2 (min 4)
Skia GPU threads unset unset scales with VRAM
Web process memory (MB) unset 768 unset
Network process memory (MB) unset 384 unset
Conservative threshold unset 0.25 unset
Strict threshold unset 0.4 unset
WebView pool prewarm 4 2 scales with RAM

Example:

[performance]
profile = "default"  # WebKit baseline default

# For WebKit baseline behavior:
# profile = "default"

# For heavy pages (GitHub PRs, complex web apps):
# profile = "max"

# For manual control:
# profile = "custom"

Custom Profile Settings

When profile = "custom", you can configure individual tuning options:

Key Type Default Description
performance.skia_cpu_painting_threads int 0 Skia CPU rendering threads (0=unset)
performance.skia_gpu_painting_threads int -1 Skia GPU rendering threads (-1=unset, 0=disable)
performance.skia_enable_cpu_rendering bool false Force CPU rendering
performance.web_process_memory_limit_mb int 0 Web process memory limit in MB (0=unset)
performance.web_process_memory_poll_interval_sec float 0 Memory check interval (0=WebKit default: 30s)
performance.web_process_memory_conservative_threshold float 0 Conservative cleanup threshold (0=unset)
performance.web_process_memory_strict_threshold float 0 Strict cleanup threshold (0=unset)
performance.network_process_memory_limit_mb int 0 Network process memory limit in MB
performance.network_process_memory_poll_interval_sec float 0 Network memory check interval
performance.network_process_memory_conservative_threshold float 0 Network conservative threshold
performance.network_process_memory_strict_threshold float 0 Network strict threshold
performance.webview_pool_prewarm_count int 4 WebViews to pre-create at startup
performance.zoom_cache_size int 256 Domain zoom levels to cache

Custom profile example:

[performance]
profile = "custom"

# Skia threading - tune for your CPU
skia_cpu_painting_threads = 4
skia_gpu_painting_threads = 2

# Web process memory pressure
web_process_memory_limit_mb = 1024
web_process_memory_conservative_threshold = 0.4
web_process_memory_strict_threshold = 0.6

# WebView pool
webview_pool_prewarm_count = 6

Important: Individual tuning fields are ignored unless profile = "custom". Setting individual fields with any other profile will produce a validation warning.

Downloads

Key Type Default Description
downloads.path string "" Download directory path (empty = $XDG_DOWNLOAD_DIR or ~/Downloads)

Downloads are saved to the configured directory with toast notifications for download started, completed, and failed events.

Example:

[downloads]
path = ""  # Use system default ($XDG_DOWNLOAD_DIR or ~/Downloads)

# Or specify a custom directory:
# path = "/home/user/my-downloads"

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)
# CEF defaults to the GPU-first Vulkan DMABUF stack.
# Use EGL/OpenGL for driver compatibility:
# DUMBER_ENGINE_CEF_RENDER_STACK=egl
DUMBER_RENDERING_MODE=cpu
# WebKit-specific rendering overrides:
# 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 Guide
2
3**Location**: `~/.config/dumber/config.toml`
4**Formats**: TOML (recommended), JSON, YAML
5
6## Database
7
8| Key | Type | Default | Description |
9|-----|------|---------|-------------|
10| `database.path` | string | `~/.local/share/dumber/dumber.db` | Database file path |
11
12## History
13
14| Key | Type | Default | Valid Values | Description |
15|-----|------|---------|--------------|-------------|
16| `history.max_entries` | int | `10000` | > 0 | Maximum number of history entries |
17| `history.retention_period_days` | int | `365` | > 0 | Days to keep history (1 year) |
18| `history.cleanup_interval_days` | int | `1` | > 0 | How often to run cleanup |
19
20## Search Configuration
21
22| Key | Type | Default | Description |
23|-----|------|---------|-------------|
24| `default_search_engine` | string | `"https://duckduckgo.com/?q=%s"` | Default search engine URL template (must contain `%s` placeholder) |
25| `search_shortcuts` | map | See defaults | Map of shortcut aliases to URLs |
26
27**Example:**
28```toml
29# Default search engine - used when no shortcut is specified
30default_search_engine = "https://duckduckgo.com/?q=%s"
31
32# Alternative search engines:
33# default_search_engine = "https://www.google.com/search?q=%s"
34# default_search_engine = "https://www.startpage.com/search?q=%s"
35# default_search_engine = "https://search.brave.com/search?q=%s"
36```
37
38**Default shortcuts (usage: `!shortcut query`):**
39```toml
40# Examples:
41#   !ddg golang      → DuckDuckGo search for "golang"
42#   !g rust tutorial → Google search for "rust tutorial"
43#   !gi cats         → Google Images search for "cats"
44#   !gh opencode     → GitHub search for "opencode"
45#   !yt music video  → YouTube search for "music video"
46
47[search_shortcuts.ddg]
48url = "https://duckduckgo.com/?q=%s"
49description = "DuckDuckGo search"
50
51[search_shortcuts.g]
52url = "https://google.com/search?q=%s"
53description = "Google Search"
54
55[search_shortcuts.gi]
56url = "https://google.com/search?tbm=isch&q=%s"
57description = "Google Images"
58
59[search_shortcuts.gh]
60url = "https://github.com/search?q=%s"
61description = "GitHub"
62
63[search_shortcuts.yt]
64url = "https://youtube.com/results?search_query=%s"
65description = "YouTube"
66```
67
68## Dmenu / Launcher
69
70These settings control the `dumber dmenu` CLI command for rofi/fuzzel integration.
71
72| Key | Type | Default | Description |
73|-----|------|---------|-------------|
74| `dmenu.max_history_days` | int | `30` | Number of days of history to show (0 = all) |
75| `dmenu.show_visit_count` | bool | `true` | Show visit counts in output |
76| `dmenu.show_last_visited` | bool | `true` | Show last visited dates in output |
77| `dmenu.history_prefix` | string | `"🕒"` | Prefix for history items |
78| `dmenu.shortcut_prefix` | string | `"🔍"` | Prefix for shortcuts |
79| `dmenu.url_prefix` | string | `"🌐"` | Prefix for URLs |
80| `dmenu.date_format` | string | `"2006-01-02 15:04"` | Go time format string |
81| `dmenu.sort_by_visit_count` | bool | `true` | Sort by visit count instead of recency |
82
83**CLI Usage:**
84```bash
85# Pipe mode (default) - outputs history for rofi/fuzzel with favicons
86dumber dmenu | rofi -dmenu -show-icons -p "Browse: " | dumber dmenu --select
87dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select
88
89# Interactive TUI mode
90dumber dmenu --interactive
91
92# Override history days via CLI flag (show last 7 days)
93dumber dmenu --days 7
94
95# Sort by most visited instead of recency
96dumber dmenu --most-visited
97
98# Combined: most visited from last 14 days
99dumber dmenu --days 14 --most-visited
100```
101
102## Omnibox
103
104| Key | Type | Default | Valid Values | Description |
105|-----|------|---------|--------------|-------------|
106| `omnibox.initial_behavior` | string | `"recent"` | `recent`, `most_visited`, `none` | Initial history display behavior |
107| `omnibox.most_visited_days` | int | `30` | `>= 0` | Days of history to consider when `initial_behavior = "most_visited"` (`0` = all history) |
108| `omnibox.auto_open_on_new_pane` | bool | `false` | - | Automatically open the omnibox after creating a new pane |
109
110**Example:**
111```toml
112[omnibox]
113initial_behavior = "recent"  # Show recent history when omnibox opens
114most_visited_days = 30        # Days of history used for most_visited
115auto_open_on_new_pane = false
116
117# Alternative options:
118# initial_behavior = "most_visited"  # Show most visited sites
119# initial_behavior = "none"          # Show no initial suggestions
120```
121
122## Logging
123
124| Key | Type | Default | Valid Values | Description |
125|-----|------|---------|--------------|-------------|
126| `logging.level` | string | `"info"` | `trace`, `debug`, `info`, `warn`, `error`, `fatal` | Log level |
127| `logging.format` | string | `"text"` | `text`, `json`, `console` | Log format |
128| `logging.max_age` | int | `7` | `>= 0` | Days to keep logs |
129| `logging.max_files` | int | `100` | `>= 0` | Session log files to keep (`0` disables count cleanup) |
130| `logging.log_dir` | string | `~/.local/state/dumber/logs` | any path | Log directory |
131| `logging.enable_file_log` | bool | `true` | - | Enable file logging |
132| `logging.capture_console` | bool | `false` | - | Capture browser console to logs |
133| `logging.capture_gtk_logs` | bool | `false` | - | Capture GTK and WebKit logs for debugging. |
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 | `"auto"` | `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| `engine.type` | string | `"cef"` | `cef`, `webkit` | Browser engine. WebKit remains available as a fallback. |
193| `engine.cef.render_stack` | string | `"vulkan"` | `vulkan`, `egl` | CEF GPU render stack |
194| `engine.cef.adaptive_windowless_frame_rate` | bool | `true` | - | Enable adaptive CEF OSR FPS polling (only applies when `windowless_frame_rate = 0`) |
195| `engine.cef.windowless_frame_rate` | int32 | `0` | >= 0 | Explicit CEF OSR FPS cap; 0 uses adaptive mode if enabled, otherwise CEF default |
196| `engine.cef.windowless_frame_rate_max` | int32 | `240` | >= 0 | Hard cap for adaptive CEF OSR FPS; 0 falls back to the built-in default cap selected by Dumber/CEF |
197| `default_ui_scale` | float | `1.0` | > 0 | GTK widget UI scale (1.0=100%, 2.0=200%) |
198| `default_webpage_zoom` | float | `1.2` | > 0 | Default page zoom (1.0=100%, 1.2=120%) |
199
200## Workspace Configuration
201
202### General
203
204| Key | Type | Default | Description |
205|-----|------|---------|-------------|
206| `workspace.new_pane_url` | string | `"about:blank"` | URL loaded for new panes/tabs (supports `http(s)://`, `dumb://`, `file://`, `about:`) |
207| `workspace.switch_to_tab_on_move` | bool | `true` | When moving a pane to another tab, automatically switch to the destination tab |
208
209**Example:**
210```toml
211[workspace]
212new_pane_url = "dumb://history"
213```
214
215### Pane Mode
216
217| Key | Type | Default | Description |
218|-----|------|---------|-------------|
219| `workspace.pane_mode.activation_shortcut` | string | `"ctrl+p"` | Pane mode activation key |
220| `workspace.pane_mode.timeout_ms` | int | `3000` | Pane mode timeout (ms) |
221| `workspace.pane_mode.actions` | map | See below | Action→keys mappings |
222
223**Default pane mode actions:**
224```toml
225[workspace.pane_mode.actions]
226split-right = ["arrowright", "r"]
227split-left = ["arrowleft", "l"]
228split-up = ["arrowup", "u"]
229split-down = ["arrowdown", "d"]
230stack-pane = ["s"]
231close-pane = ["x"]
232move-pane-to-tab = ["m"]
233move-pane-to-next-tab = ["M", "shift+m"]
234
235# Consume-or-expel (niri-style) - very alpha
236consume-or-expel-left = ["["]
237consume-or-expel-right = ["]"]
238consume-or-expel-up = ["{"]
239consume-or-expel-down = ["}"]
240
241focus-right = ["shift+arrowright", "shift+l"]
242focus-left = ["shift+arrowleft", "shift+h"]
243focus-up = ["shift+arrowup", "shift+k"]
244focus-down = ["shift+arrowdown", "shift+j"]
245confirm = ["enter"]
246cancel = ["escape"]
247```
248
249> **Note:** Actions are inverted to key→action map in memory for O(1) lookup performance during navigation.
250
251### Tab Mode
252
253| Key | Type | Default | Description |
254|-----|------|---------|-------------|
255| `workspace.tab_mode.activation_shortcut` | string | `"ctrl+t"` | Tab mode activation key |
256| `workspace.tab_mode.timeout_ms` | int | `3000` | Tab mode timeout (ms) |
257| `workspace.tab_mode.actions` | map | See below | Action→keys mappings |
258
259**Default tab mode actions:**
260```toml
261[workspace.tab_mode.actions]
262new-tab = ["n", "c"]
263close-tab = ["x"]
264next-tab = ["l", "tab"]
265previous-tab = ["h", "shift+tab"]
266rename-tab = ["r"]
267confirm = ["enter"]
268cancel = ["escape"]
269```
270
271> **Note:** Actions are inverted to key→action map in memory for O(1) lookup performance during navigation.
272
273### Resize Mode
274
275| Key | Type | Default | Description |
276|-----|------|---------|-------------|
277| `workspace.resize_mode.activation_shortcut` | string | `"ctrl+n"` | Resize mode activation key |
278| `workspace.resize_mode.timeout_ms` | int | `3000` | Resize mode timeout (ms) |
279| `workspace.resize_mode.step_percent` | float | `5.0` | Split ratio step per keystroke (percent) |
280| `workspace.resize_mode.min_pane_percent` | float | `10.0` | Minimum pane size (percent) |
281| `workspace.resize_mode.actions` | map | See below | Action→keys mappings |
282
283**Default resize mode actions:**
284```toml
285[workspace.resize_mode.actions]
286resize-increase-left = ["h", "arrowleft"]
287resize-increase-down = ["j", "arrowdown"]
288resize-increase-up = ["k", "arrowup"]
289resize-increase-right = ["l", "arrowright"]
290resize-decrease-left = ["H"]
291resize-decrease-down = ["J"]
292resize-decrease-up = ["K"]
293resize-decrease-right = ["L"]
294resize-increase = ["+", "="]
295resize-decrease = ["-"]
296confirm = ["enter"]
297cancel = ["escape"]
298```
299
300Notes:
301- Directional actions (`resize-increase-*/resize-decrease-*`) move the split divider.
302- Smart actions (`resize-increase` / `resize-decrease`) grow/shrink the active pane (best-effort) by picking a direction automatically.
303- Timeout is refreshed on each resize keypress so you can keep adjusting without re-entering the mode.
304
305### Global Shortcuts
306
307Global shortcuts are configured under `workspace.shortcuts.actions` using the same `ActionBinding` structure as modal keybindings:
308
309| Action | Default Keys | Description |
310|--------|--------------|-------------|
311| `toggle_floating_pane` | `alt+f` | Toggle the workspace floating pane (persistent session) |
312| `close_pane` | `ctrl+w` | Close active pane (or release floating pane when floating is active) |
313| `next_tab` | `ctrl+tab` | Switch to next tab |
314| `previous_tab` | `ctrl+shift+tab` | Switch to previous tab |
315| `consume_or_expel_left` | `alt+[` | Consume into left sibling stack, or expel left if stacked |
316| `consume_or_expel_right` | `alt+]` | Consume into right sibling stack, or expel right if stacked |
317| `consume_or_expel_up` | `alt+{` | Consume into upper sibling stack, or expel up if stacked |
318| `consume_or_expel_down` | `alt+}` | Consume into lower sibling stack, or expel down if stacked |
319
320**Example:**
321```toml
322[workspace.shortcuts.actions.close_pane]
323  keys = ["ctrl+w"]
324  desc = "Close active pane"
325
326[workspace.shortcuts.actions.next_tab]
327  keys = ["ctrl+tab", "alt+l"]
328  desc = "Switch to next tab"
329
330[workspace.shortcuts.actions.toggle_floating_pane]
331  keys = ["alt+f"]
332  desc = "Toggle floating pane"
333```
334
335> **Tip:** Use `dumb://config` → Keybindings tab to edit shortcuts visually.
336>
337> **Note:** New tab creation uses modal tab mode (Ctrl+T then n/c). This follows the Zellij-style modal keyboard interface.
338>
339> **Note:** Consume-or-expel is experimental and may change behavior between releases.
340>
341> **Warning:** Some `Alt+<key>` shortcuts may conflict with WebKit defaults, website handlers, or your desktop environment.
342> If a binding does not fire, rebind it to a different key.
343
344### Floating Pane
345
346The floating workspace pane is a persistent overlay session: hiding it does not destroy its web content.
347
348- Default behavior includes exactly one floating shortcut: `Alt+F` (`toggle_floating_pane`).
349- URL shortcuts (for example `Alt+G`) are user-defined via `workspace.floating_pane.profiles` and are empty by default.
350- `Alt+F` toggles visibility only and preserves floating state.
351- `Ctrl+W` on an active floating pane closes and releases that floating session for a fresh next open.
352- Floating profile keybindings support modifier combos with `ctrl`, `shift`, and `alt` (for example `ctrl+shift+y` or `ctrl+alt+m`).
353
354| Key | Type | Default | Description |
355|-----|------|---------|-------------|
356| `workspace.floating_pane.width_pct` | float | `0.82` | Floating pane width as fraction of workspace width (`(0,1]`) |
357| `workspace.floating_pane.height_pct` | float | `0.72` | Floating pane height as fraction of workspace height (`(0,1]`) |
358| `workspace.floating_pane.profiles` | map | `{}` | Named URL profiles, each with `keys[]`, `url`, optional `desc` |
359
360**Example:**
361
362```toml
363[workspace.shortcuts.actions.toggle_floating_pane]
364keys = ["alt+f"]
365desc = "Toggle floating pane"
366
367[workspace.floating_pane]
368width_pct = 0.82
369height_pct = 0.72
370
371[workspace.floating_pane.profiles]
372# Empty by default. Add as many entries as needed.
373
374[workspace.floating_pane.profiles.google]
375keys = ["alt+g"]
376url = "https://google.com"
377desc = "Open floating pane on Google"
378
379[workspace.floating_pane.profiles.github]
380keys = ["alt+h"]
381url = "https://github.com"
382desc = "Open floating pane on GitHub"
383```
384
385### Browsing Context Behavior
386
387| Key | Type | Default | Valid Values | Description |
388|-----|------|---------|--------------|-------------|
389| `workspace.browsing_contexts.behavior` | string | `"split"` | `split`, `stacked`, `tabbed`, `windowed` | Placement mode for script-opened browsing contexts |
390| `workspace.browsing_contexts.placement` | string | `"right"` | `right`, `left`, `top`, `bottom` | Split direction when behavior is `split` |
391| `workspace.browsing_contexts.open_in_new_pane` | bool | `true` | - | Allow new browsing contexts to open in the workspace |
392| `workspace.browsing_contexts.follow_pane_context` | bool | `true` | - | Keep new browsing contexts aligned with the parent pane context |
393| `workspace.browsing_contexts.blank_target_behavior` | string | `"stacked"` | `split`, `stacked`, `tabbed` | Placement mode for `_blank` / new-page link contexts |
394| `workspace.browsing_contexts.enable_smart_detection` | bool | `true` | - | Use window properties to refine browsing-context classification |
395| `workspace.browsing_contexts.oauth_auto_close` | bool | `true` | - | Auto-close OAuth browsing contexts after success |
396
397### Workspace Styling
398
399| Key | Type | Default | Description |
400|-----|------|---------|-------------|
401| `workspace.styling.border_width` | int | `1` | Active pane border width (px) - overlay |
402| `workspace.styling.border_color` | string | `"@theme_selected_bg_color"` | Active pane border color |
403| `workspace.styling.mode_border_width` | int | `4` | Modal mode border width (px) - applies to all modes |
404| `workspace.styling.pane_mode_color` | string | `"#4A90E2"` | Pane mode color (blue) - used for border and toaster |
405| `workspace.styling.tab_mode_color` | string | `"#FFA500"` | Tab mode color (orange) - used for border and toaster |
406| `workspace.styling.session_mode_color` | string | `"#9B59B6"` | Session mode color (purple) - used for border and toaster |
407| `workspace.styling.resize_mode_color` | string | `"#00D4AA"` | Resize mode color (teal) - used for border and toaster |
408| `workspace.styling.mode_indicator_toaster_enabled` | bool | `true` | Show toaster notification when modal modes are active |
409| `workspace.styling.transition_duration` | int | `120` | Border transition duration (ms) |
410
411**Example:**
412```toml
413[workspace.styling]
414border_width = 1
415border_color = "@theme_selected_bg_color"
416mode_border_width = 4
417pane_mode_color = "#4A90E2"      # Blue for pane mode
418tab_mode_color = "#FFA500"       # Orange for tab mode
419session_mode_color = "#9B59B6"   # Purple for session mode
420resize_mode_color = "#00D4AA"    # Teal for resize mode
421mode_indicator_toaster_enabled = true
422transition_duration = 120
423```
424
425## Session
426
427| Key | Type | Default | Description |
428|-----|------|---------|-------------|
429| `session.auto_restore` | bool | `false` | Automatically restore the last session on startup |
430| `session.snapshot_interval_ms` | int | `5000` | Minimum interval between snapshots in milliseconds |
431| `session.max_exited_sessions` | int | `50` | Maximum number of exited sessions to keep |
432| `session.max_exited_session_age_days` | int | `7` | Maximum age in days for exited sessions (auto-deleted on startup) |
433
434### Session Mode
435
436| Key | Type | Default | Description |
437|-----|------|---------|-------------|
438| `session.session_mode.activation_shortcut` | string | `"ctrl+o"` | Session mode activation key |
439| `session.session_mode.timeout_ms` | int | `3000` | Session mode timeout (ms) |
440| `session.session_mode.actions` | map | See below | Action to keys mappings |
441
442**Default session mode actions:**
443```toml
444[session.session_mode.actions]
445session-manager = ["s", "w"]
446confirm = ["enter"]
447cancel = ["escape"]
448```
449
450**Example:**
451```toml
452[session]
453auto_restore = false              # Don't auto-restore on startup
454snapshot_interval_ms = 5000       # Save state every 5 seconds (debounced)
455max_exited_sessions = 50          # Keep last 50 exited sessions
456max_exited_session_age_days = 7   # Delete sessions older than 7 days on startup
457```
458
459## Media
460
461| Key | Type | Default | Valid Values | Description |
462|-----|------|---------|--------------|-------------|
463| `media.hardware_decoding` | string | `"auto"` | `auto`, `force`, `disable` | Hardware video decoding mode |
464| `media.prefer_av1` | bool | `false` | - | Prefer AV1 codec when available |
465| `media.show_diagnostics` | bool | `false` | - | Show media diagnostics warnings at startup |
466| `media.force_vsync` | bool | `false` | - | Force VSync for video playback (may help with tearing) |
467| `media.gl_rendering_mode` | string | `"auto"` | `auto`, `gles2`, `gl3`, `none` | OpenGL API selection for video rendering |
468| `media.gstreamer_debug_level` | int | `0` | `0-5` | GStreamer debug verbosity (0=off) |
469
470**Hardware decoding modes:**
471- `auto` (recommended): Hardware preferred with software fallback - fixes Twitch Error #4000
472- `force`: Hardware only - fails if unavailable
473- `disable`: Software only - higher CPU usage
474
475**GL rendering modes:**
476- `auto` (default): Let GStreamer choose the best OpenGL API
477- `gles2`: Force GLES2 (better for some mobile/embedded GPUs)
478- `gl3`: Force OpenGL 3.x desktop
479- `none`: Disable GL-based rendering
480
481**GPU auto-detection:**
482Dumber automatically detects your GPU vendor (AMD/Intel/NVIDIA) and sets optimal VA-API driver settings:
483- **AMD**: Uses `radeonsi` driver
484- **Intel**: Uses `iHD` driver (modern, for Broadwell+)
485- **NVIDIA**: Uses `nvidia` driver with EGL platform
486
487**Example:**
488```toml
489[media]
490hardware_decoding = "auto"    # HW preferred, SW fallback
491prefer_av1 = false            # Let site choose codec
492show_diagnostics = false      # Keep off for daily use
493force_vsync = false           # Let compositor handle VSync
494gl_rendering_mode = "auto"    # GStreamer picks best GL API
495gstreamer_debug_level = 0     # Increase to 3-5 for debugging
496```
497
498**Diagnostic mode toggle path:**
499
500```toml
501# ~/.config/dumber/config.toml
502[media]
503show_diagnostics = true
504gstreamer_debug_level = 3
505```
506
507Set `show_diagnostics = false` and `gstreamer_debug_level = 0` to return to normal mode.
508
509**Diagnostics CLI:**
510```bash
511# Check GStreamer plugins and VA-API status
512dumber doctor --media
513```
514
515## Runtime
516
517| Key | Type | Default | Description |
518|-----|------|---------|-------------|
519| `runtime.prefix` | string | `""` | Optional runtime prefix (e.g., `/opt/webkitgtk`) used to locate newer GTK/WebKitGTK installs |
520
521If set, dumber prepends prefix-derived paths to:
522- `PKG_CONFIG_PATH` (for version checks)
523- `LD_LIBRARY_PATH` (for runtime library loading)
524- `GI_TYPELIB_PATH` (GObject introspection)
525- `XDG_DATA_DIRS` (schemas/resources)
526
527**Example:**
528```toml
529[runtime]
530prefix = "/opt/webkitgtk"
531```
532
533## Clipboard
534
535| Key | Type | Default | Description |
536|-----|------|---------|-------------|
537| `clipboard.auto_copy_on_selection` | bool | `true` | Automatically copy selected text to clipboard (zellij/tmux-style) |
538
539When enabled, selecting text in a web page immediately copies it to the clipboard with a brief toast notification. Does not apply to text selection in input fields or textareas.
540
541**Example:**
542```toml
543[clipboard]
544auto_copy_on_selection = true  # Enabled by default
545```
546
547## Content Filtering
548
549| Key | Type | Default | Description |
550|-----|------|---------|-------------|
551| `content_filtering.enabled` | bool | `true` | Enable ad blocking |
552| `content_filtering.auto_update` | bool | `true` | Automatically update filters |
553
554Notes:
555- Filter data is downloaded from `bnema/ublock-webkit-filters` GitHub releases.
556- Domain whitelist is managed via the database (`content_whitelist` table), not the config file.
557
558## Update
559
560| Key | Type | Default | Description |
561|-----|------|---------|-------------|
562| `update.enable_on_startup` | bool | `true` | Check for updates when browser starts |
563| `update.auto_download` | bool | `false` | Automatically download updates in background |
564| `update.notify_on_new_settings` | bool | `true` | Show toast notification when new config settings are available |
565
566**Example:**
567```toml
568[update]
569enable_on_startup = true       # Check for updates on startup
570auto_download = false          # Don't auto-download (prompt instead)
571notify_on_new_settings = true  # Show toast when config migration available
572```
573
574**CLI Commands:**
575```bash
576# Check config status and available migrations
577dumber config status
578
579# Add missing settings with default values
580dumber config migrate
581
582# Skip confirmation prompt
583dumber config migrate --yes
584```
585
586## Performance Profiles
587
588Performance profiles provide preset configurations for WebKitGTK tuning. These settings affect Skia rendering threads, memory pressure handling, and WebView pool behavior.
589
590> **Note:** Performance settings are applied at browser startup. Changes require a restart to take effect.
591
592| Key | Type | Default | Valid Values | Description |
593|-----|------|---------|--------------|-------------|
594| `performance.profile` | string | `"default"` | `default`, `lite`, `max`, `custom` | Performance profile selection |
595
596### Profiles
597
598| Profile | Description | Use Case |
599|---------|-------------|----------|
600| `default` | No tuning, uses WebKit defaults | Compatibility baseline, troubleshooting |
601| `lite` | Reduced resource usage | Low-RAM systems (< 4GB), battery saving |
602| `max` | Maximum responsiveness | Heavy pages (GitHub PRs, complex SPAs), high-end systems |
603| `custom` | Manual control over all settings | Advanced users who want fine-grained control |
604
605### Profile Settings Matrix
606
607| Setting | default | lite | max |
608|---------|---------|------|-----|
609| Skia CPU threads | unset | 2 | `NumCPU()/2` (min 4) |
610| Skia GPU threads | unset | unset | scales with VRAM |
611| Web process memory (MB) | unset | 768 | unset |
612| Network process memory (MB) | unset | 384 | unset |
613| Conservative threshold | unset | 0.25 | unset |
614| Strict threshold | unset | 0.4 | unset |
615| WebView pool prewarm | 4 | 2 | scales with RAM |
616
617**Example:**
618```toml
619[performance]
620profile = "default"  # WebKit baseline default
621
622# For WebKit baseline behavior:
623# profile = "default"
624
625# For heavy pages (GitHub PRs, complex web apps):
626# profile = "max"
627
628# For manual control:
629# profile = "custom"
630```
631
632### Custom Profile Settings
633
634When `profile = "custom"`, you can configure individual tuning options:
635
636| Key | Type | Default | Description |
637|-----|------|---------|-------------|
638| `performance.skia_cpu_painting_threads` | int | `0` | Skia CPU rendering threads (0=unset) |
639| `performance.skia_gpu_painting_threads` | int | `-1` | Skia GPU rendering threads (-1=unset, 0=disable) |
640| `performance.skia_enable_cpu_rendering` | bool | `false` | Force CPU rendering |
641| `performance.web_process_memory_limit_mb` | int | `0` | Web process memory limit in MB (0=unset) |
642| `performance.web_process_memory_poll_interval_sec` | float | `0` | Memory check interval (0=WebKit default: 30s) |
643| `performance.web_process_memory_conservative_threshold` | float | `0` | Conservative cleanup threshold (0=unset) |
644| `performance.web_process_memory_strict_threshold` | float | `0` | Strict cleanup threshold (0=unset) |
645| `performance.network_process_memory_limit_mb` | int | `0` | Network process memory limit in MB |
646| `performance.network_process_memory_poll_interval_sec` | float | `0` | Network memory check interval |
647| `performance.network_process_memory_conservative_threshold` | float | `0` | Network conservative threshold |
648| `performance.network_process_memory_strict_threshold` | float | `0` | Network strict threshold |
649| `performance.webview_pool_prewarm_count` | int | `4` | WebViews to pre-create at startup |
650| `performance.zoom_cache_size` | int | `256` | Domain zoom levels to cache |
651
652**Custom profile example:**
653```toml
654[performance]
655profile = "custom"
656
657# Skia threading - tune for your CPU
658skia_cpu_painting_threads = 4
659skia_gpu_painting_threads = 2
660
661# Web process memory pressure
662web_process_memory_limit_mb = 1024
663web_process_memory_conservative_threshold = 0.4
664web_process_memory_strict_threshold = 0.6
665
666# WebView pool
667webview_pool_prewarm_count = 6
668```
669
670> **Important:** Individual tuning fields are ignored unless `profile = "custom"`. Setting individual fields with any other profile will produce a validation warning.
671
672## Downloads
673
674| Key | Type | Default | Description |
675|-----|------|---------|-------------|
676| `downloads.path` | string | `""` | Download directory path (empty = `$XDG_DOWNLOAD_DIR` or `~/Downloads`) |
677
678Downloads are saved to the configured directory with toast notifications for download started, completed, and failed events.
679
680**Example:**
681```toml
682[downloads]
683path = ""  # Use system default ($XDG_DOWNLOAD_DIR or ~/Downloads)
684
685# Or specify a custom directory:
686# path = "/home/user/my-downloads"
687```
688
689## Environment Variables
690
691All config values can be overridden via environment variables with the prefix `DUMBER_`:
692
693```bash
694# Database
695DUMBER_DATABASE_PATH=/custom/path/db.sqlite
696
697# Rendering (examples)
698# CEF defaults to the GPU-first Vulkan DMABUF stack.
699# Use EGL/OpenGL for driver compatibility:
700# DUMBER_ENGINE_CEF_RENDER_STACK=egl
701DUMBER_RENDERING_MODE=cpu
702# WebKit-specific rendering overrides:
703# DUMBER_RENDERING_DISABLE_DMABUF_RENDERER=true
704# DUMBER_RENDERING_GSK_RENDERER=opengl
705DUMBER_DEFAULT_WEBPAGE_ZOOM=1.5
706
707# Logging
708DUMBER_LOG_LEVEL=debug
709DUMBER_LOG_FORMAT=json
710```

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close