v0.6.0 5c50dd3

README.md RawHistoryFolder

Dumber, fully unfeatured unbloated browser for tiling WMs

Dumber is a minimalist browser and launcher companion focused on speed and simplicity. It ships a built‑in WebKitGTK (GTK4) window for navigation and a CLI with dmenu‑style launcher integration (rofi, fuzzel).

  • Native GUI via WebKitGTK 6 (GTK4, 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..) it's a tiny companion that interact nicely with your launcher.
  • Uses a native WebKitGTKdo i 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)
  • Hardware video acceleration with automatic GPU detection (VA-API/VDPAU)
  • Custom dumb:// scheme serving embedded frontend assets
  • Keyboard and mouse controls: comprehensive shortcuts and gestures
  • Persistent history with search and stats
  • Per‑domain zoom persistence
  • dmenu‑style launcher integration (rofi, fuzzel) with history and shortcut suggestions

Controls & Shortcuts

Keyboard Shortcuts

Shortcut Action Notes
F12 Open Developer Tools WebKit inspector
Ctrl/Cmd+L Open Omnibox URL/search input with history
Ctrl/Cmd+F Find in Page Search text within current page
Ctrl/Cmd+= Zoom In Firefox-compatible zoom levels
Ctrl/Cmd++ Zoom In Alternative plus key
Ctrl/Cmd+- Zoom Out Works across keyboard layouts
Ctrl/Cmd+0 Reset Zoom Return to 100% zoom
Ctrl/Cmd+Shift+C Copy URL Copy current URL to clipboard with toast
Ctrl/Cmd+R Reload Page Refresh current page
Ctrl/Cmd+Shift+R Hard Reload Refresh ignoring cache
F5 Reload Page Alternative reload key
Alt+← Navigate Back Go to previous page
Alt+→ Navigate Forward Go to next page

Mouse Controls

Action Result Notes
Ctrl+Scroll Up Zoom In Smooth zoom control
Ctrl+Scroll Down Zoom Out Smooth zoom control
Mouse Button 8 Navigate Back Side button (back)
Mouse Button 9 Navigate Forward Side button (forward)
Two-finger Swipe Back/Forward When supported by touchpad

Omnibox/Find Mode (when active)

Shortcut Action Notes
Escape Close overlay Exit omnibox or find mode
Enter Execute/Navigate Navigate to URL or jump to match
Shift+Enter Previous Match Find mode: go to previous match
Alt+Enter Center Match Find mode: center on match, keep open
↑/↓ Arrow Navigate Results Browse suggestions/matches

All zoom changes are automatically persisted per-domain and restored on next visit.

Quick Start

Prerequisites:

  • Go 1.25+
  • Node.js 20+ and npm (for building the embedded TypeScript frontend)
  • For GUI build: WebKitGTK 6 and GTK4 dev packages (examples)
    • Debian/Ubuntu: libwebkitgtk-6.0-dev libgtk-4-dev build-essential
    • Arch: webkitgtk-6.0 gtk4 base-devel

Build options:

  • GUI (default, recommended):
    • make build # builds frontend + Go with -tags=webkit_cgo
    • Run: ./dist/dumber # opens the embedded homepage
  • CLI‑only (no GUI, CGO disabled):
    • make build-no-gui
    • Run: ./dist/dumber-no-gui version

Development:

  • make dev runs go run . (non‑CGO; GUI stubs log to console)
  • make test runs tests; make lint runs golangci‑lint

Install

Note: go install will not work for this project because the frontend assets must be built first and embedded into the binary. Use the build commands instead:

  • GUI build (default, recommended):
    • Ensure WebKit2GTK/GTK dev packages are installed (see prerequisites)
    • Clone the repo and run make build (builds frontend first, then Go with GUI support)
    • The resulting ./dist/dumber binary includes the native GUI window
  • CLI‑only (no native window):
    • Clone the repo and run make build-no-gui
    • The resulting ./dist/dumber-no-gui binary runs CLI flows with GUI code stubbed

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
  • Clean up data and cache:
    • dumber purge # purge all data (with confirmation)
    • dumber purge --force # purge all data (no confirmation)
    • dumber purge -d -H -c # purge database and both caches
    • dumber purge --browser-data # purge WebKit data (cookies, etc.)
  • Manage logs:
    • dumber logs list # list available log files
    • dumber logs tail # tail current log file
    • dumber logs clean # clean up old log files

Dmenu mode invocation

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. Config changes are watched and applied at runtime when possible.

Complete Configuration Reference

Database Configuration

"database": {
  "path": "~/.local/state/dumber/history.db",
  "max_connections": 1,
  "max_idle_time": "5m0s",
  "query_timeout": "30s"
}

