agent-browser

agent-browser

기존 브라우저 도구는 AI를 위해 만들어지지 않았다

Selenium, Puppeteer, Playwright—브라우저 자동화 도구는 이미 충분히 성숙하다. 그런데 이 도구들을 AI 에이전트에 연결하면 예상치 못한 문제들이 드러난다.

이 도구들은 사람 개발자가 쓰도록 설계되었다. 개발자가 직접 DevTools를 열고, DOM 구조를 파악하고, CSS 셀렉터를 작성한다. 하지만 AI 에이전트는 이 과정을 완전히 다른 방식으로 수행해야 한다:

토큰으로 변환된 DOM은 비싸고 비효율적이다. 일반적인 웹 페이지의 HTML은 3,000~5,000 토큰을 차지한다. 복잡한 SPA라면 10,000 토큰도 넘긴다. 페이지 하나를 "보는" 데만 수천 토큰을 쓰는 건, 수십 번의 페이지 탐색이 필요한 실제 작업에서 비현실적이다.

CSS 셀렉터는 AI에게 너무 깨지기 쉽다. AI가 생성한 #app > div:nth-child(3) > ul > li:first-child > a 같은 셀렉터는 DOM 구조가 조금만 바뀌어도 무너진다. 사람은 시각적으로 "검색 버튼"을 인식하지만, AI는 매번 정확한 셀렉터 문자열을 생성해야 한다.

세션 상태가 유지되지 않는다. 로그인한 세션을 다음 명령에서 이어쓰고 싶은데, 프로세스가 종료되면 상태가 사라진다.

CLI 오버헤드가 누적된다. AI 에이전트는 하나의 태스크에서 수십~수백 개의 브라우저 명령을 실행한다. 매번 Node.js 런타임을 시작하는 수백 밀리초가 쌓이면 체감 성능이 급격히 떨어진다.

결국 핵심 문제는 하나다: 기존 도구는 사람이 DOM을 이해한 상태에서 쓰도록 설계되었고, AI 에이전트가 웹을 "인식"하는 방식에 맞춰져 있지 않다.

**agent-browser**는 이 문제를 해결한다. 2026년 1월 첫 릴리즈 이후 두 달 만에 GitHub 스타 16,500개를 넘긴 건, "AI 에이전트에게 제대로 된 브라우저 도구가 없었다"는 문제 인식에 그만큼 많은 개발자가 공감했다는 뜻이다.


agent-browser의 해법

위에서 정의한 문제들을 agent-browser가 어떻게 풀었는지 하나씩 살펴보자.

1. 접근성 트리 기반 스냅샷

웹 브라우저는 스크린 리더를 지원하기 위해 **접근성 트리(Accessibility Tree)**를 내부적으로 관리한다. DOM의 부분집합으로, 장식용 <div>나 CSS 레이아웃 컨테이너는 빠지고, 링크, 버튼, 입력 필드 같은 의미 있는 요소만 남는다.

agent-browser는 이 접근성 트리에서 AI가 상호작용할 수 있는 요소만 추출한 경량 표현을 제공한다. 같은 페이지를 전체 HTML로 넘기면 이런 모습이다:

<nav class="main-nav" role="navigation" aria-label="Main">
  <div class="nav-container">
    <ul class="nav-list">
      <li class="nav-item"><a href="/" class="nav-link active">Home</a></li>
      <li class="nav-item"><a href="/about" class="nav-link">About</a></li>
      <li class="nav-item"><a href="/contact" class="nav-link">Contact</a></li>
    </ul>
  </div>
</nav>
<main id="content" class="page-wrapper">
  <div class="hero-section">
    <h1 class="hero-title">Welcome to Example</h1>
  </div>
  <div class="search-container">
    <input type="text" class="search-input" placeholder="Search..." />
    <button class="btn btn-primary search-btn">Search</button>
  </div>
</main>

agent-browser의 snapshot -i 커맨드는 같은 페이지를 이렇게 표현한다:

$ agent-browser snapshot -i

[document] Example Page
  [navigation] Main Menu
    [@e1 link] Home
    [@e2 link] About
    [@e3 link] Contact
  [main]
    [@e4 heading] Welcome to Example
    [@e5 textbox] Search...
    [@e6 button] Search

