hwatu
A daemon-based web browser for tiling window managers.
Real WebKit rendering, terminal-emulator spawn times.
curl -fsSL
https://raw.githubusercontent.com/hongnoul/hwatu/main/scripts/install.sh
| bash
GitHub · Releases · MIT · Linux
Why
Browsers conflate two things: the engine (slow to start, RAM-hungry)
and the window (what you actually ask for). hwatu splits them, the
same way emacsclient and wezterm do:
-
hwatudowns WebKitGTK 6, a prewarmed WebView pool, and all windows. -
hwatuis a thin client: one Unix-socket roundtrip to open a window.
Measured: 13 ms median (p90 35 ms) from
hwatu <url> to a mapped, loading window on a warm
daemon; background and headless opens land at 14–16 ms. The
first-ever window pays a one-time engine/GPU init. Full data:
docs/benchmarks.md.
Compared
If you want a minimal browser for a tiling WM (Hyprland, sway, i3, river), the usual suspects trade differently:
| hwatu | surf | qutebrowser | luakit | |
|---|---|---|---|---|
| Window spawn | 13 ms median (warm daemon) | engine start per window | engine start | engine start |
| Engine | WebKitGTK 6 | WebKitGTK 2 | QtWebEngine | WebKitGTK 2 |
| Tabs | none, WM tiles | none | built-in | built-in |
| Keyboard UI | your WM's binds | patches | vim binds | lua config |
| Memory model | one shared engine, N views | process per window | one big process | one process |
Philosophy
- No tabs. A tab is a window. Your tiling WM is the tab manager.
- No chrome. The WebView is the whole window.
- Real rendering. Full WebKit: JS, CSS, media, WebGL, as the frontend intended. No custom half-engine.
- Spawn speed precedes everything. Every engine knob is paid on the daemon's idle path, never at window open. A spawn-latency benchmark gates every change.
Usage
hwatu # open the launcher (autostarts hwatud)
hwatu example.com # open a URL (https:// implied)
hwatu list # id, url, title of every window
hwatu close 2 # close window 2
hwatu quit # stop the daemon
Ctrl+w (or Ctrl+q) closes the focused window.
Ctrl+Shift+j / Ctrl+Shift+k scroll the
page down/up by half a viewport. The daemon and engine
stay warm.
For coding agents
The same daemon doubles as a verification harness for AI coding agents: real WebKit, 14 ms headless windows, a 216 ms open→wait→eval→screenshot→close loop, one JSON protocol over the Unix socket. Full guide: docs/agents.md.
hwatu --headless localhost:3000 # live session, no window at all
hwatu --background localhost:3000 # window mapped, focus stays put
hwatu eval 'document.title' # run JS in the page, JSON out
hwatu goto /checkout # navigate + wait for the load
hwatu shot /tmp/page.png # screenshot (--full = whole document)
hwatu scroll h2 --contains Total # scroll into view, reports what it hit
hwatu upload 'input[type=file]' ./fixture.png
hwatu focus 3 # hand the session to the human
Agent CLIs (jcode, Claude Code, Codex, Cursor, ...) are
auto-detected and default to --background, so
verification never steals your focus. focus promotes
any headless or background window to a normal one, session
intact.
Tuning
No config file. Engine knobs are set to their correct values in code (GPU compositing always on). The only surface is environment variables:
| Variable | Meaning |
|---|---|
HWATU_HOME |
Page opened by a bare hwatu. Defaults to the
built-in launcher (keybind cheat sheet + URL bar).
|
HWATU_DISCARD_SECS |
Seconds an unfocused window keeps its live WebView before being suspended to save RAM (default 120, 0 disables). |
HWATU_WEBKIT_FEATURES |
Ident:on,Other:off — flip individual WebKit runtime
features on odd hardware. Unknown identifiers are ignored.
|
Standard WEBKIT_* and GSK_RENDERER
variables pass through untouched. Scrolling smoothness scales with
your distro's WebKitGTK: 2.46+ paints with Skia on the GPU.
Architecture
hwatu <url> --unix socket--> hwatud (GTK main loop)
├── prewarmed WebView (adopted instantly,
│ next one warmed in idle time)
├── window registry (id -> WebView)
└── WebKit: shared network process,
per-site web processes
Unfocused windows are suspended after a timeout: history is serialized, the web process is killed, and RAM comes back. Focus restores them instantly from the prewarm pool.