Voltar às atualizações
New releaseJul 25, 2026

kuri v0.4.12

Automação de navegador, web crawling e controle de dispositivos iOS + Android para agentes de IA. Snapshots CDP nativos em Zig, eficientes em tokens, gravação HAR, cliente nativo do protocolo adb e um fetcher independente.

Compartilhar

Kuri

Kuri 🌰

Stable release License Zig node_modules status

Instalação```sh

curl -fsSL https://kuri.trilok.ai/download | sh

macOS arm64/x86_64 e Linux x86_64/arm64. Binário único, sem dependências de runtime.

Downloads diretos: [macOS arm64](https://kuri.trilok.ai/download/v0.6.0/kuri-v0.6.0-aarch64-macos.tar.gz) · [macOS x86_64](https://kuri.trilok.ai/download/v0.6.0/kuri-v0.6.0-x86_64-macos.tar.gz) · [Linux x86_64](https://kuri.trilok.ai/download/v0.6.0/kuri-v0.6.0-x86_64-linux.tar.gz) · [Linux arm64](https://kuri.trilok.ai/download/v0.6.0/kuri-v0.6.0-aarch64-linux.tar.gz)

---

**Automação de navegador e web crawling para agentes de IA. Escrito em Zig. Zero Node.js.**

Automação CDP · Snapshots A11y · Gravação de HAR · Fetcher autônomo · Navegador de terminal interativo · CLI agêntica · Testes de segurança · Controle de dispositivos iOS + Android

[Início Rápido](#-quick-start) · [Benchmarks](#-benchmarks) · [kuri-agent](#-kuri-agent) · [Testes de Segurança](#-security-testing) · [API](#-http-api) · [Habilidades](#-skills) · [Changelog](https://github.com/justrach/kuri/blob/HEAD/CHANGELOG.md)

> **Por que as equipes migram para o Kuri:** builds `ReleaseFast` atuais para Apple Silicon permanecem abaixo de 2 MB por binário, e uma nova execução no Google Flights em 2026-04-23 mediu **3,392 tokens** para um loop completo de `kuri-agent` (`go→snap→click→snap→eval`). Deltas entre ferramentas devem ser executados novamente no mesmo ambiente antes de citar uma porcentagem.

---

## Por que o Kuri vence para agentes

A maioria das ferramentas de navegador foi construída para engenheiros de QA. O Kuri é construído para loops de agentes: leia a página, mantenha o custo de tokens baixo, aja com base em refs estáveis e siga em frente.

- **135 endpoints HTTP** — paridade total com agent-browser e browser-use, da inspeção React ao Core Web Vitals.
- **7 a 12% menos tokens** do que agent-browser em páginas reais, graças ao formato de ref `@eN` e à renderização sem prefixo.
- **Observações 44x mais leves** com `/page/state` (48 tokens) vs snapshot completo (2,124 tokens) para a mesma página do Google Flights.
- **Execução em lote** — `POST /batch` envia N comandos em uma única chamada HTTP, eliminando N-1 round-trips e N-1 turnos de LLM.
- **Compatível com React** — eventos de mouse CDP confiáveis e eventos de teclado por caractere disparam `onClick` e `onChange` do React 18/19.

### Tokens de snapshot: Google Flights `SIN → TPE`

Nova execução em 2026-05-24 neste workspace, medida com `wc -c` e aproximação `chars/4`.

| Ferramenta / Modo | Chars | ~Tokens | Nota |
|---|---:|---:|---|
| `kuri snap` (completo) | 8,499 | **2,124** | Todos os nós + refs interativos |
| `kuri snap` (somente interativos) | ~3,000 | **~750** | Melhor para loops de agente |
| `kuri /page/state` | 190 | **48** | Observação leve (url, título, scroll%, contagens) |
| agent-browser snap (estimado) | ~9,183 | **~2,295** | Sobrecarga de formato `[ref=e0]` |

### Eficiência de tokens: kuri vs agent-browser

| Página | tokens kuri | tokens agent-browser | Economia |
|---|---:|---:|---|
| example.com | 40 | 35 | -13% (página trivial, agent-browser pula a raiz) |
| Hacker News | 386 | ~440 | **12% menos** |
| Google Flights SIN→TPE | 2,124 | ~2,295 | **7% menos** |

A economia vem do formato compacto do kuri:
- Refs `@e0` (3 caracteres) vs `[ref=e0]` (9 caracteres)
- Sem prefixo `- ` por linha (economiza 2 caracteres × número de linhas)
- Mesma indentação, mesma filtragem de nós

### Custo do fluxo completo: `go → snap → click → snap → eval`

| Ferramenta | Tokens por ciclo |
|---|---:|
| **kuri-agent** | **~3,400** |
| Com `/page/state` em vez do segundo snap | **~1,700** |
| Com `POST /batch` (tudo em uma chamada) | **~1,700** (mesmos tokens, 1 chamada HTTP em vez de 5) |

### kuri vs libretto

[libretto](https://github.com/saffron-health/libretto) (Playwright + Node) é o concorrente mais próximo em custo de tokens por etapa. Medido frente a frente em 2026-07-04 — mesmo Chrome, mesma aba, contagens reais de `tiktoken` `o200k_base` (metodologia completa e reprodução: **[benchmarks/libretto_comparison.md](https://github.com/justrach/kuri/blob/HEAD/benchmarks/libretto_comparison.md)**). A divisão honesta:

| Eixo | Vencedor | Detalhe |
|---|---|---|
| Latência por chamada | **kuri** | 4–117 ms vs 1,344–1,500 ms (**13–376× mais rápido** — servidor persistente vs Node por comando) |
| Tokens de snapshot, página típica | **kuri** | simples 61 vs 151 (2.5×), artigo 265 vs 363 (1.37×) — gramática mais enxuta |
| Tokens de snapshot, lista grande | dividido | padrão do kuri 4,424 vs 813 — o kuri emite todos os 259 refs, o libretto trunca por padrão. Com `limit=5`, o kuri renderiza 555 tokens (**1.46× abaixo do libretto**), 34 refs + marcadores `… +45 more` |
| Trajetória (feed, 9 cliques) | **kuri**, por pouco | 898 vs 939 tokens (base `limit=5` + loop de diff vs loop de exec) — paridade a leve vantagem; a perda de 5.1× da manhã foi devida à base não truncada |
| Execuções repetidas | **libretto** | compila trajetórias em um script Playwright → repetições de 0 tokens; o kuri volta a pagar o loop a cada execução |

**O que o kuri ganhou ao estudar o libretto** (tudo incluído nesta versão): um loop diff-first (`take_snapshot_diff`, ~38 tokens/etapa); um diff adaptativo que recorre a um snapshot completo com um cabeçalho `! page replaced` na navegação; linhas de remoção apenas com a identidade; capturas de tela gravadas em disco (o caminho é retornado, os bytes nunca entram no contexto); `get_page_state` via MCP; e — após reescrever `parseA11yNodes` como um verdadeiro caminhamento de árvore DFS — **truncamento de lista opt-in** (`/snapshot?limit=N`, uma linha `… +K more` por execução limitada), **recaptura com escopo** (`scope=@ref`) e **indentação hierárquica**, também expostos como `uid`/`limit` no `take_snapshot` do MCP. A trajetória de feed de 9 cliques que custava 44,285 tokens com re-snapshots completos ingênuos custa **898** com base truncada + diffs — 49× mais barata, ficando abaixo dos 939 do libretto.

> As tabelas mais antigas acima usam uma aproximação de tokens `chars/4`; a comparação com libretto usa contagens reais de `tiktoken`. Rode novamente os números entre ferramentas no seu próprio ambiente antes de citar uma porcentagem.

### Tamanho do binário e memória

Medido em Apple M4 Pro, macOS 26.4.1. Os binários atuais foram compilados com `-Doptimize=ReleaseFast`.

| Binário | Tamanho atual |
|---|---:|
| `kuri` | 1,093,840 B (1.04 MiB) |
| `kuri-agent` | 629,904 B (615 KiB) |
| `kuri-browse` | 1,089,120 B (1.04 MiB) |
| `kuri-fetch` | 2,063,488 B (1.97 MiB) |

### O RSS permaneceu estável durante a migração para o Zig 0.16

Medido em relação ao build `v0.4.3` `ReleaseFast` atual com `/usr/bin/time -l`.

| Comando | RSS máximo médio `v0.4.3` |
|---|---:|
| `kuri-fetch --version` | ~2.45 MiB |
| `kuri-browse --version` | ~2.45 MiB |
| `kuri-fetch --quiet --dump markdown http://example.com/` | ~9.17 MiB |

