hwatu
Visual verification browser for coding agents: daemon-based headless WebKit with snapshot, click/type, console capture, screenshots, and pixel-diff scoring. One static binary, Linux/Wayland. MCP server via `hwatu mcp` (stdio).
Documentación
hwatu es un arnés de verificación headless para agentes de codificación: un
daemon WebKit cálido controlado por CLI, MCP o una línea JSON por
conexión de socket Unix. En lugar de "se ve bien para mí", el agente obtiene
verificaciones de página en una sola llamada en ~35 ms, puntuaciones de diff de píxeles que puede mejorar,
animaciones como números y ventanas headless que nunca roban el
foco, a cualquier paralelismo. Jcode lo impulsa de forma nativa como su backend browser.
Cuando una verificación necesita a un humano (un CAPTCHA, una decisión subjetiva),
hwatu focus <id> materializa la misma sesión en vivo como una ventana real.
Documentos
- Guía del agente: protocolo, primitivas, bucles de verificación
- Benchmarks: cada número, medido, con metodología
- Visión: principios de producto duraderos, estrategia de plataforma nativa
- Guía humana: hwatu como navegador de WM de mosaico, atajos de teclado, traspaso
- Hoja de ruta: prioridades de cartera y límites de producto
- Investigación de macOS: sondas WKWebView medidas, análisis de competidores y por qué macOS es solo verificación
- Mejora continua: métrica de activación, bucle de retroalimentación, cadencia semanal
- Kit de lanzamiento: copia reutilizable, canales y plan de medición
Instalación
curl -fsSL https://raw.githubusercontent.com/hongnoul/hwatu/main/scripts/install.sh | bash
Un binario estático más el webkitgtk-6.0 de tu distribución (el instalador
lo verifica). En Arch: yay -S hwatu. Desde el código fuente: cargo build --release.
Luego conecta un agente:
hwatu setup # detect Claude Code, Cursor, Jcode, or MCP
Verificación, no vibraciones
- "Pixel-perfect" es una afirmación.
match_percent: 97.49es una medición. - Una llamada de herramienta por verificación de página, ~35 ms. El mismo pase con Playwright en servidor cálido son 5 llamadas y ~9x más lento.
- Headless por defecto. Sin ventanas emergentes, sin robo de foco, sigues escribiendo.
- Un binario estático + webkitgtk de tu distribución. Sin Node, sin descarga de Chromium de 170 MB.
hwatu setup detecta agentes de codificación compatibles sin cambiar su
configuración. Elige un cliente explícitamente:
hwatu doctor
hwatu setup --client claude --scope project --dry-run
hwatu setup --client claude --scope project
hwatu demo
La configuración es previsualizable (--dry-run), idempotente y reversible
(--undo). La configuración manual de MCP es una entrada portátil:
{ "mcpServers": { "hwatu": { "command": "hwatu", "args": ["mcp"] } } }
O salta MCP: cada comando es una llamada CLI corta o una línea JSON delimitada por nueva línea sobre un socket Unix.
Conectar hwatu hace que sus herramientas estén disponibles; una instrucción de proyecto le
dice al agente cuándo usarlas. Añade esto a AGENTS.md, CLAUDE.md o
reglas de Cursor:
## Frontend verification
Use Hwatu after frontend changes. Exercise the affected user journey and
verify its intended visible, navigational, or persisted result with `expect`.
A successful click or clean console is not proof of success. Check `console`
for additional JavaScript and request failures after verifying the outcome.
Luego haz concreta la prueba de la tarea:
Implement display-name editing on /settings. Use Hwatu to enter “Test User,”
save it, verify the visible success state, reload, confirm persistence, and
report any console errors.
El bucle de verificación:
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
Este bucle llevó un clon de la página de inicio de stripe.com de 85.1% a 98.8% de coincidencia de píxeles. Reprodúcelo: scripts/demo/. Un segundo escenario real de agente (cuatro diffs de viewport responsivo, luego traspaso humano en vivo) con manifiestos de evidencia: scripts/demo-aiuc/.
Un pase de verificación completo (abrir, cargar, evaluar, captura, cerrar) es un comando, una llamada de herramienta, ~35 ms de mediana (benchmarks):
hwatu check localhost:5173 --eval 'document.title' --shot=/tmp/after.png
# {"title":"My App","eval":"My App","shot":"/tmp/after.png",
# "console":[...],"load_ms":13,"total_ms":35}
Para un contrato de repositorio repetible que también gestiona el preflight, el servidor de desarrollo local, las capturas responsivas, la verificación de código fuente desactualizado y el informe de evidencia:
hwatu verify .hwatu/about.verify.json
El mismo ejecutor se expone a los clientes MCP como verify_ui, por lo que los
arneses de agentes no reconstruyen el bucle de orquestación. Consulta la
guía del agente.
¿HTML generado en mano y sin servidor? hwatu render es el mismo
pase de una llamada con el marcado como entrada: sin archivo temporal, sin
python3 -m http.server:
echo '<h1>generated</h1>' | hwatu render --stdin --shot=/tmp/gen.png
# {"rendered":true,"shot":"/tmp/gen.png","load_ms":5,"total_ms":28}
# React to load, console, download, and window events without polling.
hwatu watch --kinds load,console
# {"event":"load","seq":1,"window_id":7,"data":{"state":"started",...}}
Los clientes MCP llaman a subscribe_events para el mismo flujo que
notifications/hwatu/event. Protocolo completo y bucles de verificación:
guía del agente.
En otros lugares, headless se decide en el lanzamiento y un humano nunca puede ver
la sesión. En hwatu es una propiedad de ventana, cambiable en vivo, en
ambas direcciones: hwatu focus <id> promueve cualquier sesión headless a
una ventana real para el humano, con el estado intacto.
challenge es solo detección y traspaso, por diseño: sin APIs de
resolución, sin inyección de tokens, sin juegos de huellas.
El destino del traspaso
El traspaso funciona porque hwatu también es un navegador real, construido para
WMs de mosaico. hwatu <url> abre una ventana como tu terminal abre un
shell (tu WM es la barra de pestañas, no hay ninguna en la ventana):
atajos de teclado convencionales (ctrl+l, ctrl+f, paleta ctrl+k,
reconfigurables), bloqueo de anuncios nativo (~119k reglas EasyList compiladas en
el motor de extensiones de contenido de WebKit, cero JS en la ruta de solicitud),
desplazamiento estilo Chromium y controles unificados de formato corto. Cada
ventana comparte el único daemon cálido (~56 MB por ventana extra),
se suspende cuando no está enfocada y restaura tras un fallo en su última URL. Brechas
honestas: sin Widevine ni passkeys en WebKitGTK. Configuraciones de WM
(hyprland, sway,
niri), atajos de teclado y configuración:
docs/human.md.
Características
- Headless / fondo / enfocado como propiedad por ventana, cambiable en vivo
- Traspaso humano:
hwatu focus <id>deja la sesión en vivo en tu WM de mosaico - Puntuación de diff de píxeles: porcentaje de coincidencia + regiones de diff + mapa de calor (
diff) - Animaciones como números: duración, easing, velocidad (
motion) - Fotogramas de animación deterministas: fija todas las animaciones en el tiempo t (
seek) - Estado de página como JSON, tokens no píxeles (
snapshot) - Eventos de entrada reales con errores estructurados (
click/type/scroll/upload) - Errores de JS, salida de consola, solicitudes fallidas (
console) - Suscripciones a eventos push como líneas JSON o notificaciones MCP (
watch) - Aserciones de página en una llamada con polling (
expect) - Detección de CAPTCHA / anti-bot con espera/reanudación estructurada (
challenge) - Servidor MCP, CLI simple y protocolo de socket JSON de 1 línea
- Un navegador real como destino de traspaso: atajos de teclado, medios, bloqueo de anuncios, restauración tras fallos
¿Por qué no Playwright o chrome-devtools-mcp?
Tres formas de darle un navegador a un agente:
| Cómo se ejecuta | Qué le cuesta al bucle del agente | |
|---|---|---|
| Biblioteca fría (Playwright, lanzada por tarea) | el motor arranca cuando el script lo hace | rápido de llamar, lento de ejecutar: cada verificación paga el arranque del motor; no sobrevive estado entre tareas |
| Navegador cálido (tu Chrome + devtools-mcp) | un navegador humano completo permanece residente | recursos gastados en pestañas, extensiones, sincronización, UI que nunca renderizas, y sus ventanas roban tu foco mientras trabajas |
| hwatu | "el daemon cálido más frío": motor caliente, todo lo demás ausente | spawns de 8 ms, verificaciones de 35 ms, invisible hasta que tú pides verlo (focus), interrumpible en ambas direcciones |
hwatu conserva exactamente lo que hace instantáneas las verificaciones (motor, contexto GPU, adblock compilado, una WebView precalentada) y nada que sirva a un humano a menos que ese humano pida una ventana. Por eso está inactivo cálido sin barra de pestañas, y por eso un servidor Playwright mantenido cálido impulsado de la misma manera cuesta 341 ms por cliente frente a los 39 de hwatu (benchmarks).
La segunda diferencia es lo que devuelve. Playwright y
chrome-devtools-mcp son APIs de automatización: dejan que un agente conduzca un
navegador, luego devuelven capturas y DOM crudos para inspeccionar. hwatu es
un navegador de verificación: las primitivas de medición (check,
diff, motion, expect) están integradas, una ventana cuesta 13 ms, y
headless es una propiedad de ventana, no un modo de lanzamiento.
Cómo se compara hwatu
Leyenda: ✅ Sí / integrado · 🟡 Parcial / limitado · ❌ No
| Capacidad | Playwright | chrome-devtools-mcp | hwatu |
|---|---|---|---|
| Pase de verificación (cargar + evaluar + captura), cálido en proceso | 82 ms | n/a | 35 ms |
| Pase de verificación como servicio cálido (cliente nuevo por verificación) | 341 ms | n/a | 39 ms |
| Llamadas de herramienta por pase de verificación | 5 | 5 | 1 |
| Puntuación de diff de píxeles + regiones + mapa de calor | 🟡 1 | ❌ | ✅ |
| Animaciones como números, fijadas a mitad de vuelo | ❌ 2 | 🟡 3 | ✅ |
| Headless ↔ con ventana en una sesión en vivo | ❌ | ❌ | ✅ |
| Traspaso humano a mitad de sesión, estado intacto | ❌ | ❌ | ✅ |
| Sin robo de foco con N agentes paralelos | 🟡 4 | 🟡 4 | ✅ |
| Detección de CAPTCHA + espera/reanudación estructurada | ❌ | ❌ | ✅ |
| Sin Node, sin descarga de navegador por versión | ❌ | ❌ | ✅ |
1 toHaveScreenshot compara contra goldens almacenados: pasa/falla para
suites de pruebas, no una puntuación que un agente pueda mejorar.
2 La práctica estándar es deshabilitar animaciones o avanzar rápido al estado final para evitar fallos intermitentes.
3 CDP crudo puede consultar el estado de animación, pero no hay resumen numérico de easing/velocidad/keyframes.
4 Bien headless; cada ventana con ventana emerge y toma el foco.
La comparación refleja cada proyecto al momento de escribir; las correcciones son bienvenidas. Advertencias honestas: Playwright aún gana en arranque en frío (190 vs 435 ms, pagado una vez por arranque) y memoria; hwatu renderiza WebKit no Chromium (mantén una matriz de Playwright en CI para errores específicos del motor), y es solo Linux hoy. Datos completos cara a cara y metodología: docs/benchmarks.md.
¿Qué pasa con Claude en Chrome? Categoría diferente. Claude en Chrome es un producto de agente que impulsa tu Chrome a través de una extensión, compartiendo tu perfil, pestañas y foco, no invocable por nada más. hwatu es un daemon agnóstico al cliente que cualquier agente llama por CLI/MCP, con su propio motor WebKit cálido, headless por defecto y primitivas de verificación integradas. Usa Claude en Chrome para que Claude navegue junto a ti; usa hwatu cuando los agentes necesiten verificaciones de página baratas, repetidas y medibles.
Retroalimentación
Una verificación exitosa, una instalación fallida, un atajo de teclado faltante y un sitio que se rompió son señales útiles. Comparte un informe de uso de dos minutos o reporta un error.
Licencia MIT. Linux. WebKitGTK 6.

