
AI 에이전트를 위한 브라우저 자동화, 웹 크롤링, iOS + Android 기기 제어. Zig 네이티브, 토큰 효율적인 CDP 스냅샷, HAR 기록, 네이티브 adb 와이어 프로토콜 클라이언트, 그리고 독립형 페처.
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 에이전트를 위한 브라우저 자동화 및 웹 크롤링. Zig로 작성. Node.js 제로.**
CDP 자동화 · A11y 스냅샷 · HAR 녹화 · 독립형 페처 · 인터랙티브 터미널 브라우저 · 에이전틱 CLI · 보안 테스트 · iOS + Android 기기 제어
[빠른 시작](#-quick-start) · [벤치마크](#-benchmarks) · [kuri-agent](#-kuri-agent) · [보안 테스트](#-security-testing) · [API](#-http-api) · [스킬](#-skills) · [Changelog](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는 에이전트 루프를 위해 설계되었습니다: 페이지를 읽고, 토큰 비용을 낮게 유지하고, 안정적인 ref로 동작한 다음 다음 단계로 넘어갑니다.
- **HTTP 엔드포인트 135개** — React 검사부터 Core Web Vitals까지 agent-browser 및 browser-use와 완전한 동등성.
- 실제 페이지에서 `@eN` ref 형식과 zero-prefix 렌더링 덕분에 agent-browser보다 **토큰 7-12% 절감**.
- 동일한 Google Flights 페이지에서 전체 스냅샷(2,124 토큰) 대신 `/page/state`(48 토큰)로 **44배 더 가벼운 관측**.
- **배치 실행** — `POST /batch`는 단일 HTTP 호출로 N개 명령을 보내 N-1회 왕복과 N-1회 LLM 턴을 제거합니다.
- **React 호환** — 신뢰할 수 있는 CDP 마우스 이벤트와 문자별 키 이벤트가 React 18/19의 `onClick` 및 `onChange`를 발생시킵니다.
### 스냅샷 토큰: Google Flights `SIN → TPE`
이 워크스페이스에서 2026-05-24에 새로 실행했으며 `wc -c`와 `chars/4` 근사 방식으로 측정했습니다.
| 도구/모드 | 문자 수 | ~토큰 | 비고 |
|---|---:|---:|---|
| `kuri snap` (full) | 8,499 | **2,124** | 모든 노드 + 인터랙티브 ref |
| `kuri snap` (interactive only) | ~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` ref(3자) vs `[ref=e0]`(9자)
- 줄마다 `- ` 접두사 없음(2자 × 줄 수 절약)
- 동일한 들여쓰기, 동일한 노드 필터링
### 전체 워크플로 비용: `go → snap → click → snap → eval`
| 도구 | 주기당 토큰 |
|---|---:|
| **kuri-agent** | **~3,400** |
| 두 번째 snap 대신 `/page/state` 사용 시 | **~1,700** |
| `POST /batch` 사용 시(단일 호출로 모두 처리) | **~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–117 ms vs 1,344–1,500 ms(**13–376배 빠름** — 상주 서버 vs 명령마다 Node) |
| 스냅샷 토큰, 일반 페이지 | **kuri** | 단순 페이지 61 vs 151(2.5×), 기사 265 vs 363(1.37×) — 더 타이트한 문법 |
| 스냅샷 토큰, 대형 목록 | 분할 | kuri 기본 4,424 vs 813 — kuri는 259개 ref를 모두 출력하고 libretto는 기본적으로 잘라냅니다. `limit=5`를 사용하면 kuri는 555토큰을 렌더링하며(**libretto보다 1.46× 적음**), 34개 ref + `… +45 more` 마커를 표시 |
| 트라젝토리(feed, 클릭 9회) | **kuri**, 근소한 차이 | 898 vs 939 토큰(`limit=5` 베이스 + diff 루프 vs exec 루프) — 동등 수준에서 약간 우위; 앞선 5.1× 손실은 잘리지 않은 베이스 때문 |
| 반복 실행 | **libretto** | 트라젝토리를 Playwright 스크립트로 컴파일 → 0-토큰 재생; kuri는 실행마다 루프 비용을 다시 지불 |
**kuri가 libretto를 연구하여 얻은 것들**(이번 릴리스에 모두 포함): diff 우선 루프(`take_snapshot_diff`, 단계당 ~38 토큰); 내비게이션 시 `! page replaced` 헤더와 함께 전체 스냅샷으로 폴백하는 적응형 diff; 항목별 제거 라인; 스크린샷을 디스크에 저장(경로만 반환, 바이트는 컨텍스트에 들어가지 않음); MCP를 통한 `get_page_state`; 그리고 `parseA11yNodes`를 실제 DFS 트리 탐색으로 재작성한 후 — **옵트인 목록 잘라내기**(`/snapshot?limit=N`, 제한된 실행마다 `… +K more` 라인 1개), **범위 재캡처**(`scope=@ref`), **계층 들여쓰기**, MCP `take_snapshot`에서 `uid`/`limit`로도 노출됩니다. 순진한 전체 재스냅샷으로 44,285 토큰이 들던 9클릭 feed 트라젝토리는 잘린 베이스 + diff로 **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(~300 MB), Node.js 런타임, 그리고 npm 의존성의 연쇄를 끌어들입니다. AI 에이전트는 그저 페이지를 읽고, 버튼을 클릭하고, 다음으로 넘어가기를 원합니다.
**Kuri는 단일 Zig 바이너리입니다.** 네 가지 모드, 런타임 제로:```
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)
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.shhttps://raw.githubusercontent.com/justrach/kuri/release-channel/stable/latest.jsonhttps://github.com/justrach/kuri/tree/release-channel/stablehttps://raw.githubusercontent.com/justrach/kuri/release-channel/stable/<version>/kuri-<version>-<target>.tar.gz플랫폼에 맞는 tarball을 안정 릴리스 매니페스트 또는 GitHub 릴리스 페이지에서 다운로드하여 $PATH에 압축을 풉니다.
안정 설치 URL:```sh curl -fsSL https://raw.githubusercontent.com/justrach/kuri/release-channel/stable/install.sh | sh
The manifest includes exact asset URLs plus SHA-256 checksums for `aarch64-linux`, `x86_64-linux`, `aarch64-macos`, and `x86_64-macos`.
### Platform support
| Platform | Status |
|---|---|
| macOS (`aarch64`, `x86_64`) | Prebuilt binaries, signed + notarized |
| Linux (`aarch64`, `x86_64`) | Prebuilt binaries |
| Windows (`x86_64`) | **Experimental — cross-compile only.** `zig build -Dtarget=x86_64-windows-gnu` is CI-verified, but Chrome automation, daemonization, signal-based shutdown, HAR recording, and the file-backed auth store are all stubbed with `error.UnsupportedOnWindows` at runtime. Use **WSL2** if you need the real feature set. Tracked at [#153](https://github.com/justrach/kuri/issues/153). |
Kuri는 여러 곳에서 POSIX 기본 요소(`fork`, `clock_gettime`, 원시 소켓)에 의존하므로, 완전한 네이티브 Windows 포트는 상당한 작업입니다. 위의 컴파일 수준 기준선 덕분에 `--version`/`--help` 경로와 순수 인메모리 작업은 실행할 수 있습니다. 까다로운 부분(Chrome, 소켓, 데몬화)은 스텁 목록에서 제외되려면 실제 Win32 구현이 필요합니다. 이 중 하나를 진행하려면 [#153](https://github.com/justrach/kuri/issues/153)에 +1 하거나 PR을 열어주세요.
### Build from source
Requires [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
./zig-out/bin/kuri
./zig-out/bin/kuri-fetch https://example.com
./zig-out/bin/kuri-browse https://example.com
(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
curl -s http://localhost:8080/discover
curl -s http://localhost:8080/tabs
curl -s "http://localhost:8080/navigate?tab_id=ABC123&url=https://vercel.com"
curl -s "http://localhost:8080/snapshot?tab_id=ABC123&filter=interactive"
---
## 🌐 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/제목/준비 상태/뷰포트/스크롤 |
| `GET /page/state` | 간결한 페이지 관찰: url, title, scroll%, viewport, forms/links/images/inputs 개수 |
| `POST /batch` | 단일 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` 또는 `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 패턴/네트워크 유휴/로드 상태 대기 |
| `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` | 쿠키 가져오기 |
| `GET /cookies/set` | 쿠키 설정 |
| `GET /cookies/delete` | 쿠키 삭제 |
| `GET /cookies/clear` | 모든 쿠키 지우기 |
| `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` | 쿠키 + 스토리지를 이름이 있는 인증 프로필로 저장 |
| `GET /auth/profile/load` | 이름이 있는 인증 프로필을 탭으로 복원 |
| `GET /auth/profile/list` | 저장된 인증 프로필 목록 |
| `GET /auth/profile/delete` | 저장된 인증 프로필 삭제 |
| `GET /auth/extract` | 인증 토큰 추출 (JWT, 쿠키, 헤더) |
| `GET /set/credentials` | HTTP 기본 인증 자격 증명 설정 |
macOS에서는 인증 프로필 시크릿이 사용자 키체인(Keychain)에 저장됩니다.
### 에뮬레이션
| 경로 | 파라미터 | 설명 |
|------|--------|-------------|
| `GET /emulate` | device type, screen size | 기기 에뮬레이션 |
| `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` | 권한 허용/거부 (위치 정보, 알림, 클립보드) |
### 스크립트 및 주입
| 경로 | 설명 |
|------|-------------|
| `GET /script/inject` | 페이지에 JavaScript 주입 (탐색 간 유지) |
| `GET /initscript/remove` | 이전에 주입된 초기화 스크립트 제거 |
| `GET /addstyle` | CSS 스타일시트 주입 |
| `GET /expose` | 페이지 JS 컨텍스트에 이름이 있는 함수 노출 |
### React 검사
| 경로 | 설명 |
|------|-------------|
| `GET /react/tree` | DevTools 훅을 통한 React 컴포넌트 트리 |
| `GET /react/inspect` | React 컴포넌트 props 및 state |
| `GET /react/renders` | React 렌더 추적 (시작/중지) |
| `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` | 이 탭의 이전 호출 대비 간결한 `+`/`~`/`-` diff — 토큰 효율적인 작업 루프 (`/snapshot/changes`로 별칭). 대량 변경 시 `! page replaced` 헤더와 함께 전체 스냅샷으로 폴백합니다. |
| `GET /diff/url` | 두 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. 반복 — 또는 한 번의 호출로 여러 단계 작업을 수행하려면 `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: 세션, 스냅샷, 작업, HAR, 쿠키, 스크린샷을 지원하는 프로덕션 Chrome/CDP 자동화
- `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`): `20,523`바이트 PNG에서 JPEG 품질 50으로 `18,183`바이트, `2,340`바이트 또는 `11%` 절감.
### 고급
| 경로 | 설명 |
|------|-------------|
| `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` | 한 참조에서 다른 참조로 드래그 |
| `GET /keyboard/type` | 키 이벤트로 텍스트 입력 |
| `GET /keyboard/inserttext` | 텍스트 직접 삽입 |
| `GET /keydown` | keydown 이벤트 디스패치 |
| `GET /keyup` | keyup 이벤트 디스패치 |
| `GET /wait` | 준비 상태 또는 요소 조건 대기 |
| `GET /tab/close` | 탭 닫기 |
| `GET /highlight` | 참조 또는 선택자로 요소 강조 |
| `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 스푸핑** — 지문 기반 탐지 무력화
- **UA 순환** — 현실적인 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, 일반 캡차.
KURI_PROXY=socks5://user:pass@residential-proxy:1080 ./zig-out/bin/kuri KURI_PROXY=http://proxy:8080 ./zig-out/bin/kuri
### 테스트된 사이트
| 사이트 | 보호 | 결과 |
|------|-----------|--------|
| Singapore Airlines | Akamai WAF | ✅ 우회됨 (v0.4.0 이전에는 차단됨) |
| Shopee SG | 맞춤형 사기 방지 | ✅ 페이지 로드, 로그인으로 리디렉션 |
| Google Flights | 없음 | ✅ 전체 상호작용 |
| Booking.com | PerimeterX | ⚠️ 프록시 필요 |
---
## 🔧 kuri-fetch
독립형 HTTP 페처 — Chrome 없음, Playwright 없음, npm 없음. JS 실행을 위한 내장 QuickJS와 함께 ~2 MB 바이너리로 제공됩니다.```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
markdown, html, links, text, json--js는 인라인 <script> 태그를 실행합니다document.querySelector, getElementById, window.location, document.title, console.log, setTimeout (SSR 방식)NO_COLOR, , , TTY 감지를 존중합니다대화형 터미널 브라우저 — 터미널에서 웹을 탐색하세요. Chrome이 필요 없습니다.```bash zig build browse # build + run
kuri-browse https://example.com
Please provide the Markdown content to be translated.```
🌰 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
[N]이 붙으며, 번호를 입력해 해당 링크로 이동/term은 모든 일치 항목을 강조javascript: 및 mailto: href 건너뜀Chrome 자동화를 위한 스크립트 가능 CLI — 터미널이나 셸 스크립트에서 브라우저를 명령 단위로 구동합니다. ~/.kuri/session.json을 통해 호출 간에 세션 상태를 공유합니다.```bash
zig build agent # build kuri-agent
kuri-agent tabs
kuri-agent use ws://127.0.0.1:9222/devtools/page/ABC123
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
### Commands
| Command | Description |
|---------|-------------|
| `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>` | 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` | 보안 플래그가 있는 쿠키 나열 |
| `headers` | 보안 응답 헤더 확인 |
| `audit` | 전체 보안 감사 |
| `storage [local\|session\|all]` | localStorage / sessionStorage 덤프 |
| `jwt` | 쿠키와 저장소에서 JWT 추출 및 디코딩 |
| `fetch <method> <url> [--data <json>]` | 페이지 쿠키를 사용한 인증된 fetch |
| `probe <url-template> <start> <end>` | IDOR 프로브: URL에서 숫자 ID 순회 |
| `grab <ref>` | ref 클릭, `window.open` 가로채기, 탭 내에서 리디렉션 따라가기 |
| `wait-for-tab [--port N]` | 새 탭 폴링, 세션 자동 전환 |
| `stealth` | 탐지 방지 패치 적용 |
| `set-header <name> <value>` | 모든 요청에 사용자 정의 헤더 추가 |
| `show-headers` | 저장된 추가 헤더 표시 |
| `clear-headers` | 모든 추가 헤더 제거 |
---
## 📱 kuri-mobile (iOS + Android)
iOS 시뮬레이터, 실제 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-hex 프레이밍), Android XML UI 트리 파서, usbmuxd ListDevices plist 클라이언트.
외부 명령 실행: xcrun simctl (iOS 시뮬레이터), xcrun devicectl (iOS 실제 기기 실행/종료).
설계상 드라이버리스: 기기에 앱이 설치되지 않으므로 실제 iOS 기기에서 run_code 샌드박스와 XCUITest 기반 tap/uitree는 의도적으로 사용할 수 없습니다. 업스트림 대비 전체 패리티 매트릭스는 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
**헤더 감사** — 대상이 보내는 보안 헤더를 확인합니다:```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에 노출된 쿠키를 한 번에:```bash kuri-agent audit
**계정 간 트레이젝토리** — `eval`을 사용하여 다른 토큰으로 API 호출을 재생하세요:```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로 파이프하여 분류(triage)하세요:```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) │
└──────────────────────────────────────────────────────────┘
deinit() 호출로 해제됩니다.GeneralPurposeAllocator가 모든 누수를 잡아냅니다.Launcher → Bridge → CdpClients → HarRecorders → Snapshots → Tabserrdefer 가드 — 부분 실패 시 깔끔하게 롤백됩니다.| 모드 | 동작 |
|---|---|
Managed (CDP_URL 없음) | 헤드리스 Chrome을 시작하고, 사용 가능한 CDP 포트를 탐색하며, 감독하고, 충돌 시 자동으로 재시작하며(최대 3회), 종료 시 프로세스를 종료합니다. |
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을 제출하기 전에 이슈를 먼저 열어 접근 방식에 대해 의견을 맞추시기 바랍니다.```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)
기여 가이드라인은 CONTRIBUTORS.md를 참조하세요.
Apache-2.0
TERM=dumb--no-color-o / --output 및 바이트 수 + 시간 요약--user-agent 플래그-q는 stderr 상태를 억제합니다| Command | Action |
|---|
<number> | 링크 [N] 따라가기 |
<url> | 이동 (. 포함 시) |
:go <url> | URL로 이동 |
:back, :b | 기록에서 뒤로 가기 |
:forward, :f | 앞으로 가기 |
:reload, :r | 현재 페이지 다시 불러오기 |
:links, :l | 링크 인덱스 표시 |
/<term> | 페이지에서 검색 (일치 항목 강조) |
:search <t> | 페이지에서 검색 |
:n, :next | 검색 결과 다시 강조 |
:history | 탐색 기록 표시 |
:help, :h | 모든 명령 표시 |
:quit, :q | 종료 |
External (CDP_URL 설정) | 기존 Chrome에 연결하고, /json/version을 통해 상태를 확인하며, 종료 시 프로세스를 종료하지 않습니다. |
| 프로젝트 | 참고한 내용 |
|---|
| agent-browser | @eN 참조 시스템, 스냅샷 diffing, HAR 기록 패턴 |
| Pinchtab | AI 에이전트용 브라우저 제어 아키텍처 |
| Pathik | 고성능 크롤링 패턴 |
| QuickJS-ng 경유 mitchellh/zig-quickjs-ng | kuri-fetch용 JS 엔진 |
| Lightpanda | Zig 기반 헤드리스 브라우저 선구자, CDP 호환성 패턴 |
| Zig 0.16.0 | 전체 스택 |