## O Problema

Toda ferramenta de automação de navegador arrasta consigo Playwright (~300 MB), um runtime Node.js e uma cascata de dependências npm. Seu agente de IA só quer ler uma página, clicar em um botão e seguir em frente.
**Kuri é um único binário Zig.** Quatro modos, zero runtime:```
kuri           →  CDP server (Chrome automation, a11y snapshots, HAR)
kuri-fetch     →  standalone fetcher (no Chrome, QuickJS for JS, ~2 MB)
kuri-browse    →  interactive terminal browser (navigate, follow links, search)
kuri-agent     →  agentic CLI (scriptable Chrome automation + security testing)

📦 Instalação

Instalação em uma linha (macOS / Linux)```sh

curl -fsSL https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh | sh

Detecta sua plataforma, baixa o binário correto e instala em `~/.local/bin`.
Os downloads vêm do branch `release-channel` autogerenciado do Kuri. Os binários do macOS são assinados localmente com um certificado Developer ID. Os assets do GitHub Release espelham esses mesmos tarballs.

### bun / npm```sh
bun install -g kuri-agent
# or: npm install -g kuri-agent

Baixa o binário nativo correto para a sua plataforma no momento da instalação.

Canal de lançamento

Os binários estáveis do Kuri ficam no branch release-channel e são servidos diretamente de URLs raw do GitHub.

  • Instalador estável: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh
  • Manifesto estável: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/latest.json
  • Visualização do branch: https://github.com/justrach/kuri/tree/release-channel/stable
  • Padrão de download direto: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/<version>/kuri-<version>-<target>.tar.gz

Manual

Baixe o tarball para a sua plataforma a partir do manifesto de lançamento estável ou da página de lançamentos do GitHub e descompacte-o no seu $PATH.

URL de instalação estável:```sh curl -fsSL https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh | sh

The manifest includes exact asset URLs plus SHA-256 checksums for `aarch64-linux`, `x86_64-linux`, `aarch64-macos`, and `x86_64-macos`.

### Platform support

| Platform | Status |
|---|---|
| macOS (`aarch64`, `x86_64`) | Binários pré-compilados, assinados + notarizados |
| Linux (`aarch64`, `x86_64`) | Binários pré-compilados |
| Windows (`x86_64`) | **Experimental — apenas compilação cruzada.** `zig build -Dtarget=x86_64-windows-gnu` é verificado pelo CI, mas automação do Chrome, daemonização, desligamento baseado em sinais, gravação de HAR e o armazenamento de autenticação baseado em arquivo são todos stubs com `error.UnsupportedOnWindows` em tempo de execução. Use **WSL2** se você precisar do conjunto de recursos real. Rastreado em [#153](https://github.com/justrach/kuri/issues/153). |

Kuri depende de primitivas POSIX (`fork`, `clock_gettime`, sockets brutos) em vários pontos, portanto uma porta nativa completa para Windows é um trabalho considerável. A base em nível de compilação acima permite que os caminhos `--version`/`--help` e operações puramente em memória sejam executados; as partes complicadas (Chrome, sockets, daemonize) precisam de implementações Win32 reais antes de saírem da lista de stubs. Se você quiser assumir alguma delas, +1 [#153](https://github.com/justrach/kuri/issues/153) ou abra um PR.

### Compilar a partir do código-fonte

Requer [Zig ≥ 0.16.0](https://ziglang.org/download/).```bash
git clone https://github.com/justrach/kuri.git
cd kuri
zig build -Doptimize=ReleaseFast
# Binaries in zig-out/bin/: kuri  kuri-agent  kuri-fetch  kuri-browse

⚡ Início Rápido

Requisitos: Zig ≥ 0.16.0 · Chrome/Chromium (para modo CDP)```bash git clone https://github.com/justrach/kuri.git cd kuri

zig build # build everything zig build test # run 252+ tests

CDP mode — launches Chrome automatically

./zig-out/bin/kuri

Standalone mode — no Chrome needed

./zig-out/bin/kuri-fetch https://example.com

Interactive browser — browse from your terminal

./zig-out/bin/kuri-browse https://example.com

Experimental standalone browser runtime — separate build, not production

(cd kuri-browser && zig build run -- render https://example.com) (cd kuri-browser && zig build run -- bench --offline)

### Primeira execução, caminho mais curto```bash
# start the server; if CDP_URL is unset, kuri launches managed Chrome for you
./zig-out/bin/kuri

