Dumber — a tiny, dumb browser for Wayland
Dumber is a minimalist browser and launcher companion focused on speed and simplicity. It ships a built‑in WebKit2GTK window for navigation and a CLI with dmenu‑style launcher integration (rofi, fuzzel).
- Native GUI via WebKit2GTK (CGO) with an embedded homepage UI.
- CLI that parses URLs, supports search shortcuts (e.g.,
g:query), and integrates with rofi/dmenu.
- Persistent history and per‑domain zoom levels (SQLite, XDG locations).
- Configurable via
config.json and environment variables, with live reload.
Wayland‑First
- Dumb on purpose, designed for Wayland window managers (Sway, Hyprland, River, Niri, etc..) — a tiny companion that plays nicely with your launcher.
- Uses a native WebKit2GTK window; no external browser required and no X11/XWayland dependency.
- Optimized for dmenu‑style launchers (rofi, fuzzel, wofi) and keyboard‑driven workflows.
Status
- Very early stage — expect sharp edges and breaking changes, but it works well enough to browse and play with the launcher flows.
Features
- Built‑in browser window (no external browser needed)
- Custom
dumb:// scheme serving embedded frontend assets
- Keyboard shortcuts: DevTools (F12), Omnibox toggle (Ctrl/Cmd+L), Zoom In/Out/Reset
- Persistent history with search and stats
- Per‑domain zoom persistence
- dmenu‑style launcher integration (rofi, fuzzel) with history and shortcut suggestions
Quick Start
Prerequisites:
- Go 1.25+
- Node.js 20+ (for building the embedded frontend)
- For GUI build: WebKit2GTK and GTK dev packages (examples)
- Debian/Ubuntu:
libwebkit2gtk-4.1-dev libgtk-3-dev build-essential
- Arch:
webkit2gtk gtk3 base-devel
Build options:
- GUI (recommended):
make build-gui # builds with -tags=webkit_cgo
- Run:
./dist/dumber # opens the embedded homepage
- CLI‑only (no GUI, CGO disabled):
make build-static
- Run:
./dist/dumber-static version
- Full build pipeline (frontend + Go):
Development:
make dev runs go run . (non‑CGO; GUI stubs log to console)
make test runs tests; make lint runs golangci‑lint
Install
- CLI‑only (no native window):
go install github.com/bnema/dumber@latest
- Useful everywhere; runs the CLI and non‑CGO flows. In this mode the GUI code is stubbed (no native window shown).
- GUI build (Wayland + WebKit2GTK via CGO):
- Ensure WebKit2GTK/GTK dev packages are installed (see prerequisites) and CGO is enabled in your environment.
go install -tags webkit_cgo github.com/bnema/dumber@latest
- If pkg‑config can’t find headers, set
PKG_CONFIG_PATH appropriately or prefer make build-gui.
Usage
- Open a URL or search:
dumber browse https://example.com
dumber browse example.com # scheme auto‑added
dumber browse g:golang # Google search via shortcut
- Launch the GUI directly:
dumber # no args → opens GUI homepage
- Launcher integration (dmenu‑style examples):
- rofi:
dumber dmenu | rofi -dmenu -p "Browse: " | dumber dmenu --select
- fuzzel:
dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select
You can invoke dmenu mode in two ways:
- Subcommand (recommended):
dumber dmenu … and dumber dmenu --select
- Root flag (generate options only):
dumber --dmenu
Note: The root flag path only generates options; for processing a selection (--select), use the dmenu subcommand as the receiving command.
In GUI mode the app serves an embedded homepage via dumb://homepage, and frontend assets under dumb://app/....
Configuration
Dumber follows the XDG Base Directory spec:
- Config:
~/.config/dumber/config.json
- Data:
~/.local/share/dumber
- State:
~/.local/state/dumber (default DB lives here)
A default config.json is created on first run. Key fields:
database.path: SQLite database path (defaults to XDG state dir history.db)
search_shortcuts: map of search shortcuts, e.g.
{
"g": { "url": "https://www.google.com/search?q=%s", "description": "Google" },
"gh": { "url": "https://github.com/search?q=%s", "description": "GitHub" }
}
appearance: default fonts and base font size for pages without specified fonts
dmenu: options for launcher integration (history count, prefixes, etc.)
Environment variables use the DUMB_BROWSER_ prefix (managed by Viper). Examples:
DUMB_BROWSER_DATABASE_PATH=...
DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50
Config changes are watched and applied at runtime when possible.
Data Model
SQLite tables (created automatically):
history(id, url, title, visit_count, last_visited, created_at)
shortcuts(shortcut, url_template, description, created_at)
zoom_levels(domain PRIMARY KEY, zoom_factor, updated_at)
Building With WebKit2GTK
- The GUI requires building with
-tags=webkit_cgo and CGO enabled.
- Ensure WebKit2GTK and GTK dev headers are installed (see prerequisites).
- Make targets handle both frontend and Go build steps:
make build-gui (CGO enabled)
make build (CGO enabled by default in the Makefile’s main build)
Without the native tag, a stub backend is used: you can still run CLI flows and see logs, but no native window is displayed.
Project Structure
main.go: CLI/GUI entrypoint, dumb:// scheme, service wiring
internal/cli: Cobra commands (browse, dmenu, version)
internal/config: Viper‑backed config, XDG helpers, defaults
internal/db: SQLite schema init and sqlc‑generated queries
services: app services (parser/history/config/browser)
pkg/webkit: WebKit2GTK bindings (CGO and stub implementations)
frontend: TypeScript homepage UI bundled into the binary
Security & Privacy
- History and zoom settings are stored locally in SQLite under XDG state.
- The
tmp/ directory is ignored by Git and kept out of history.
Roadmap
- Full Vim-style motion and keyboard navigation across pages and UI.
- Performance work: faster startup, lower memory, snappier UI.
- Basic ad-block extension — because fuck ads.
- Other shiny things I’m not yet aware of.
License
This project is licensed under the MIT License. See LICENSE for details.
source
1# Dumber — a tiny, dumb browser for Wayland
2
3Dumber is a minimalist browser and launcher companion focused on speed and simplicity. It ships a built‑in WebKit2GTK window for navigation and a CLI with dmenu‑style launcher integration (rofi, fuzzel).
4
5- Native GUI via WebKit2GTK (CGO) with an embedded homepage UI.
6- CLI that parses URLs, supports search shortcuts (e.g., `g:query`), and integrates with rofi/dmenu.
7- Persistent history and per‑domain zoom levels (SQLite, XDG locations).
8- Configurable via `config.json` and environment variables, with live reload.
9
10## Wayland‑First
11- Dumb on purpose, designed for Wayland window managers (Sway, Hyprland, River, Niri, etc..) — a tiny companion that plays nicely with your launcher.
12- Uses a native WebKit2GTK window; no external browser required and no X11/XWayland dependency.
13- Optimized for dmenu‑style launchers (rofi, fuzzel, wofi) and keyboard‑driven workflows.
14
15## Status
16- Very early stage — expect sharp edges and breaking changes, but it works well enough to browse and play with the launcher flows.
17
18## Features
19- Built‑in browser window (no external browser needed)
20- Custom `dumb://` scheme serving embedded frontend assets
21- Keyboard shortcuts: DevTools (F12), Omnibox toggle (Ctrl/Cmd+L), Zoom In/Out/Reset
22- Persistent history with search and stats
23- Per‑domain zoom persistence
24- dmenu‑style launcher integration (rofi, fuzzel) with history and shortcut suggestions
25
26## Quick Start
27Prerequisites:
28- Go 1.25+
29- Node.js 20+ (for building the embedded frontend)
30- For GUI build: WebKit2GTK and GTK dev packages (examples)
31 - Debian/Ubuntu: `libwebkit2gtk-4.1-dev libgtk-3-dev build-essential`
32 - Arch: `webkit2gtk gtk3 base-devel`
33
34Build options:
35- GUI (recommended):
36 - `make build-gui` # builds with `-tags=webkit_cgo`
37 - Run: `./dist/dumber` # opens the embedded homepage
38- CLI‑only (no GUI, CGO disabled):
39 - `make build-static`
40 - Run: `./dist/dumber-static version`
41- Full build pipeline (frontend + Go):
42 - `make build`
43
44Development:
45- `make dev` runs `go run .` (non‑CGO; GUI stubs log to console)
46- `make test` runs tests; `make lint` runs golangci‑lint
47
48## Install
49- CLI‑only (no native window):
50 - `go install github.com/bnema/dumber@latest`
51 - Useful everywhere; runs the CLI and non‑CGO flows. In this mode the GUI code is stubbed (no native window shown).
52- GUI build (Wayland + WebKit2GTK via CGO):
53 - Ensure WebKit2GTK/GTK dev packages are installed (see prerequisites) and CGO is enabled in your environment.
54 - `go install -tags webkit_cgo github.com/bnema/dumber@latest`
55 - If pkg‑config can’t find headers, set `PKG_CONFIG_PATH` appropriately or prefer `make build-gui`.
56
57## Usage
58- Open a URL or search:
59 - `dumber browse https://example.com`
60 - `dumber browse example.com` # scheme auto‑added
61 - `dumber browse g:golang` # Google search via shortcut
62- Launch the GUI directly:
63 - `dumber` # no args → opens GUI homepage
64- Launcher integration (dmenu‑style examples):
65 - rofi: `dumber dmenu | rofi -dmenu -p "Browse: " | dumber dmenu --select`
66 - fuzzel: `dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select`
67
68### Dmenu mode invocation
69You can invoke dmenu mode in two ways:
70- Subcommand (recommended): `dumber dmenu` … and `dumber dmenu --select`
71- Root flag (generate options only): `dumber --dmenu`
72
73Note: The root flag path only generates options; for processing a selection (`--select`), use the `dmenu` subcommand as the receiving command.
74
75In GUI mode the app serves an embedded homepage via `dumb://homepage`, and frontend assets under `dumb://app/...`.
76
77## Configuration
78Dumber follows the XDG Base Directory spec:
79- Config: `~/.config/dumber/config.json`
80- Data: `~/.local/share/dumber`
81- State: `~/.local/state/dumber` (default DB lives here)
82
83A default `config.json` is created on first run. Key fields:
84- `database.path`: SQLite database path (defaults to XDG state dir `history.db`)
85- `search_shortcuts`: map of search shortcuts, e.g.
86 ```json
87 {
88 "g": { "url": "https://www.google.com/search?q=%s", "description": "Google" },
89 "gh": { "url": "https://github.com/search?q=%s", "description": "GitHub" }
90 }
91 ```
92- `appearance`: default fonts and base font size for pages without specified fonts
93- `dmenu`: options for launcher integration (history count, prefixes, etc.)
94
95Environment variables use the `DUMB_BROWSER_` prefix (managed by Viper). Examples:
96- `DUMB_BROWSER_DATABASE_PATH=...`
97- `DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50`
98
99Config changes are watched and applied at runtime when possible.
100
101## Data Model
102SQLite tables (created automatically):
103- `history(id, url, title, visit_count, last_visited, created_at)`
104- `shortcuts(shortcut, url_template, description, created_at)`
105- `zoom_levels(domain PRIMARY KEY, zoom_factor, updated_at)`
106
107## Building With WebKit2GTK
108- The GUI requires building with `-tags=webkit_cgo` and CGO enabled.
109- Ensure WebKit2GTK and GTK dev headers are installed (see prerequisites).
110- Make targets handle both frontend and Go build steps:
111 - `make build-gui` (CGO enabled)
112 - `make build` (CGO enabled by default in the Makefile’s main build)
113
114Without the native tag, a stub backend is used: you can still run CLI flows and see logs, but no native window is displayed.
115
116## Project Structure
117- `main.go`: CLI/GUI entrypoint, `dumb://` scheme, service wiring
118- `internal/cli`: Cobra commands (`browse`, `dmenu`, `version`)
119- `internal/config`: Viper‑backed config, XDG helpers, defaults
120- `internal/db`: SQLite schema init and sqlc‑generated queries
121- `services`: app services (parser/history/config/browser)
122- `pkg/webkit`: WebKit2GTK bindings (CGO and stub implementations)
123- `frontend`: TypeScript homepage UI bundled into the binary
124
125## Security & Privacy
126- History and zoom settings are stored locally in SQLite under XDG state.
127- The `tmp/` directory is ignored by Git and kept out of history.
128
129## Roadmap
130- Full Vim-style motion and keyboard navigation across pages and UI.
131- Performance work: faster startup, lower memory, snappier UI.
132- Basic ad-block extension — because fuck ads.
133- Other shiny things I’m not yet aware of.
134
135## License
136This project is licensed under the MIT License. See `LICENSE` for details.