
kuri v0.4.14
ブラウザ自動化、Webクローリング、iOSおよびAndroidデバイス制御をAIエージェント向けに提供。Zigネイティブ、トークン効率の良いCDPスナップショット、HAR記録、ネイティブなadbワイヤープロトコルクライアント、そしてスタンドアロンフェッチャー。
Kuri 🌰
インストール```sh
curl -fsSL https://kuri.trilok.ai/download | sh
macOS arm64/x86_64 および Linux x86_64/arm64。単一バイナリ、ランタイム依存関係なし。
直接ダウンロード: [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)
---
**AIエージェントのためのブラウザ自動化&Webクローリング。Zig製。Node.jsゼロ。**
CDP自動化 · A11yスナップショット · HAR記録 · スタンドアロンフェッチャー · 対話型ターミナルブラウザ · エージェント型CLI · セキュリティテスト · iOS + Androidデバイス制御
[クイックスタート](#-quick-start) · [ベンチマーク](#-benchmarks) · [kuri-agent](#-kuri-agent) · [セキュリティテスト](#-security-testing) · [API](#-http-api) · [スキル](#-skills) · [変更履歴](https://github.com/justrach/kuri/blob/HEAD/CHANGELOG.md)
> **Kuriに乗り換えるチームの理由:** 現在のApple Silicon向け`ReleaseFast`ビルドはバイナリあたり2MB未満を維持しており、2026-04-23に実行したGoogle Flightsの最新再実行では、`kuri-agent`のフルループ(`go→snap→click→snap→eval`)で**3,392トークン**と測定されました。パーセンテージを引用する前に、クロスツール間の差分は同じ環境で再実行してください。
---
## Kuriがエージェントに選ばれる理由
ほとんどのブラウザツールはQAエンジニア向けに作られています。Kuriはエージェントループ向けに作られています。ページを読み、トークンコストを低く抑え、安定した参照に対して操作し、次へ進む、という流れです。
- **135のHTTPエンドポイント** — React inspectionからCore Web Vitalsまで、agent-browserおよびbrowser-useと完全な互換性。
- **agent-browserより7〜12%少ないトークン** — 実際のページでの数値で、`@eN`参照形式とゼロプレフィックスレンダリングによる効果です。
- **44倍軽量な観測** — 同じGoogle Flightsページで`/page/state`(48トークン)はフルスナップショット(2,124トークン)と比較して44倍軽量。
- **バッチ実行** — `POST /batch`はN個のコマンドを1回のHTTP呼び出しで送信し、N-1回のラウンドトリップとN-1回のLLMターンを排除します。
- **React互換** — 信頼できるCDPマウスイベントと1文字単位のキーイベントがReact 18/19の`onClick`と`onChange`を発火。
### スナップショットトークン: Google Flights `SIN → TPE`
このワークスペースで2026-05-24に再実行した最新結果。`wc -c`と`chars/4`近似で測定。
| ツール / モード | 文字数 | ~トークン | 備考 |
|---|---:|---:|---|
| `kuri snap`(フル) | 8,499 | **2,124** | 全ノード + インタラクティブ参照 |
| `kuri snap`(インタラクティブのみ) | ~3,000 | **~750** | エージェントループに最適 |
| `kuri /page/state` | 190 | **48** | 軽量な観測(url、タイトル、スクロール%、カウント) |
| agent-browser snap(推定) | ~9,183 | **~2,295** | `[ref=e0]`形式のオーバーヘッド |
### トークン効率: kuri vs agent-browser
| ページ | kuriトークン | agent-browserトークン | 削減率 |
|---|---:|---:|---|
| example.com | 40 | 35 | -13%(単純なページ。agent-browserはルートをスキップ) |
| Hacker News | 386 | ~440 | **12%削減** |
| Google Flights SIN→TPE | 2,124 | ~2,295 | **7%削減** |
削減はkuriのコンパクトな形式によるものです:
- `@e0`参照(3文字) vs `[ref=e0]`(9文字)
- 行ごとの`- `プレフィックスなし(行数 × 2文字の削減)
- 同じインデント、同じノードフィルタリング
### フルワークフローコスト: `go → snap → click → snap → eval`
| ツール | サイクルあたりのトークン |
|---|---:|
| **kuri-agent** | **~3,400** |
| 2回目のスナップの代わりに`/page/state`を使用 | **~1,700** |
| `POST /batch`を使用(すべて1回の呼び出しで) | **~1,700**(同じトークン、5回ではなく1回のHTTP呼び出し) |
### kuri vs libretto
[libretto](https://github.com/saffron-health/libretto)(Playwright + Node)は、ステップごとのトークンコストで最も近い競合です。2026-07-04に同じChrome、同じタブで直接比較測定し、実際の`tiktoken` `o200k_base`カウントを使用しました(完全な方法論と再現手順: **[benchmarks/libretto_comparison.md](https://github.com/justrach/kuri/blob/HEAD/benchmarks/libretto_comparison.md)**)。正直な内訳は以下の通りです:
| 軸 | 勝者 | 詳細 |
|---|---|---|
| 呼び出しあたりのレイテンシ | **kuri** | 4〜117ms vs 1,344〜1,500ms(**13〜376倍高速** — 常駐サーバー vs コマンドごとのNode) |
| スナップショットトークン(一般的なページ) | **kuri** | シンプルなページ 61 vs 151(2.5倍)、記事 265 vs 363(1.37倍)— よりコンパクトな文法 |
| スナップショットトークン(大きなリスト) | 分かれる | kuriはデフォルトで4,424 vs 813 — kuriは259個すべての参照を出力し、librettoはデフォルトで切り詰めます。`limit=5`の場合、kuriは555トークンをレンダリング(**librettoの1.46倍少ない**)、34個の参照 + `… +45 more`マーカー |
| トラジェクトリ(フィード、9クリック) | **kuri**(僅差) | 898 vs 939トークン(`limit=5`ベース + 差分ループ vs 実行ループ)— 同等から僅かに優勢。朝の5.1倍の劣勢は、切り詰めていないベースが原因 |
| 繰り返し実行 | **libretto** | トラジェクトリをPlaywrightスクリプトにコンパイル → 0トークンでリプレイ。kuriは実行のたびにループのコストを再び支払う |
**kuriがlibrettoの研究から得たもの**(すべてこのリリースで導入済み):差分ファーストのループ(`take_snapshot_diff`、ステップあたり約38トークン);ナビゲーション時に`! page replaced`ヘッダー付きのフルスナップショットへフォールバックする適応型差分;IDのみの削除行;スクリーンショットのディスク書き込み(パスが返され、バイトがコンテキストに入ることはありません);MCP上の`get_page_state`;そして`parseA11yNodes`を実際のDFSツリーウォークとして書き直した後 — **オプトインのリスト切り詰め**(`/snapshot?limit=N`、上限到達ランごとに`… +K more`を1行)、**スコープ指定の再キャプチャ**(`scope=@ref`)、**階層インデント**。これらはMCPの`take_snapshot`でも`uid`/`limit`として公開されています。単純なフル再スナップショットで44,285トークンかかっていた9クリックのフィードトラジェクトリは、切り詰めベース + 差分で**898**トークン — 49倍安く、librettoの939をも下回ります。
> 上記の古い表は`chars/4`トークン近似を使用しています。librettoとの比較では実際の`tiktoken`カウントを使用しています。パーセンテージを引用する前に、ご自身の環境でクロスツールの数値を再実行してください。
### バイナリサイズとメモリ
Apple M4 Pro、macOS 26.4.1で測定。現在のバイナリは`-Doptimize=ReleaseFast`でビルドされています。
| バイナリ | 現在のサイズ |
|---|---:|
| `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) |
### Zig 0.16移行後もRSSは横ばい
現在の`v0.4.3` `ReleaseFast`ビルドを`/usr/bin/time -l`で測定。
| コマンド | `v0.4.3`平均最大RSS |
|---|---:|
| `kuri-fetch --version` | ~2.45 MiB |
| `kuri-browse --version` | ~2.45 MiB |
| `kuri-fetch --quiet --dump markdown http://example.com/` | ~9.17 MiB |
## 問題
すべてのブラウザ自動化ツールはPlaywright(約300MB)、Node.jsランタイム、そして大量のnpm依存関係を引き込みます。AIエージェントがやりたいのは、ページを読み、ボタンをクリックし、次へ進むことだけです。
**Kuriは単一のZigバイナリです。** 4つのモード、ランタイムゼロ:```
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)
📦 インストール
ワンラインインストール(macOS / Linux)```sh
curl -fsSL https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh | sh
あなたのプラットフォームを検出し、適切なバイナリをダウンロードして、`~/.local/bin` にインストールします。
ダウンロードはKuriの自己管理型`release-channel`ブランチから取得されます。macOSバイナリはDeveloper ID証明書でローカル署名されています。GitHub Releaseのアセットはこれらと同じtarballをミラーリングしています。
### bun / npm```sh
bun install -g kuri-agent
# or: npm install -g kuri-agent
インストール時に、お使いのプラットフォームに適したネイティブバイナリをダウンロードします。
リリースチャンネル
Kuri の安定版バイナリは release-channel ブランチに置かれ、GitHub の raw URL から直接配信されます。
- 安定版インストーラ:
https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh - 安定版マニフェスト:
https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/latest.json - ブランチ表示:
https://github.com/justrach/kuri/tree/release-channel/stable - 直接ダウンロード形式:
https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/<version>/kuri-<version>-<target>.tar.gz
手動
お使いのプラットフォーム用の tarball を 安定版リリースマニフェスト または GitHub Releases ページ からダウンロードし、$PATH に展開します。
安定版インストール URL:```sh curl -fsSL https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh | sh
マニフェストには、`aarch64-linux`、`x86_64-linux`、`aarch64-macos`、`x86_64-macos` の正確なアセットURLとSHA-256チェックサムが含まれています。
### 対応プラットフォーム
| プラットフォーム | ステータス |
|---|---|
| macOS (`aarch64`, `x86_64`) | プリビルドバイナリ、署名済み+公証済み |
| Linux (`aarch64`, `x86_64`) | プリビルドバイナリ |
| Windows (`x86_64`) | **実験的 — クロスコンパイルのみ。** `zig build -Dtarget=x86_64-windows-gnu` はCIで検証済みですが、Chrome自動化、デーモン化、シグナルベースのシャットダウン、HAR記録、ファイルベースの認証ストアは、実行時にすべて `error.UnsupportedOnWindows` でスタブ化されています。実際の機能セットが必要な場合は **WSL2** を使用してください。追跡: [#153](https://github.com/justrach/kuri/issues/153)。 |
Kuriは、いくつかの箇所でPOSIXプリミティブ(`fork`、`clock_gettime`、rawソケット)に依存しているため、完全なネイティブWindows移植は本格的な作業になります。上記のコンパイルレベルのベースラインにより、`--version`/`--help` パスと純粋なインメモリ操作は実行できますが、厄介な部分(Chrome、ソケット、デーモン化)は、スタブリストから外す前に実際のWin32実装が必要です。これらに取り組む場合は、[#153](https://github.com/justrach/kuri/issues/153) に+1するか、PRを開いてください。
### ソースからビルド
[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
⚡ クイックスタート
要件: Zig ≥ 0.16.0 · Chrome/Chromium (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)
### 初回実行、最短経路```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
セッションファーストのエージェントループ
エージェントスタイルのHTTP利用では、毎回の呼び出しでtab_idを繰り返す代わりに、セッションヘッダーと/tab/new、/page/info、/snapshotを使用することを推奨します。```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"
同じ HTTP サーフェス上で Python ヘルパーを利用したい場合は、`tools/kuri_harness.py` という薄い実験用ラッパーもあります。
既にリモートデバッグで Chrome を実行している場合は、`CDP_URL` を WebSocket または 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
4つのコマンドでvercel.comを閲覧する```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
すべてのエンドポイントはJSONを返します。オプションの認証は `KURI_SECRET` 環境変数経由。**135エンドポイント** — agent-browser および browser-use との完全なパリティ。
### コア
| パス | 説明 |
|------|-------------|
| `GET /health` | サーバーのステータス、タブ数、バージョン |
| `GET /tabs` | 登録済みの全タブを一覧表示 |
| `GET /discover` | CDP経由でChromeタブを自動検出 |
| `GET /tab/current` | `X-Kuri-Session` の現在のタブを取得または設定 |
| `GET /page/info` | アクティブタブのライブURL/タイトル/ready-state/ビューポート/スクロール |
| `GET /page/state` | コンパクトなページ観測: url、title、scroll%、viewport、forms/links/images/inputsの数 |
| `POST /batch` | 1回のHTTP呼び出しで複数のコマンドを実行 — 結果の配列を返します |
| `GET /browdie` | 🌰 (イースターエッグ) |
### ブラウザ制御
| パス | パラメータ | 説明 |
|------|--------|-------------|
| `GET /navigate` | `tab_id`, `url` | タブをURLへ移動 |
| `GET /tab/new` | `url`, `activate`, `wait` | 新しいタブを作成し、必要に応じてハイドレート/現在タブとして設定 |
| `GET /tab/close` | `tab_id` | タブを閉じる |
| `GET /window/new` | `url`, `activate`, `wait` | 新しいウィンドウ/タブターゲットを作成 |
| `GET /snapshot` | `tab_id`, `filter`, `format` | `eN` 参照付きのA11yツリースナップショット。低トークンのエージェントループには `filter=interactive&format=compact` を使用します。 |
| `GET /text` | `tab_id` | ページのテキストを抽出 |
| `GET /screenshot` | `tab_id`, `format`, `quality`, `save` | スクリーンショットを撮影 (base64)。`save=true` の場合はPNGを `STATE_DIR/screenshots` に書き込み、代わりに `{path,bytes}` を返します |
| `GET /screenshot/annotated` | `tab_id` | 番号付き要素ラベル付きスクリーンショット |
| `GET /screenshot/diff` | `tab_id`, `baseline` | 現在とベースラインのスクリーンショット間のビジュアル差分 |
| `GET /action` | `tab_id`, `ref`, `action`, `value` | refによるクリック/タイプ/フィル/選択/スクロール/ホバー/ダブルクリック/チェック/チェック解除/ブラー |
| `GET /evaluate` | `tab_id`, `expression` | JavaScriptを実行 |
| `GET /evalhandle` | `tab_id`, `expression` | JSを実行し、objectIdハンドルを返す (値は返しません) |
| `GET /close` | `tab_id` | タブを閉じる + クリーンアップ |
| `GET /bringtofront` | `tab_id` | タブを前面に移動 |
### アクション
| パス | パラメータ | 説明 |
|------|--------|-------------|
| `GET /clear` | `ref` | 入力フィールドの値をクリア |
| `GET /selectall` | `ref` | input/contenteditable内の全テキストを選択 |
| `GET /setvalue` | `ref`, `value` | 入力値を直接設定 (キーイベントをバイパス) |
| `GET /dispatch` | `ref`, `type` | 要素上でカスタムDOMイベントをディスパッチ |
| `GET /boundingbox` | `ref` | 要素のバウンディング矩形を取得 (x, y, width, height, centerX, centerY) |
| `GET /getattribute` | `ref`, `name` | 名前で要素の属性を取得 |
| `GET /inputvalue` | `ref` | 現在の入力要素の値を取得 |
| `GET /element/state` | `ref`, `check` | クイック真偽値: `exists`, `visible`, `enabled`, `checked` |
| `GET /find-element` | `text`/`role`/`label`/`placeholder`/`testid` | セマンティックロケーター — スナップなしで要素を検索 |
| `GET /highlight` | `ref` or `selector` | オーバーレイで要素をハイライト |
### マウス & タッチ
| パス | パラメータ | 説明 |
|------|--------|-------------|
| `GET /mouse/move` | `x`, `y` | マウスを座標へ移動 |
| `GET /mouse/down` | `x`, `y`, `button` | マウスボタンを押す |
| `GET /mouse/up` | `x`, `y`, `button` | マウスボタンを離す |
| `GET /mouse/wheel` | `x`, `y`, `deltaX`, `deltaY` | マウスホイールスクロール |
| `GET /tap` | `x`, `y` | タッチタップ (touchStart + touchEnd) |
| `GET /swipe` | `startX`, `startY`, `endX`, `endY` | タッチスワイプジェスチャー |
| `GET /drag` | `src_ref`, `tgt_ref` | 要素をターゲットへドラッグ |
### キーボード
| パス | パラメータ | 説明 |
|------|--------|-------------|
| `GET /keyboard/type` | `tab_id`, `text` | キーイベント経由でテキストを入力 |
| `GET /keyboard/inserttext` | `tab_id`, `text` | テキストを直接挿入 |
| `GET /keydown` | `tab_id`, `key` | キーダウンイベント |
| `GET /keyup` | `tab_id`, `key` | キーアップイベント |
### コンテンツ抽出
| パス | 説明 |
|------|-------------|
| `GET /markdown` | ページをMarkdownに変換 |
| `GET /links` | すべてのリンクを抽出 |
| `GET /dom/query` | CSSセレクタークエリ |
| `GET /dom/html` | 要素のHTMLを取得 |
| `GET /dom/attributes` | 要素の属性を取得 |
| `GET /pdf` | ページをPDFに印刷 |
| `GET /find` | ページ内テキスト検索 |
### 待機
| パス | パラメータ | 説明 |
|------|--------|-------------|
| `GET /wait` | `selector`, `text`, `url`, `state`, `visible`, `timeout` | セレクター/テキスト/URLパターン/networkidle/ロード状態を待機 |
| `GET /wait/function` | `expression`, `timeout` | 任意のJS式が真になるまで待機 |
| `GET /wait/download` | `timeout` | ファイルのダウンロード完了を待機 |
### ダイアログ処理
| パス | 説明 |
|------|-------------|
| `GET /dialog/auto` | すべてのJSダイアログを自動処理 (承諾またはキャンセル) |
| `GET /dialog/accept` | 現在のダイアログを承諾 (オプションでプロンプトテキスト付き) |
| `GET /dialog/dismiss` | 現在のダイアログをキャンセル |
### ネットワーク & HAR
| パス | 説明 |
|------|-------------|
| `GET /har/start` | ネットワークトラフィックの記録を開始 |
| `GET /har/stop` | 停止してHAR 1.2 JSONを返す |
| `GET /har/status` | 記録状態 + エントリ数 |
| `GET /har/replay` | curl/fetch/pythonコードスニペット付きのAPIマップ |
| `GET /cookies` | Cookieを取得 |
| `GET /cookies/set` | Cookieを設定 |
| `GET /cookies/delete` | Cookieを削除 |
| `GET /cookies/clear` | すべてのCookieをクリア |
| `GET /headers` | カスタムリクエストヘッダーを設定 |
| `GET /intercept/start` | リクエストインターセプトを開始 |
| `GET /intercept/stop` | リクエストインターセプトを停止 |
| `GET /intercept/requests` | インターセプトされたリクエストを一覧表示 |
| `GET /request/detail` | リクエストIDのレスポンスボディを取得 |
| `GET /response/body` | URLをフェッチしてレスポンスボディを返す |
| `GET /network` | ネットワークトラフィック統計 |
| `GET /download` | ファイルダウンロードをトリガー |
### ナビゲーション & 状態
| パス | 説明 |
|------|-------------|
| `GET /back` | ブラウザの戻る |
| `GET /forward` | ブラウザの進む |
| `GET /reload` | ページを再読み込み |
| `GET /stop` | ページの読み込みを停止 |
| `GET /pushstate` | history.pushStateによるSPAナビゲーション |
| `GET /storage/local` | localStorageを取得/設定 |
| `GET /storage/session` | sessionStorageを取得/設定 |
| `GET /storage/local/clear` | localStorageをクリア |
| `GET /storage/session/clear` | sessionStorageをクリア |
| `GET /session/save` | ブラウザセッションを保存 |
| `GET /session/load` | ブラウザセッションを復元 |
| `GET /session/list` | 保存済みセッションを一覧表示 |
| `GET /setcontent` | ページのHTMLを直接設定 (POST) |
### 認証プロファイル
| パス | 説明 |
|------|-------------|
| `GET /auth/profile/save` | Cookie + ストレージを名前付き認証プロファイルとして保存 |
| `GET /auth/profile/load` | 名前付き認証プロファイルをタブに復元 |
| `GET /auth/profile/list` | 保存済み認証プロファイルを一覧表示 |
| `GET /auth/profile/delete` | 保存済み認証プロファイルを削除 |
| `GET /auth/extract` | 認証トークンを抽出 (JWT, cookies, headers) |
| `GET /set/credentials` | HTTP基本認証の資格情報を設定 |
macOSでは、認証プロファイルのシークレットはユーザーのキーチェーンに保存されます。
### エミュレーション
| パス | パラメータ | 説明 |
|------|--------|-------------|
| `GET /emulate` | デバイスタイプ, 画面サイズ | デバイスエミュレーション |
| `GET /set/viewport` | `width`, `height` | ビューポートサイズを設定 |
| `GET /set/useragent` | `ua` | ユーザーエージェントを設定 |
| `GET /set/media` | `media` | メディアタイプをエミュレート |
| `GET /set/offline` | `offline` | オフラインモードを切り替え |
| `GET /geolocation` | `lat`, `lng` | 地理位置情報を上書き |
| `GET /timezone` | `timezone` | タイムゾーンを上書き (例: `America/New_York`) |
| `GET /locale` | `locale` | ロケールを上書き (例: `en-US`) |
| `GET /permissions` | `name`, `state` | 権限を許可/拒否 (geolocation, notifications, clipboard) |
### スクリプト & インジェクション
| パス | 説明 |
|------|-------------|
| `GET /script/inject` | ページにJavaScriptを注入 (ナビゲーション間で維持) |
| `GET /initscript/remove` | 以前に注入されたinitスクリプトを削除 |
| `GET /addstyle` | CSSスタイルシートを注入 |
| `GET /expose` | 名前付き関数をページのJSコンテキストに公開 |
### Reactインスペクション
| パス | 説明 |
|------|-------------|
| `GET /react/tree` | DevToolsフック経由のReactコンポーネントツリー |
| `GET /react/inspect` | Reactコンポーネントのpropsとstate |
| `GET /react/renders` | Reactレンダーの追跡 (start/stop) |
| `GET /react/suspense` | React Suspenseバウンダリのステータス |
### レコーディング & パフォーマンス
| パス | 説明 |
|------|-------------|
| `GET /recording/start` | ユーザーアクションを記録 (click, input, navigate) |
| `GET /recording/stop` | 記録を停止してアクションログを返す |
| `GET /vitals` | Core Web Vitals (LCP, CLS, FID, TTFB, FCP, domInteractive) |
| `GET /perf/lcp` | Largest Contentful Paintのタイミング |
| `GET /trace/start` | パフォーマンストレースを開始 |
| `GET /trace/stop` | トレースを停止 |
| `GET /profiler/start` | JSプロファイラーを開始 |
| `GET /profiler/stop` | プロファイラーを停止 |
### デバッグ
| パス | 説明 |
|------|-------------|
| `GET /debug/enable` | ページ内デバッグHUDとオプションのフリーズモードを有効化 |
| `GET /debug/disable` | ページ内デバッグHUDを無効化 |
| `GET /inspect` | 要素の検査 |
| `GET /errors` | JSエラーを収集 |
| `GET /console` | コンソールログを読み取る |
| `GET /frames` | ページフレームを一覧表示 |
| `GET /frame` | 名前またはURLでiframeコンテキストに切り替え |
| `GET /mainframe` | メインフレームに戻る |
| `GET /diff/snapshot` | このタブの前回呼び出しとのコンパクトな `+`/`~`/`-` 差分 — トークン効率的なアクションループ (`/snapshot/changes` のエイリアス)。大幅な変更時は `! page replaced` ヘッダー付きの完全スナップショットにフォールバックします。 |
| `GET /diff/url` | 2つのURLを並べて比較 (navigate, snapshot, diff) |
### ストリーミング
| パス | 説明 |
|------|-------------|
| `GET /screencast/start` | 画面録画を開始 |
| `GET /screencast/stop` | 画面録画を停止 |
| `GET /video/start` | ビデオキャプチャを開始 |
| `GET /video/stop` | ビデオキャプチャを停止 |
| `GET /ws/start` | WebSocketトンネルを開始 |
| `GET /ws/stop` | WebSocketトンネルを停止 |
### エージェント向けループ
最も手間のかからないサーバーループは以下のとおりです:
1. `GET /tab/new?url=...`
2. `GET /page/state` (軽量) または `GET /snapshot?filter=interactive&format=compact` (完全)
3. `GET /action?action=click&ref=eN`
4. 繰り返す — または、1回の呼び出しで複数ステップの操作を行うには `POST /batch` を使用します
`url` と `expression` クエリパラメータはパーセントデコードされます。タブコンテキストをサーバー側に保持するには、`X-Kuri-Session: my-agent` を送信してください。
## 🧠 スキル
このリポジトリには、ユーザーが拡張可能なスキル領域が含まれています:
- `skills/kuri-skill.md` は基本のKuri HTTPエージェントスキルです
- `skills/custom/` はプロジェクト固有のスキル用に予約されています
- `skills/custom/hackernews-page-2.md` は具体的なカスタムスキルの例です
- `.claude/skills/kuri-server/SKILL.md` はClaudeスタイルのリポジトリスキルと同期が保たれます
基本スキルには、どのブラウザパスを使用するかの説明も追加されました:
- `kuri` HTTP API: 本番環境向けのChrome/CDPオートメーション。セッション、スナップショット、アクション、HAR、Cookie、スクリーンショットに対応
- `kuri-fetch`: Chrome不要のスタンドアロンfetch/テキスト抽出
- `kuri-browse`: 対話型ターミナルブラウジング
- `kuri-agent`: Kuriサーバーに対するスクリプト可能なCLIオートメーション
- `kuri-browser/`: パリティ作業用の実験的な独立Zigネイティブブラウザランタイム
実験的なブラウザ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 は、Chrome スタイルの HTTP ディスカバリと、プロトコルのスモークテスト用の最小限の WebSocket JSON-RPC ルーターを公開します。ランタイム eval は、QuickJS をバックエンドとする V8 形式の CDP リモートオブジェクトを返します。これは V8 への依存を追加するものではなく、まだ Playwright/Puppeteer との完全な互換性はありません。
kuri-browser のスクリーンショットは現在、メインの Kuri/CDP レンダラーに委譲しています。最初に ./zig-out/bin/kuri を起動してから、次のようにします:```bash
cd kuri-browser
zig build run -- screenshot https://example.com --out example.jpg --compress --kuri-base http://127.0.0.1:8080
`--compress` はPNGベースラインとJPEG候補をキャプチャし、小さい方のファイルを書き込み、バイト削減量を報告します。`https://example.com` での現在のローカル測定値: PNG `20,523` バイトからJPEG品質50で `18,183` バイトへ、`2,340` バイト(`11%`)の削減。
### 高度な操作
| Path | Description |
|------|-------------|
| `GET /diff/snapshot` | 以前のスナップショットとのコンパクトな `+`/`~`/`-` 差分(エージェントアクションループ) |
| `GET /emulate` | デバイスエミュレーション |
| `GET /geolocation` | 地理位置情報の設定 |
| `POST /upload` | ファイルアップロード |
| `GET /script/inject` | JavaScriptを注入 |
| `GET /intercept/start` | リクエストインターセプトの開始 |
| `GET /intercept/stop` | インターセプトの停止 |
| `GET /screenshot/annotated` | 要素アノテーション付きスクリーンショット |
| `GET /screenshot/diff` | スクリーンショット間のビジュアル差分 |
| `GET /screencast/start` | スクリーンキャスト開始 |
| `GET /screencast/stop` | スクリーンキャスト停止 |
| `GET /video/start` | ビデオ録画の開始 |
| `GET /video/stop` | ビデオ録画の停止 |
| `GET /console` | コンソールメッセージの取得 |
| `GET /stop` | ページ読み込みの停止 |
| `GET /get` | 直接HTTPフェッチ(サーバーサイド) |
| `GET /scrollintoview` | 参照された要素をビューまでスクロール |
| `GET /drag` | あるrefから別のrefへドラッグ |
| `GET /keyboard/type` | キーイベントでテキストを入力 |
| `GET /keyboard/inserttext` | テキストを直接挿入 |
| `GET /keydown` | keydownイベントを発火 |
| `GET /keyup` | keyupイベントを発火 |
| `GET /wait` | 準備完了状態または要素条件が満たされるまで待機 |
| `GET /tab/close` | タブを閉じる |
| `GET /highlight` | refまたはセレクタで要素をハイライト |
| `GET /errors` | ページ/ランタイムエラーの取得 |
| `GET /set/offline` | オフラインのネットワークエミュレーションを切り替え |
| `GET /set/media` | エミュレートするメディア特性を設定 |
| `GET /set/credentials` | HTTP基本認証資格情報を設定 |
| `GET /find` | 現在のページ内でテキスト一致を検索 |
| `GET /trace/start` | Chromeトレースの開始 |
| `GET /trace/stop` | トレースを停止してトレースデータを返す |
| `GET /profiler/start` | JSプロファイラーの開始 |
| `GET /profiler/stop` | JSプロファイラーの停止 |
| `GET /inspect` | 要素またはページの状態を検査 |
| `GET /set/viewport` | ビューポートサイズを設定 |
| `GET /set/useragent` | ユーザーエージェントを上書き |
| `GET /dom/attributes` | 要素属性を取得 |
| `GET /frames` | フレームツリーを一覧表示 |
| `GET /network` | ネットワーク状態/リクエストを検査 |
---
## 🛡️ ステルス&ボット回避
Kuriは起動時に自動で検出回避パッチを適用します — 手動設定は不要です。
### 適用される内容
- **`Page.addScriptToEvaluateOnNewDocument`** — ステルスパッチはページのJSよりも先に実行されます
- **navigator.webdriver = false** — Chromiumレベルで自動化フラグを隠します(`--disable-blink-features=AutomationControlled`)
- **WebGL/Canvas/AudioContext spoofing** — フィンガープリントベースの検出を無効化します
- **UA rotation** — Chrome/Safari/Firefoxのリアルなユーザーエージェント5種
- **chrome.csi/chrome.loadTimes** — Akamai固有のチェック用スタブ
### ボットブロック検出
Navigateはブロックを自動検出し、構造化されたフォールバックを返します:```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
検出: Akamai、Cloudflare、PerimeterX、DataDome、汎用CAPTCHA。
プロキシ対応```bash
KURI_PROXY=socks5://user:pass@residential-proxy:1080 ./zig-out/bin/kuri KURI_PROXY=http://proxy:8080 ./zig-out/bin/kuri
### テスト済みサイト
| Site | Protection | Result |
|------|-----------|--------|
| Singapore Airlines | Akamai WAF | ✅ バイパスされました(v0.4.0 より前はブロックされていました) |
| Shopee SG | カスタム不正防止 | ✅ ページが読み込まれ、ログインにリダイレクトされます |
| Google Flights | なし | ✅ フル操作が可能 |
| Booking.com | PerimeterX | ⚠️ プロキシが必要 |
---
## 🔧 kuri-fetch
スタンドアロンHTTPフェッチャー — Chrome不要、Playwright不要、npm不要。QuickJSを内蔵した約2MBのバイナリとして配布され、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
Features
- 5つの出力モード —
markdown,html,links,text,json - QuickJS JS エンジン —
--jsはインラインの<script>タグを実行します - DOM スタブ —
document.querySelector、getElementById、window.location、document.title、console.log、setTimeout(SSR スタイル) - SSRF 防御 — プライベート IP、メタデータエンドポイント、非 HTTP スキームをブロックします
- カラー出力 —
NO_COLOR、TERM=dumb、--no-color、TTY 検出を尊重します - ファイル出力 —
-o/--output、バイト数 + タイミングサマリー付き - カスタム UA —
--user-agentフラグ - クワイエットモード —
-qは stderr へのステータス出力を抑制します
🌐 kuri-browse
ターミナルからウェブを閲覧できる対話型ターミナルブラウザ。Chrome は不要です。```bash zig build browse # build + run
kuri-browse https://example.com
The INPUT section is empty — no content was provided to translate. Please supply chunk 35 of 57 so I can translate it into Japanese.```
🌰 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
コマンド
| コマンド | 動作 |
|---|---|
<number> | リンク [N] を開く |
<url> | 移動(. を含む場合) |
:go <url> | URL へ移動 |
:back, :b | 履歴を戻る |
:forward, :f | 履歴を進む |
:reload, :r | 現在のページを再取得 |
:links, :l | リンク索引を表示 |
/<term> | ページ内を検索(一致箇所をハイライト) |
:search <t> | ページ内を検索 |
:n, :next | 検索結果を再ハイライト |
:history | ナビゲーション履歴を表示 |
:help, :h | すべてのコマンドを表示 |
:quit, :q | 終了 |
機能
- 色付きMarkdownレンダリング — 見出し、リンク、コードブロック、太字、引用
- 番号付きリンク — すべてのリンクに
[N]が付与され、数字を入力して移動 - ナビゲーション履歴 — 実際のブラウザのように戻る/進む
- ページ内検索 —
/termで一致箇所をすべてハイライト - 相対URL解決 — ページ間でリンクを自然に辿る
- スマートフィルタリング —
javascript:およびmailto:のhrefをスキップ
🤖 kuri-agent
Chrome自動化のためのスクリプト可能なCLI — ターミナルまたはシェルスクリプトからブラウザをコマンド単位で操作します。~/.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
### コマンド
| コマンド | 説明 |
|---------|-------------|
| `tabs [--port N]` | Chrome のタブ一覧を表示 |
| `use <ws_url>` | タブに接続(セッションを保存) |
| `open [url] [--port N]` | 新しいタブを開く(任意で url に移動) |
| `status` | 現在のセッションを表示 |
| `go <url>` | URL に移動 |
| `snap [--interactive] [--json] [--text] [--depth N]` | A11y スナップショット、`eN` リファレンスを保存 |
| `click <ref>` | リファレンスで要素をクリック(CDP マウスイベント、React 互換) |
| `type <ref> <text>` | 要素に文字入力(文字単位のキーイベント、React 互換) |
| `fill <ref> <text>` | 入力値を設定 |
| `select <ref> <value>` | ドロップダウンのオプションを選択 |
| `hover <ref>` | 要素にホバー |
| `focus <ref>` | 要素にフォーカス |
| `scroll` | ページをスクロール |
| `viewport [width height]` | ビューポートのサイズを取得または設定 |
| `eval <js>` | JavaScript を評価 |
| `text [selector]` | ページのテキストを取得 |
| `shot [--out file.png]` | スクリーンショット |
| `back` | 前のページに戻る |
| `forward` | 次のページに進む |
| `reload` | 現在のページを再読み込み |
| `cookies` | セキュリティフラグ付きで Cookie を一覧表示 |
| `headers` | セキュリティレスポンスヘッダーを確認 |
| `audit` | 完全なセキュリティ監査を実行 |
| `storage [local\|session\|all]` | localStorage / sessionStorage をダンプ |
| `jwt` | Cookie とストレージから JWT を抽出・デコード |
| `fetch <method> <url> [--data <json>]` | ページの Cookie を使用した認証付き fetch |
| `probe <url-template> <start> <end>` | IDOR プローブ:URL 内の数値 ID を反復 |
| `grab <ref>` | リファレンスをクリックし、`window.open` をインターセプトしてリダイレクトをタブ内で追跡 |
| `wait-for-tab [--port N]` | 新しいタブをポーリングし、セッションを自動切り替え |
| `stealth` | 検出回避パッチを適用 |
| `set-header <name> <value>` | すべてのリクエストにカスタムヘッダーを追加 |
| `show-headers` | 保存された追加ヘッダーを表示 |
| `clear-headers` | すべての追加ヘッダーを削除 |
---
## 📱 kuri-mobile(iOS + Android)
iOS Simulator、実機 iPhone(一覧表示+起動/終了)、Android デバイス/エミュレータを操作するためのネイティブ Zig CLI — [`mobile-device-mcp`](https://github.com/srmorete/mobile-device-mcp) にインスパイアされ、ビルドパスに Bun/Node/Gradle/Xcode を含めずに Zig で再実装されました。```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
Zigネイティブ実装: adbホストプロトコル(libcソケット、host:transport:/shell:/exec: を介した4桁16進フレーミング)、Android XML UIツリーパーサー、usbmuxd ListDevices plistクライアント。
シェルアウトするもの: xcrun simctl(iOS Simulator)、xcrun devicectl(iOS実機の起動/終了)。
設計上ドライバーレス: デバイス上のアプリはインストールされないため、run_codeサンドボックスとXCUITestベースのtap/uitreeは実iOSデバイスでは意図的に利用できません。上流との完全なパリティマトリクスについては kuri-mobile/README.md を参照してください。
🔒 セキュリティテスト
kuri-agent はブラウザネイティブなセキュリティトラジェクトリをサポートしています。一度ログインすれば、ターミナルから離れることなく偵察とヘッダー/クッキー監査を実行できます。
トラジェクトリ
列挙 → 検査 — 認証後、認証クッキーをダンプしてセキュリティフラグを確認します:```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]
**ヘッダー監査** — ターゲットが送信するセキュリティヘッダーを確認します:```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", ...}}
完全監査 — HTTPS、欠落ヘッダー、JSから見えるCookieを一度に:```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'", ...}}
**クロスアカウントの軌跡** — 異なるトークンで API 呼び出しをリプレイするには `eval` を使用します:```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)"
軌道レポート形式
kuri-agent はパイプライン統合に適した JSON を出力します。各セキュリティコマンドは単一の JSON 行を出力します — jq にパイプしてトリアージしてください:```bash
kuri-agent audit | jq '.issues[]'
kuri-agent cookies | head -20
kuri-agent headers | jq '.headers | to_entries[] | select(.value == "(missing)") | .key'
---
## 🏗 アーキテクチャ```
┌──────────────────────────────────────────────────────────┐
│ 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) │
└──────────────────────────────────────────────────────────┘
メモリモデル
- リクエストごとのアリーナ — すべてのリクエスト単位のメモリが1回の
deinit()呼び出しで解放されます - GCなし — デバッグモードの
GeneralPurposeAllocatorがすべてのリークを検出します - 適切なクリーンアップチェーン —
Launcher → Bridge → CdpClients → HarRecorders → Snapshots → Tabs errdeferガード — 部分的な失敗はきれいにロールバックされます
Chromeライフサイクル
| モード | 動作 |
|---|---|
管理対象 (CDP_URL未設定) | Chromeをヘッドレスで起動し、空いているCDPポートを見つけ、監視し、クラッシュ時には自動再起動(最大3回)し、シャットダウン時に終了します |
外部 (CDP_URL設定時) | 既存のChromeに接続し、/json/versionでヘルスチェックし、シャットダウン時には終了しません |
📁 構造```
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
---
## ⚙️ 設定
| 環境変数 | デフォルト | 説明 |
|---------|---------|-------------|
| `HOST` | `127.0.0.1` | サーバーのバインドアドレス |
| `PORT` | `8080` | サーバーポート |
| `CDP_URL` | *(なし)* | 既存のChromeに接続(`ws://...` または `http://127.0.0.1:9222`) |
| `KURI_SECRET` | *(なし)* | APIリクエスト用の認証シークレット |
| `STATE_DIR` | `.kuri` | セッション状態ディレクトリ |
| `REQUEST_TIMEOUT_MS` | `30000` | HTTPリクエストのタイムアウト |
| `NAVIGATE_TIMEOUT_MS` | `30000` | ナビゲーションのタイムアウト |
| `STALE_TAB_INTERVAL_S` | `30` | 古いタブのクリーンアップ間隔 |
| `NO_COLOR` | *(なし)* | CLIの色付き出力を無効化 |
---
## 💰 トークンコスト
50ページの監視タスクの場合(Pinchtabベンチマークより):
| 手法 | トークン | コスト ($) | 最適な用途 |
|--------|--------|----------|----------|
| `/text` | ~40,000 | $0.20 | 読み取り主体(スクリーンショットより13倍安価) |
| `/snapshot?filter=interactive&format=compact` | ~40,000 | $0.20 | 低トークンでの要素操作 |
| `/snapshot`(完全版) | ~525,000 | $2.63 | ページ全体の理解 |
| `/screenshot` | ~100,000 | $1.00 | 視覚的な検証 |
---
## 🤝 貢献
大きなPRを送る前にissueを開いて、アプローチを合わせましょう。```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)
See CONTRIBUTORS.md for guidelines.
クレジット
| Project | What we borrowed |
|---|---|
| agent-browser | @eN 参照システム、スナップショット差分、HAR 記録パターン |
| Pinchtab | AIエージェント向けのブラウザ制御アーキテクチャ |
| Pathik | 高性能クローリングパターン |
| QuickJS-ng via mitchellh/zig-quickjs-ng | kuri-fetch 用の JS エンジン |
| Lightpanda | Zigネイティブのヘッドレスブラウザの先駆者、CDP互換パターン |
| Zig 0.16.0 | スタック全体 |
ライセンス
Apache-2.0