Torna agli aggiornamenti
New releaseJul 31, 2026

kuri v0.5.1

Automazione del browser, web crawling e controllo di dispositivi iOS e Android per agenti AI. Snapshots CDP nativi di Zig e token-efficient, registrazione HAR, client nativo del wire-protocol adb e un fetcher autonomo.

Condividi

Kuri

Kuri 🌰

Stable release License Zig node_modules status

Installazione```sh

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

macOS arm64/x86_64 e Linux x86_64/arm64. Singolo binario, nessuna dipendenza runtime.

Download diretti: [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)

---

**Automazione browser e web crawling per agenti AI. Scritto in Zig. Zero Node.js.**

Automazione CDP · Snapshot A11y · Registrazione HAR · Fetcher standalone · Browser terminale interattivo · CLI agentica · Test di sicurezza · Controllo dispositivi iOS + Android

[Guida rapida](#-quick-start) · [Benchmark](#-benchmarks) · [kuri-agent](#-kuri-agent) · [Test di sicurezza](#-security-testing) · [API](#-http-api) · [Competenze](#-skills) · [Changelog](https://github.com/justrach/kuri/blob/HEAD/CHANGELOG.md)

> **Perché i team passano a Kuri:** le build `ReleaseFast` attuali su Apple Silicon restano sotto i 2 MB per binario, e una nuova esecuzione di Google Flights il 2026-04-23 ha misurato **3,392 token** per un ciclo completo di `kuri-agent` (`go→snap→click→snap→eval`). Le differenze tra strumenti andrebbero ricalcolate nello stesso ambiente prima di citare una percentuale.

---

## Perché Kuri vince per gli agenti

La maggior parte degli strumenti browser è stata costruita per ingegneri QA. Kuri è costruito per i cicli degli agenti: leggi la pagina, mantieni basso il costo in token, agisci su riferimenti stabili e vai avanti.

- **135 endpoint HTTP** — parità completa con agent-browser e browser-use, dall'ispezione React alle Core Web Vitals.
- **7-12% di token in meno** rispetto ad agent-browser su pagine reali grazie al formato ref `@eN` e al rendering a prefisso zero.
- **Osservazioni 44x più leggere** con `/page/state` (48 token) rispetto allo snapshot completo (2,124 token) per la stessa pagina di Google Flights.
- **Esecuzione batch** — `POST /batch` invia N comandi in un'unica chiamata HTTP, eliminando N-1 round-trip e N-1 passaggi LLM.
- **Compatibile con React** — eventi mouse CDP affidabili ed eventi tastiera per carattere attivano `onClick` e `onChange` di React 18/19.

### Token dello snapshot: Google Flights `SIN → TPE`

Nuova esecuzione il 2026-05-24 in questo workspace, misurata con `wc -c` e approssimazione `chars/4`.

| Tool / Modalità | Caratteri | ~Token | Nota |
|---|---:|---:|---|
| `kuri snap` (complete) | 8,499 | **2,124** | Tutti i nodi + ref interattivi |
| `kuri snap` (solo interattivi) | ~3,000 | **~750** | Ideale per i cicli degli agenti |
| `kuri /page/state` | 190 | **48** | Osservazione leggera (url, titolo, scroll%, conteggi) |
| snapshot agent-browser (stimato) | ~9,183 | **~2,295** | Overhead del formato `[ref=e0]` |

### Efficienza dei token: kuri vs agent-browser

| Pagina | token kuri | token agent-browser | Risparmio |
|---|---:|---:|---|
| example.com | 40 | 35 | -13% (pagina banale, agent-browser salta la root) |
| Hacker News | 386 | ~440 | **12% in meno** |
| Google Flights SIN→TPE | 2,124 | ~2,295 | **7% in meno** |

Il risparmio deriva dal formato compatto di kuri:
- ref `@e0` (3 caratteri) vs `[ref=e0]` (9 caratteri)
- Nessun prefisso `- ` per riga (risparmia 2 caratteri × numero di righe)
- Stessa indentazione, stesso filtraggio dei nodi

### Costo del flusso di lavoro completo: `go → snap → click → snap → eval`

| Strumento | Token per ciclo |
|---|---:|
| **kuri-agent** | **~3,400** |
| Con `/page/state` al posto del secondo snap | **~1,700** |
| Con `POST /batch` (tutto in un'unica chiamata) | **~1,700** (stessi token, 1 chiamata HTTP invece di 5) |

### kuri vs libretto

[libretto](https://github.com/saffron-health/libretto) (Playwright + Node) è il concorrente più vicino per costo di token per passaggio. Misurato testa a testa il 2026-07-04 — stesso Chrome, stessa scheda, conteggi reali con `tiktoken` `o200k_base` (metodologia completa e riproduzione: **[benchmarks/libretto_comparison.md](https://github.com/justrach/kuri/blob/HEAD/benchmarks/libretto_comparison.md)**). La ripartizione onesta:

| Aspetto | Vincitore | Dettaglio |
|---|---|---|
| Latenza per chiamata | **kuri** | 4–117 ms vs 1,344–1,500 ms (**13–376× più veloce** — server persistente vs Node per comando) |
| Token snapshot, pagina tipica | **kuri** | semplice 61 vs 151 (2.5×), articolo 265 vs 363 (1.37×) — grammatica più compatta |
| Token snapshot, lista grande | in parità | kuri di default 4,424 vs 813 — kuri emette tutti i 259 ref, libretto tronca di default. Con `limit=5` kuri genera 555 token (**1.46× sotto libretto**), 34 ref + marcatori `… +45 more` |
| Traiettoria (feed, 9 click) | **kuri**, di poco | 898 vs 939 token (base `limit=5` + loop di diff vs loop di exec) — parità-leggero vantaggio; la perdita 5.1× del mattino era la base non troncata |
| Esecuzioni ripetute | **libretto** | compila le traiettorie in uno script Playwright → replay a 0 token; kuri ripaga il loop a ogni esecuzione |

**Cosa kuri ha imparato studiando libretto** (tutto incluso in questa release): un loop diff-first (`take_snapshot_diff`, ~38 token/passaggio); un diff adattivo che ripiega su uno snapshot completo con un'intestazione `! page replaced` alla navigazione; righe di rimozione con sola identità; screenshot scritti su disco (viene restituito il percorso, i byte non entrano mai nel contesto); `get_page_state` via MCP; e — dopo la riscrittura di `parseA11yNodes` come vera traversata DFS dell'albero — **troncamento opt-in delle liste** (`/snapshot?limit=N`, una riga `… +K more` per esecuzione limitata), **riacquisizione con scope** (`scope=@ref`) e **indentazione gerarchica**, il tutto esposto anche come `uid`/`limit` su MCP `take_snapshot`. La traiettoria del feed con 9 click che costava 44,285 token con ingenui re-snapshot completi ora costa **898** con base troncata + diff — 49× più economica, e sotto i 939 di libretto.

> Le tabelle precedenti usano un'approssimazione dei token `chars/4`; il confronto con libretto usa conteggi reali di `tiktoken`. Ricalcola i numeri tra strumenti nel tuo ambiente prima di citare una percentuale.

### Dimensioni del binario e memoria

Misurato su Apple M4 Pro, macOS 26.4.1. I binari attuali sono stati compilati con `-Doptimize=ReleaseFast`.

| Binario | Dimensioni attuali |
|---|---:|
| `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) |

