Zurück zu den Updates
New releaseJul 31, 2026

kuri v0.5.1

Browser-Automation, Web-Crawling und iOS + Android Gerätesteuerung für KI-Agenten. Zig-nativ, token-effiziente CDP-Snapshots, HAR-Aufzeichnung, nativer adb Wire-Protocol-Client und ein eigenständiger Fetcher.

Teilen

Kuri

Kuri 🌰

Stabile Version Lizenz Zig node_modules Status

Installation```sh

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

macOS arm64/x86_64 und Linux x86_64/arm64. Ein einzelnes Binary, keine Laufzeitabhängigkeiten.

Direkte Downloads: [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)

---

**Browser-Automatisierung & Web-Crawling für KI-Agenten. Geschrieben in Zig. Kein Node.js.**

CDP-Automatisierung · A11y-Snapshots · HAR-Aufzeichnung · Eigenständiger Fetcher · Interaktiver Terminal-Browser · Agentische CLI · Sicherheitstests · iOS + Android-Gerätesteuerung

[Schnellstart](#-quick-start) · [Benchmarks](#-benchmarks) · [kuri-agent](#-kuri-agent) · [Sicherheitstests](#-security-testing) · [API](#-http-api) · [Fähigkeiten](#-skills) · [Changelog](https://github.com/justrach/kuri/blob/HEAD/CHANGELOG.md)

> **Warum Teams auf Kuri umsteigen:** Aktuelle `ReleaseFast`-Builds für Apple Silicon bleiben unter 2 MB pro Binary, und ein frischer Google-Flights-Durchlauf am 2026-04-23 maß **3,392 Token** für eine vollständige `kuri-agent`-Schleife (`go→snap→click→snap→eval`). Toolübergreifende Differenzen sollten in derselben Umgebung neu gemessen werden, bevor ein Prozentsatz genannt wird.

---

## Warum Kuri für Agenten gewinnt

Die meisten Browser-Tools wurden für QA-Ingenieure gebaut. Kuri ist für Agentenschleifen gebaut: Seite lesen, Token-Kosten niedrig halten, auf stabile Referenzen reagieren und weitermachen.

- **135 HTTP-Endpunkte** — volle Parität mit agent-browser und browser-use, von der React-Inspektion bis zu Core Web Vitals.
- **7-12% weniger Token** als agent-browser auf echten Seiten dank `@eN`-Referenzformat und Zero-Prefix-Rendering.
- **44x leichtere Beobachtungen** mit `/page/state` (48 Token) gegenüber vollständigem Snapshot (2,124 Token) für dieselbe Google-Flights-Seite.
- **Batch-Ausführung** — `POST /batch` sendet N Befehle in einem HTTP-Aufruf und eliminiert N-1 Round-Trips und N-1 LLM-Turns.
- **React-kompatibel** — echte CDP-Mausereignisse und zeichenweise Tastaturereignisse lösen React 18/19 `onClick` und `onChange` aus.

### Snapshot-Token: Google Flights `SIN → TPE`

Frischer Durchlauf am 2026-05-24 in diesem Workspace, gemessen mit `wc -c` und `chars/4`-Näherung.

| Tool / Modus | Zeichen | ~Token | Hinweis |
|---|---:|---:|---|
| `kuri snap` (vollständig) | 8,499 | **2,124** | Alle Knoten + interaktive Referenzen |
| `kuri snap` (nur interaktiv) | ~3,000 | **~750** | Am besten für Agentenschleifen |
| `kuri /page/state` | 190 | **48** | Leichte Beobachtung (url, title, scroll%, counts) |
| agent-browser snap (geschätzt) | ~9,183 | **~2,295** | Overhead durch `[ref=e0]`-Format |

### Token-Effizienz: kuri vs. agent-browser

| Seite | kuri-Token | agent-browser-Token | Ersparnis |
|---|---:|---:|---|
| example.com | 40 | 35 | -13% (triviale Seite, agent-browser überspringt Root) |
| Hacker News | 386 | ~440 | **12% weniger** |
| Google Flights SIN→TPE | 2,124 | ~2,295 | **7% weniger** |

Die Ersparnis ergibt sich aus kuris kompaktem Format:
- `@e0`-Referenzen (3 Zeichen) vs. `[ref=e0]` (9 Zeichen)
- Kein `- `-Präfix pro Zeile (spart 2 Zeichen × Zeilenanzahl)
- Gleiche Einrückung, gleiche Knotenfilterung

### Vollständige Workflow-Kosten: `go → snap → click → snap → eval`

| Tool | Token pro Zyklus |
|---|---:|
| **kuri-agent** | **~3,400** |
| Mit `/page/state` statt zweitem Snap | **~1,700** |
| Mit `POST /batch` (alles in einem Aufruf) | **~1,700** (gleiche Token, 1 HTTP-Aufruf statt 5) |

### kuri vs. libretto

[libretto](https://github.com/saffron-health/libretto) (Playwright + Node) ist der engste Konkurrent bei den Token-Kosten pro Schritt. Direkt im Vergleich gemessen am 2026-07-04 — gleiches Chrome, gleicher Tab, echte `tiktoken`-`o200k_base`-Zählungen (vollständige Methodik und Reproduktion: **[benchmarks/libretto_comparison.md](https://github.com/justrach/kuri/blob/HEAD/benchmarks/libretto_comparison.md)**). Die ehrliche Aufteilung:

| Achse | Gewinner | Detail |
|---|---|---|
| Latenz pro Aufruf | **kuri** | 4–117 ms vs. 1,344–1,500 ms (**13–376× schneller** — persistenter Server vs. Node-pro-Befehl) |
| Snapshot-Token, typische Seite | **kuri** | einfach 61 vs. 151 (2.5×), Artikel 265 vs. 363 (1.37×) — straffere Grammatik |
| Snapshot-Token, große Liste | geteilt | kuri Standard 4,424 vs. 813 — kuri emittiert alle 259 Referenzen, libretto kürzt standardmäßig. Mit `limit=5` rendert kuri 555 Token (**1.46× unter libretto**), 34 Referenzen + `… +45 more`-Marker |
| Trajektorie (Feed, 9 Klicks) | **kuri**, knapp | 898 vs. 939 Token (`limit=5`-Basis + Diff-Schleife vs. Exec-Schleife) — Parität bis leichter Vorsprung; der 5.1×-Verlust am Morgen war die ungekürzte Basis |
| Wiederholte Läufe | **libretto** | kompiliert Trajektorien zu einem Playwright-Skript → 0-Token-Wiedergaben; kuri zahlt die Schleife bei jedem Lauf erneut |

**Was kuri aus der Untersuchung von libretto gewonnen hat** (alles in diesem Release enthalten): eine diff-first-Schleife (`take_snapshot_diff`, ~38 Token/Schritt); ein adaptiver Diff, der bei Navigation auf einen vollständigen Snapshot mit `! page replaced`-Header zurückfällt; Entfernungszeilen nur mit Identität; Screenshots, die auf die Festplatte geschrieben werden (Pfad wird zurückgegeben, Bytes gelangen nie in den Kontext); `get_page_state` über MCP; und — nachdem `parseA11yNodes` als echter DFS-Tree-Walk neu geschrieben wurde — **optionale Listenkürzung** (`/snapshot?limit=N`, eine `… +K more`-Zeile pro begrenztem Lauf), **bereichsbezogene Neuerfassung** (`scope=@ref`) und **Hierarchie-Einrückung**, ebenfalls als `uid`/`limit` im MCP-`take_snapshot` verfügbar. Die 9-Klick-Feed-Trajektorie, die mit naiven vollständigen Re-Snapshots 44,285 Token kostete, kostet mit gekürzter Basis + Diffs **898** — 49× günstiger und besser als librettos 939.

> Die älteren Tabellen oben verwenden eine `chars/4`-Token-Näherung; der libretto-Vergleich verwendet echte `tiktoken`-Zählungen. Führen Sie die toolübergreifenden Zahlen in Ihrer eigenen Umgebung erneut aus, bevor Sie einen Prozentsatz angeben.

### Binary-Größe und Speicher

Gemessen auf Apple M4 Pro, macOS 26.4.1. Die aktuellen Binaries wurden mit `-Doptimize=ReleaseFast` erstellt.

| Binary | Aktuelle Größe |
|---|---:|
| `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) |

