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

Latest Release License: MIT CI

Verificação headless de interface para agentes de codificação

An agent verifies aiuc.com with hwatu: one command returns pixel-match scores for four responsive viewports, then the live page pops into view for human hand-off

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

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.

hwatu as the hand-off destination: quarter-width window spawns and Chromium-curve scrolling in a tiling WM

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 executaO que custa ao loop do agente
Biblioteca fria (Playwright, iniciado por tarefa)o mecanismo inicia quando o script iniciará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 residenterecursos 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 ausentespawns 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

CapacidadePlaywrightchrome-devtools-mcphwatu
Passada de verificação (carregar + avaliar + capturar tela), aquecido em processo82 msn/a35 ms
Passada de verificação como serviço aquecido (cliente novo por verificação)341 msn/a39 ms
Chamadas de ferramenta por passada de verificação551
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.