### La RSS è rimasta stabile durante la migrazione a Zig 0.16

Misurata sulla build attuale `v0.4.3` `ReleaseFast` con `/usr/bin/time -l`.

| Comando | RSS massima media `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 |

## Il Problema

Ogni strumento di automazione browser si trascina dietro Playwright (~300 MB), un runtime Node.js e una cascata di dipendenze npm. Il tuo agente AI vuole solo leggere una pagina, cliccare un pulsante e andare avanti.
**Kuri è un singolo binario Zig.** Quattro modalità, 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)

📦 Installazione

Installazione con una riga di comando (macOS / Linux)```sh

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

Rileva la tua piattaforma, scarica il binario corretto, installa in `~/.local/bin`.
I download provengono dal branch `release-channel` gestito da Kuri. I binari macOS sono firmati localmente con un certificato Developer ID. Gli asset delle Release di GitHub rispecchiano questi stessi tarball.

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

Scarica il binario nativo corretto per la tua piattaforma al momento dell'installazione.

Canale di rilascio

I binari stabili di Kuri vivono sul ramo release-channel e vengono serviti direttamente dagli URL raw di GitHub.

  • Installer stabile: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh
  • Manifesto stabile: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/latest.json
  • Vista del ramo: https://github.com/justrach/kuri/tree/release-channel/stable
  • Modello di download diretto: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/<version>/kuri-<version>-<target>.tar.gz

Manuale

Scarica il tarball per la tua piattaforma dal manifesto dei rilasci stabili o dalla pagina delle release di GitHub e decomprimilo nel tuo $PATH.

URL di installazione stabile:```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`.

### Supporto piattaforme