# discover tabs from that managed browser
curl -s http://127.0.0.1:8080/discover

# inspect the discovered tab list
curl -s http://127.0.0.1:8080/tabs

Loop de agente que prioriza a sessão

Para uso de HTTP no estilo agente, prefira um cabeçalho de sessão mais /tab/new, /page/info e /snapshot em vez de repetir tab_id em cada chamada.```bash SESSION=hn-demo BASE=http://127.0.0.1:8080

curl -s -H "X-Kuri-Session: $SESSION"
"$BASE/tab/new?url=https%3A%2F%2Fnews.ycombinator.com"

curl -s -H "X-Kuri-Session: $SESSION" "$BASE/page/info" SNAP=$(curl -s -H "X-Kuri-Session: $SESSION" "$BASE/snapshot?filter=interactive&format=compact") MORE_REF=$(printf '%s' "$SNAP" | python3 -c 'import re,sys; print(re.search(r""More" @(e\d+)", sys.stdin.read()).group(1))') curl -s -H "X-Kuri-Session: $SESSION" "$BASE/action?action=click&ref=$MORE_REF" curl -s -H "X-Kuri-Session: $SESSION" "$BASE/page/info"

Existe também um wrapper experimental leve em `tools/kuri_harness.py` se você quiser auxiliares em Python sobre a mesma superfície HTTP.

Se você já tem o Chrome em execução com depuração remota, defina `CDP_URL` para o endpoint WebSocket ou HTTP:```bash
CDP_URL=ws://127.0.0.1:9222/devtools/browser/... ./zig-out/bin/kuri
# or
CDP_URL=http://127.0.0.1:9222 ./zig-out/bin/kuri

1. Discover Chrome tabs

curl -s http://localhost:8080/discover

→ {"discovered":1,"total_tabs":1}

2. Get tab ID

curl -s http://localhost:8080/tabs

→ [{"id":"ABC123","url":"chrome://newtab/","title":"New Tab"}]

3. Navigate

curl -s "http://localhost:8080/navigate?tab_id=ABC123&url=https://vercel.com"

4. Get accessibility snapshot (token-optimized for LLMs)

curl -s "http://localhost:8080/snapshot?tab_id=ABC123&filter=interactive"

→ [{"ref":"e0","role":"link","name":"VercelLogotype"},

{"ref":"e1","role":"button","name":"Ask AI"}, ...]

---

## 🌐 HTTP API

Todos os endpoints retornam JSON. Autenticação opcional via variável de ambiente `KURI_SECRET`. **135 endpoints** — paridade total com agent-browser e browser-use.

### Núcleo

| Caminho | Descrição |
|------|-------------|
| `GET /health` | Status do servidor, contagem de abas, versão |
| `GET /tabs` | Lista todas as abas registradas |
| `GET /discover` | Descobre automaticamente abas do Chrome via CDP |
| `GET /tab/current` | Obtém ou define a aba atual para uma `X-Kuri-Session` |
| `GET /page/info` | URL/título/ready-state/viewport/scroll em tempo real da aba ativa |
| `GET /page/state` | Observação compacta da página: url, título, scroll%, viewport, contagens de formulários/links/imagens/inputs |
| `POST /batch` | Executa vários comandos em uma única chamada HTTP — retorna uma matriz de resultados |
| `GET /browdie` | 🌰 (easter egg) |

### Controle do Navegador

| Caminho | Parâmetros | Descrição |
|------|--------|-------------|
| `GET /navigate` | `tab_id`, `url` | Navega a aba para a URL |
| `GET /tab/new` | `url`, `activate`, `wait` | Cria uma nova aba e opcionalmente hidrata/define a aba atual |
| `GET /tab/close` | `tab_id` | Fecha uma aba |
| `GET /window/new` | `url`, `activate`, `wait` | Cria um novo alvo de janela/aba |
| `GET /snapshot` | `tab_id`, `filter`, `format` | Snapshot da árvore a11y com refs `eN`. Use `filter=interactive&format=compact` para loops de agente com baixo consumo de tokens. |
| `GET /text` | `tab_id` | Extrai o texto da página |
| `GET /screenshot` | `tab_id`, `format`, `quality`, `save` | Captura screenshot (base64); `save=true` grava o PNG em `STATE_DIR/screenshots` e retorna `{path,bytes}` em vez disso |
| `GET /screenshot/annotated` | `tab_id` | Screenshot com rótulos numerados de elementos |
| `GET /screenshot/diff` | `tab_id`, `baseline` | Diff visual entre a screenshot atual e a de referência |
| `GET /action` | `tab_id`, `ref`, `action`, `value` | Click/type/fill/select/scroll/hover/dblclick/check/uncheck/blur por ref |
| `GET /evaluate` | `tab_id`, `expression` | Executa JavaScript |
| `GET /evalhandle` | `tab_id`, `expression` | Executa JS, retorna o handle objectId (não o valor) |
| `GET /close` | `tab_id` | Fecha aba + limpeza |
| `GET /bringtofront` | `tab_id` | Traz a aba para a frente |

### Ações

| Caminho | Parâmetros | Descrição |
|------|--------|-------------|
| `GET /clear` | `ref` | Limpa o valor do campo de entrada |
| `GET /selectall` | `ref` | Seleciona todo o texto em input/contenteditable |
| `GET /setvalue` | `ref`, `value` | Define o valor do campo de entrada diretamente (ignora eventos de teclado) |
| `GET /dispatch` | `ref`, `type` | Despacha evento DOM personalizado no elemento |
| `GET /boundingbox` | `ref` | Obtém o retângulo delimitador do elemento (x, y, width, height, centerX, centerY) |
| `GET /getattribute` | `ref`, `name` | Obtém o atributo do elemento pelo nome |
| `GET /inputvalue` | `ref` | Obtém o valor atual do elemento de entrada |
| `GET /element/state` | `ref`, `check` | Booleano rápido: `exists`, `visible`, `enabled`, `checked` |
| `GET /find-element` | `text`/`role`/`label`/`placeholder`/`testid` | Localizador semântico — encontra o elemento sem snapshot |
| `GET /highlight` | `ref` ou `selector` | Destaca o elemento com sobreposição |

### Mouse e Toque

| Caminho | Parâmetros | Descrição |
|------|--------|-------------|
| `GET /mouse/move` | `x`, `y` | Move o mouse para as coordenadas |
| `GET /mouse/down` | `x`, `y`, `button` | Botão do mouse pressionado |
| `GET /mouse/up` | `x`, `y`, `button` | Botão do mouse solto |
| `GET /mouse/wheel` | `x`, `y`, `deltaX`, `deltaY` | Rolagem da roda do mouse |
| `GET /tap` | `x`, `y` | Toque (touchStart + touchEnd) |
| `GET /swipe` | `startX`, `startY`, `endX`, `endY` | Gesto de deslize por toque |
| `GET /drag` | `src_ref`, `tgt_ref` | Arrasta o elemento até o alvo |