History Management

"history": {
  "max_entries": 10000,
  "retention_period_days": 365,
  "cleanup_interval_days": 1
}

Search Shortcuts

"search_shortcuts": {
  "g":   { "url": "https://www.google.com/search?q=%s", "description": "Google search" },
  "gh":  { "url": "https://github.com/search?q=%s", "description": "GitHub search" },
  "yt":  { "url": "https://www.youtube.com/results?search_query=%s", "description": "YouTube search" },
  "w":   { "url": "https://en.wikipedia.org/wiki/%s", "description": "Wikipedia search" },
  "ddg": { "url": "https://duckduckgo.com/?q=%s", "description": "DuckDuckGo search" },
  "so":  { "url": "https://stackoverflow.com/search?q=%s", "description": "Stack Overflow search" },
  "r":   { "url": "https://www.reddit.com/search?q=%s", "description": "Reddit search" },
  "npm": { "url": "https://www.npmjs.com/search?q=%s", "description": "npm package search" },
  "go":  { "url": "https://pkg.go.dev/search?q=%s", "description": "Go package search" },
  "mdn": { "url": "https://developer.mozilla.org/en-US/search?q=%s", "description": "MDN Web Docs search" }
}

Dmenu Integration

"dmenu": {
  "max_history_items": 20,
  "show_visit_count": true,
  "show_last_visited": true,
  "history_prefix": "🕒",
  "shortcut_prefix": "🔍",
  "url_prefix": "🌐",
  "date_format": "2006-01-02 15:04",
  "sort_by_visit_count": true
}

Logging Configuration

"logging": {
  "level": "info",
  "format": "text",
  "filename": "",
  "max_size": 100,
  "max_backups": 3,
  "max_age": 7,
  "compress": true
}

Appearance Settings

"appearance": {
  "sans_font": "Fira Sans",
  "serif_font": "Fira Sans", 
  "monospace_font": "Fira Code",
  "default_font_size": 16
}

Rendering Mode (GPU/CPU)

"rendering_mode": "auto"
  • auto: Detect GPU availability and use GPU when available (default)
  • gpu: Force GPU acceleration (Vulkan/OpenGL via GTK4)
  • cpu: Force software rendering

Environment Variables

All config values can be overridden with environment variables using the DUMB_BROWSER_ prefix:

# Database
DUMB_BROWSER_DATABASE_PATH="./browser.db"
DUMB_BROWSER_DATABASE_MAX_CONNECTIONS=5

# Rendering mode (special variable name)
DUMBER_RENDERING_MODE="gpu"

# Dmenu settings
DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50
DUMB_BROWSER_DMENU_SHOW_VISIT_COUNT=false

# Logging
DUMB_BROWSER_LOGGING_LEVEL="debug"
DUMB_BROWSER_LOGGING_FORMAT="json"

CLI Flags

The browse command supports additional runtime flags:

dumber browse --rendering-mode=gpu https://example.com

Building With WebKitGTK 6 (GTK4)

  • The GUI requires building with -tags=webkit_cgo and CGO enabled.
  • Ensure WebKitGTK 6 and GTK4 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.

Media (GStreamer) & Hardware Acceleration

WebKitGTK uses GStreamer for media playback. Dumber includes automatic hardware video acceleration support that detects your GPU and configures the appropriate drivers.

Hardware Acceleration Features:

  • Automatic GPU detection (AMD, NVIDIA, Intel)
  • VA-API and VDPAU driver configuration
  • Support for H.264, HEVC, VP9, and AV1 codecs
  • Significantly reduced CPU usage during video streaming

Required packages:

  • Arch Linux:
    • sudo pacman -S gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-plugin-pipewire pipewire pipewire-pulse
    • Hardware accel: gstreamer-vaapi libva-mesa-driver (AMD), libva-vdpau-driver (NVIDIA), intel-media-driver (Intel)
  • Debian/Ubuntu:
    • sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-pipewire
    • Hardware accel: gstreamer1.0-vaapi va-driver-all (covers most GPUs)

Theme and Runtime Updates

  • The homepage and pages respect your system’s light/dark preference.
  • The app updates color‑scheme live when your GTK theme changes (no relaunch needed).

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

  • ✅ WebKitGTK 6 (GTK4) migration (GPU/Vulkan path complete)
  • ✅ GPU rendering (Vulkan via GTK4 renderer) with graceful CPU fallback
  • 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, fully unfeatured unbloated browser for tiling WMs