장식용 <div>, CSS 클래스, 레이아웃 컨테이너는 전부 사라지고, AI가 실제로 상호작용할 수 있는 요소만 남는다.

Token Consumption

Full DOM (HTML):          3,000-5,000  ████████████████████████████
agent-browser snapshot:     200-400    ████

-> ~10x reduction

같은 정보를 10분의 1 비용으로 전달한다. 이건 단순한 최적화가 아니라, AI 에이전트 기반 브라우저 자동화를 경제적으로 가능하게 만드는 핵심 설계 결정이다.

2. Ref 시스템: CSS 셀렉터 없이 요소 지정

Playwright나 Puppeteer로 자동화 스크립트를 작성해본 개발자라면 알 것이다. CSS 셀렉터나 XPath는 DOM 구조 변경에 취약하다. 디자인 리팩토링 한 번으로 수십 개의 셀렉터가 무효화된다.

AI 에이전트에게 이 문제는 더 심각하다. 에이전트가 button.submit-btn.primary 같은 셀렉터를 생성해서 사용하면, 다음 페이지 로드에서 클래스 이름이 바뀌거나 DOM 계층이 달라지는 순간 실패한다.

agent-browser는 CSS 셀렉터 대신, Ref 시스템으로 요소를 참조한다. 위의 스냅샷에서 @e1, @e2, @e3 같은 레이블이 바로 ref다. 접근성 트리를 순회하면서 인터랙티브 요소(링크, 버튼, 입력 필드 등)를 만날 때마다 순서대로 할당된다. 같은 페이지 상태에서 같은 스냅샷을 찍으면 항상 같은 ref가 나온다.

AI 에이전트는 @e6이라고만 지정하면 된다. 내부 DOM 구조에 의존하지 않으므로, "검색 버튼"의 클래스 이름이 바뀌든, 부모 요소가 변경되든 상관없다.

중요한 제약: DOM이 변경되면 ref가 무효화된다. 버튼을 클릭해서 페이지가 바뀌었다면, 반드시 다시 snapshot을 찍어서 새 ref를 확인해야 한다.

전통적 자동화:  "CSS 셀렉터를 분석하고 → DOM을 탐색하고 → 요소를 찾아서 → 클릭"
AIDOM 구조를 이해해야 함, 토큰 낭비

agent-browser:  "snapshot → @e3 클릭"
                 ↳ 접근성 트리에서 ref 확인 후 바로 상호작용

snapshot → 분석 → 상호작용 → snapshot 루프가 agent-browser의 기본 패턴이다:

# 1. 페이지 열기
agent-browser open https://example.com

# 2. 스냅샷으로 페이지 파악
agent-browser snapshot -i
# → AI가 @e5 textbox를 발견: "Search..."라는 검색창이 있다

# 3. ref로 상호작용
agent-browser fill @e5 "agent-browser tutorial"
agent-browser click @e6

# 4. 페이지가 변경되었으니 다시 스냅샷
agent-browser snapshot -i

# 5. 결과 텍스트 추출
agent-browser get text @e10

현대 웹 앱에는 <div onclick="..."> 같은 비표준 클릭 가능 요소가 많다. 접근성 트리에서 이런 요소는 인터랙티브로 인식되지 않을 수 있는데, -C 플래그를 추가하면 cursor: pointer CSS 속성을 가진 요소도 인터랙티브로 분류한다.

3. 다층 보안 레이어

agent-browser는 AI 에이전트의 위험한 행동을 방어하기 위해 여러 보안 레이어를 내장했다:

  • 도메인 허용목록: 지정된 도메인만 방문 가능. 서브리소스, WebSocket까지 차단
  • 액션 정책: JSON 파일로 특정 액션을 deny/confirm/allow 제어
  • 인증 볼트: 자격 증명을 암호화 저장하여 LLM이 비밀번호를 절대 볼 수 없음
  • 콘텐츠 경계: 도구 출력과 웹 콘텐츠를 구분하여 프롬프트 인젝션 방어
  • 출력 제한: 컨텍스트 플러딩 방지를 위한 최대 출력 문자 수 제한