### Teclado

| Caminho | Parâmetros | Descrição |
|------|--------|-------------|
| `GET /keyboard/type` | `tab_id`, `text` | Digita texto via eventos de teclado |
| `GET /keyboard/inserttext` | `tab_id`, `text` | Insere texto diretamente |
| `GET /keydown` | `tab_id`, `key` | Evento de tecla pressionada |
| `GET /keyup` | `tab_id`, `key` | Evento de tecla solta |

### Extração de Conteúdo

| Caminho | Descrição |
|------|-------------|
| `GET /markdown` | Converte página para Markdown |
| `GET /links` | Extrai todos os links |
| `GET /dom/query` | Consulta de seletor CSS |
| `GET /dom/html` | Obtém o HTML do elemento |
| `GET /dom/attributes` | Obtém os atributos do elemento |
| `GET /pdf` | Imprime a página em PDF |
| `GET /find` | Pesquisa de texto na página |

### Aguardando

| Caminho | Parâmetros | Descrição |
|------|--------|-------------|
| `GET /wait` | `selector`, `text`, `url`, `state`, `visible`, `timeout` | Aguarda seletor/texto/padrão de URL/networkidle/estado de carregamento |
| `GET /wait/function` | `expression`, `timeout` | Aguarda até que uma expressão JS arbitrária seja truthy |
| `GET /wait/download` | `timeout` | Aguarda a conclusão do download do arquivo |

### Tratamento de Diálogos

| Caminho | Descrição |
|------|-------------|
| `GET /dialog/auto` | Lida automaticamente com todos os diálogos JS (aceitar ou dispensar) |
| `GET /dialog/accept` | Aceita o diálogo atual (com texto de prompt opcional) |
| `GET /dialog/dismiss` | Dispensa o diálogo atual |

### Rede e HAR

| Caminho | Descrição |
|------|-------------|
| `GET /har/start` | Inicia a gravação do tráfego de rede |
| `GET /har/stop` | Para e retorna o JSON HAR 1.2 |
| `GET /har/status` | Estado da gravação + contagem de entradas |
| `GET /har/replay` | Mapa da API com trechos de código curl/fetch/python |
| `GET /cookies` | Obtém cookies |
| `GET /cookies/set` | Define cookies |
| `GET /cookies/delete` | Exclui cookies |
| `GET /cookies/clear` | Limpa todos os cookies |
| `GET /headers` | Define cabeçalhos de requisição personalizados |
| `GET /intercept/start` | Inicia a interceptação de requisições |
| `GET /intercept/stop` | Para a interceptação de requisições |
| `GET /intercept/requests` | Lista requisições interceptadas |
| `GET /request/detail` | Obtém o corpo da resposta para um ID de requisição |
| `GET /response/body` | Busca a URL e retorna o corpo da resposta |
| `GET /network` | Estatísticas de tráfego de rede |
| `GET /download` | Dispara o download de arquivo |

### Navegação e Estado

| Caminho | Descrição |
|------|-------------|
| `GET /back` | Voltar no navegador |
| `GET /forward` | Avançar no navegador |
| `GET /reload` | Recarrega a página |
| `GET /stop` | Para o carregamento da página |
| `GET /pushstate` | Navegação SPA via history.pushState |
| `GET /storage/local` | Obtém/define localStorage |
| `GET /storage/session` | Obtém/define sessionStorage |
| `GET /storage/local/clear` | Limpa localStorage |
| `GET /storage/session/clear` | Limpa sessionStorage |
| `GET /session/save` | Salva a sessão do navegador |
| `GET /session/load` | Restaura a sessão do navegador |
| `GET /session/list` | Lista sessões salvas |
| `GET /setcontent` | Define o HTML da página diretamente (POST) |

### Perfis de Autenticação

| Caminho | Descrição |
|------|-------------|
| `GET /auth/profile/save` | Salva cookies + storage como um perfil de autenticação nomeado |
| `GET /auth/profile/load` | Restaura um perfil de autenticação nomeado em uma aba |
| `GET /auth/profile/list` | Lista perfis de autenticação salvos |
| `GET /auth/profile/delete` | Exclui um perfil de autenticação salvo |
| `GET /auth/extract` | Extrai tokens de autenticação (JWT, cookies, headers) |
| `GET /set/credentials` | Define credenciais de autenticação básica HTTP |

No macOS, os segredos do perfil de autenticação são armazenados no Keychain do usuário.

### Emulação

| Caminho | Parâmetros | Descrição |
|------|--------|-------------|
| `GET /emulate` | tipo de dispositivo, tamanho de tela | Emulação de dispositivo |
| `GET /set/viewport` | `width`, `height` | Define o tamanho do viewport |
| `GET /set/useragent` | `ua` | Define o user agent |
| `GET /set/media` | `media` | Emula o tipo de mídia |
| `GET /set/offline` | `offline` | Alterna o modo offline |
| `GET /geolocation` | `lat`, `lng` | Substitui a geolocalização |
| `GET /timezone` | `timezone` | Substitui o fuso horário (ex.: `America/New_York`) |
| `GET /locale` | `locale` | Substitui o locale (ex.: `en-US`) |
| `GET /permissions` | `name`, `state` | Concede/nega permissões (geolocalização, notificações, área de transferência) |

### Scripts e Injeção

| Caminho | Descrição |
|------|-------------|
| `GET /script/inject` | Injeta JavaScript na página (persiste entre navegações) |
| `GET /initscript/remove` | Remove um script init injetado anteriormente |
| `GET /addstyle` | Injeta folha de estilo CSS |
| `GET /expose` | Expõe uma função nomeada ao contexto JS da página |

### Inspeção React

| Caminho | Descrição |
|------|-------------|
| `GET /react/tree` | Árvore de componentes React via hook do DevTools |
| `GET /react/inspect` | Props e estado de componentes React |
| `GET /react/renders` | Rastreamento de renderização React (iniciar/parar) |
| `GET /react/suspense` | Status do limite Suspense do React |

### Gravação e Desempenho