### RSS blieb über die Zig-0.16-Migration hinweg stabil

Gemessen gegen den aktuellen `v0.4.3`-`ReleaseFast`-Build mit `/usr/bin/time -l`.

| Befehl | `v0.4.3` mittlerer max. RSS |
|---|---:|
| `kuri-fetch --version` | ~2.45 MiB |
| `kuri-browse --version` | ~2.45 MiB |
| `kuri-fetch --quiet --dump markdown http://example.com/` | ~9.17 MiB |

## Das Problem

Jedes Browser-Automatisierungstool schleppt Playwright (~300 MB), eine Node.js-Laufzeit und eine Kaskade von npm-Abhängigkeiten mit. Ihr KI-Agent möchte einfach nur eine Seite lesen, einen Button klicken und weitermachen.
**Kuri ist ein einzelnes Zig-Binary.** Vier Modi, null Laufzeit:```
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

Einzeilige Installation (macOS / Linux)```sh

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

Erkennt deine Plattform, lädt das passende Binary herunter und installiert es in `~/.local/bin`.
Die Downloads stammen aus dem selbstverwalteten `release-channel`-Branch von Kuri. macOS-Binaries sind lokal mit einem Developer-ID-Zertifikat signiert. GitHub-Release-Assets spiegeln dieselben Tarballs wider.

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

Lädt zur Installationszeit das richtige native Binary für deine Plattform herunter.

Release-Kanal

Die stabilen Binaries von Kuri liegen auf dem Branch release-channel und werden direkt über GitHub-Raw-URLs ausgeliefert.

  • Stabiler Installer: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh
  • Stabiles Manifest: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/latest.json
  • Branch-Ansicht: https://github.com/justrach/kuri/tree/release-channel/stable
  • Direkt-Download-Muster: https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/<version>/kuri-<version>-<target>.tar.gz

Manuell

Lade das Tarball für deine Plattform aus dem stabilen Release-Manifest oder von der GitHub-Releases-Seite herunter und entpacke es in deinen $PATH.

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

Das Manifest enthält exakte Asset-URLs sowie SHA-256-Prüfsummen für `aarch64-linux`, `x86_64-linux`, `aarch64-macos` und `x86_64-macos`.

### Plattformunterstützung