2
3<p align="center">
4  <img src="assets/logo.svg" alt="Dumber Logo" width="256" height="256" />
5</p>
6
7Dumber is a minimalist browser and launcher companion focused on speed and simplicity. It ships a built‑in WebKitGTK (GTK4) window for navigation and a CLI with dmenu‑style launcher integration (rofi, fuzzel).
8
9- Native GUI via WebKitGTK 6 (GTK4, CGO) with an embedded homepage UI.
10- CLI that parses URLs, supports search shortcuts (e.g., `g:query`), and integrates with rofi/dmenu.
11- Persistent history and per‑domain zoom levels (SQLite, XDG locations).
12- Configurable via `config.json` and environment variables, with live reload.
13
14## Wayland‑First
15- Dumb on purpose, designed for Wayland window managers (Sway, Hyprland, River, Niri, etc..) it's a tiny companion that interact nicely with your launcher.
16- Uses a native WebKitGTKdo i window; no external browser required and no X11/XWayland dependency.
17- Optimized for dmenu‑style launchers (rofi, fuzzel, wofi) and keyboard‑driven workflows.
18
19## Status
20- Very early stage, expect sharp edges and breaking changes, but it works well enough to browse and play with the launcher flows.
21
22## Features
23- Built‑in browser window (no external browser needed)
24- Hardware video acceleration with automatic GPU detection (VA-API/VDPAU)
25- Custom `dumb://` scheme serving embedded frontend assets
26- Keyboard and mouse controls: comprehensive shortcuts and gestures
27- Persistent history with search and stats
28- Per‑domain zoom persistence
29- dmenu‑style launcher integration (rofi, fuzzel) with history and shortcut suggestions
30
31## Controls & Shortcuts
32
33### Keyboard Shortcuts
34| Shortcut | Action | Notes |
35|----------|--------|-------|
36| **F12** | Open Developer Tools | WebKit inspector |
37| **Ctrl/Cmd+L** | Open Omnibox | URL/search input with history |
38| **Ctrl/Cmd+F** | Find in Page | Search text within current page |
39| **Ctrl/Cmd+=** | Zoom In | Firefox-compatible zoom levels |
40| **Ctrl/Cmd++** | Zoom In | Alternative plus key |
41| **Ctrl/Cmd+-** | Zoom Out | Works across keyboard layouts |
42| **Ctrl/Cmd+0** | Reset Zoom | Return to 100% zoom |
43| **Ctrl/Cmd+Shift+C** | Copy URL | Copy current URL to clipboard with toast |
44| **Ctrl/Cmd+R** | Reload Page | Refresh current page |
45| **Ctrl/Cmd+Shift+R** | Hard Reload | Refresh ignoring cache |
46| **F5** | Reload Page | Alternative reload key |
47| **Alt+←** | Navigate Back | Go to previous page |
48| **Alt+→** | Navigate Forward | Go to next page |
49
50### Mouse Controls
51| Action | Result | Notes |
52|--------|---------|-------|
53| **Ctrl+Scroll Up** | Zoom In | Smooth zoom control |
54| **Ctrl+Scroll Down** | Zoom Out | Smooth zoom control |
55| **Mouse Button 8** | Navigate Back | Side button (back) |
56| **Mouse Button 9** | Navigate Forward | Side button (forward) |
57| **Two-finger Swipe** | Back/Forward | When supported by touchpad |
58
59### Omnibox/Find Mode (when active)
60| Shortcut | Action | Notes |
61|----------|--------|-------|
62| **Escape** | Close overlay | Exit omnibox or find mode |
63| **Enter** | Execute/Navigate | Navigate to URL or jump to match |
64| **Shift+Enter** | Previous Match | Find mode: go to previous match |
65| **Alt+Enter** | Center Match | Find mode: center on match, keep open |
66| **↑/↓ Arrow** | Navigate Results | Browse suggestions/matches |
67
68All zoom changes are automatically persisted per-domain and restored on next visit.
69
70## Quick Start
71Prerequisites:
72- Go 1.25+
73- Node.js 20+ and npm (for building the embedded TypeScript frontend)
74- For GUI build: WebKitGTK 6 and GTK4 dev packages (examples)
75  - Debian/Ubuntu: `libwebkitgtk-6.0-dev libgtk-4-dev build-essential`
76  - Arch: `webkitgtk-6.0 gtk4 base-devel`
77
78Build options:
79- GUI (default, recommended):
80  - `make build`          # builds frontend + Go with `-tags=webkit_cgo`
81  - Run: `./dist/dumber`  # opens the embedded homepage
82- CLI‑only (no GUI, CGO disabled):
83  - `make build-no-gui`
84  - Run: `./dist/dumber-no-gui version`
85
86Development:
87- `make dev` runs `go run .` (non‑CGO; GUI stubs log to console)
88- `make test` runs tests; `make lint` runs golangci‑lint
89
90## Install
91**Note**: `go install` will not work for this project because the frontend assets must be built first and embedded into the binary. Use the build commands instead:
92
93- GUI build (default, recommended):
94  - Ensure WebKit2GTK/GTK dev packages are installed (see prerequisites)
95  - Clone the repo and run `make build` (builds frontend first, then Go with GUI support)
96  - The resulting `./dist/dumber` binary includes the native GUI window
97- CLI‑only (no native window):
98  - Clone the repo and run `make build-no-gui`
99  - The resulting `./dist/dumber-no-gui` binary runs CLI flows with GUI code stubbed
100
101## Usage
102- Open a URL or search:
103  - `dumber browse https://example.com`
104  - `dumber browse example.com`        # scheme auto‑added
105  - `dumber browse g:golang`           # Google search via shortcut
106- Launch the GUI directly:
107  - `dumber`                           # no args → opens GUI homepage
108- Launcher integration (dmenu‑style examples):
109  - rofi:   `dumber dmenu | rofi -dmenu -p "Browse: " | dumber dmenu --select`
110  - fuzzel: `dumber dmenu | fuzzel --dmenu -p "Browse: " | dumber dmenu --select`
111- Clean up data and cache:
112  - `dumber purge`                        # purge all data (with confirmation)
113  - `dumber purge --force`                # purge all data (no confirmation)
114  - `dumber purge -d -H -c`               # purge database and both caches
115  - `dumber purge --browser-data`         # purge WebKit data (cookies, etc.)
116- Manage logs:
117  - `dumber logs list`                    # list available log files
118  - `dumber logs tail`                    # tail current log file
119  - `dumber logs clean`                   # clean up old log files
120
121### Dmenu mode invocation
122You can invoke dmenu mode in two ways:
123- Subcommand (recommended): `dumber dmenu` … and `dumber dmenu --select`
124- Root flag (generate options only): `dumber --dmenu`
125
126Note: The root flag path only generates options; for processing a selection (`--select`), use the `dmenu` subcommand as the receiving command.
127
128In GUI mode the app serves an embedded homepage via `dumb://homepage`, and frontend assets under `dumb://app/...`.
129
130## Configuration
131
132Dumber follows the XDG Base Directory spec:
133- Config: `~/.config/dumber/config.json`
134- Data:   `~/.local/share/dumber`
135- State:  `~/.local/state/dumber` (default DB lives here)
136
137A default `config.json` is created on first run. Config changes are watched and applied at runtime when possible.
138
139### Complete Configuration Reference
140
141#### Database Configuration
142```json
143"database": {
144  "path": "~/.local/state/dumber/history.db",
145  "max_connections": 1,
146  "max_idle_time": "5m0s",
147  "query_timeout": "30s"
148}
149```
150
151#### History Management
152```json
153"history": {
154  "max_entries": 10000,
155  "retention_period_days": 365,
156  "cleanup_interval_days": 1
157}
158```
159
160#### Search Shortcuts
161```json
162"search_shortcuts": {
163  "g":   { "url": "https://www.google.com/search?q=%s", "description": "Google search" },
164  "gh":  { "url": "https://github.com/search?q=%s", "description": "GitHub search" },
165  "yt":  { "url": "https://www.youtube.com/results?search_query=%s", "description": "YouTube search" },
166  "w":   { "url": "https://en.wikipedia.org/wiki/%s", "description": "Wikipedia search" },
167  "ddg": { "url": "https://duckduckgo.com/?q=%s", "description": "DuckDuckGo search" },
168  "so":  { "url": "https://stackoverflow.com/search?q=%s", "description": "Stack Overflow search" },
169  "r":   { "url": "https://www.reddit.com/search?q=%s", "description": "Reddit search" },
170  "npm": { "url": "https://www.npmjs.com/search?q=%s", "description": "npm package search" },
171  "go":  { "url": "https://pkg.go.dev/search?q=%s", "description": "Go package search" },
172  "mdn": { "url": "https://developer.mozilla.org/en-US/search?q=%s", "description": "MDN Web Docs search" }
173}
174```
175
176#### Dmenu Integration
177```json
178"dmenu": {
179  "max_history_items": 20,
180  "show_visit_count": true,
181  "show_last_visited": true,
182  "history_prefix": "🕒",
183  "shortcut_prefix": "🔍",
184  "url_prefix": "🌐",
185  "date_format": "2006-01-02 15:04",
186  "sort_by_visit_count": true
187}
188```
189
190#### Logging Configuration
191```json
192"logging": {
193  "level": "info",
194  "format": "text",
195  "filename": "",
196  "max_size": 100,
197  "max_backups": 3,
198  "max_age": 7,
199  "compress": true
200}
201```
202
203#### Appearance Settings
204```json
205"appearance": {
206  "sans_font": "Fira Sans",
207  "serif_font": "Fira Sans", 
208  "monospace_font": "Fira Code",
209  "default_font_size": 16
210}
211```
212
213#### Rendering Mode (GPU/CPU)
214```json
215"rendering_mode": "auto"
216```
217- `auto`: Detect GPU availability and use GPU when available (default)
218- `gpu`: Force GPU acceleration (Vulkan/OpenGL via GTK4)
219- `cpu`: Force software rendering
220
221### Environment Variables
222All config values can be overridden with environment variables using the `DUMB_BROWSER_` prefix:
223
224```bash
225# Database
226DUMB_BROWSER_DATABASE_PATH="./browser.db"
227DUMB_BROWSER_DATABASE_MAX_CONNECTIONS=5
228
229# Rendering mode (special variable name)
230DUMBER_RENDERING_MODE="gpu"
231
232# Dmenu settings
233DUMB_BROWSER_DMENU_MAX_HISTORY_ITEMS=50
234DUMB_BROWSER_DMENU_SHOW_VISIT_COUNT=false
235
236# Logging
237DUMB_BROWSER_LOGGING_LEVEL="debug"
238DUMB_BROWSER_LOGGING_FORMAT="json"
239```
240
241### CLI Flags
242The browse command supports additional runtime flags:
243```bash
244dumber browse --rendering-mode=gpu https://example.com
245```
246
247
248## Building With WebKitGTK 6 (GTK4)
249- The GUI requires building with `-tags=webkit_cgo` and CGO enabled.
250- Ensure WebKitGTK 6 and GTK4 dev headers are installed (see prerequisites).
251- Make targets handle both frontend and Go build steps:
252  - `make build-gui` (CGO enabled)
253  - `make build` (CGO enabled by default in the Makefile’s main build)
254
255Without the native tag, a stub backend is used: you can still run CLI flows and see logs, but no native window is displayed.
256
257## Media (GStreamer) & Hardware Acceleration
258
259WebKitGTK uses GStreamer for media playback. Dumber includes automatic hardware video acceleration support that detects your GPU and configures the appropriate drivers.
260
261**Hardware Acceleration Features:**
262- Automatic GPU detection (AMD, NVIDIA, Intel)
263- VA-API and VDPAU driver configuration
264- Support for H.264, HEVC, VP9, and AV1 codecs
265- Significantly reduced CPU usage during video streaming
266
267**Required packages:**
268- Arch Linux:
269  - `sudo pacman -S gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav gst-plugin-pipewire pipewire pipewire-pulse`
270  - Hardware accel: `gstreamer-vaapi libva-mesa-driver` (AMD), `libva-vdpau-driver` (NVIDIA), `intel-media-driver` (Intel)
271- Debian/Ubuntu:
272  - `sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-pipewire`
273  - Hardware accel: `gstreamer1.0-vaapi va-driver-all` (covers most GPUs)
274
275## Theme and Runtime Updates
276- The homepage and pages respect your system’s light/dark preference.
277- The app updates color‑scheme live when your GTK theme changes (no relaunch needed).
278
279## Project Structure
280- `main.go`: CLI/GUI entrypoint, `dumb://` scheme, service wiring
281- `internal/cli`: Cobra commands (`browse`, `dmenu`, `version`)
282- `internal/config`: Viper‑backed config, XDG helpers, defaults
283- `internal/db`: SQLite schema init and sqlc‑generated queries
284- `services`: app services (parser/history/config/browser)
285- `pkg/webkit`: WebKit2GTK bindings (CGO and stub implementations)
286- `frontend`: TypeScript homepage UI bundled into the binary
287
288## Security & Privacy
289- History and zoom settings are stored locally in SQLite under XDG state.
290- The `tmp/` directory is ignored by Git and kept out of history.
291
292## Roadmap
293- ✅ WebKitGTK 6 (GTK4) migration (GPU/Vulkan path complete)
294- ✅ GPU rendering (Vulkan via GTK4 renderer) with graceful CPU fallback
295- Full Vim-style motion and keyboard navigation across pages and UI
296- Performance work: faster startup, lower memory, snappier UI
297- Basic ad-block extension — because fuck ads
298- Other shiny things I'm not yet aware of
299
300## License
301This project is licensed under the MIT License. See `LICENSE` for details.

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