| Caminho | Descrição |
|------|-------------|
| `GET /recording/start` | Grava ações do usuário (clique, entrada, navegação) |
| `GET /recording/stop` | Para a gravação + retorna o log de ações |
| `GET /vitals` | Core Web Vitals (LCP, CLS, FID, TTFB, FCP, domInteractive) |
| `GET /perf/lcp` | Tempo do Largest Contentful Paint |
| `GET /trace/start` | Inicia o trace de desempenho |
| `GET /trace/stop` | Para o trace |
| `GET /profiler/start` | Inicia o profiler JS |
| `GET /profiler/stop` | Para o profiler |

### Depuração

| Caminho | Descrição |
|------|-------------|
| `GET /debug/enable` | Ativa o HUD de depuração na página e o modo de congelamento opcional |
| `GET /debug/disable` | Desativa o HUD de depuração na página |
| `GET /inspect` | Inspeção de elemento |
| `GET /errors` | Coleta erros JS |
| `GET /console` | Lê os logs do console |
| `GET /frames` | Lista os frames da página |
| `GET /frame` | Alterna para o contexto do iframe por nome ou URL |
| `GET /mainframe` | Volta para o frame principal |
| `GET /diff/snapshot` | Diff compacto `+`/`~`/`-` em relação à chamada anterior para esta aba — o loop de ações eficiente em tokens (com alias `/snapshot/changes`). Em mudanças em massa, recorre a um snapshot completo com um cabeçalho `! page replaced`. |
| `GET /diff/url` | Compara duas URLs lado a lado (navegar, snapshot, diff) |

### Streaming

| Caminho | Descrição |
|------|-------------|
| `GET /screencast/start` | Inicia a gravação de tela |
| `GET /screencast/stop` | Para a gravação de tela |
| `GET /video/start` | Inicia a captura de vídeo |
| `GET /video/stop` | Para a captura de vídeo |
| `GET /ws/start` | Inicia o túnel WebSocket |
| `GET /ws/stop` | Para o túnel WebSocket |

### Loop amigável para agentes

O loop de servidor com menor atrito é:

1. `GET /tab/new?url=...`
2. `GET /page/state` (leve) ou `GET /snapshot?filter=interactive&format=compact` (completo)
3. `GET /action?action=click&ref=eN`
4. Repita — ou use `POST /batch` para operações de várias etapas em uma única chamada

Os parâmetros de consulta `url` e `expression` são decodificados via percent-encoding. Envie `X-Kuri-Session: my-agent` para persistir o contexto da aba no lado do servidor.

---

## 🧠 Habilidades

O repositório inclui uma área de habilidades extensível pelo usuário:

- `skills/kuri-skill.md` é a habilidade base do agente HTTP Kuri
- `skills/custom/` é reservado para suas próprias habilidades específicas do projeto
- `skills/custom/hackernews-page-2.md` é um exemplo concreto de habilidade personalizada
- `.claude/skills/kuri-server/SKILL.md` permanece sincronizado para habilidades de repositório no estilo Claude

A habilidade base agora também explica qual caminho de navegador usar:

- `kuri` API HTTP: automação de Chrome/CDP em produção com sessões, snapshots, ações, HAR, cookies e screenshots
- `kuri-fetch`: extração de fetch/texto independente, sem Chrome
- `kuri-browse`: navegação interativa via terminal
- `kuri-agent`: automação CLI via script contra o servidor Kuri
- `kuri-browser/`: runtime de navegador experimental separado, nativo em Zig, para trabalho de paridade

Para o CLI experimental do navegador:```bash
cd kuri-browser
zig build run -- render https://news.ycombinator.com --selector ".titleline a" --dump text
zig build run -- render https://todomvc.com/examples/react/dist/ --js --wait-eval "document.querySelectorAll('.todo-list li').length >= 1"
zig build run -- parity --offline
zig build run -- bench --offline
zig build run -- serve-cdp --port 9333

kuri-browser serve-cdp expõe descoberta HTTP no estilo Chrome, além de um roteador mínimo de JSON-RPC WebSocket para testes de fumaça de protocolo.

O eval em tempo de execução retorna objetos remotos CDP no formato V8, suportados pelo QuickJS; isso não adiciona uma dependência do V8 e ainda não é totalmente compatível com Playwright/Puppeteer.

As capturas de tela em kuri-browser atualmente são delegadas ao renderizador principal Kuri/CDP. Inicie ./zig-out/bin/kuri primeiro e depois:```bash cd kuri-browser zig build run -- screenshot https://example.com --out example.jpg --compress --kuri-base http://127.0.0.1:8080

`--compress` captura uma linha de base PNG e um candidato JPEG, grava o arquivo menor e relata a economia de bytes. Medição local atual em `https://example.com`: `20.523` bytes PNG para `18.183` bytes JPEG qualidade 50, economizando `2.340` bytes ou `11%`.

### Avançado

| Path | Descrição |
|------|-------------|
| `GET /diff/snapshot` | Delta compacto `+`/`~`/`-` em relação ao snapshot anterior (loop de ação do agente) |
| `GET /emulate` | Emulação de dispositivo |
| `GET /geolocation` | Definir geolocalização |
| `POST /upload` | Upload de arquivo |
| `GET /script/inject` | Injetar JavaScript |
| `GET /intercept/start` | Iniciar interceptação de requisições |
| `GET /intercept/stop` | Parar interceptação |
| `GET /screenshot/annotated` | Captura de tela com anotações de elementos |
| `GET /screenshot/diff` | Diferença visual entre capturas de tela |
| `GET /screencast/start` | Iniciar screencast |
| `GET /screencast/stop` | Parar screencast |
| `GET /video/start` | Iniciar gravação de vídeo |
| `GET /video/stop` | Parar gravação de vídeo |
| `GET /console` | Obter mensagens do console |
| `GET /stop` | Parar carregamento da página |
| `GET /get` | Busca HTTP direta (lado do servidor) |
| `GET /scrollintoview` | Rolar até um elemento referenciado ficar visível |
| `GET /drag` | Arrastar de uma referência para outra |
| `GET /keyboard/type` | Digitar texto com eventos de tecla |
| `GET /keyboard/inserttext` | Inserir texto diretamente |
| `GET /keydown` | Disparar evento keydown |
| `GET /keyup` | Disparar evento keyup |
| `GET /wait` | Aguardar estado de prontidão ou condições do elemento |
| `GET /tab/close` | Fechar uma aba |
| `GET /highlight` | Destacar um elemento por referência ou seletor |
| `GET /errors` | Obter erros de página/execução |
| `GET /set/offline` | Alternar emulação de rede offline |
| `GET /set/media` | Definir recursos de mídia emulados |
| `GET /set/credentials` | Definir credenciais de autenticação básica HTTP |
| `GET /find` | Encontrar correspondências de texto na página atual |
| `GET /trace/start` | Iniciar tracing do Chrome |
| `GET /trace/stop` | Parar tracing e retornar dados de trace |
| `GET /profiler/start` | Iniciar profiler JS |
| `GET /profiler/stop` | Parar profiler JS |
| `GET /inspect` | Inspecionar um elemento ou estado da página |
| `GET /set/viewport` | Definir tamanho do viewport |
| `GET /set/useragent` | Substituir user agent |
| `GET /dom/attributes` | Obter atributos do elemento |
| `GET /frames` | Listar árvore de frames |
| `GET /network` | Inspecionar estado/requisições de rede |