예를 들어, 다음과 같이 파괴적인 액션에 확인을 요구할 수 있다:

{
  "rules": [
    { "action": "eval", "effect": "deny" },
    { "action": "click", "selector": ".delete-btn", "effect": "confirm" }
  ]
}

eval 명령은 아예 거부하고, 삭제 버튼 클릭에는 사전 확인을 요구한다. 모든 보안 기능은 opt-in 방식이라, 기존 워크플로우를 깨뜨리지 않으면서 필요한 수준의 보안을 점진적으로 적용할 수 있다.

4. 세션 상태 관리

agent-browser는 세 가지 수준의 상태 관리를 제공한다:

  1. Ephemeral (기본): 데몬이 살아있는 동안 상태 유지. 가장 간단
  2. Profile: 디렉토리에 모든 브라우저 상태를 영구 저장. 실제 Chrome 프로필처럼 동작
  3. Session State: 쿠키와 localStorage를 파일로 저장하고 AES-256-GCM으로 암호화 가능

멀티 세션도 지원한다:

# 독립적인 브라우저 인스턴스
agent-browser --session agent1 open https://site-a.com
agent-browser --session agent2 open https://site-b.com

각 세션은 독립된 소켓과 PID 파일을 가지므로, 서로 간섭 없이 병렬로 작업할 수 있다.

5. Rust 네이티브 CLI

이건 사소해 보이지만 실제로 중요한 문제다. AI 에이전트는 하나의 태스크를 수행하면서 수십~수백 개의 브라우저 명령을 실행한다. 매번 Node.js 런타임을 시작하고 스크립트를 로드하는 데 걸리는 수백 밀리초가 누적되면 체감 성능이 크게 떨어진다.

agent-browser는 CLI를 Rust 네이티브 바이너리로 구현했다. 약 867KB 크기의 바이너리가 서브밀리초 단위로 커맨드를 파싱하고 결과를 출력한다. 일반적인 Node.js CLI 도구가 매 실행마다 런타임 시작 + 모듈 로딩으로 수백 밀리초를 소비하는 것과 비교하면 체감 차이가 확연하다.


아키텍처

agent-browser의 아키텍처는 겉보기에 특이하다. Rust CLINode.js 데몬, 두 개의 완전히 다른 런타임이 하나의 도구를 구성한다. 왜 이런 선택을 했을까?

Rust CLI + Node.js Daemon 하이브리드 구조

┌─────────────────────────────────────────────────────────┐
│                     사용자 / AI 에이전트                    │
│                                                         │
│   agent-browser click @e1  →  agent-browser snapshot    │
└────────────┬───────────────────────────┬────────────────┘
             │                           │
             ▼                           ▼
┌────────────────────────┐  ┌────────────────────────┐
Rust CLI          │  │      Rust CLI  (커맨드 파싱, 출력)  (커맨드 파싱, 출력)│  서브밀리초 오버헤드     │  │                        │
└────────────┬───────────┘  └────────────┬───────────┘
IPC (JSON)IPC (JSON)
             ▼                           ▼
┌─────────────────────────────────────────────────────────┐
Node.js Daemon (상주 프로세스)│                                                         │
│  ┌──────────────┐  ┌──────────────┐  ┌───────────────┐ │
│  │ BrowserManager│ActionHandler│SessionState │ │
 (Playwright)  (50+ 커맨드)  (암호화/저장) │ │
│  └──────┬───────┘  └──────────────┘  └───────────────┘ │
│         │                                               │
│         ▼                                               │
│  ┌──────────────┐                                       │
│  │   Chromium    │                                       │
│  │   Browser     │                                       │
│  └──────────────┘                                       │
└─────────────────────────────────────────────────────────┘

왜 하이브리드인가

이 구조는 두 가지 상충하는 요구사항에서 비롯된다:

요구사항최적 언어이유
빠른 CLI 파싱과 출력Rust서브밀리초 시작 시간, ~867KB 바이너리, 크로스 플랫폼
브라우저 자동화Node.jsPlaywright 생태계 직접 활용, 풍부한 라이브러리