| Plattform | Status |
|---|---|
| macOS (`aarch64`, `x86_64`) | Vorgefertigte Binärdateien, signiert + notarisiert |
| Linux (`aarch64`, `x86_64`) | Vorgefertigte Binärdateien |
| Windows (`x86_64`) | **Experimentell — nur Cross-Compile.** `zig build -Dtarget=x86_64-windows-gnu` ist CI-verifiziert, aber Chrome-Automatisierung, Dämonisierung, signalbasierter Shutdown, HAR-Aufzeichnung und der dateigestützte Auth-Speicher sind zur Laufzeit alle als Stubs mit `error.UnsupportedOnWindows` implementiert. Verwende **WSL2**, wenn du den echten Funktionsumfang benötigst. Nachverfolgt unter [#153](https://github.com/justrach/kuri/issues/153). |

Kuri stützt sich an mehreren Stellen auf POSIX-Primitive (`fork`, `clock_gettime`, Raw-Sockets), daher ist ein vollständiger nativer Windows-Port echte Arbeit. Die obige Baseline auf Kompilierungsebene lässt die `--version`/`--help`-Pfade und reine In-Memory-Operationen laufen; die kniffligen Teile (Chrome, Sockets, Dämonisierung) benötigen echte Win32-Implementierungen, bevor sie von der Stub-Liste genommen werden. Wenn du eine davon übernehmen möchtest, +1 bei [#153](https://github.com/justrach/kuri/issues/153) oder eröffne einen PR.

### Build aus dem Quellcode

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

⚡ Schnellstart

Voraussetzungen: Zig ≥ 0.16.0 · Chrome/Chromium (für den CDP-Modus)```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)

### Erster Lauf, kürzester Pfad```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

Session-first-Agentenschleife

Verwende für agentenbasierte HTTP-Nutzung bevorzugt einen Session-Header plus /tab/new, /page/info und /snapshot anstatt tab_id bei jedem Aufruf zu wiederholen.```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"

Es gibt auch einen dünnen experimentellen Wrapper unter `tools/kuri_harness.py`, falls Sie Python-Helfer auf derselben HTTP-Oberfläche nutzen möchten.

Wenn Sie bereits Chrome mit Remote-Debugging ausführen, setzen Sie `CDP_URL` entweder auf den WebSocket- oder HTTP-Endpunkt:```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

vercel.com in 4 Befehlen durchsuchen```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"}, ...]

---

## 🌐 HTTP-API

Alle Endpunkte geben JSON zurück. Optionale Authentifizierung über die `KURI_SECRET`-Umgebungsvariable. **135 Endpunkte** — volle Parität mit agent-browser und browser-use.

### Kern

| Pfad | Beschreibung |
|------|-------------|
| `GET /health` | Serverstatus, Tab-Anzahl, Version |
| `GET /tabs` | Alle registrierten Tabs auflisten |
| `GET /discover` | Chrome-Tabs automatisch über CDP erkennen |
| `GET /tab/current` | Aktuellen Tab für eine `X-Kuri-Session` abrufen oder setzen |
| `GET /page/info` | Live-URL/Titel/Ready-State/Viewport/Scroll für den aktiven Tab |
| `GET /page/state` | Kompakte Seitenbeobachtung: url, title, scroll%, viewport, Anzahl von Formularen/Links/Bildern/Inputs |
| `POST /batch` | Mehrere Befehle in einem HTTP-Aufruf ausführen — gibt ein Array mit Ergebnissen zurück |
| `GET /browdie` | 🌰 (Osterei) |

### Browser-Steuerung

| Pfad | Parameter | Beschreibung |
|------|--------|-------------|
| `GET /navigate` | `tab_id`, `url` | Tab zur URL navigieren |
| `GET /tab/new` | `url`, `activate`, `wait` | Neuen Tab erstellen und optional hydratisieren/als aktuellen Tab setzen |
| `GET /tab/close` | `tab_id` | Tab schließen |
| `GET /window/new` | `url`, `activate`, `wait` | Neues Fenster/Tab-Ziel erstellen |
| `GET /snapshot` | `tab_id`, `filter`, `format` | A11y-Baum-Snapshot mit `eN`-Referenzen. Verwende `filter=interactive&format=compact` für tokenarme Agent-Schleifen. |
| `GET /text` | `tab_id` | Seitentext extrahieren |
| `GET /screenshot` | `tab_id`, `format`, `quality`, `save` | Screenshot aufnehmen (base64); `save=true` schreibt das PNG nach `STATE_DIR/screenshots` und gibt stattdessen `{path,bytes}` zurück |
| `GET /screenshot/annotated` | `tab_id` | Screenshot mit nummerierten Elementbeschriftungen |
| `GET /screenshot/diff` | `tab_id`, `baseline` | Visueller Diff zwischen aktuellen und Basis-Screenshots |
| `GET /action` | `tab_id`, `ref`, `action`, `value` | Klicken/Tippen/Ausfüllen/Auswählen/Scrollen/Hover/Doppelklick/Aktivieren/Deaktivieren/Blur per Referenz |
| `GET /evaluate` | `tab_id`, `expression` | JavaScript ausführen |
| `GET /evalhandle` | `tab_id`, `expression` | JS ausführen, objectId-Handle zurückgeben (nicht den Wert) |
| `GET /close` | `tab_id` | Tab schließen + aufräumen |
| `GET /bringtofront` | `tab_id` | Tab in den Vordergrund bringen |

### Aktionen

| Pfad | Parameter | Beschreibung |
|------|--------|-------------|
| `GET /clear` | `ref` | Wert des Eingabefelds leeren |
| `GET /selectall` | `ref` | Gesamten Text in input/contenteditable auswählen |
| `GET /setvalue` | `ref`, `value` | Eingabewert direkt setzen (umgeht Tastaturereignisse) |
| `GET /dispatch` | `ref`, `type` | Benutzerdefiniertes DOM-Ereignis auf Element auslösen |
| `GET /boundingbox` | `ref` | Begrenzungsrechteck des Elements abrufen (x, y, width, height, centerX, centerY) |
| `GET /getattribute` | `ref`, `name` | Elementattribut nach Name abrufen |
| `GET /inputvalue` | `ref` | Aktuellen Wert des Eingabeelements abrufen |
| `GET /element/state` | `ref`, `check` | Schneller boolescher Wert: `exists`, `visible`, `enabled`, `checked` |
| `GET /find-element` | `text`/`role`/`label`/`placeholder`/`testid` | Semantischer Locator — Element ohne Snapshot finden |
| `GET /highlight` | `ref` oder `selector` | Element mit Overlay hervorheben |

### Maus & Touch

| Pfad | Parameter | Beschreibung |
|------|--------|-------------|
| `GET /mouse/move` | `x`, `y` | Maus zu Koordinaten bewegen |
| `GET /mouse/down` | `x`, `y`, `button` | Maustaste gedrückt |
| `GET /mouse/up` | `x`, `y`, `button` | Maustaste losgelassen |
| `GET /mouse/wheel` | `x`, `y`, `deltaX`, `deltaY` | Mausrad-Scrollen |
| `GET /tap` | `x`, `y` | Touch-Tippen (touchStart + touchEnd) |
| `GET /swipe` | `startX`, `startY`, `endX`, `endY` | Touch-Wisch-Geste |
| `GET /drag` | `src_ref`, `tgt_ref` | Element zum Ziel ziehen |

### Tastatur

| Pfad | Parameter | Beschreibung |
|------|--------|-------------|
| `GET /keyboard/type` | `tab_id`, `text` | Text über Tastaturereignisse eingeben |
| `GET /keyboard/inserttext` | `tab_id`, `text` | Text direkt einfügen |
| `GET /keydown` | `tab_id`, `key` | Taste-gedrückt-Ereignis |
| `GET /keyup` | `tab_id`, `key` | Taste-losgelassen-Ereignis |

### Inhaltsextraktion

| Pfad | Beschreibung |
|------|-------------|
| `GET /markdown` | Seite in Markdown konvertieren |
| `GET /links` | Alle Links extrahieren |
| `GET /dom/query` | CSS-Selektor-Abfrage |
| `GET /dom/html` | Element-HTML abrufen |
| `GET /dom/attributes` | Elementattribute abrufen |
| `GET /pdf` | Seite als PDF drucken |
| `GET /find` | Textsuche auf der Seite |

### Warten

| Pfad | Parameter | Beschreibung |
|------|--------|-------------|
| `GET /wait` | `selector`, `text`, `url`, `state`, `visible`, `timeout` | Auf Selektor/Text/URL-Muster/networkidle/Ladestatus warten |
| `GET /wait/function` | `expression`, `timeout` | Warten, bis ein beliebiger JS-Ausdruck truthy ist |
| `GET /wait/download` | `timeout` | Auf Abschluss des Dateidownloads warten |

### Dialogbehandlung

| Pfad | Beschreibung |
|------|-------------|
| `GET /dialog/auto` | Alle JS-Dialoge automatisch behandeln (akzeptieren oder ablehnen) |
| `GET /dialog/accept` | Aktuellen Dialog akzeptieren (mit optionalem Prompt-Text) |
| `GET /dialog/dismiss` | Aktuellen Dialog ablehnen |

### Netzwerk & HAR

| Pfad | Beschreibung |
|------|-------------|
| `GET /har/start` | Aufzeichnung des Netzwerkverkehrs starten |
| `GET /har/stop` | Stoppen + HAR-1.2-JSON zurückgeben |
| `GET /har/status` | Aufzeichnungsstatus + Anzahl der Einträge |
| `GET /har/replay` | API-Zuordnung mit curl/fetch/python-Codeausschnitten |
| `GET /cookies` | Cookies abrufen |
| `GET /cookies/set` | Cookies setzen |
| `GET /cookies/delete` | Cookies löschen |
| `GET /cookies/clear` | Alle Cookies löschen |
| `GET /headers` | Benutzerdefinierte Request-Header setzen |
| `GET /intercept/start` | Request-Interception starten |
| `GET /intercept/stop` | Request-Interception stoppen |
| `GET /intercept/requests` | Abgefangene Requests auflisten |
| `GET /request/detail` | Antworttext für eine Request-ID abrufen |
| `GET /response/body` | URL abrufen und Antworttext zurückgeben |
| `GET /network` | Statistiken zum Netzwerkverkehr |
| `GET /download` | Dateidownload auslösen |

### Navigation & Zustand

| Pfad | Beschreibung |
|------|-------------|
| `GET /back` | Browser zurück |
| `GET /forward` | Browser vor |
| `GET /reload` | Seite neu laden |
| `GET /stop` | Seitenladen stoppen |
| `GET /pushstate` | SPA-Navigation über history.pushState |
| `GET /storage/local` | localStorage abrufen/setzen |
| `GET /storage/session` | sessionStorage abrufen/setzen |
| `GET /storage/local/clear` | localStorage leeren |
| `GET /storage/session/clear` | sessionStorage leeren |
| `GET /session/save` | Browsersitzung speichern |
| `GET /session/load` | Browsersitzung wiederherstellen |
| `GET /session/list` | Gespeicherte Sitzungen auflisten |
| `GET /setcontent` | Seiten-HTML direkt setzen (POST) |

### Auth-Profile

| Pfad | Beschreibung |
|------|-------------|
| `GET /auth/profile/save` | Cookies + Speicher als benanntes Auth-Profil speichern |
| `GET /auth/profile/load` | Benanntes Auth-Profil in einen Tab wiederherstellen |
| `GET /auth/profile/list` | Gespeicherte Auth-Profile auflisten |
| `GET /auth/profile/delete` | Gespeichertes Auth-Profil löschen |
| `GET /auth/extract` | Auth-Tokens extrahieren (JWT, Cookies, Header) |
| `GET /set/credentials` | HTTP-Basic-Auth-Anmeldedaten setzen |

Unter macOS werden Auth-Profil-Geheimnisse in der Benutzer-Keychain gespeichert.

### Emulation

| Pfad | Parameter | Beschreibung |
|------|--------|-------------|
| `GET /emulate` | Gerätetyp, Bildschirmgröße | Geräteemulation |
| `GET /set/viewport` | `width`, `height` | Viewport-Größe setzen |
| `GET /set/useragent` | `ua` | User-Agent setzen |
| `GET /set/media` | `media` | Medientyp emulieren |
| `GET /set/offline` | `offline` | Offline-Modus umschalten |
| `GET /geolocation` | `lat`, `lng` | Geolokalisierung überschreiben |
| `GET /timezone` | `timezone` | Zeitzone überschreiben (z. B. `America/New_York`) |
| `GET /locale` | `locale` | Locale überschreiben (z. B. `en-US`) |
| `GET /permissions` | `name`, `state` | Berechtigungen erteilen/verweigern (Geolokalisierung, Benachrichtigungen, Zwischenablage) |

### Skripte & Injection

| Pfad | Beschreibung |
|------|-------------|
| `GET /script/inject` | JavaScript in die Seite injizieren (bleibt über Navigationen hinweg erhalten) |
| `GET /initscript/remove` | Ein zuvor injiziertes Init-Skript entfernen |
| `GET /addstyle` | CSS-Stylesheet injizieren |
| `GET /expose` | Eine benannte Funktion für den JS-Kontext der Seite bereitstellen |

### React-Inspektion

| Pfad | Beschreibung |
|------|-------------|
| `GET /react/tree` | React-Komponentenbaum über DevTools-Hook |
| `GET /react/inspect` | Props und State der React-Komponente |
| `GET /react/renders` | React-Render-Tracking (start/stop) |
| `GET /react/suspense` | Status der React-Suspense-Grenzen |

### Aufzeichnung & Leistung

| Pfad | Beschreibung |
|------|-------------|
| `GET /recording/start` | Benutzeraktionen aufzeichnen (Klick, Eingabe, Navigation) |
| `GET /recording/stop` | Aufzeichnung stoppen + Aktionsprotokoll zurückgeben |
| `GET /vitals` | Core Web Vitals (LCP, CLS, FID, TTFB, FCP, domInteractive) |
| `GET /perf/lcp` | Timing des Largest Contentful Paint |
| `GET /trace/start` | Leistungs-Trace starten |
| `GET /trace/stop` | Trace stoppen |
| `GET /profiler/start` | JS-Profiler starten |
| `GET /profiler/stop` | Profiler stoppen |

### Debugging

| Pfad | Beschreibung |
|------|-------------|
| `GET /debug/enable` | In-Seiten-Debug-HUD und optionalen Freeze-Modus aktivieren |
| `GET /debug/disable` | In-Seiten-Debug-HUD deaktivieren |
| `GET /inspect` | Elementinspektion |
| `GET /errors` | JS-Fehler sammeln |
| `GET /console` | Konsolenprotokolle lesen |
| `GET /frames` | Seiten-Frames auflisten |
| `GET /frame` | Zum iframe-Kontext nach Name oder URL wechseln |
| `GET /mainframe` | Zurück zum Hauptframe wechseln |
| `GET /diff/snapshot` | Kompakter `+`/`~`/`-`-Diff gegen den vorherigen Aufruf für diesen Tab — die tokeneffiziente Aktionsschleife (als Alias über `/snapshot/changes`). Fällt bei massiven Änderungen auf einen vollständigen Snapshot mit einem `! page replaced`-Header zurück. |
| `GET /diff/url` | Zwei URLs nebeneinander vergleichen (navigate, snapshot, diff) |

### Streaming

| Pfad | Beschreibung |
|------|-------------|
| `GET /screencast/start` | Bildschirmaufnahme starten |
| `GET /screencast/stop` | Bildschirmaufnahme stoppen |
| `GET /video/start` | Videoaufnahme starten |
| `GET /video/stop` | Videoaufnahme stoppen |
| `GET /ws/start` | WebSocket-Tunnel starten |
| `GET /ws/stop` | WebSocket-Tunnel stoppen |

### Agentenfreundliche Schleife

Die reibungsloseste Server-Schleife ist:

1. `GET /tab/new?url=...`
2. `GET /page/state` (leichtgewichtig) oder `GET /snapshot?filter=interactive&format=compact` (vollständig)
3. `GET /action?action=click&ref=eN`
4. Wiederholen — oder `POST /batch` für mehrstufige Vorgänge in einem Aufruf verwenden

`url`- und `expression`-Query-Parameter werden prozent-dekodiert. Sende `X-Kuri-Session: my-agent`, um den Tab-Kontext serverseitig beizubehalten.
---

## 🧠 Skills

Das Repository enthält einen benutzererweiterbaren Skill-Bereich:

- `skills/kuri-skill.md` ist das Basis-Kuri-HTTP-Agent-Skill
- `skills/custom/` ist für deine eigenen projektspezifischen Skills reserviert
- `skills/custom/hackernews-page-2.md` ist ein konkretes Beispiel für ein benutzerdefiniertes Skill
- `.claude/skills/kuri-server/SKILL.md` bleibt für Claude-artige Repository-Skills synchron

Das Basis-Skill erklärt nun auch, welcher Browser-Pfad verwendet werden soll:

- `kuri` HTTP-API: Produktions-Chrome/CDP-Automatisierung mit Sitzungen, Snapshots, Aktionen, HAR, Cookies und Screenshots
- `kuri-fetch`: eigenständige Fetch-/Textextraktion ohne Chrome
- `kuri-browse`: interaktives Terminal-Browsing
- `kuri-agent`: skriptbare CLI-Automatisierung gegen den Kuri-Server
- `kuri-browser/`: experimentelle separate Zig-native Browser-Laufzeit für Paritätsarbeit

Für die experimentelle Browser-CLI:```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 bietet eine Chrome-ähnliche HTTP-Erkennung sowie einen minimalen WebSocket-JSON-RPC-Router für Protokoll-Smoke-Tests. Runtime eval gibt V8-förmige CDP-Remoteobjekte zurück, die auf QuickJS basieren; dies fügt keine V8-Abhängigkeit hinzu und ist noch keine vollständige Playwright/Puppeteer-Kompatibilität.

Screenshots in kuri-browser werden derzeit an den Haupt-Kuri/CDP-Renderer delegiert. Starten Sie zuerst ./zig-out/bin/kuri, dann:```bash cd kuri-browser zig build run -- screenshot https://example.com --out example.jpg --compress --kuri-base http://127.0.0.1:8080

`--compress` erfasst eine PNG-Baseline und einen JPEG-Kandidaten, schreibt die kleinere Datei und meldet die eingesparten Bytes. Aktuelle lokale Messung auf `https://example.com`: `20,523` Bytes PNG zu `18,183` Bytes JPEG-Qualität 50, spart `2,340` Bytes oder `11%`.

### Erweitert

| Pfad | Beschreibung |
|------|--------------|
| `GET /diff/snapshot` | Kompaktes `+`/`~`/`-`-Delta gegenüber dem vorherigen Snapshot (Agenten-Aktionsschleife) |
| `GET /emulate` | Geräteemulation |
| `GET /geolocation` | Geolokalisierung festlegen |
| `POST /upload` | Datei-Upload |
| `GET /script/inject` | JavaScript injizieren |
| `GET /intercept/start` | Anfrage-Interception starten |
| `GET /intercept/stop` | Interception stoppen |
| `GET /screenshot/annotated` | Screenshot mit Element-Anmerkungen |
| `GET /screenshot/diff` | Visueller Diff zwischen Screenshots |
| `GET /screencast/start` | Screencast starten |
| `GET /screencast/stop` | Screencast stoppen |
| `GET /video/start` | Videoaufzeichnung starten |
| `GET /video/stop` | Videoaufzeichnung stoppen |
| `GET /console` | Konsolenmeldungen abrufen |
| `GET /stop` | Seitenladen stoppen |
| `GET /get` | Direkter HTTP-Abruf (serverseitig) |
| `GET /scrollintoview` | Ein referenziertes Element in den sichtbaren Bereich scrollen |
| `GET /drag` | Von einem Ref zu einem anderen ziehen |
| `GET /keyboard/type` | Text mit Tastaturereignissen eingeben |
| `GET /keyboard/inserttext` | Text direkt einfügen |
| `GET /keydown` | Ein Keydown-Ereignis auslösen |
| `GET /keyup` | Ein Keyup-Ereignis auslösen |
| `GET /wait` | Auf Ready-State oder Elementbedingungen warten |
| `GET /tab/close` | Tab schließen |
| `GET /highlight` | Ein Element per Ref oder Selektor hervorheben |
| `GET /errors` | Seiten-/Laufzeitfehler abrufen |
| `GET /set/offline` | Offline-Netzwerkemulation umschalten |
| `GET /set/media` | Emulierte Medienfunktionen festlegen |
| `GET /set/credentials` | HTTP-Basisauthentifizierungsdaten festlegen |
| `GET /find` | Textübereinstimmungen auf der aktuellen Seite finden |
| `GET /trace/start` | Chrome-Tracing starten |
| `GET /trace/stop` | Tracing stoppen und Tracedaten zurückgeben |
| `GET /profiler/start` | JS-Profiler starten |
| `GET /profiler/stop` | JS-Profiler stoppen |
| `GET /inspect` | Ein Element oder den Seitenzustand untersuchen |
| `GET /set/viewport` | Viewport-Größe festlegen |
| `GET /set/useragent` | User-Agent überschreiben |
| `GET /dom/attributes` | Elementattribute abrufen |
| `GET /frames` | Frame-Baum auflisten |
| `GET /network` | Netzwerkstatus/-anfragen untersuchen |

---

## 🛡️ Stealth & Bot-Umgehung

Kuri wendet Anti-Erkennungs-Patches beim Start automatisch an — keine manuelle Konfiguration erforderlich.

### Was angewendet wird

- **`Page.addScriptToEvaluateOnNewDocument`** — Stealth-Patches werden vor jedem Seiten-JS ausgeführt
- **navigator.webdriver = false** — verbirgt das Automatisierungsflag auf Chromium-Ebene (`--disable-blink-features=AutomationControlled`)
- **WebGL/Canvas/AudioContext-Spoofing** — überwindet fingerabdruckbasierte Erkennung
- **UA-Rotation** — 5 realistische Chrome-/Safari-/Firefox-User-Agents
- **chrome.csi/chrome.loadTimes** — Stubs für Akamai-spezifische Prüfungen

### Bot-Block-Erkennung

Navigate erkennt Blockierungen automatisch und gibt ein strukturiertes Fallback zurück:```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

Detects: Akamai, Cloudflare, PerimeterX, DataDome, generisches Captcha.

Proxy-Unterstützung```bash

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

### Getestete Websites

| Website | Schutz | Ergebnis |
|------|-----------|--------|
| Singapore Airlines | Akamai WAF | ✅ Umgangen (war vor v0.4.0 blockiert) |
| Shopee SG | Eigener Anti-Fraud-Schutz | ✅ Seite lädt, leitet zur Anmeldung um |
| Google Flights | Keiner | ✅ Vollständige Interaktion |
| Booking.com | PerimeterX | ⚠️ Benötigt Proxy |

---

## 🔧 kuri-fetch

Eigenständiger HTTP-Fetcher — kein Chrome, kein Playwright, kein npm. Wird als ~2 MB große Binärdatei mit integriertem QuickJS für die JavaScript-Ausführung geliefert.```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

Funktionen

  • 5 Ausgabemodimarkdown, html, links, text, json
  • QuickJS-JS-Engine--js führt Inline-<script>-Tags aus
  • DOM-Stubsdocument.querySelector, getElementById, window.location, document.title, console.log, setTimeout (SSR-Stil)
  • SSRF-Schutz — blockiert private IPs, Metadaten-Endpunkte, Nicht-HTTP-Schemas
  • Farbige Ausgabe — berücksichtigt NO_COLOR, TERM=dumb, --no-color, TTY-Erkennung
  • Dateiausgabe-o / --output mit Byteanzahl + Timing-Zusammenfassung
  • Benutzerdefinierter UA--user-agent-Flag
  • Stiller Modus-q unterdrückt die stderr-Statusausgabe

🌐 kuri-browse

Interaktiver Terminal-Browser — durchstöbere das Web von deinem Terminal aus. Kein Chrome erforderlich.```bash zig build browse # build + run

kuri-browse https://example.com

Bitte fügen Sie den zu übersetzenden Markdown-Inhalt ein.```
🌰 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

Befehle

BefehlAktion
<number>Link [N] folgen
<url>Navigieren (wenn . enthalten)
:go <url>Zu URL navigieren
:back, :bIn der Historie zurückgehen
:forward, :fVorwärtsgehen
:reload, :rAktuelle Seite neu laden
:links, :lLink-Index anzeigen
/<term>In Seite suchen (markiert Treffer)
:search <t>In Seite suchen
:n, :nextSuche erneut hervorheben
:historyNavigationsverlauf anzeigen
:help, :hAlle Befehle anzeigen
:quit, :qBeenden

Funktionen

  • Farbige Markdown-Darstellung — Überschriften, Links, Codeblöcke, Fettdruck, Blockzitate
  • Nummerierte Links — jeder Link erhält [N]; gib die Nummer ein, um ihm zu folgen
  • Navigationsverlauf — zurück/vorwärts wie in einem echten Browser
  • Suche in der Seite/term markiert alle Treffer
  • Relative URL-Auflösung — folgt Links natürlich über Seiten hinweg
  • Intelligente Filterung — überspringt javascript:- und mailto:-hrefs

🤖 kuri-agent

Skriptbare CLI für die Chrome-Automatisierung — steuert den Browser Befehl für Befehl von deinem Terminal oder Shell-Skripten. Teilt den Sitzungszustand über Aufrufe hinweg über ~/.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

### Befehle

| Befehl | Beschreibung |
|---------|-------------|
| `tabs [--port N]` | Chrome-Tabs auflisten |
| `use <ws_url>` | An einen Tab anhängen (speichert Sitzung) |
| `open [url] [--port N]` | Neuen Tab öffnen (optional zu URL navigieren) |
| `status` | Aktuelle Sitzung anzeigen |
| `go <url>` | Zu URL navigieren |
| `snap [--interactive] [--json] [--text] [--depth N]` | A11y-Snapshot, speichert `eN`-Referenzen |
| `click <ref>` | Element anhand der Referenz anklicken (CDP-Mausereignisse, React-kompatibel) |
| `type <ref> <text>` | In Element tippen (Tastaturereignisse pro Zeichen, React-kompatibel) |
| `fill <ref> <text>` | Eingabewert ausfüllen |
| `select <ref> <value>` | Dropdown-Option auswählen |
| `hover <ref>` | Maus über Element bewegen |
| `focus <ref>` | Element fokussieren |
| `scroll` | Seite scrollen |
| `viewport [width height]` | Viewport-Abmessungen abrufen oder festlegen |
| `eval <js>` | JavaScript auswerten |
| `text [selector]` | Seitentext abrufen |
| `shot [--out file.png]` | Screenshot |
| `back` | Zurück navigieren |
| `forward` | Vorwärts navigieren |
| `reload` | Aktuelle Seite neu laden |
| `cookies` | Cookies mit Sicherheitsflags auflisten |
| `headers` | Sicherheits-Response-Header prüfen |
| `audit` | Vollständiger Sicherheits-Audit |
| `storage [local\|session\|all]` | localStorage / sessionStorage ausgeben |
| `jwt` | JWTs aus Cookies und Storage extrahieren und decodieren |
| `fetch <method> <url> [--data <json>]` | Authentifizierten Fetch mit Seiten-Cookies durchführen |
| `probe <url-template> <start> <end>` | IDOR-Probe: numerische IDs in der URL durchlaufen |
| `grab <ref>` | Referenz anklicken, `window.open` abfangen, Weiterleitung im Tab verfolgen |
| `wait-for-tab [--port N]` | Auf neuen Tab warten (Polling), Sitzung automatisch wechseln |
| `stealth` | Anti-Erkennungs-Patches anwenden |
| `set-header <name> <value>` | Benutzerdefinierten Header zu allen Anfragen hinzufügen |
| `show-headers` | Gespeicherte zusätzliche Header anzeigen |
| `clear-headers` | Alle zusätzlichen Header entfernen |
---

## 📱 kuri-mobile (iOS + Android)

Native Zig-CLI zum Steuern von iOS-Simulatoren, echten iPhones (Auflisten + Starten/Beenden) und Android-Geräten/Emulatoren — inspiriert von [`mobile-device-mcp`](https://github.com/srmorete/mobile-device-mcp), in Zig neu implementiert, ohne Bun/Node/Gradle/Xcode im Build-Pfad.```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

Was nativ in Zig ist: adb-Hostprotokoll (libc-Sockets, 4-Hex-Framing über host:transport:/shell:/exec:), Android-XML-UI-Tree-Parser, usbmuxd-ListDevices-Plist-Client. Was extern aufruft: xcrun simctl (iOS-Simulator), xcrun devicectl (Starten/Beenden auf echten iOS-Geräten). Konstruktionsbedingt treiberlos: es wird keine App auf dem Gerät installiert, daher sind run_code-Sandboxes und die auf XCUITest basierenden tap/uitree-Funktionen auf echten iOS-Geräten bewusst nicht verfügbar. Siehe kuri-mobile/README.md für die vollständige Paritätsmatrix im Vergleich zum Upstream.


🔒 Sicherheitstests

kuri-agent unterstützt browser-native Sicherheits-Trajektorien — melde dich einmal an und führe dann Reconnaissance- sowie Header-/Cookie-Audits durch, ohne das Terminal zu verlassen.

Trajektorien

Enumerate → Inspect — nach der Authentifizierung Authentifizierungs-Cookies ausgeben und Sicherheits-Flags prüfen:```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-Überprüfung** — prüfen, welche Sicherheits-Header das Ziel sendet:```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", ...}}

Vollständiges Audit — HTTPS, fehlende Header, JS-sichtbare Cookies auf einen Schlag:```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'", ...}}

**Kontenübergreifende Trajektorie** — verwenden Sie `eval`, um API-Aufrufe mit unterschiedlichen Tokens erneut auszuführen:```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)"

Format des Trajektorienberichts

kuri-agent gibt JSON aus, das für die Pipeline-Integration geeignet ist. Jeder Sicherheitsbefehl erzeugt eine einzelne JSON-Zeile – zur Triage durch jq leiten:```bash kuri-agent audit | jq '.issues[]' kuri-agent cookies | head -20 kuri-agent headers | jq '.headers | to_entries[] | select(.value == "(missing)") | .key'

---


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

Speichermodell

  • Arena-pro-Anfrage — der gesamte Anfrage-Speicher wird in einem einzigen deinit()-Aufruf freigegeben
  • Kein GCGeneralPurposeAllocator im Debug-Modus fängt jedes Speicherleck
  • Saubere BereinigungskettenLauncher → Bridge → CdpClients → HarRecorders → Snapshots → Tabs
  • errdefer-Schutzmechanismen — Teilfehler werden sauber zurückgerollt

Chrome-Lebenszyklus

ModusVerhalten
Verwaltet (keine CDP_URL)Startet Chrome headless, findet freien CDP-Port, überwacht, startet bei Absturz automatisch neu (max. 3 Versuche), beendet beim Herunterfahren
Extern (CDP_URL gesetzt)Verbindet sich mit vorhandenem Chrome, führt einen Health-Check über /json/version durch, beendet beim Herunterfahren NICHT

📁 Struktur```

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

---

## ⚙️ Konfiguration

| Umgebungsvariable | Standard | Beschreibung |
|---------|---------|-------------|
| `HOST` | `127.0.0.1` | Bindeadresse des Servers |
| `PORT` | `8080` | Server-Port |
| `CDP_URL` | *(none)* | Mit bestehendem Chrome verbinden (`ws://...` oder `http://127.0.0.1:9222`) |
| `KURI_SECRET` | *(none)* | Auth-Secret für API-Anfragen |
| `STATE_DIR` | `.kuri` | Verzeichnis für den Sitzungsstatus |
| `REQUEST_TIMEOUT_MS` | `30000` | HTTP-Anfrage-Timeout |
| `NAVIGATE_TIMEOUT_MS` | `30000` | Navigations-Timeout |
| `STALE_TAB_INTERVAL_S` | `30` | Intervall für die Bereinigung veralteter Tabs |
| `NO_COLOR` | *(none)* | Farbige CLI-Ausgabe deaktivieren |

---

## 💰 Token-Kosten

Für eine Monitoring-Aufgabe über 50 Seiten (aus Pinchtab-Benchmarks):

| Methode | Token | Kosten ($) | Geeignet für |
|--------|--------|----------|----------|
| `/text` | ~40,000 | $0.20 | Leselastig (13× günstiger als Screenshots) |
| `/snapshot?filter=interactive&format=compact` | ~40,000 | $0.20 | Elementinteraktion mit geringem Token-Verbrauch |
| `/snapshot` (voll) | ~525,000 | $2.63 | Verständnis der gesamten Seite |
| `/screenshot` | ~100,000 | $1.00 | Visuelle Verifizierung |

---

## 🤝 Mitwirken

Öffne ein Issue, bevor du einen großen PR einreichst, damit wir uns über die Vorgehensweise abstimmen können.```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)

Siehe CONTRIBUTORS.md für Richtlinien.


Danksagungen

ProjektWas wir übernommen haben
agent-browser@eN-Referenzsystem, Snapshot-Diffing, HAR-Aufzeichnungsmuster
PinchtabBrowsersteuerungsarchitektur für KI-Agenten
PathikHochleistungs-Crawling-Muster
QuickJS-ng via mitchellh/zig-quickjs-ngJS-Engine für kuri-fetch
LightpandaZig-nativer Headless-Browser-Pionier, CDP-Kompatibilitätsmuster
Zig 0.16.0Der gesamte Stack

Lizenz

Apache-2.0

Kategorien