---

## 🛡️ Furtividade e Evasão de Bots

A Kuri aplica patches anti-detecção automaticamente na inicialização — nenhuma configuração manual é necessária.

### O que é aplicado

- **`Page.addScriptToEvaluateOnNewDocument`** — patches de stealth são executados antes de qualquer JS da página
- **`navigator.webdriver = false`** — oculta o sinalizador de automação no nível do Chromium (`--disable-blink-features=AutomationControlled`)
- **WebGL/Canvas/AudioContext spoofing** — derrota a detecção baseada em fingerprint
- **UA rotation** — 5 user agents realistas do Chrome/Safari/Firefox
- **chrome.csi/chrome.loadTimes** — stubs para verificações específicas da Akamai

### Detecção de bloqueio de bot

Navigate detecta automaticamente bloqueios e retorna fallback estruturado:```bash
curl -s "http://localhost:8080/navigate?tab_id=ABC&url=https://protected-site.com"
# If blocked:
# {"blocked":true,"blocker":"akamai","ref_code":"0.7d...",
#  "fallback":{"suggestions":["Open URL directly in browser","Use KURI_PROXY"]}}
# If ok: normal CDP response

Detecta: Akamai, Cloudflare, PerimeterX, DataDome, captcha genérico.

Suporte a proxy```bash

KURI_PROXY=socks5://user:pass@residential-proxy:1080 ./zig-out/bin/kuri KURI_PROXY=http://proxy:8080 ./zig-out/bin/kuri

### Sites testados

| Site | Proteção | Resultado |
|------|-----------|--------|
| Singapore Airlines | Akamai WAF | ✅ Contornado (era bloqueado antes da v0.4.0) |
| Shopee SG | Antifraude personalizado | ✅ Página carrega, redireciona para login |
| Google Flights | Nenhuma | ✅ Interação completa |
| Booking.com | PerimeterX | ⚠️ Precisa de proxy |

---

## 🔧 kuri-fetch

Buscador HTTP autônomo — sem Chrome, sem Playwright, sem npm. Vem como um binário de ~2 MB com QuickJS embutido para execução de JS.```bash
zig build fetch    # build + run

# Default: convert to Markdown
kuri-fetch https://example.com

# Extract links
kuri-fetch -d links https://news.ycombinator.com

# Structured JSON output
kuri-fetch --json https://example.com

# Execute inline scripts via QuickJS
kuri-fetch --js https://example.com

# Write to file, quiet mode
kuri-fetch -o page.md -q https://example.com

# Pipe-friendly: content → stdout, status → stderr
kuri-fetch -d text https://example.com | wc -w

Recursos

  • 5 modos de saídamarkdown, html, links, text, json
  • Motor JS QuickJS--js executa tags <script> inline
  • DOM stubsdocument.querySelector, getElementById, window.location, document.title, console.log, setTimeout (estilo SSR)
  • Defesa SSRF — bloqueia IPs privados, endpoints de metadados, esquemas não HTTP
  • Saída colorida — respeita NO_COLOR, TERM=dumb, --no-color, detecção de TTY
  • Saída de arquivo-o / --output com contagem de bytes + resumo de tempo
  • UA personalizado — flag --user-agent
  • Modo silencioso-q suprime o status do stderr

🌐 kuri-browse

Navegador de terminal interativo — navegue na web a partir do seu terminal. Não é necessário Chrome.```bash zig build browse # build + run

kuri-browse https://example.com

I don't see any source text to translate — the INPUT section is empty. Please provide the chunk content to translate.```
🌰 kuri-browse — terminal browser
→ loading https://example.com

# Example Domain
This domain is for use in documentation examples...
Learn more [1]

───── Links ─────
  [1] https://iana.org/domains/example

✓ 528 bytes, 1 links (133ms)
[nav] https://example.com> 1     ← type 1 to follow the link

Commands

CommandAction
<number>Seguir o link [N]
<url>Navegar (se contiver .)
:go <url>Navegar para URL
:back, :bVoltar no histórico
:forward, :fAvançar
:reload, :rRecarregar a página atual
:links, :lMostrar índice de links
/<term>Buscar na página (destaca correspondências)
:search <t>Buscar na página
:n, :nextRe-destacar a busca
:historyMostrar histórico de navegação
:help, :hMostrar todos os comandos
:quit, :qSair

Features

  • Renderização de markdown colorido — títulos, links, blocos de código, negrito, citações em bloco
  • Links numerados — cada link recebe [N], digite o número para segui-lo
  • Histórico de navegação — voltar/avançar como em um navegador real
  • Busca na página/term destaca todas as correspondências
  • Resolução de URLs relativas — segue links naturalmente entre páginas
  • Filtragem inteligente — ignora hrefs javascript: e mailto:

🤖 kuri-agent