Rust만으로 구현하면 Playwright의 성숙한 브라우저 자동화 기능을 처음부터 다시 만들어야 한다. Playwright는 수년간 브라우저 자동화의 엣지 케이스를 다뤄온 프로젝트로, 이를 재구현하는 건 비현실적이다.

Node.js만으로 구현하면 CLI 시작 시간이 느려진다. 매번 Node.js 런타임 시작 + 모듈 로딩으로 수백 밀리초가 소비된다. AI 에이전트가 수십~수백 개의 명령을 연속 실행하는 시나리오에서 이 오버헤드는 치명적이다.

하이브리드 구조는 이 두 세계의 장점을 결합한다: Rust로 파싱, Node.js로 실행.

IPC 통신: 두 세계를 잇는 다리

Rust CLI와 Node.js 데몬은 **IPC(Inter-Process Communication)**로 통신한다:

플랫폼방식경로
macOS / LinuxUnix Domain Socket~/.agent-browser/{session}.sock
WindowsTCPlocalhost:49152-65535 (세션 해시 기반)

프로토콜은 Line-based JSON이다. JSON-RPC 스타일로, 각 메시지가 줄바꿈으로 구분된 JSON 객체이다. 각 세션은 독립된 소켓과 PID 파일을 가지므로, 멀티 세션 환경에서도 깔끔하게 격리된다.

커맨드 실행 흐름: 8단계

agent-browser click @e3을 실행했을 때 내부에서 일어나는 일을 따라가보자:

1. 사용자가 입력: agent-browser click @e3

2. Rust CLI가 커맨드를 파싱
"click" 액션, 타겟 "@e3"으로 분해
JSON 요청 생성: {"action": "click", "ref": "@e3"}

3. Rust CLI가 소켓에 연결 시도
   → 데몬이 없으면? 자동으로 Node.js 데몬을 시작하고 연결 대기

4. Node.js 데몬이 JSON 요청을 수신
Zod 스키마로 요청 구조를 검증

5. ActionHandler가 해당 커맨드를 처리
"click" 액션에 매핑된 핸들러 실행

6. Playwright를 통해 실제 브라우저 조작
Chromium에서 @e3에 해당하는 요소를 클릭

7. 데몬이 결과를 JSON으로 응답
{"success": true, "result": ...}

8. Rust CLI가 응답을 포맷팅하여 사용자에게 출력

이 흐름에서 주목할 부분은 3단계: 데몬 자동 시작이다. 첫 번째 명령을 실행할 때 데몬이 자동으로 뜨고, 이후 명령은 이미 살아있는 데몬에 연결된다. 브라우저 상태(열린 탭, 쿠키, 세션)가 데몬에 유지되므로, 이어서 보내는 명령들이 같은 브라우저 컨텍스트에서 실행된다.

이 "상주 데몬" 패턴 덕분에 커맨드 체이닝이 자연스럽게 동작한다:

agent-browser open https://example.com && \
agent-browser snapshot -i && \
agent-browser click @e3 && \
agent-browser snapshot -i

각 명령이 독립된 프로세스지만, 모두 같은 데몬의 같은 브라우저 세션을 공유한다.

코드베이스 구조

agent-browser/
├── cli/src/           # Rust CLI
│   ├── commands.rs    # 모든 CLI 커맨드 파싱
│   ├── output.rs      # 출력 포맷팅
│   ├── flags.rs       # CLI 플래그 정의
│   ├── main.rs        # 진입점, 데몬 통신
│   └── connection.rs  # 소켓/TCP 클라이언트
└── src/               # Node.js Daemon
    ├── actions.ts     # 50+ 브라우저 커맨드 실행
    ├── browser.ts     # Playwright 래퍼
    ├── types.ts       # TypeScript 인터페이스
    ├── protocol.ts    # Zod 기반 메시지 검증
    ├── daemon.ts      # Unix socket 서버
    └── snapshot.ts    # 접근성 트리 파싱, ref 할당

Rust CLI 쪽은 커맨드 파싱과 출력 포맷팅이 핵심 역할이고, Node.js 데몬 쪽은 Playwright를 통한 브라우저 조작과 접근성 트리 파싱이 핵심이다.


기존 도구와의 비교

agent-browser가 기존 도구와 어떻게 다른지, 핵심 차원별로 비교해보자.

