Skip to content

hongnoul/hwatu

Repository files navigation

hwatu

Latest Release License: MIT CI

Lightweight verification browser for coding agents.

  • STOP your agent claiming "pixel-perfect." Make it prove 97.49%.
  • STOP browser windows stealing your focus. Headless by default, you keep typing.
  • STOP shipping 170 MB of Chromium. One static binary + your distro's webkitgtk.

hwatu real workflow: open headless, verify the rendered page, then hand the live browser to a human

Documents

  • Agent guide — protocol, primitives, verification loops
  • Human guide — the tiling-WM browser side
  • Benchmarks — every number, measured, with methodology
  • Roadmap — plan of record, priorities, non-goals

Quick Start

Install → Detect workflow → Connect agent → Verify page → Hand off to human

curl -fsSL https://raw.githubusercontent.com/hongnoul/hwatu/main/scripts/install.sh | bash
hwatu setup

One static binary plus your distro's webkitgtk-6.0 (the installer checks). On Arch: yay -S hwatu. From source: cargo build --release.

The installer installs binaries only. hwatu setup detects supported coding agents and prints the available connections without changing their config. Choose a client explicitly when you are ready:

hwatu doctor
hwatu setup --client claude --scope project --dry-run
hwatu setup --client claude --scope project
hwatu demo
  • Install: download two binaries and check WebKitGTK.
  • Detect: find Claude Code, Cursor, Jcode, or a generic MCP workflow.
  • Connect: use Jcode's native socket, MCP, or the CLI fallback.
  • Verify: run a headless rendered smoke test with doctor or demo.
  • Hand off: materialize the same live session only when a human is needed.

Setup is previewable, idempotent, and reversible with the same client and scope plus --undo. Project scope creates shareable configuration; user scope keeps it personal. Claude Code asks each user to approve project-scoped MCP servers when it next starts.

Manual MCP configuration remains one portable entry:

{ "mcpServers": { "hwatu": { "command": "hwatu", "args": ["mcp"] } } }

Or skip MCP entirely: every command is a short CLI call or one newline-delimited JSON line over a Unix socket.

hwatu localhost:3000       # open a window like you open a terminal

Features

  • Pixel-diff scoring: match percent + diff regions + heatmap (diff)
  • Animations as numbers: duration, easing, velocity (motion)
  • Deterministic animation frames: pin all animations at time t (seek)
  • Page state as JSON, tokens not pixels (snapshot)
  • Real input events with structured errors (click / type / scroll / upload)
  • JS errors, console output, failed requests (console)
  • One-call page assertions with polling (expect)
  • Headless / background / focused as a per-window property, switchable live
  • Human hand-off: hwatu focus <id> drops the live session into your tiling WM
  • CAPTCHA / anti-bot detection with structured wait/resume (challenge)
  • MCP server, plain CLI, and a 1-line JSON socket protocol
  • A minimal WebKit browser for humans: native ad blocking, vim-style bar, crash restore

Why not Playwright or chrome-devtools-mcp?

Playwright and chrome-devtools-mcp are, at their core, automation APIs: they let an agent drive a browser, then hand back raw screenshots and DOM for the agent to eyeball.

hwatu is different. It is a verification browser: the measurement primitives are built in, and the browser itself is a warm daemon where a window costs 13 ms and headless is a window property, not a launch mode.

That is why the loop looks like this, real commands, real output:

hwatu --headless localhost:3000        # its window; you never see it
hwatu --headless staging.example.com   # the reference

hwatu diff --id 2 --other 1 --heatmap /tmp/heat.png
# {"match_percent":85.13,"regions":[{"x":0,"y":160,"w":2048,...}]}

hwatu motion --id 1                    # the reference's animations, as numbers
# easing cubic-bezier(0.25,1,0.5,1), 300ms, marquee 29.78px/s ...

# ...agent edits code...

hwatu diff --id 2 --other 1
# {"match_percent":97.49}              # climbing beats guessing

We ran this loop against a clone of stripe.com's landing page: an agent took it from 85.1% to 98.8% pixel match. Reproduce it: scripts/demo/. A full verification pass (open, load, eval, screenshot, close) is 87 ms median (benchmarks).

And when the agent hits a CAPTCHA or a judgment call, hwatu focus materializes its live session, cookies and state intact, in your tiling WM. You act for ten seconds. It takes back over. No other tool can do this, because everywhere else headless is decided at launch.

How hwatu compares

Legend: ✅ Yes / built-in · 🟡 Partial / limited · ❌ No

Capability Playwright chrome-devtools-mcp hwatu
Pixel-diff score + regions + heatmap 🟡 1
Animations as numbers, pinned mid-flight ❌ 2 🟡 3
Headless ↔ headed on a live session
Human hand-off mid-session, state intact
No focus stealing at N parallel agents 🟡 4 🟡 4
CAPTCHA detection + structured wait/resume
No Node, no per-version browser download

1 toHaveScreenshot compares against stored goldens: pass/fail for test suites, not a score an agent can climb.

2 Standard practice is to disable animations or fast-forward to the end state to avoid flakes.

3 Raw CDP can query animation state, but there is no numeric summary of easing/velocity/keyframes.

4 Fine headless; every headed window pops and takes focus.

Comparison reflects each project at the time of writing; corrections are welcome. Honest caveats: raw warm latency vs Playwright is a tie (83 vs 82 ms), hwatu renders WebKit not Chromium (keep a Playwright matrix in CI for engine-specific bugs), and it is Linux-only today. Full head-to-head data: docs/benchmarks.md.


MIT licensed. Linux. WebKitGTK 6.

Releases

Packages

Contributors

Languages