CLI com script para automação do Chrome — controla o navegador comando por comando a partir do seu terminal ou scripts de shell. Compartilha o estado da sessão entre invocações via ~/.kuri/session.json.```bash zig build agent # build kuri-agent

1. Find a Chrome tab

kuri-agent tabs

→ ws://127.0.0.1:9222/devtools/page/ABC123 https://example.com

2. Attach to it

kuri-agent use ws://127.0.0.1:9222/devtools/page/ABC123

3. Navigate + interact

kuri-agent go https://example.com kuri-agent snap --interactive # → [{"ref":"e0","role":"link","name":"More info"}] kuri-agent click e0 kuri-agent shot # saves ~/.kuri/screenshots/.png

### Comandos

| Comando | Descrição |
|---------|-------------|
| `tabs [--port N]` | Listar abas do Chrome |
| `use <ws_url>` | Anexar a uma aba (salva a sessão) |
| `open [url] [--port N]` | Abrir uma nova aba (opcionalmente navegando para a URL) |
| `status` | Mostrar a sessão atual |
| `go <url>` | Navegar para URL |
| `snap [--interactive] [--json] [--text] [--depth N]` | Snapshot de acessibilidade, salva refs `eN` |
| `click <ref>` | Clicar no elemento por ref (eventos de mouse CDP, compatível com React) |
| `type <ref> <text>` | Digitar no elemento (eventos de tecla por caractere, compatível com React) |
| `fill <ref> <text>` | Preencher o valor do input |
| `select <ref> <value>` | Selecionar opção do dropdown |
| `hover <ref>` | Passar o mouse sobre o elemento |
| `focus <ref>` | Focar o elemento |
| `scroll` | Rolar a página |
| `viewport [width height]` | Obter ou definir dimensões da viewport |
| `eval <js>` | Avaliar JavaScript |
| `text [selector]` | Obter o texto da página |
| `shot [--out file.png]` | Captura de tela |
| `back` | Navegar de volta |
| `forward` | Navegar para frente |
| `reload` | Recarregar a página atual |
| `cookies` | Listar cookies com sinalizadores de segurança |
| `headers` | Verificar cabeçalhos de resposta de segurança |
| `audit` | Auditoria de segurança completa |
| `storage [local\|session\|all]` | Despejar localStorage / sessionStorage |
| `jwt` | Extrair e decodificar JWTs de cookies e do armazenamento |
| `fetch <method> <url> [--data <json>]` | Fetch autenticado usando cookies da página |
| `probe <url-template> <start> <end>` | Teste de IDOR: iterar IDs numéricos na URL |
| `grab <ref>` | Clicar na ref, interceptar `window.open`, seguir redirecionamento na mesma aba |
| `wait-for-tab [--port N]` | Verificar periodicamente uma nova aba, alternar a sessão automaticamente |
| `stealth` | Aplicar patches anti-detecção |
| `set-header <name> <value>` | Adicionar um cabeçalho personalizado a todas as requisições |
| `show-headers` | Mostrar cabeçalhos extras armazenados |
| `clear-headers` | Remover todos os cabeçalhos extras |
---

## 📱 kuri-mobile (iOS + Android)

CLI nativo em Zig para controlar simuladores iOS, iPhones reais (listagem + iniciar/encerrar) e dispositivos/emuladores Android — inspirado em [`mobile-device-mcp`](https://github.com/srmorete/mobile-device-mcp), reimplementado em Zig sem Bun/Node/Gradle/Xcode no caminho de build.```bash
cd kuri-mobile && zig build && cp zig-out/bin/kuri-mobile ../zig-out/bin/

# The main `kuri` binary forwards android/ios subcommands to kuri-mobile:
kuri ios list-devices                              # sims + real devices (usbmuxd, native)
kuri ios openurl https://example.com               # navigate Safari
kuri ios screenshot out.png                        # auto-picks booted sim
kuri ios launch com.apple.Preferences

kuri android list-devices                          # native Zig adb wire-protocol client
kuri android tap 540 1200
kuri android swipe 100 1500 100 500
kuri android screenshot phone.png
kuri android uitree                                # flat element list via uiautomator dump

O que é Zig nativo: protocolo host adb (sockets libc, framing de 4 hex sobre host:transport:/shell:/exec:), parser de árvore XML da UI Android, cliente plist ListDevices do usbmuxd. O que usa subprocessos: xcrun simctl (Simulador iOS), xcrun devicectl (inicializar/encerrar em dispositivos iOS reais). Sem driver por design: nenhum app no dispositivo é instalado, portanto o sandbox do run_code e o tap/uitree via XCUITest em dispositivos iOS reais estão intencionalmente não disponíveis. Consulte kuri-mobile/README.md para a matriz de paridade completa em relação ao upstream.


🔒 Testes de Segurança

O kuri-agent suporta trajetórias de segurança nativas do navegador — faça login uma vez e então execute reconhecimento e auditorias de cabeçalhos/cookies sem sair do terminal.

Trajetórias

Enumerar → Inspecionar — após autenticar, despeje os cookies de autenticação e verifique os sinalizadores de segurança:```bash kuri-agent go https://target.example.com/login kuri-agent snap --interactive kuri-agent fill e2 myuser kuri-agent fill e3 mypassword kuri-agent click e4 # submit login

kuri-agent cookies

cookies (3):

session_id domain=.example.com path=/ [Secure] [HttpOnly] [SameSite=Strict]

csrf_token domain=.example.com path=/ [Secure] [!HttpOnly]

tracking domain=.example.com path=/ [!Secure] [!HttpOnly]

**Auditoria de cabeçalhos** — verifique quais cabeçalhos de segurança o alvo envia:```bash
kuri-agent go https://target.example.com
kuri-agent headers
# → {"url":"https://...","status":200,"headers":{
#     "content-security-policy":"default-src 'self'",
#     "strict-transport-security":"max-age=31536000",
#     "x-frame-options":"(missing)",
#     "x-content-type-options":"nosniff", ...}}

Auditoria completa — HTTPS, cabeçalhos ausentes, cookies visíveis em JS de uma só vez:```bash kuri-agent audit

→ {"protocol":"https:","url":"https://...","score":6,

"issues":["MISSING:x-frame-options","COOKIES_EXPOSED_TO_JS:2"],

"headers":{"content-security-policy":"default-src 'self'", ...}}

**Trajetória cross-account** — use `eval` para reproduzir chamadas de API com tokens diferentes:```bash
# After login, grab the auth token from localStorage
kuri-agent eval "localStorage.getItem('token')"

# Probe a resource ID with the current session
kuri-agent eval "fetch('/api/assessments/42').then(r=>r.status)"

# Check for IDOR: does a different user's resource return 200 or 403?
kuri-agent eval "fetch('/api/assessments/99').then(r=>r.status)"

Formato do Relatório de Trajetória

kuri-agent emite JSON adequado para integração em pipeline. Cada comando de segurança emite uma única linha JSON — canalize via jq para triagem:```bash kuri-agent audit | jq '.issues[]' kuri-agent cookies | head -20 kuri-agent headers | jq '.headers | to_entries[] | select(.value == "(missing)") | .key'

---

## 🏗 Arquitetura```
┌──────────────────────────────────────────────────────────┐
│                     HTTP API Layer                        │
│         (std.http.Server, thread-per-connection)          │
├──────────────┬──────────────────┬────────────────────────┤
│   Browser    │  Crawler Engine  │   kuri-fetch / browse   │
│   Bridge     │                  │   (standalone CLIs)     │
├──────────────┼──────────────────┼────────────────────────┤
│ CDP Client   │ URL Validator    │ std.http.Client         │
│ Tab Registry │ HTML→Markdown    │ QuickJS JS Engine       │
│ A11y Snapshot│ Link Extractor   │ DOM Stubs (Layer 3)     │
│ Ref Cache    │ Text Extractor   │ SSRF Validator          │
│ HAR Recorder │                  │ Colored Renderer        │
│ Stealth JS   │                  │ History + REPL          │
├──────────────┴──────────────────┴────────────────────────┤
│  Chrome Lifecycle Manager                                 │
│  (launch, health-check, auto-restart, port detection)     │
└──────────────────────────────────────────────────────────┘

