
Automatisation de navigateur, exploration du web et contrôle d'appareils iOS + Android pour les agents IA. Instantanés CDP natifs Zig et économes en jetons, enregistrement HAR, client natif du protocole filaire adb et un fetcher autonome.
<p align="center">
<img src="https://assets.kitploit.com/production/public/readmes/13639/7915bba5fb25229c11f59482cfcd4a0eaf2945ee066dbf5cec395df880b53268.png" alt="Kuri" width="200" />
</p>
<h1 align="center">Kuri 🌰</h1>
<p align="center">
<a href="https://kuri.trilok.ai/download/latest.json"><img src="https://img.shields.io/badge/stable-v0.6.1-brightgreen?style=flat-square" alt="Stable release"></a>
<a href="https://github.com/justrach/kuri/blob/main/LICENSE"><img src="https://img.shields.io/github/license/justrach/kuri?style=flat-square" alt="License"></a>
<img src="https://img.shields.io/badge/zig-0.16.0-f7a41d?style=flat-square" alt="Zig">
<img src="https://img.shields.io/badge/node__modules-0_files-brightgreen?style=flat-square" alt="node_modules">
<img src="https://img.shields.io/badge/status-stable-brightgreen?style=flat-square" alt="status">
</p>
## Installation
```sh
curl -fsSL https://kuri.trilok.ai/download | sh
```
macOS arm64/x86_64 et Linux x86_64/arm64. Binaire unique, aucune dépendance d'exécution.
Téléchargements directs : [macOS arm64](https://kuri.trilok.ai/download/v0.6.1/kuri-v0.6.1-aarch64-macos.tar.gz) · [macOS x86_64](https://kuri.trilok.ai/download/v0.6.1/kuri-v0.6.1-x86_64-macos.tar.gz) · [Linux x86_64](https://kuri.trilok.ai/download/v0.6.1/kuri-v0.6.1-x86_64-linux.tar.gz) · [Linux arm64](https://kuri.trilok.ai/download/v0.6.1/kuri-v0.6.1-aarch64-linux.tar.gz)
---
**Automatisation de navigateur et crawling web pour agents IA. Écrit en Zig. Zéro Node.js.**
Automatisation CDP · Instantanés A11y · Enregistrement HAR · Récupérateur autonome · Navigateur terminal interactif · CLI agentique · Tests de sécurité · Contrôle d'appareils iOS + Android
[Démarrage rapide](#-quick-start) · [Benchmarks](#-benchmarks) · [kuri-agent](#-kuri-agent) · [Tests de sécurité](#-security-testing) · [API](#-http-api) · [Skills](#-skills) · [Changelog](https://github.com/justrach/kuri/blob/main/CHANGELOG.md)
> **Pourquoi les équipes passent à Kuri :** les builds `ReleaseFast` actuels sur Apple Silicon restent sous les 2 Mo par binaire, et une nouvelle exécution de Google Flights le 2026-04-23 a mesuré **3 392 tokens** pour une boucle `kuri-agent` complète (`go→snap→click→snap→eval`). Les écarts entre outils doivent être remesurés dans le même environnement avant de citer un pourcentage.
---
## Pourquoi Kuri gagne pour les agents
La plupart des outils d'automatisation de navigateur ont été conçus pour les ingénieurs QA. Kuri est conçu pour les boucles d'agents : lire la page, garder un coût en tokens faible, agir sur des références stables, et passer à la suite.
- **135 endpoints HTTP** — parité complète avec agent-browser et browser-use, de l'inspection React aux Core Web Vitals.
- **7 à 12 % de tokens en moins** qu'agent-browser sur des pages réelles grâce au format de référence `@eN` et au rendu sans préfixe.
- **Observations 44× plus légères** avec `/page/state` (48 tokens) contre un instantané complet (2 124 tokens) pour la même page Google Flights.
- **Exécution par lots** — `POST /batch` envoie N commandes en un seul appel HTTP, éliminant N-1 allers-retours et N-1 tours de LLM.
- **Compatible React** — les événements souris CDP de confiance et les événements clavier caractère par caractère déclenchent les `onClick` et `onChange` de React 18/19.
### Tokens d'instantané : Google Flights `SIN → TPE`
Nouvelle exécution le 2026-05-24 dans cet espace de travail, mesurée avec `wc -c` et l'approximation `chars/4`.
| Outil / Mode | Caractères | ~Tokens | Remarque |
|---|---:|---:|---|
| `kuri snap` (complet) | 8 499 | **2 124** | Tous les nœuds + références interactives |
| `kuri snap` (interactif uniquement) | ~3 000 | **~750** | Idéal pour les boucles d'agents |
| `kuri /page/state` | 190 | **48** | Observation légère (url, title, scroll%, counts) |
| agent-browser snap (estimé) | ~9 183 | **~2 295** | Surcoût du format `[ref=e0]` |
### Efficacité des tokens : kuri vs agent-browser
| Page | tokens kuri | tokens agent-browser | Économie |
|---|---:|---:|---|
| example.com | 40 | 35 | -13 % (page triviale, agent-browser ignore la racine) |
| Hacker News | 386 | ~440 | **12 % de moins** |
| Google Flights SIN→TPE | 2 124 | ~2 295 | **7 % de moins** |
Les économies proviennent du format compact de kuri :
- Références `@e0` (3 caractères) contre `[ref=e0]` (9 caractères)
- Aucun préfixe `- ` par ligne (économise 2 caractères × nombre de lignes)
- Même indentation, même filtrage des nœuds
### Coût complet du workflow : `go → snap → click → snap → eval`
| Outil | Tokens par cycle |
|---|---:|
| **kuri-agent** | **~3 400** |
| Avec `/page/state` au lieu du second snap | **~1 700** |
| Avec `POST /batch` (tout en un seul appel) | **~1 700** (mêmes tokens, 1 appel HTTP au lieu de 5) |
### kuri vs libretto
[libretto](https://github.com/saffron-health/libretto) (Playwright + Node) est le concurrent le plus proche sur le coût en tokens par étape. Mesuré en confrontation directe le 2026-07-04 — même Chrome, même onglet, comptages réels `tiktoken` `o200k_base` (méthodologie complète et reproduction : **[benchmarks/libretto_comparison.md](https://github.com/justrach/kuri/blob/main/benchmarks/libretto_comparison.md)**). Le partage honnête :
| Axe | Gagnant | Détail |
|---|---|---|
| Latence par appel | **kuri** | 4–117 ms contre 1 344–1 500 ms (**13–376× plus rapide** — serveur persistant contre Node-par-commande) |
| Tokens d'instantané, page typique | **kuri** | simple 61 contre 151 (2,5×), article 265 contre 363 (1,37×) — grammaire plus serrée |
| Tokens d'instantané, grande liste | partagé | kuri par défaut 4 424 contre 813 — kuri émet les 259 références, libretto tronque par défaut. Avec `limit=5`, kuri rend 555 tokens (**1,46× sous libretto**), 34 références + marqueurs `… +45 more` |
| Trajectoire (feed, 9 clics) | **kuri**, de justesse | 898 contre 939 tokens (base `limit=5` + boucle de diff contre boucle exec) — parité à léger avantage ; la perte de 5,1× du matin était due à la base non tronquée |
| Exécutions répétées | **libretto** | compile les trajectoires en un script Playwright → rejeux à 0 token ; kuri repaie la boucle à chaque exécution |
**Ce que kuri a gagné en étudiant libretto** (tout livré dans cette version) : une boucle diff-first (`take_snapshot_diff`, ~38 tokens/étape) ; un diff adaptatif qui retombe sur un instantané complet avec un en-tête `! page replaced` lors d'une navigation ; des lignes de suppression d'identité uniquement ; des captures d'écran écrites sur disque (chemin retourné, les octets n'entrent jamais dans le contexte) ; `get_page_state` via MCP ; et — après réécriture de `parseA11yNodes` en véritable parcours d'arbre DFS — la **troncature de liste optionnelle** (`/snapshot?limit=N`, une ligne `… +K more` par exécution plafonnée), la **recapture ciblée** (`scope=@ref`), et l'**indentation hiérarchique**, également exposées comme `uid`/`limit` sur le `take_snapshot` MCP. La trajectoire de feed à 9 clics qui coûtait 44 285 tokens avec des re-snapshots complets naïfs coûte **898** avec une base tronquée + diffs — 49× moins cher, et au-delà des 939 de libretto.
> Les tableaux plus anciens ci-dessus utilisent une approximation de tokens `chars/4` ; la comparaison avec libretto utilise de vrais comptages `tiktoken`. Remesurez les chiffres entre outils dans votre propre environnement avant de citer un pourcentage.
### Taille des binaires et mémoire
Mesuré sur Apple M4 Pro, macOS 26.4.1. Les binaires actuels ont été compilés avec `-Doptimize=ReleaseFast`.
| Binaire | Taille actuelle |
|---|---:|
| `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) |
### Le RSS est resté stable durant la migration vers Zig 0.16
Mesuré sur le build `ReleaseFast` actuel `v0.4.3` avec `/usr/bin/time -l`.
| Commande | RSS max moyen `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 |
## Le problème
Chaque outil d'automatisation de navigateur traîne Playwright (~300 Mo), un runtime Node.js et une cascade de dépendances npm. Votre agent IA veut simplement lire une page, cliquer sur un bouton et passer à la suite.
**Kuri est un binaire Zig unique.** Quatre modes, zéro 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)
```
---
## 📦 Installation
### Installation en une ligne (macOS / Linux)
```sh
curl -fsSL https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh | sh
```
Détecte votre plateforme, télécharge le bon binaire, installe dans `~/.local/bin`.
Les téléchargements proviennent de la branche `release-channel` auto-gérée de Kuri. Les binaires macOS sont signés localement avec un certificat Developer ID. Les ressources GitHub Release reflètent ces mêmes tarballs.
### bun / npm
```sh
bun install -g kuri-agent
# or: npm install -g kuri-agent
```
Télécharge le binaire natif correct pour votre plateforme au moment de l'installation.
### Canal de publication
Les binaires stables de Kuri résident sur la branche `release-channel` et sont servis directement depuis les URL brutes de GitHub.
- Installateur stable : `https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh`
- Manifeste stable : `https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/latest.json`
- Vue de la branche : `https://github.com/justrach/kuri/tree/release-channel/stable`
- Modèle de téléchargement direct : `https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/<version>/kuri-<version>-<target>.tar.gz`
### Manuel
Téléchargez l'archive tar pour votre plateforme depuis le [manifeste de publication stable](https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/latest.json) ou depuis la [page GitHub Releases](https://github.com/justrach/kuri/releases) et décompressez-la dans votre `$PATH`.
URL d'installation stable :
```sh
curl -fsSL https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh | sh
```
Le manifeste inclut les URL exactes des ressources ainsi que les sommes de contrôle SHA-256 pour `aarch64-linux`, `x86_64-linux`, `aarch64-macos` et `x86_64-macos`.
### Prise en charge des plateformes
| Plateforme | Statut |
|---|---|
| macOS (`aarch64`, `x86_64`) | Binaires précompilés, signés + notariés |
| Linux (`aarch64`, `x86_64`) | Binaires précompilés |
| Windows (`x86_64`) | **Expérimental — compilation croisée uniquement.** `zig build -Dtarget=x86_64-windows-gnu` est vérifié par CI, mais l'automatisation Chrome, la daemonisation, l'arrêt basé sur les signaux, l'enregistrement HAR et le stockage d'authentification basé sur des fichiers sont tous stubés avec `error.UnsupportedOnWindows` à l'exécution. Utilisez **WSL2** si vous avez besoin de l'ensemble des fonctionnalités réelles. Suivi dans [#153](https://github.com/justrach/kuri/issues/153). |
Kuri s'appuie sur des primitives POSIX (`fork`, `clock_gettime`, sockets bruts) à plusieurs endroits, donc un portage Windows natif complet représente un vrai travail. La base au niveau de la compilation ci-dessus permet aux chemins `--version`/`--help` et aux opérations purement en mémoire de fonctionner ; les parties délicates (Chrome, sockets, daemonize) nécessitent de véritables implémentations Win32 avant de sortir de la liste des stubs. Si vous souhaitez vous attaquer à l'une d'entre elles, +1 [#153](https://github.com/justrach/kuri/issues/153) ou ouvrez une PR.
### Compiler depuis les sources
Nécessite [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
```
---
## ⚡ Démarrage rapide
**Prérequis :** [Zig ≥ 0.16.0](https://ziglang.org/download/) · Chrome/Chromium (pour le mode 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)
```
### Premier lancement, chemin le plus court
```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
```
### Boucle d'agent orientée session
Pour une utilisation HTTP de type agent, préférez un en-tête de session accompagné de `/tab/new`, `/page/info` et `/snapshot` plutôt que de répéter `tab_id` à chaque appel.
```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"
```
Il existe également un wrapper expérimental léger dans `tools/kuri_harness.py` si vous souhaitez des assistants Python au-dessus de la même surface HTTP.
Si vous avez déjà Chrome en cours d'exécution avec le débogage distant, définissez `CDP_URL` sur le point de terminaison 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
```
### Parcourir vercel.com en 4 commandes
```bash
# 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
Tous les endpoints renvoient du JSON. Authentification optionnelle via la variable d'environnement `KURI_SECRET`. **135 endpoints** — parité complète avec agent-browser et browser-use.
### Cœur
| Chemin | Description |
|------|-------------|
| `GET /health` | État du serveur, nombre d'onglets, version |
| `GET /tabs` | Lister tous les onglets enregistrés |
| `GET /discover` | Découverte automatique des onglets Chrome via CDP |
| `GET /tab/current` | Obtenir ou définir l'onglet courant pour un `X-Kuri-Session` |
| `GET /page/info` | URL/titre/état de chargement/viewport/défilement en direct pour l'onglet actif |
| `GET /page/state` | Observation compacte de la page : url, titre, % de défilement, viewport, nombre de formulaires/liens/images/champs |
| `POST /batch` | Exécuter plusieurs commandes en un seul appel HTTP — renvoie un tableau de résultats |
| `GET /browdie` | 🌰 (easter egg) |
### Contrôle du navigateur
| Chemin | Paramètres | Description |
|------|--------|-------------|
| `GET /navigate` | `tab_id`, `url` | Naviguer l'onglet vers l'URL |
| `GET /tab/new` | `url`, `activate`, `wait` | Créer un nouvel onglet et éventuellement l'hydrater/définir comme onglet courant |
| `GET /tab/close` | `tab_id` | Fermer un onglet |
| `GET /window/new` | `url`, `activate`, `wait` | Créer une nouvelle cible fenêtre/onglet |
| `GET /snapshot` | `tab_id`, `filter`, `format` | Instantané de l'arbre d'accessibilité avec des références `eN`. Utilisez `filter=interactive&format=compact` pour des boucles d'agent à faible consommation de tokens. |
| `GET /text` | `tab_id` | Extraire le texte de la page |
| `GET /screenshot` | `tab_id`, `format`, `quality`, `save` | Capturer une capture d'écran (base64) ; `save=true` écrit le PNG dans `STATE_DIR/screenshots` et renvoie `{path,bytes}` à la place |
| `GET /screenshot/annotated` | `tab_id` | Capture d'écran avec étiquettes d'éléments numérotées |
| `GET /screenshot/diff` | `tab_id`, `baseline` | Diff visuel entre la capture actuelle et la capture de référence |
| `GET /action` | `tab_id`, `ref`, `action`, `value` | Cliquer/saisir/remplir/sélectionner/défiler/survoler/double-cliquer/cocher/décocher/flouter par référence |
| `GET /evaluate` | `tab_id`, `expression` | Exécuter du JavaScript |
| `GET /evalhandle` | `tab_id`, `expression` | Exécuter du JS, renvoyer un handle objectId (pas la valeur) |
| `GET /close` | `tab_id` | Fermer l'onglet + nettoyage |
| `GET /bringtofront` | `tab_id` | Mettre l'onglet au premier plan |
### Actions
| Chemin | Paramètres | Description |
|------|--------|-------------|
| `GET /clear` | `ref` | Vider la valeur d'un champ de saisie |
| `GET /selectall` | `ref` | Sélectionner tout le texte dans un champ/contenteditable |
| `GET /setvalue` | `ref`, `value` | Définir directement la valeur d'un champ (contourne les événements clavier) |
| `GET /dispatch` | `ref`, `type` | Déclencher un événement DOM personnalisé sur un élément |
| `GET /boundingbox` | `ref` | Obtenir le rectangle englobant d'un élément (x, y, width, height, centerX, centerY) |
| `GET /getattribute` | `ref`, `name` | Obtenir un attribut d'élément par nom |
| `GET /inputvalue` | `ref` | Obtenir la valeur actuelle d'un champ de saisie |
| `GET /element/state` | `ref`, `check` | Booléen rapide : `exists`, `visible`, `enabled`, `checked` |
| `GET /find-element` | `text`/`role`/`label`/`placeholder`/`testid` | Localisateur sémantique — trouver un élément sans snapshot |
| `GET /highlight` | `ref` ou `selector` | Mettre en surbrillance un élément avec une superposition |
### Souris et tactile
| Chemin | Paramètres | Description |
|------|--------|-------------|
| `GET /mouse/move` | `x`, `y` | Déplacer la souris vers des coordonnées |
| `GET /mouse/down` | `x`, `y`, `button` | Bouton de souris enfoncé |
| `GET /mouse/up` | `x`, `y`, `button` | Bouton de souris relâché |
| `GET /mouse/wheel` | `x`, `y`, `deltaX`, `deltaY` | Défilement à la molette |
| `GET /tap` | `x`, `y` | Appui tactile (touchStart + touchEnd) |
| `GET /swipe` | `startX`, `startY`, `endX`, `endY` | Geste de balayage tactile |
| `GET /drag` | `src_ref`, `tgt_ref` | Glisser un élément vers une cible |
### Clavier
| Chemin | Paramètres | Description |
|------|--------|-------------|
| `GET /keyboard/type` | `tab_id`, `text` | Saisir du texte via des événements clavier |
| `GET /keyboard/inserttext` | `tab_id`, `text` | Insérer du texte directement |
| `GET /keydown` | `tab_id`, `key` | Événement d'appui de touche |
| `GET /keyup` | `tab_id`, `key` | Événement de relâchement de touche |
### Extraction de contenu
| Chemin | Description |
|------|-------------|
| `GET /markdown` | Convertir la page en Markdown |
| `GET /links` | Extraire tous les liens |
| `GET /dom/query` | Requête par sélecteur CSS |
| `GET /dom/html` | Obtenir le HTML d'un élément |
| `GET /dom/attributes` | Obtenir les attributs d'un élément |
| `GET /pdf` | Imprimer la page en PDF |
| `GET /find` | Recherche de texte dans la page |
### Attente
| Chemin | Paramètres | Description |
|------|--------|-------------|
| `GET /wait` | `selector`, `text`, `url`, `state`, `visible`, `timeout` | Attendre un sélecteur/texte/motif d'URL/networkidle/état de chargement |
| `GET /wait/function` | `expression`, `timeout` | Attendre qu'une expression JS arbitraire soit vraie |
| `GET /wait/download` | `timeout` | Attendre la fin d'un téléchargement de fichier |
### Gestion des dialogues
| Chemin | Description |
|------|-------------|
| `GET /dialog/auto` | Gérer automatiquement tous les dialogues JS (accepter ou rejeter) |
| `GET /dialog/accept` | Accepter le dialogue courant (avec texte de prompt optionnel) |
| `GET /dialog/dismiss` | Rejeter le dialogue courant |
### Réseau et HAR
| Chemin | Description |
|------|-------------|
| `GET /har/start` | Démarrer l'enregistrement du trafic réseau |
| `GET /har/stop` | Arrêter + renvoyer le JSON HAR 1.2 |
| `GET /har/status` | État de l'enregistrement + nombre d'entrées |
| `GET /har/replay` | Carte API avec extraits de code curl/fetch/python |
| `GET /cookies` | Obtenir les cookies |
| `GET /cookies/set` | Définir les cookies |
| `GET /cookies/delete` | Supprimer les cookies |
| `GET /cookies/clear` | Effacer tous les cookies |
| `GET /headers` | Définir des en-têtes de requête personnalisés |
| `GET /intercept/start` | Démarrer l'interception des requêtes |
| `GET /intercept/stop` | Arrêter l'interception des requêtes |
| `GET /intercept/requests` | Lister les requêtes interceptées |
| `GET /request/detail` | Obtenir le corps de la réponse pour un ID de requête |
| `GET /response/body` | Récupérer une URL et renvoyer le corps de la réponse |
| `GET /network` | Statistiques du trafic réseau |
| `GET /download` | Déclencher le téléchargement d'un fichier |
### Navigation et état
| Chemin | Description |
|------|-------------|
| `GET /back` | Retour navigateur |
| `GET /forward` | Avancer navigateur |
| `GET /reload` | Recharger la page |
| `GET /stop` | Arrêter le chargement de la page |
| `GET /pushstate` | Navigation SPA via history.pushState |
| `GET /storage/local` | Obtenir/définir localStorage |
| `GET /storage/session` | Obtenir/définir sessionStorage |
| `GET /storage/local/clear` | Effacer localStorage |
| `GET /storage/session/clear` | Effacer sessionStorage |
| `GET /session/save` | Sauvegarder la session du navigateur |
| `GET /session/load` | Restaurer la session du navigateur |
| `GET /session/list` | Lister les sessions sauvegardées |
| `GET /setcontent` | Définir directement le HTML de la page (POST) |
### Profils d'authentification
| Chemin | Description |
|------|-------------|
| `GET /auth/profile/save` | Sauvegarder cookies + storage comme profil d'authentification nommé |
| `GET /auth/profile/load` | Restaurer un profil d'authentification nommé dans un onglet |
| `GET /auth/profile/list` | Lister les profils d'authentification sauvegardés |
| `GET /auth/profile/delete` | Supprimer un profil d'authentification sauvegardé |
| `GET /auth/extract` | Extraire les jetons d'authentification (JWT, cookies, en-têtes) |
| `GET /set/credentials` | Définir les identifiants d'authentification HTTP basic |
Sur macOS, les secrets des profils d'authentification sont stockés dans le Keychain de l'utilisateur.
### Émulation
| Chemin | Paramètres | Description |
|------|--------|-------------|
| `GET /emulate` | type d'appareil, taille d'écran | Émulation d'appareil |
| `GET /set/viewport` | `width`, `height` | Définir la taille du viewport |
| `GET /set/useragent` | `ua` | Définir le user agent |
| `GET /set/media` | `media` | Émuler le type de média |
| `GET /set/offline` | `offline` | Basculer le mode hors ligne |
| `GET /geolocation` | `lat`, `lng` | Remplacer la géolocalisation |
| `GET /timezone` | `timezone` | Remplacer le fuseau horaire (ex. `America/New_York`) |
| `GET /locale` | `locale` | Remplacer la locale (ex. `en-US`) |
| `GET /permissions` | `name`, `state` | Accorder/refuser des permissions (géolocalisation, notifications, presse-papiers) |
### Scripts et injection
| Chemin | Description |
|------|-------------|
| `GET /script/inject` | Injecter du JavaScript dans la page (persiste à travers la navigation) |
| `GET /initscript/remove` | Supprimer un script d'init précédemment injecté |
| `GET /addstyle` | Injecter une feuille de style CSS |
| `GET /expose` | Exposer une fonction nommée au contexte JS de la page |
### Inspection React
| Chemin | Description |
|------|-------------|
| `GET /react/tree` | Arbre de composants React via le hook DevTools |
| `GET /react/inspect` | Props et état d'un composant React |
| `GET /react/renders` | Suivi des rendus React (démarrer/arrêter) |
| `GET /react/suspense` | État des frontières Suspense de React |
### Enregistrement et performance
| Chemin | Description |
|------|-------------|
| `GET /recording/start` | Enregistrer les actions utilisateur (clic, saisie, navigation) |
| `GET /recording/stop` | Arrêter l'enregistrement + renvoyer le journal des actions |
| `GET /vitals` | Core Web Vitals (LCP, CLS, FID, TTFB, FCP, domInteractive) |
| `GET /perf/lcp` | Timing du Largest Contentful Paint |
| `GET /trace/start` | Démarrer la trace de performance |
| `GET /trace/stop` | Arrêter la trace |
| `GET /profiler/start` | Démarrer le profileur JS |
| `GET /profiler/stop` | Arrêter le profileur |
### Débogage
| Chemin | Description |
|------|-------------|
| `GET /debug/enable` | Activer le HUD de débogage dans la page et le mode gel optionnel |
| `GET /debug/disable` | Désactiver le HUD de débogage dans la page |
| `GET /inspect` | Inspection d'élément |
| `GET /errors` | Collecter les erreurs JS |
| `GET /console` | Lire les logs de la console |
| `GET /frames` | Lister les frames de la page |
| `GET /frame` | Basculer vers le contexte iframe par nom ou URL |
| `GET /mainframe` | Revenir à la frame principale |
| `GET /diff/snapshot` | Diff compact `+`/`~`/`-` par rapport à l'appel précédent pour cet onglet — la boucle d'action économe en tokens (aliasée par `/snapshot/changes`). Revient à un snapshot complet avec un en-tête `! page replaced` en cas de changement massif. |
| `GET /diff/url` | Comparer deux URLs côte à côte (naviguer, snapshot, diff) |
### Streaming
| Chemin | Description |
|------|-------------|
| `GET /screencast/start` | Démarrer l'enregistrement d'écran |
| `GET /screencast/stop` | Arrêter l'enregistrement d'écran |
| `GET /video/start` | Démarrer la capture vidéo |
| `GET /video/stop` | Arrêter la capture vidéo |
| `GET /ws/start` | Démarrer le tunnel WebSocket |
| `GET /ws/stop` | Arrêter le tunnel WebSocket |
### Boucle adaptée aux agents
La boucle serveur la plus fluide est :
1. `GET /tab/new?url=...`
2. `GET /page/state` (léger) ou `GET /snapshot?filter=interactive&format=compact` (complet)
3. `GET /action?action=click&ref=eN`
4. Répéter — ou utiliser `POST /batch` pour des opérations multi-étapes en un seul appel
Les paramètres de requête `url` et `expression` sont décodés en pourcentage. Envoyez `X-Kuri-Session: my-agent` pour persister le contexte d'onglet côté serveur.
---
## 🧠 Compétences
Le dépôt inclut une zone de compétences extensible par l'utilisateur :
- `skills/kuri-skill.md` est la compétence de base de l'agent HTTP Kuri
- `skills/custom/` est réservé à vos propres compétences spécifiques au projet
- `skills/custom/hackernews-page-2.md` est un exemple concret de compétence personnalisée
- `.claude/skills/kuri-server/SKILL.md` reste synchronisé pour les compétences de dépôt de style Claude
La compétence de base explique désormais aussi quel chemin de navigateur utiliser :
- `kuri` API HTTP : automatisation Chrome/CDP en production avec sessions, snapshots, actions, HAR, cookies et captures d'écran
- `kuri-fetch` : récupération/extraction de texte autonome sans Chrome
- `kuri-browse` : navigation interactive dans le terminal
- `kuri-agent` : automatisation CLI scriptable contre le serveur Kuri
- `kuri-browser/` : runtime de navigateur natif Zig séparé et expérimental pour le travail de parité
Pour le CLI du navigateur expérimental :
```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` expose la découverte HTTP de style Chrome ainsi qu'un routeur JSON-RPC WebSocket minimal pour les tests de fumée du protocole. L'évaluation à l'exécution renvoie des objets distants CDP au format V8, adossés à QuickJS ; cela n'ajoute pas de dépendance V8 et ne constitue pas encore une compatibilité complète avec Playwright/Puppeteer.
Les captures d'écran dans `kuri-browser` délèguent actuellement au moteur de rendu principal Kuri/CDP. Démarrez d'abord `./zig-out/bin/kuri`, puis :
```bash
cd kuri-browser
zig build run -- screenshot https://example.com --out example.jpg --compress --kuri-base http://127.0.0.1:8080
```
`--compress` capture une baseline PNG et un candidat JPEG, écrit le fichier le plus petit, et rapporte les octets économisés. Mesure locale actuelle sur `https://example.com` : `20,523` octets PNG à `18,183` octets JPEG qualité 50, économisant `2,340` octets soit `11%`.
### Avancé
| Chemin | Description |
|------|-------------|
| `GET /diff/snapshot` | Delta compact `+`/`~`/`-` par rapport au snapshot précédent (boucle d'action de l'agent) |
| `GET /emulate` | Émulation d'appareil |
| `GET /geolocation` | Définir la géolocalisation |
| `POST /upload` | Téléversement de fichier |
| `GET /script/inject` | Injecter du JavaScript |
| `GET /intercept/start` | Démarrer l'interception des requêtes |
| `GET /intercept/stop` | Arrêter l'interception |
| `GET /screenshot/annotated` | Capture d'écran avec annotations d'éléments |
| `GET /screenshot/diff` | Diff visuel entre captures d'écran |
| `GET /screencast/start` | Démarrer le screencast |
| `GET /screencast/stop` | Arrêter le screencast |
| `GET /video/start` | Démarrer l'enregistrement vidéo |
| `GET /video/stop` | Arrêter l'enregistrement vidéo |
| `GET /console` | Obtenir les messages de la console |
| `GET /stop` | Arrêter le chargement de la page |
| `GET /get` | Requête HTTP directe (côté serveur) |
| `GET /scrollintoview` | Faire défiler un élément référencé dans la vue |
| `GET /drag` | Glisser d'une référence à une autre |
| `GET /keyboard/type` | Saisir du texte avec des événements clavier |
| `GET /keyboard/inserttext` | Insérer du texte directement |
| `GET /keydown` | Envoyer un événement keydown |
| `GET /keyup` | Envoyer un événement keyup |
| `GET /wait` | Attendre l'état prêt ou des conditions d'élément |
| `GET /tab/close` | Fermer un onglet |
| `GET /highlight` | Mettre en surbrillance un élément par référence ou sélecteur |
| `GET /errors` | Obtenir les erreurs de page/runtime |
| `GET /set/offline` | Basculer l'émulation réseau hors ligne |
| `GET /set/media` | Définir les fonctionnalités média émulées |
| `GET /set/credentials` | Définir les identifiants d'authentification HTTP basique |
| `GET /find` | Rechercher des correspondances de texte dans la page actuelle |
| `GET /trace/start` | Démarrer le traçage Chrome |
| `GET /trace/stop` | Arrêter le traçage et retourner les données de trace |
| `GET /profiler/start` | Démarrer le profileur JS |
| `GET /profiler/stop` | Arrêter le profileur JS |
| `GET /inspect` | Inspecter un élément ou l'état de la page |
| `GET /set/viewport` | Définir la taille du viewport |
| `GET /set/useragent` | Remplacer le user agent |
| `GET /dom/attributes` | Obtenir les attributs d'un élément |
| `GET /frames` | Lister l'arbre des frames |
| `GET /network` | Inspecter l'état/les requêtes réseau |
---
## 🛡️ Furtivité & Évasion des Bots
Kuri applique automatiquement des correctifs anti-détection au démarrage — aucune configuration manuelle nécessaire.
---
[Read more](https://github.com/justrach/kuri)