한눈에 보는 비교표

기능agent-browserPlaywright MCPSeleniumPuppeteer
AI 에이전트 최적화핵심 설계부분적XX
토큰 효율성 (스냅샷)200-4003,000-5,000N/AN/A
Ref 시스템 (@e1, @e2)OXXX
CLI 인터페이스Rust 네이티브Node.jsJava/PythonNode.js
세션 암호화AES-256-GCMXXX
보안 정책 (도메인/액션)OXXX
클라우드 브라우저 지원O (3개 프로바이더)X일부X
iOS 지원O (시뮬레이터/실기기)XAppium 별도X
커맨드 체이닝O (데몬 유지)XN/AN/A

Playwright MCP와의 핵심 차이 5가지

가장 자주 비교되는 것은 Playwright MCP다. 둘 다 AI 에이전트에 브라우저 기능을 제공한다는 점에서 비슷해 보이지만, 접근 방식이 근본적으로 다르다.

1. 토큰 효율: 10배 차이

Playwright MCP는 DOM을 그대로 노출한다. agent-browser는 접근성 트리로 변환한다. 같은 페이지를 표현하는 데 200-400 토큰 vs 3,000-5,000 토큰. AI 에이전트가 수십 번 페이지를 "보는" 워크플로우에서 이 10배 차이는 비용과 속도 모두에 큰 영향을 미친다.

2. 요소 참조: Ref vs CSS 셀렉터

Playwright MCP는 CSS 셀렉터로 요소를 지정한다. AI가 #search-form > input[type="text"] 같은 셀렉터를 생성해야 한다. agent-browser는 @e5라고만 하면 된다. AI의 실수 가능성이 줄고, 토큰도 절약된다.

3. 실행 모델: 상주 데몬 vs MCP 서버

Playwright MCP는 MCP(Model Context Protocol) 서버로 작동하여 AI에게 Playwright API를 직접 노출한다. agent-browser는 CLI + 상주 데몬 구조로, 셸 명령어를 통해 AI와 상호작용한다. 이는 agent-browser가 MCP를 지원하지 않는 에이전트에서도 작동한다는 뜻이다. 셸 명령을 실행할 수 있는 모든 AI 에이전트(Claude Code, Cursor, GitHub Copilot, Codex 등)에서 바로 사용할 수 있다.

4. 보안: 내장 vs 부재

Playwright MCP에는 AI 에이전트 전용 보안 기능이 없다. agent-browser는 도메인 허용목록, 액션 정책, 인증 볼트, 콘텐츠 경계, 출력 제한 등 다층 보안을 내장하고 있다. 프로덕션 환경에서 AI 에이전트에게 브라우저를 맡기려면 이 보안 레이어는 선택이 아니라 필수다.

5. 상태 관리: 완전 내장 vs 미지원

세션 암호화, 프로필 영속성, 멀티 세션 격리—agent-browser는 이 모든 것을 도구 자체에 내장하고 있다. Playwright MCP에서 같은 기능이 필요하면 직접 구현해야 한다.


agent-browser가 의미하는 것

AI 에이전트가 웹을 "보는" 방식은 사람과 다르다. 그렇다면 도구도 달라야 한다.

사람은 픽셀로 렌더링된 웹 페이지를 시각적으로 인식한다. AI는 텍스트 토큰으로 변환된 페이지 구조를 읽는다. 접근성 트리 기반 스냅샷은 이 차이를 정면으로 인정하고, AI에게 최적화된 표현을 제공한다. Ref 시스템은 DOM의 복잡성을 숨기고, 안정적인 참조 방식을 제공한다.

하이브리드 아키텍처(Rust CLI + Node.js 데몬)는 "빠른 파싱"과 "풍부한 브라우저 자동화"라는 상충하는 요구를 깔끔하게 해결했다. 보안 레이어는 AI 에이전트라는 새로운 실행 주체에 맞는 안전장치를 제공한다.

파일 시스템, 터미널, API 호출—AI 에이전트의 도구 체인에서 빠져 있던 마지막 퍼즐 조각이 브라우저였다. agent-browser는 그 조각을 채워넣고 있다.