Modelo de Memória

  • Arena por requisição — toda a memória por requisição é liberada em uma única chamada deinit()
  • Sem GCGeneralPurposeAllocator em modo de depuração detecta todos os vazamentos
  • Cadeias de limpeza adequadasLauncher → Bridge → CdpClients → HarRecorders → Snapshots → Tabs
  • Guardas errdefer — falhas parciais são revertidas de forma limpa

Ciclo de Vida do Chrome

ModoComportamento
Gerenciado (sem CDP_URL)Inicia Chrome headless, encontra porta CDP livre, supervisiona, reinicia automaticamente em caso de falha (máx. 3 tentativas), encerra no desligamento
Externo (CDP_URL definido)Conecta-se ao Chrome existente, verifica a saúde via /json/version, NÃO encerra no desligamento

📁 Estrutura```

kuri/ ├── build.zig # Build system (Zig 0.16.0) ├── build.zig.zon # Package manifest + QuickJS dep ├── src/ │ ├── main.zig # CDP server entry point │ ├── fetch_main.zig # kuri-fetch CLI entry point │ ├── browse_main.zig # kuri-browse CLI entry point │ ├── js_engine.zig # QuickJS wrapper + DOM stubs │ ├── bench.zig # Benchmark harness │ ├── chrome/ │ │ └── launcher.zig # Chrome lifecycle manager │ ├── server/ │ │ ├── router.zig # HTTP route dispatch (40+ endpoints) │ │ ├── middleware.zig # Auth (constant-time comparison) │ │ └── response.zig # JSON response helpers │ ├── bridge/ │ │ ├── bridge.zig # Central state (tabs, CDP, HAR, snapshots) │ │ └── config.zig # Env var configuration │ ├── cdp/ │ │ ├── client.zig # CDP WebSocket client │ │ ├── websocket.zig # WebSocket frame codec │ │ ├── protocol.zig # CDP method constants │ │ ├── actions.zig # High-level CDP actions │ │ ├── stealth.zig # Bot detection bypass │ │ └── har.zig # HAR 1.2 recorder │ ├── snapshot/ │ │ ├── a11y.zig # A11y tree with interactive filter │ │ ├── diff.zig # Snapshot delta diffing │ │ └── ref_cache.zig # eN ref → node ID cache │ ├── crawler/ │ │ ├── validator.zig # SSRF defense, URL validation │ │ ├── markdown.zig # HTML → Markdown (SIMD tag counting) │ │ ├── fetcher.zig # Page fetching │ │ ├── extractor.zig # Readability extraction │ │ └── pipeline.zig # Parallel crawl pipeline │ ├── storage/ │ │ ├── local.zig # Local file writer │ │ └── r2.zig # R2/S3 uploader │ ├── util/ │ │ └── json.zig # JSON helpers │ └── test/ │ ├── harness.zig # Test HTTP client │ ├── integration.zig # Integration tests │ └── merjs_e2e.zig # E2E tests ├── js/ │ ├── stealth.js # Bot detection bypass │ └── readability.js # Content extraction ├── kuri-browser/ # Native Zig rendering experiments └── kuri-mobile/ # iOS + Android device control (Zig-native adb + usbmuxd) ├── src/ │ ├── common/ # io helpers, unified UI tree parser │ ├── android/ # adb wire protocol client, driver, CLI │ └── ios/ # simctl, usbmuxd, devicectl, CLI └── README.md # Full parity matrix vs mobile-device-mcp

---

## ⚙️ Configuração

| Env Var | Padrão | Descrição |
|---------|--------|-----------|
| `HOST` | `127.0.0.1` | Endereço de bind do servidor |
| `PORT` | `8080` | Porta do servidor |
| `CDP_URL` | *(nenhum)* | Conectar a um Chrome existente (`ws://...` ou `http://127.0.0.1:9222`) |
| `KURI_SECRET` | *(nenhum)* | Segredo de autenticação para requisições de API |
| `STATE_DIR` | `.kuri` | Diretório de estado da sessão |
| `REQUEST_TIMEOUT_MS` | `30000` | Timeout de requisição HTTP |
| `NAVIGATE_TIMEOUT_MS` | `30000` | Timeout de navegação |
| `STALE_TAB_INTERVAL_S` | `30` | Intervalo de limpeza de abas obsoletas |
| `NO_COLOR` | *(nenhum)* | Desativar saída CLI colorida |

---

## 💰 Custo de Tokens

Para uma tarefa de monitoramento de 50 páginas (dos benchmarks do Pinchtab):

| Método | Tokens | Custo ($) | Melhor para |
|--------|--------|-----------|-------------|
| `/text` | ~40.000 | $0,20 | Leitura intensiva (13× mais barato que capturas de tela) |
| `/snapshot?filter=interactive&format=compact` | ~40.000 | $0,20 | Interação de elementos com baixo uso de tokens |
| `/snapshot` (completo) | ~525.000 | $2,63 | Compreensão completa da página |
| `/screenshot` | ~100.000 | $1,00 | Verificação visual |

---

## 🤝 Contribuindo

Abra uma issue antes de enviar um PR grande para podermos alinhar a abordagem.

---```bash
git clone https://github.com/justrach/kuri.git
cd kuri
zig build test         # 252+ tests must pass
zig build test-fetch   # kuri-fetch tests (69 tests)
zig build test-browse  # kuri-browse tests (22 tests)

Consulte CONTRIBUTORS.md para obter diretrizes.


Créditos

ProjetoO que aproveitamos
agent-browsersistema de referência @eN, diffing de snapshots, padrões de gravação HAR
PinchtabArquitetura de controle de navegador para agentes de IA
PathikPadrões de rastreamento de alta performance
QuickJS-ng via mitchellh/zig-quickjs-ngMotor JS para kuri-fetch
LightpandaPioneiro em navegador headless nativo em Zig, padrões de compatibilidade com CDP
Zig 0.16.0Toda a stack

Licença

Apache-2.0

Categorias