| Platform | Stato |
|---|---|
| macOS (`aarch64`, `x86_64`) | Binari precompilati, firmati e notarizzati |
| Linux (`aarch64`, `x86_64`) | Binari precompilati |
| Windows (`x86_64`) | **Sperimentale — solo cross-compile.** `zig build -Dtarget=x86_64-windows-gnu` è verificato tramite CI, ma l'automazione di Chrome, la daemonizzazione, lo spegnimento basato su segnali, la registrazione HAR e l'archivio di autenticazione basato su file sono tutti stub con `error.UnsupportedOnWindows` a runtime. Usa **WSL2** se ti serve il vero set di funzionalità. Monitorato in [#153](https://github.com/justrach/kuri/issues/153). |

Kuri si basa su primitive POSIX (`fork`, `clock_gettime`, socket raw) in diversi punti, quindi una porta Windows nativa completa è un lavoro impegnativo. La baseline di compilazione sopra indicata consente di eseguire i percorsi `--version`/`--help` e le operazioni puramente in memoria; le parti spinose (Chrome, socket, daemonize) richiedono implementazioni Win32 reali prima di poter essere rimosse dalla lista degli stub. Se vuoi occuparti di una di queste, metti +1 su [#153](https://github.com/justrach/kuri/issues/153) o apri una PR.

### Compilazione dal sorgente

Richiede [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

⚡ Avvio rapido

Requisiti: Zig ≥ 0.16.0 · Chrome/Chromium (per la modalità 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)

### Prima esecuzione, percorso più breve```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

Ciclo agente incentrato sulla sessione

Per un utilizzo HTTP in stile agente, preferisci un header di sessione insieme a /tab/new, /page/info e /snapshot invece di ripetere tab_id a ogni chiamata.```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"

C'è anche un sottile wrapper sperimentale in `tools/kuri_harness.py` se vuoi helper Python sopra la stessa superficie HTTP.

Se hai già Chrome in esecuzione con il debug remoto, imposta `CDP_URL` sull'endpoint WebSocket o 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"}, ...]

---

## 🌐 API HTTP

Tutti gli endpoint restituiscono JSON. Autenticazione opzionale tramite la variabile d'ambiente `KURI_SECRET`. **135 endpoint** — piena parità con agent-browser e browser-use.

### Nucleo

| Path | Descrizione |
|------|-------------|
| `GET /health` | Stato del server, numero di schede, versione |
| `GET /tabs` | Elenca tutte le schede registrate |
| `GET /discover` | Scopri automaticamente le schede di Chrome tramite CDP |
| `GET /tab/current` | Ottieni o imposta la scheda corrente per una `X-Kuri-Session` |
| `GET /page/info` | URL/titolo/ready-state/viewport/scroll in tempo reale per la scheda attiva |
| `GET /page/state` | Osservazione compatta della pagina: url, titolo, scroll%, viewport, conteggi di moduli/collegamenti/immagini/input |
| `POST /batch` | Esegue più comandi in una singola chiamata HTTP — restituisce un array di risultati |
| `GET /browdie` | 🌰 (uovo di Pasqua) |

### Controllo Browser

| Path | Parametri | Descrizione |
|------|--------|-------------|
| `GET /navigate` | `tab_id`, `url` | Porta la scheda all'URL |
| `GET /tab/new` | `url`, `activate`, `wait` | Crea una nuova scheda e opzionalmente idrata/imposta la scheda corrente |
| `GET /tab/close` | `tab_id` | Chiude una scheda |
| `GET /window/new` | `url`, `activate`, `wait` | Crea un nuovo target finestra/scheda |
| `GET /snapshot` | `tab_id`, `filter`, `format` | Snapshot dell'albero di accessibilità con riferimenti `eN`. Usa `filter=interactive&format=compact` per cicli per agent a basso consumo di token. |
| `GET /text` | `tab_id` | Estrae il testo della pagina |
| `GET /screenshot` | `tab_id`, `format`, `quality`, `save` | Cattura screenshot (base64); `save=true` scrive il PNG in `STATE_DIR/screenshots` e restituisce invece `{path,bytes}` |
| `GET /screenshot/annotated` | `tab_id` | Screenshot con etichette numerate degli elementi |
| `GET /screenshot/diff` | `tab_id`, `baseline` | Diff visivo tra lo screenshot corrente e quello di riferimento |
| `GET /action` | `tab_id`, `ref`, `action`, `value` | Clic/type/fill/select/scroll/hover/dblclick/check/uncheck/blur tramite ref |
| `GET /evaluate` | `tab_id`, `expression` | Esegue JavaScript |
| `GET /evalhandle` | `tab_id`, `expression` | Esegue JS, restituisce l'handle objectId (non il valore) |
| `GET /close` | `tab_id` | Chiude la scheda + pulizia |
| `GET /bringtofront` | `tab_id` | Porta la scheda in primo piano |

### Azioni

| Path | Parametri | Descrizione |
|------|--------|-------------|
| `GET /clear` | `ref` | Cancella il valore del campo di input |
| `GET /selectall` | `ref` | Seleziona tutto il testo in input/contenteditable |
| `GET /setvalue` | `ref`, `value` | Imposta direttamente il valore dell'input (bypassa gli eventi tastiera) |
| `GET /dispatch` | `ref`, `type` | Emette un evento DOM personalizzato sull'elemento |
| `GET /boundingbox` | `ref` | Ottiene il rettangolo di bounding dell'elemento (x, y, width, height, centerX, centerY) |
| `GET /getattribute` | `ref`, `name` | Ottiene l'attributo dell'elemento per nome |
| `GET /inputvalue` | `ref` | Ottiene il valore corrente dell'elemento di input |
| `GET /element/state` | `ref`, `check` | Booleano rapido: `exists`, `visible`, `enabled`, `checked` |
| `GET /find-element` | `text`/`role`/`label`/`placeholder`/`testid` | Localizzatore semantico — trova l'elemento senza snapshot |
| `GET /highlight` | `ref` o `selector` | Evidenzia l'elemento con un overlay |

### Mouse e Touch

| Path | Parametri | Descrizione |
|------|--------|-------------|
| `GET /mouse/move` | `x`, `y` | Sposta il mouse alle coordinate |
| `GET /mouse/down` | `x`, `y`, `button` | Pressione del pulsante del mouse |
| `GET /mouse/up` | `x`, `y`, `button` | Rilascio del pulsante del mouse |
| `GET /mouse/wheel` | `x`, `y`, `deltaX`, `deltaY` | Scorrimento con la rotella del mouse |
| `GET /tap` | `x`, `y` | Tocco (touchStart + touchEnd) |
| `GET /swipe` | `startX`, `startY`, `endX`, `endY` | Gesto di scorrimento touch |
| `GET /drag` | `src_ref`, `tgt_ref` | Trascina l'elemento sul target |

### Tastiera

| Path | Parametri | Descrizione |
|------|--------|-------------|
| `GET /keyboard/type` | `tab_id`, `text` | Digita testo tramite eventi tastiera |
| `GET /keyboard/inserttext` | `tab_id`, `text` | Inserisce testo direttamente |
| `GET /keydown` | `tab_id`, `key` | Evento di pressione tasto |
| `GET /keyup` | `tab_id`, `key` | Evento di rilascio tasto |

### Estrazione dei Contenuti

| Path | Descrizione |
|------|-------------|
| `GET /markdown` | Converte la pagina in Markdown |
| `GET /links` | Estrae tutti i collegamenti |
| `GET /dom/query` | Query tramite selettore CSS |
| `GET /dom/html` | Ottiene l'HTML dell'elemento |
| `GET /dom/attributes` | Ottiene gli attributi dell'elemento |
| `GET /pdf` | Stampa la pagina in PDF |
| `GET /find` | Ricerca testo nella pagina |

### Attesa

| Path | Parametri | Descrizione |
|------|--------|-------------|
| `GET /wait` | `selector`, `text`, `url`, `state`, `visible`, `timeout` | Attende selettore/testo/pattern URL/networkidle/stato di caricamento |
| `GET /wait/function` | `expression`, `timeout` | Attende che un'espressione JS arbitraria sia truthy |
| `GET /wait/download` | `timeout` | Attende il completamento del download del file |

### Gestione dei Dialoghi

| Path | Descrizione |
|------|-------------|
| `GET /dialog/auto` | Gestisce automaticamente tutti i dialoghi JS (accetta o respingi) |
| `GET /dialog/accept` | Accetta il dialogo corrente (con testo prompt opzionale) |
| `GET /dialog/dismiss` | Respinge il dialogo corrente |

### Rete e HAR

| Path | Descrizione |
|------|-------------|
| `GET /har/start` | Avvia la registrazione del traffico di rete |
| `GET /har/stop` | Ferma e restituisce JSON HAR 1.2 |
| `GET /har/status` | Stato della registrazione + numero di voci |
| `GET /har/replay` | Mappa API con snippet di codice curl/fetch/python |
| `GET /cookies` | Ottiene i cookie |
| `GET /cookies/set` | Imposta i cookie |
| `GET /cookies/delete` | Elimina i cookie |
| `GET /cookies/clear` | Cancella tutti i cookie |
| `GET /headers` | Imposta intestazioni di richiesta personalizzate |
| `GET /intercept/start` | Avvia l'intercettazione delle richieste |
| `GET /intercept/stop` | Ferma l'intercettazione delle richieste |
| `GET /intercept/requests` | Elenca le richieste intercettate |
| `GET /request/detail` | Ottiene il corpo della risposta per un ID di richiesta |
| `GET /response/body` | Recupera l'URL e restituisce il corpo della risposta |
| `GET /network` | Statistiche del traffico di rete |
| `GET /download` | Attiva il download di un file |

### Navigazione e Stato

| Path | Descrizione |
|------|-------------|
| `GET /back` | Indietro nel browser |
| `GET /forward` | Avanti nel browser |
| `GET /reload` | Ricarica la pagina |
| `GET /stop` | Ferma il caricamento della pagina |
| `GET /pushstate` | Navigazione SPA tramite history.pushState |
| `GET /storage/local` | Ottieni/imposta localStorage |
| `GET /storage/session` | Ottieni/imposta sessionStorage |
| `GET /storage/local/clear` | Cancella localStorage |
| `GET /storage/session/clear` | Cancella sessionStorage |
| `GET /session/save` | Salva la sessione del browser |
| `GET /session/load` | Ripristina la sessione del browser |
| `GET /session/list` | Elenca le sessioni salvate |
| `GET /setcontent` | Imposta direttamente l'HTML della pagina (POST) |

### Profili di Autenticazione

| Path | Descrizione |
|------|-------------|
| `GET /auth/profile/save` | Salva cookie + storage come profilo di autenticazione con nome |
| `GET /auth/profile/load` | Ripristina un profilo di autenticazione con nome in una scheda |
| `GET /auth/profile/list` | Elenca i profili di autenticazione salvati |
| `GET /auth/profile/delete` | Elimina un profilo di autenticazione salvato |
| `GET /auth/extract` | Estrae i token di autenticazione (JWT, cookie, intestazioni) |
| `GET /set/credentials` | Imposta le credenziali di autenticazione HTTP basic |

Su macOS, i segreti dei profili di autenticazione sono memorizzati nel Keychain dell'utente.

### Emulazione

| Path | Parametri | Descrizione |
|------|--------|-------------|
| `GET /emulate` | tipo di dispositivo, dimensioni schermo | Emulazione del dispositivo |
| `GET /set/viewport` | `width`, `height` | Imposta le dimensioni del viewport |
| `GET /set/useragent` | `ua` | Imposta lo user agent |
| `GET /set/media` | `media` | Emula il tipo di media |
| `GET /set/offline` | `offline` | Attiva/disattiva la modalità offline |
| `GET /geolocation` | `lat`, `lng` | Sovrascrive la geolocalizzazione |
| `GET /timezone` | `timezone` | Sovrascrive il fuso orario (es. `America/New_York`) |
| `GET /locale` | `locale` | Sovrascrive la locale (es. `en-US`) |
| `GET /permissions` | `name`, `state` | Concede/nega permessi (geolocalizzazione, notifiche, clipboard) |

### Script e Iniezione

| Path | Descrizione |
|------|-------------|
| `GET /script/inject` | Inietta JavaScript nella pagina (persiste tra le navigazioni) |
| `GET /initscript/remove` | Rimuove uno script init precedentemente iniettato |
| `GET /addstyle` | Inietta un foglio di stile CSS |
| `GET /expose` | Espone una funzione con nome al contesto JS della pagina |

### Ispezione React

| Path | Descrizione |
|------|-------------|
| `GET /react/tree` | Albero dei componenti React tramite hook DevTools |
| `GET /react/inspect` | Props e stato dei componenti React |
| `GET /react/renders` | Tracciamento dei render React (start/stop) |
| `GET /react/suspense` | Stato dei boundary React Suspense |

### Registrazione e Prestazioni

| Path | Descrizione |
|------|-------------|
| `GET /recording/start` | Registra le azioni dell'utente (click, input, navigazione) |
| `GET /recording/stop` | Ferma la registrazione + restituisce il log delle azioni |
| `GET /vitals` | Core Web Vitals (LCP, CLS, FID, TTFB, FCP, domInteractive) |
| `GET /perf/lcp` | Timing del Largest Contentful Paint |
| `GET /trace/start` | Avvia la traccia delle prestazioni |
| `GET /trace/stop` | Ferma la traccia |
| `GET /profiler/start` | Avvia il profiler JS |
| `GET /profiler/stop` | Ferma il profiler |

### Debug

| Path | Descrizione |
|------|-------------|
| `GET /debug/enable` | Abilita l'HUD di debug nella pagina e la modalità freeze opzionale |
| `GET /debug/disable` | Disabilita l'HUD di debug nella pagina |
| `GET /inspect` | Ispezione degli elementi |
| `GET /errors` | Raccoglie gli errori JS |
| `GET /console` | Legge i log della console |
| `GET /frames` | Elenca i frame della pagina |
| `GET /frame` | Passa al contesto iframe per nome o URL |
| `GET /mainframe` | Torna al frame principale |
| `GET /diff/snapshot` | Diff compatto `+`/`~`/`-` rispetto alla chiamata precedente per questa scheda — il ciclo di azioni a basso consumo di token (alias `/snapshot/changes`). In caso di modifica massiva, torna a uno snapshot completo con un'intestazione `! page replaced`. |
| `GET /diff/url` | Confronta due URL affiancati (navigate, snapshot, diff) |

### Streaming

| Path | Descrizione |
|------|-------------|
| `GET /screencast/start` | Avvia la registrazione dello schermo |
| `GET /screencast/stop` | Ferma la registrazione dello schermo |
| `GET /video/start` | Avvia la cattura video |
| `GET /video/stop` | Ferma la cattura video |
| `GET /ws/start` | Avvia il tunnel WebSocket |
| `GET /ws/stop` | Ferma il tunnel WebSocket |

### Ciclo per agent

Il ciclo server con il minimo attrito è:

1. `GET /tab/new?url=...`
2. `GET /page/state` (leggero) o `GET /snapshot?filter=interactive&format=compact` (completo)
3. `GET /action?action=click&ref=eN`
4. Ripeti — oppure usa `POST /batch` per operazioni multi-passaggio in una singola chiamata

I parametri query `url` ed `expression` vengono decodificati in percentuale. Invia `X-Kuri-Session: my-agent` per persistire il contesto della scheda lato server.

---

## 🧠 Skills

Il repository include un'area di skill estendibile dall'utente:

- `skills/kuri-skill.md` è la skill di base dell'agente HTTP Kuri
- `skills/custom/` è riservata alle tue skill specifiche del progetto
- `skills/custom/hackernews-page-2.md` è un esempio concreto di skill personalizzata
- `.claude/skills/kuri-server/SKILL.md` resta sincronizzato per le skill di repository in stile Claude

La skill di base ora spiega anche quale percorso del browser utilizzare:

- `kuri` API HTTP: automazione Chrome/CDP in produzione con sessioni, snapshot, azioni, HAR, cookie e screenshot
- `kuri-fetch`: fetch standalone senza Chrome/estrazione testo
- `kuri-browse`: navigazione interattiva da terminale
- `kuri-agent`: automazione CLI scriptabile contro il server Kuri
- `kuri-browser/`: runtime browser sperimentale separato nativo Zig per lavoro di parità

Per la CLI del browser sperimentale:```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 espone il discovery HTTP in stile Chrome e un router JSON-RPC WebSocket minimale per test di fumo del protocollo. La valutazione runtime restituisce oggetti remoti CDP a forma di V8 supportati da QuickJS; questo non aggiunge una dipendenza da V8 e non è ancora compatibile al 100% con Playwright/Puppeteer.

Gli screenshot in kuri-browser attualmente delegano al renderer Kuri/CDP principale. Prima avvia ./zig-out/bin/kuri, quindi:```bash cd kuri-browser zig build run -- screenshot https://example.com --out example.jpg --compress --kuri-base http://127.0.0.1:8080

`--compress` acquisisce una baseline PNG e un candidato JPEG, scrive il file più piccolo e riporta il risparmio in byte. Misurazione locale attuale su `https://example.com`: da `20,523` byte PNG a `18,183` byte JPEG qualità 50, con un risparmio di `2,340` byte, pari all'`11%`.

### Avanzate

| Percorso | Descrizione |
|------|-------------|
| `GET /diff/snapshot` | Delta compatto `+`/`~`/`-` rispetto allo snapshot precedente (loop delle azioni dell'agente) |
| `GET /emulate` | Emulazione del dispositivo |
| `GET /geolocation` | Imposta la geolocalizzazione |
| `POST /upload` | Caricamento di file |
| `GET /script/inject` | Inietta JavaScript |
| `GET /intercept/start` | Avvia l'intercettazione delle richieste |
| `GET /intercept/stop` | Interrompi l'intercettazione |
| `GET /screenshot/annotated` | Screenshot con annotazioni degli elementi |
| `GET /screenshot/diff` | Diff visivo tra screenshot |
| `GET /screencast/start` | Avvia lo screencast |
| `GET /screencast/stop` | Interrompi lo screencast |
| `GET /video/start` | Avvia la registrazione video |
| `GET /video/stop` | Interrompi la registrazione video |
| `GET /console` | Ottieni i messaggi della console |
| `GET /stop` | Interrompi il caricamento della pagina |
| `GET /get` | Fetch HTTP diretto (lato server) |
| `GET /scrollintoview` | Scorri fino a portare un elemento referenziato in vista |
| `GET /drag` | Trascina da un ref a un altro |
| `GET /keyboard/type` | Digita testo con eventi da tastiera |
| `GET /keyboard/inserttext` | Inserisci testo direttamente |
| `GET /keydown` | Invia un evento keydown |
| `GET /keyup` | Invia un evento keyup |
| `GET /wait` | Attendi lo stato ready o condizioni sugli elementi |
| `GET /tab/close` | Chiudi una scheda |
| `GET /highlight` | Evidenzia un elemento tramite ref o selettore |
| `GET /errors` | Ottieni gli errori di pagina/runtime |
| `GET /set/offline` | Attiva/disattiva l'emulazione di rete offline |
| `GET /set/media` | Imposta le funzionalità media emulate |
| `GET /set/credentials` | Imposta le credenziali di autenticazione HTTP Basic |
| `GET /find` | Trova corrispondenze di testo nella pagina corrente |
| `GET /trace/start` | Avvia il tracing di Chrome |
| `GET /trace/stop` | Interrompi il tracing e restituisci i dati del trace |
| `GET /profiler/start` | Avvia il profiler JS |
| `GET /profiler/stop` | Interrompi il profiler JS |
| `GET /inspect` | Ispeziona un elemento o lo stato della pagina |
| `GET /set/viewport` | Imposta la dimensione del viewport |
| `GET /set/useragent` | Sovrascrivi lo user agent |
| `GET /dom/attributes` | Ottieni gli attributi degli elementi |
| `GET /frames` | Elenca l'albero dei frame |
| `GET /network` | Ispeziona lo stato/le richieste di rete |

---

## 🛡️ Stealth ed elusione dei bot

Kuri applica automaticamente le patch anti-rilevamento all'avvio — nessuna configurazione manuale richiesta.

### Cosa viene applicato

- **`Page.addScriptToEvaluateOnNewDocument`** — le patch stealth vengono eseguite prima di qualsiasi JS della pagina
- **navigator.webdriver = false** — nasconde il flag di automazione a livello di Chromium (`--disable-blink-features=AutomationControlled`)
- **Spoofing di WebGL/Canvas/AudioContext** — sconfigge il rilevamento basato sul fingerprint
- **Rotazione UA** — 5 user agent realistici di Chrome/Safari/Firefox
- **chrome.csi/chrome.loadTimes** — stub per i controlli specifici di Akamai

### Rilevamento dei blocchi bot

Navigate rileva automaticamente i blocchi e restituisce un fallback strutturato:```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

Rileva: Akamai, Cloudflare, PerimeterX, DataDome, captcha generico.

Supporto proxy```bash

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

### Siti testati

| Sito | Protezione | Risultato |
|------|-----------|--------|
| Singapore Airlines | Akamai WAF | ✅ Bypassato (era bloccato prima della v0.4.0) |
| Shopee SG | Anti-frode personalizzato | ✅ La pagina si carica, reindirizza al login |
| Google Flights | Nessuna | ✅ Interazione completa |
| Booking.com | PerimeterX | ⚠️ Richiede proxy |

---

## 🔧 kuri-fetch

Fetcher HTTP autonomo — niente Chrome, niente Playwright, niente npm. Viene distribuito come binario di ~2 MB con QuickJS integrato per l'esecuzione di 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

Funzionalità

  • 5 modalità di outputmarkdown, html, links, text, json
  • Motore JS QuickJS--js esegue i tag <script> inline
  • Stub DOMdocument.querySelector, getElementById, window.location, document.title, console.log, setTimeout (in stile SSR)
  • Difesa SSRF — blocca IP privati, endpoint dei metadati, schemi non HTTP
  • Output colorato — rispetta NO_COLOR, TERM=dumb, --no-color, rilevamento TTY
  • Output su file-o / --output con conteggio byte + riepilogo dei tempi
  • UA personalizzato — flag --user-agent
  • Modalità silenziosa-q sopprime lo stato su stderr

🌐 kuri-browse

Browser interattivo da terminale — naviga il web dal tuo terminale. Nessuna necessità di Chrome.```bash zig build browse # build + run

kuri-browse https://example.com

Please provide the Markdown 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>Segui il link [N]
<url>Naviga (se contiene .)
:go <url>Vai all'URL
:back, :bIndietro nella cronologia
:forward, :fAvanti
:reload, :rRicarica la pagina corrente
:links, :lMostra l'indice dei link
/<term>Cerca nella pagina (evidenzia le corrispondenze)
:search <t>Cerca nella pagina
:n, :nextRi-evidenzia la ricerca
:historyMostra la cronologia di navigazione
:help, :hMostra tutti i comandi
:quit, :qEsci

Caratteristiche

  • Rendering markdown a colori — intestazioni, link, blocchi di codice, grassetto, citazioni
  • Link numerati — ogni link riceve [N], digita il numero per seguirlo
  • Cronologia di navigazione — indietro/avanti come un vero browser
  • Ricerca nella pagina/term evidenzia tutte le corrispondenze
  • Risoluzione degli URL relativi — segue i link in modo naturale tra le pagine
  • Filtraggio intelligente — salta gli href javascript: e mailto:

🤖 kuri-agent

CLI scriptabile per l'automazione di Chrome — guida il browser comando per comando dal tuo terminale o dagli script di shell. Condivide lo stato della sessione tra le invocazioni tramite ~/.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

### Comandi

| Comando | Descrizione |
|---------|-------------|
| `tabs [--port N]` | Elenca le schede di Chrome |
| `use <ws_url>` | Collegati a una scheda (salva la sessione) |
| `open [url] [--port N]` | Apre una nuova scheda (facoltativamente naviga all'URL) |
| `status` | Mostra la sessione corrente |
| `go <url>` | Naviga all'URL |
| `snap [--interactive] [--json] [--text] [--depth N]` | Snapshot di accessibilità, salva i riferimenti `eN` |
| `click <ref>` | Clicca l'elemento tramite ref (eventi mouse CDP, compatibile con React) |
| `type <ref> <text>` | Digita nell'elemento (eventi chiave per carattere, compatibile con React) |
| `fill <ref> <text>` | Compila il valore dell'input |
| `select <ref> <value>` | Seleziona un'opzione del menu a discesa |
| `hover <ref>` | Passa il mouse sull'elemento |
| `focus <ref>` | Metti a fuoco l'elemento |
| `scroll` | Scorri la pagina |
| `viewport [width height]` | Ottieni o imposta le dimensioni del viewport |
| `eval <js>` | Valuta JavaScript |
| `text [selector]` | Ottieni il testo della pagina |
| `shot [--out file.png]` | Cattura schermata |
| `back` | Torna indietro |
| `forward` | Vai avanti |
| `reload` | Ricarica la pagina corrente |
| `cookies` | Elenca i cookie con flag di sicurezza |
| `headers` | Controlla le intestazioni di risposta di sicurezza |
| `audit` | Audit di sicurezza completo |
| `storage [local\|session\|all]` | Esporta localStorage / sessionStorage |
| `jwt` | Estrae e decodifica i JWT da cookie e storage |
| `fetch <method> <url> [--data <json>]` | Fetch autenticato utilizzando i cookie della pagina |
| `probe <url-template> <start> <end>` | Sonda IDOR: itera gli ID numerici nell'URL |
| `grab <ref>` | Clicca il ref, intercetta `window.open`, segui il redirect nella scheda |
| `wait-for-tab [--port N]` | Interroga periodicamente una nuova scheda, passa automaticamente alla sessione |
| `stealth` | Applica patch anti-rilevamento |
| `set-header <name> <value>` | Aggiungi un'intestazione personalizzata a tutte le richieste |
| `show-headers` | Mostra le intestazioni extra memorizzate |
| `clear-headers` | Rimuovi tutte le intestazioni extra |
---

## 📱 kuri-mobile (iOS + Android)

CLI Zig nativo per gestire simulatori iOS, iPhone reali (elenco + avvio/terminazione) e dispositivi/emulatori Android — ispirato a [`mobile-device-mcp`](https://github.com/srmorete/mobile-device-mcp), reimplementato in Zig senza Bun/Node/Gradle/Xcode nel percorso di 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

Cosa è nativo in Zig: protocollo host di adb (socket libc, framing a 4 cifre esadecimali su host:transport:/shell:/exec:), parser dell'albero UI XML Android, client plist ListDevices di usbmuxd. Comandi eseguiti esternamente: xcrun simctl (Simulatore iOS), xcrun devicectl (avvio/terminazione di dispositivi iOS reali). Senza driver per progettazione: nessuna app viene installata sul dispositivo, quindi le sandbox di run_code e il tap/uitree basato su XCUITest sui dispositivi iOS reali sono intenzionalmente non disponibili. Vedi kuri-mobile/README.md per la matrice di parità completa rispetto all'upstream.


🔒 Test di sicurezza

kuri-agent supporta traiettorie di sicurezza native del browser — accedi una volta, poi esegui ricognizione e audit di header/cookie senza lasciare il terminale.

Traiettorie

Enumerazione → Ispezione — dopo l'autenticazione, estrai i cookie di autenticazione e controlla i flag di sicurezza:```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]

**Header audit** — controlla quali header di sicurezza invia il target:```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", ...}}

Audit completo — HTTPS, intestazioni mancanti, cookie visibili a JS in un colpo solo:```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'", ...}}

**Traiettoria cross-account** — usa `eval` per riprodurre chiamate API con token diversi:```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 del Report di Traiettoria

kuri-agent genera JSON adatto per l'integrazione con pipeline. Ogni comando di sicurezza emette una singola riga JSON — passa attraverso jq per il triage:```bash kuri-agent audit | jq '.issues[]' kuri-agent cookies | head -20 kuri-agent headers | jq '.headers | to_entries[] | select(.value == "(missing)") | .key'

---


## 🏗 Architettura```
┌──────────────────────────────────────────────────────────┐
│                     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)     │
└──────────────────────────────────────────────────────────┘

Modello di memoria

  • Arena-per-richiesta — tutta la memoria per richiesta liberata in una singola chiamata deinit()
  • No GCGeneralPurposeAllocator in modalità debug cattura ogni leak
  • Catene di pulizia corretteLauncher → Bridge → CdpClients → HarRecorders → Snapshots → Tabs
  • Guardie errdefer — i fallimenti parziali eseguono il rollback senza problemi

Ciclo di vita di Chrome

ModalitàComportamento
Gestito (nessun CDP_URL)Avvia Chrome headless, trova una porta CDP libera, supervisiona, riavvia automaticamente in caso di crash (max 3 tentativi), termina allo spegnimento
Esterno (CDP_URL impostato)Si collega a un Chrome esistente, verifica la salute tramite /json/version, NON termina allo spegnimento

📁 Struttura```

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

---

## ⚙️ Configurazione

| Variabile d'ambiente | Predefinito | Descrizione |
|---------|---------|-------------|
| `HOST` | `127.0.0.1` | Indirizzo di bind del server |
| `PORT` | `8080` | Porta del server |
| `CDP_URL` | *(none)* | Connetti a un Chrome esistente (`ws://...` o `http://127.0.0.1:9222`) |
| `KURI_SECRET` | *(none)* | Segreto di autenticazione per le richieste API |
| `STATE_DIR` | `.kuri` | Directory dello stato della sessione |
| `REQUEST_TIMEOUT_MS` | `30000` | Timeout delle richieste HTTP |
| `NAVIGATE_TIMEOUT_MS` | `30000` | Timeout di navigazione |
| `STALE_TAB_INTERVAL_S` | `30` | Intervallo di pulizia delle schede non aggiornate |
| `NO_COLOR` | *(none)* | Disabilita l'output CLI colorato |

---

## 💰 Costo dei token

Per un'attività di monitoraggio di 50 pagine (dai benchmark Pinchtab):

| Metodo | Token | Costo ($) | Ideale per |
|--------|--------|----------|----------|
| `/text` | ~40,000 | $0.20 | Lettura intensiva (13× più economico degli screenshot) |
| `/snapshot?filter=interactive&format=compact` | ~40,000 | $0.20 | Interazione con elementi a basso consumo di token |
| `/snapshot` (completo) | ~525,000 | $2.63 | Comprensione completa della pagina |
| `/screenshot` | ~100,000 | $1.00 | Verifica visiva |

---

## 🤝 Contributi

Apri una issue prima di inviare una PR corposa, così possiamo allinearci sull'approccio.```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)

Vedi CONTRIBUTORS.md per le linee guida.


Crediti

ProgettoCosa abbiamo preso in prestito
agent-browserSistema di ref @eN, diffing degli snapshot, pattern di registrazione HAR
PinchtabArchitettura di controllo del browser per agenti AI
PathikPattern di crawling ad alte prestazioni
QuickJS-ng via mitchellh/zig-quickjs-ngMotore JS per kuri-fetch
LightpandaPioniere dei browser headless nativi Zig, pattern di compatibilità CDP
Zig 0.16.0L'intero stack

Licenza

Apache-2.0

Categorie