Browse — 헤드리스 브라우저 모듈
AI 에이전트가 웹 페이지를 읽고 조작하기 위한 최소 Playwright 래퍼. anti-bot stealth, CLI + HTTP 데몬 + 프로그래매틱 API를 제공하며,
토큰 절감에 초점을 둔 find·batch·세션 영속화가 핵심입니다.
개요
Browse는 Claude Code 등 AI 에이전트가 브라우저를 자연어 지시로 조작할 때 드는 토큰 비용과 round-trip 수를 줄이도록 설계됐습니다. 핵심 설계 원칙:
- @ref 기반 상호작용 —
snapshot·find가 반환하는@e1,@e2... 같은 안정 레퍼런스로 클릭·입력을 지정. 긴 CSS selector가 대화 로그에 누적되지 않습니다. - 영속 데몬 — 첫 명령에서 HTTP 서버를 자동 기동, 15분 idle 후 자동 종료. Chromium 재부팅 비용을 피합니다.
- 배치 실행 — 로그인 같은 5-6단계 플로우를 stdin JSON 하나로 압축해 단일 round-trip으로 처리.
- 세션 영속화 —
--session <name>플래그로 storageState(쿠키·localStorage)를 자동 저장·복원해 로그인 반복 제거.
설치 & 구조
# comad-world 루트에서
cd browse && bun install
# CLI 한 번 실행하면 데몬이 자동 기동
bun run src/cli.ts goto https://example.com
4계층 구조:
- CLI
src/cli.ts— 얇은 HTTP 클라이언트, 데몬 자동 기동 - Server
src/server.ts— 랜덤 포트 HTTP 데몬, 토큰 인증, 15분 idle shutdown - Browser
src/browser.ts— Playwright Chromium + anti-bot 스텔스, 멀티탭 관리 - Commands
src/commands.ts+src/deferred.ts— 기본 명령 + 플래그 게이트 보류 명령
상태 파일:
| 파일 | 역할 |
|---|---|
.comad/browse.json | 데몬 포트·토큰·pid |
.comad/browse-features.json | 보류 기능 플래그 |
.comad/sessions/<name>.json | Playwright storageState (쿠키 + 웹 스토리지) |
.comad/auth.json | 자격증명 금고 (auth 기능 활성 시) |
기본 명령
# 네비게이션
browse goto https://example.com
browse back
browse reload
# 읽기
browse text # body.innerText (50KB 캡)
browse html # page.content()
browse links # 앵커 전부
browse title
browse snapshot -i # 상호작용 요소만 @ref 매핑 (최대 500)
# 상호작용
browse click @e3 # ref 또는 selector
browse fill @e2 "hello world"
browse scroll down 500
browse screenshot output.png
snapshot -i는 최대 500개 엘리먼트를 반환합니다. 대부분의 경우 find로 충분하며 더 저렴합니다.
find — 스냅샷 없이 refs만
role/text/label/placeholder/testid로 필터링해 매칭되는 요소만 @e ref로 반환합니다. 전체 스냅샷을 토큰에 쏟아넣지 않아도 되죠.
browse find role=button limit=5
@e1 [button] "Submit" [testid="signup-submit"]
@e2 [button] "Cancel"
browse find text=Submit
browse find placeholder=Email
browse find testid=signup-form
# 이후 ref로 바로 상호작용
browse click @e1
batch — N개 명령 1 round-trip
로그인·검색 플로우처럼 여러 단계가 순차적일 때 stdin JSON으로 묶으면 1 round-trip에 전부 실행됩니다. 각 단계 결과가 배열로 돌아옵니다.
echo '{"steps":[
{"command":"goto","args":{"url":"https://app.example.com/login"}},
{"command":"find","args":{"role":"textbox","placeholder":"email"}},
{"command":"fill","args":{"selector":"@e1","value":"me@example.com"}},
{"command":"find","args":{"role":"textbox","placeholder":"password"}},
{"command":"fill","args":{"selector":"@e2","value":"$PASS"}},
{"command":"find","args":{"role":"button","text":"Sign in"}},
{"command":"click","args":{"selector":"@e3"}},
{"command":"wait","args":{"url":"**/dashboard","timeout":10000}}
]}' | browse batch -
기존 방식: 8 명령 × 8 round-trip × 매번 스냅샷 재호출. batch 방식: 1 round-trip, 스냅샷 불필요. 토큰 로그도 그만큼 간결해집니다.
세션 & 쿠키 지속성
--session <name> 플래그를 주면 서버 시작 시 .comad/sessions/<name>.json에서 storageState를 로드하고, 종료 시 자동 저장합니다. Playwright의 공식 storageState를 그대로 사용하므로 쿠키·localStorage·IndexedDB가 그대로 유지됩니다.
# 첫 실행 — 로그인 후 세션 자동 저장
browse --session myapp goto https://app.example.com/login
# ... 로그인 플로우 실행 ...
browse stop # close 시 세션 저장
# 다음 실행 — 이미 로그인 상태
browse --session myapp goto https://app.example.com/dashboard
# 쿠키·스토리지 수동 관리
browse cookies get
browse cookies clear
browse storage set kind=session key=token value=abc123
browse storage get kind=local
멀티 탭
browse tab list 활성 탭은 * 표시
browse tab new url=https://docs.example.com
browse tab switch id=t2
browse tab close id=t3
탭 ID는 세션 내에서 재사용되지 않는 t1, t2, ... 형태입니다. 모든 명령은 현재 활성 탭에서 동작합니다.
고급 대기
browse wait selector=.result
browse wait text=Welcome timeout=10000
browse wait url='**/dashboard'
browse wait load_state=networkidle
browse wait js='document.readyState === "complete"'
보류 기능 (dormant)
네 가지 고급 기능은 구현 완료·기본 비활성입니다. 필요할 때 플래그만 켜면 즉시 동작합니다.
| 기능 | 역할 |
|---|---|
diff | snapshot 또는 screenshot 베이스라인 대비 현재와 비교 |
har | request/response 버퍼 + JSON export |
auth | AES-256-GCM 암호화 자격증명 금고 + 자동 로그인 |
route | 네트워크 패턴 block / mock |
browse feature list 현재 상태
browse feature enable name=diff
browse feature enable name=har
browse feature enable name=auth
browse feature enable name=route
# 또는 환경 변수로
COMAD_BROWSE_DIFF=1 browse diff action=snapshot
비활성 상태에서 호출하면 힌트가 돌아옵니다: Feature "diff" is dormant. Enable with: browse feature enable name=diff
COMAD_BROWSE_AUTH_KEY 환경변수를 설정하면 AES-256-GCM으로 암호화되어 저장됩니다.
다른 모듈 연동
- Brain content-fetcher — JS가 많은 페이지는 native fetch 실패 시
browse goto+browse text로 자동 fallback. 크롤 레시피가 복잡한 SPA도 추출 가능. - Voice QA —
voice/qa.md플레이북이browse find+browse batch로 폼·라우팅 회귀를 테스트. - 프로그래매틱 API —
import { launch, getPage, close, executeCommand } from "comad-browse"로 스크립트에서 직접 사용 가능.
관련 파일: browse/src/{cli,server,browser,commands,deferred,features}.ts, voice/qa.md, brain/packages/core/src/content-fetcher.ts