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).
Documentação
hwatu é um harness de verificação headless para agentes de codificação: um daemon WebKit aquecido, controlado via CLI, MCP ou uma linha JSON por conexão de Unix socket. Em vez de "parece certo para mim", o agente recebe verificações de página em uma única chamada em ~35 ms, pontuações de diff de pixels que ele pode melhorar, animações como números e janelas headless que nunca roubam o foco, em qualquer nível de paralelismo. O Jcode o utiliza nativamente como seu backend browser. Quando uma verificação precisa de um humano (um CAPTCHA, uma decisão subjetiva), o hwatu focus <id> materializa a mesma sessão ao vivo como uma janela real.
Documentos
- Guia do agente: protocolo, primitivas, loops de verificação
- Benchmarks: cada número, medido, com metodologia
- Visão: princípios de produto duráveis, estratégia de plataforma nativa
- Guia humano: hwatu como navegador de WM de janelas lado a lado, atalhos de teclado, transferência
- Roadmap: prioridades de portfólio e limites de produto
- Pesquisa macOS: sondas WKWebView medidas, análise de concorrentes e por que macOS é apenas para verificação
- Melhoria contínua: métrica de ativação, ciclo de feedback, cadência semanal
- Kit de lançamento: textos reutilizáveis, canais e plano de medição
Instalação
curl -fsSL https://raw.githubusercontent.com/hongnoul/hwatu/main/scripts/install.sh | bash
Um binário estático mais o webkitgtk-6.0 da sua distribuição (o instalador verifica). No Arch: yay -S hwatu. A partir do código-fonte: cargo build --release.
Depois, conecte um agente:
hwatu setup # detect Claude Code, Cursor, Jcode, or MCP
Verificação, não impressões
- "Pixel-perfeito" é uma afirmação.
match_percent: 97.49é uma medição. - Uma chamada de ferramenta por verificação de página, ~35 ms. O mesmo processo com Playwright em servidor aquecido são 5 chamadas e ~9x mais lento.
- Headless por padrão. Nenhuma janela aparece, nenhum foco é roubado, você continua digitando.
- Um binário estático + o webkitgtk da sua distribuição. Sem Node, sem download de 170 MB de Chromium.
hwatu setup detecta agentes de codificação suportados sem alterar a configuração deles. Escolha um cliente explicitamente:
hwatu doctor
hwatu setup --client claude --scope project --dry-run
hwatu setup --client claude --scope project
hwatu demo
A configuração é pré-visualizável (--dry-run), idempotente e reversível (--undo). A configuração manual de MCP é uma entrada portátil:
{ "mcpServers": { "hwatu": { "command": "hwatu", "args": ["mcp"] } } }
Ou pule o MCP: todo comando é uma chamada CLI curta ou uma linha JSON delimitada por nova linha em um Unix socket.
Conectar o hwatu disponibiliza suas ferramentas; uma instrução de projeto diz ao agente quando usá-las. Adicione isto ao AGENTS.md, CLAUDE.md ou às regras do 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.
Depois, torne a prova da tarefa concreta:
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.
O loop de verificação:
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 loop levou um clone da página inicial do stripe.com de 85,1% para 98,8% de correspondência de pixels. Reproduza-o: scripts/demo/. Um segundo cenário real de agente (quatro diffs de viewport responsivo, depois transferência humana ao vivo) com manifestos de evidência: scripts/demo-aiuc/.
Uma passada completa de verificação (abrir, carregar, avaliar, capturar tela, fechar) é um comando, uma chamada de ferramenta, ~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 um contrato de repositório repetível que também gerencia o preflight, o servidor de desenvolvimento local, as capturas de tela responsivas, a verificação de código-fonte desatualizado e o relatório de evidências:
hwatu verify .hwatu/about.verify.json
O mesmo executor é exposto a clientes MCP como verify_ui, para que os harnesses de agente não reconstruam o loop de orquestração. Veja o guia do agente.
HTML gerado em mãos e sem servidor? hwatu render é a mesma passada de uma chamada com o markup como entrada: sem arquivo temporário, sem 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",...}}
Clientes MCP chamam subscribe_events para o mesmo fluxo que notifications/hwatu/event. Protocolo completo e loops de verificação: guia do agente.
Em outros lugares, o headless é decidido no lançamento e um humano nunca pode ver a sessão. No hwatu, é uma propriedade da janela, alternável ao vivo, em ambas as direções: hwatu focus <id> promove qualquer sessão headless a uma janela real para o humano, com o estado intacto.
challenge é apenas detecção e transferência, por design: sem APIs de solução, sem injeção de tokens, sem jogos de impressão digital.
O destino da transferência
A transferência funciona porque o hwatu também é um navegador real, construído para WMs de janelas lado a lado. hwatu <url> abre uma janela como seu terminal abre um shell (seu WM é a barra de abas, não há uma na janela): atalhos de teclado convencionais (ctrl+l, ctrl+f, paleta ctrl+k, reatribuíveis), bloqueio de anúncios nativo (~119 mil regras EasyList compiladas no mecanismo de extensão de conteúdo do WebKit, zero JS no caminho da solicitação), rolagem com curva de Chromium e controles unificados de formato curto. Cada janela compartilha o único daemon aquecido (~56 MB por janela extra), suspende quando não está em foco e restaura após falha na última URL. Lacunas honestas: sem Widevine ou passkeys no WebKitGTK. Configurações de WM (hyprland, sway, niri), atalhos de teclado e configuração: docs/human.md.
Recursos
- Headless / em segundo plano / em foco como uma propriedade por janela, alternável ao vivo
- Transferência humana:
hwatu focus <id>coloca a sessão ao vivo no seu WM de janelas lado a lado - Pontuação de diff de pixels: porcentagem de correspondência + regiões de diff + mapa de calor (
diff) - Animações como números: duração, easing, velocidade (
motion) - Quadros de animação determinísticos: fixar todas as animações no tempo t (
seek) - Estado da página como JSON, tokens não pixels (
snapshot) - Eventos de entrada reais com erros estruturados (
click/type/scroll/upload) - Erros de JS, saída do console, solicitações com falha (
console) - Assinaturas de eventos push como linhas JSON ou notificações MCP (
watch) - Asserções de página em uma chamada com polling (
expect) - Detecção de CAPTCHA / anti-bot com espera/retomada estruturada (
challenge) - Servidor MCP, CLI simples e protocolo de socket JSON de 1 linha
- Um navegador real como destino da transferência: atalhos de teclado, mídia, bloqueio de anúncios, restauração após falha
Por que não Playwright ou chrome-devtools-mcp?
Três maneiras de dar um navegador a um agente:
| Como executa | O que custa ao loop do agente | |
|---|---|---|
| Biblioteca fria (Playwright, iniciado por tarefa) | o mecanismo inicia quando o script inicia | rápido para chamar, lento para executar: cada verificação paga a inicialização do mecanismo; nenhum estado sobrevive entre tarefas |
| Navegador aquecido (seu Chrome + devtools-mcp) | um navegador humano completo permanece residente | recursos gastos em abas, extensões, sincronização, UI que você nunca renderiza, e suas janelas roubam seu foco enquanto você trabalha |
| hwatu | "o daemon aquecido mais frio": mecanismo quente, todo o resto ausente | spawns de 8 ms, verificações confirmadas de 35 ms, invisível até você pedir para vê-lo (focus), interrompível em ambas as direções |
hwatu mantém exatamente o que torna as verificações instantâneas (mecanismo, contexto de GPU, bloqueador de anúncios compilado, uma WebView pré-aquecida) e nada que sirva a um humano a menos que esse humano peça uma janela. É por isso que fica ocioso aquecido sem barra de abas, e por que um servidor Playwright mantido aquecido, dirigido da mesma forma, custa 341 ms por cliente contra 39 do hwatu (benchmarks).
A segunda diferença é o que retorna. Playwright e chrome-devtools-mcp são APIs de automação: permitem que um agente dirija um navegador e depois devolvam capturas de tela brutas e DOM para inspeção visual. hwatu é um navegador de verificação: as primitivas de medição (check, diff, motion, expect) são integradas, uma janela custa 13 ms, e headless é uma propriedade da janela, não um modo de lançamento.
Como o hwatu se compara
Legenda: ✅ Sim / integrado · 🟡 Parcial / limitado · ❌ Não
| Capacidade | Playwright | chrome-devtools-mcp | hwatu |
|---|---|---|---|
| Passada de verificação (carregar + avaliar + capturar tela), aquecido em processo | 82 ms | n/a | 35 ms |
| Passada de verificação como serviço aquecido (cliente novo por verificação) | 341 ms | n/a | 39 ms |
| Chamadas de ferramenta por passada de verificação | 5 | 5 | 1 |
| Pontuação de diff de pixels + regiões + mapa de calor | 🟡 1 | ❌ | ✅ |
| Animações como números, fixadas no meio do voo | ❌ 2 | 🟡 3 | ✅ |
| Headless ↔ com janela em uma sessão ao vivo | ❌ | ❌ | ✅ |
| Transferência humana no meio da sessão, estado intacto | ❌ | ❌ | ✅ |
| Sem roubo de foco com N agentes paralelos | 🟡 4 | 🟡 4 | ✅ |
| Detecção de CAPTCHA + espera/retomada estruturada | ❌ | ❌ | ✅ |
| Sem Node, sem download de navegador por versão | ❌ | ❌ | ✅ |
1 toHaveScreenshot compara com goldens armazenados: passou/falhou para suítes de teste, não uma pontuação que um agente possa melhorar.
2 A prática padrão é desabilitar animações ou avançar rapidamente para o estado final para evitar flocos.
3 CDP bruto pode consultar o estado da animação, mas não há resumo numérico de easing/velocidade/keyframes.
4 Headless funciona bem; toda janela com janela aparece e rouba o foco.
A comparação reflete cada projeto no momento da escrita; correções são bem-vindas. Ressalvas honestas: o Playwright ainda vence na inicialização a frio (190 vs 435 ms, pago uma vez por boot) e na memória; o hwatu renderiza WebKit, não Chromium (mantenha uma matriz Playwright no CI para bugs específicos de mecanismo), e é apenas para Linux hoje. Dados completos de comparação direta e metodologia: docs/benchmarks.md.
E o Claude no Chrome? Categoria diferente. Claude no Chrome é um produto de agente que dirige seu Chrome por meio de uma extensão, compartilhando seu perfil, abas e foco, e nada mais pode chamá-lo. hwatu é um daemon agnóstico de cliente que qualquer agente chama via CLI/MCP, com seu próprio mecanismo WebKit aquecido, headless por padrão e primitivas de verificação integradas. Use o Claude no Chrome para deixar o Claude navegar junto com você; use o hwatu quando agentes precisarem de verificações de página baratas, repetidas e mensuráveis.
Feedback
Uma verificação bem-sucedida, uma instalação com falha, um atalho de teclado ausente e um site que quebrou são todos sinais úteis. Compartilhe um relatório de uso de dois minutos ou relate um bug.
Licença MIT. Linux. WebKitGTK 6.

