aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authoramankumarsingh77 <amankumarsingh7702@gmal.com>2026-04-29 00:40:36 +0530
committeramankumarsingh77 <amankumarsingh7702@gmal.com>2026-04-29 00:40:36 +0530
commit8fff91522918a8309dea2e9fa725e15f6ed1c3ea (patch)
treea2f5fb863fd6ac260a3f37e4ed308d0c6df0a9ed /README.md
Initial release: pi-browser-harness
Browser control extension for pi — 20 browser_* tools for navigating, clicking, typing, screenshotting, and extracting data from real Chrome via CDP. Includes self-extending harness (register_tool/remove_tool), guided /browser-setup, session persistence, and custom TUI renderers.
Diffstat (limited to 'README.md')
-rw-r--r--README.md513
1 files changed, 513 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..eab9652
--- /dev/null
+++ b/README.md
@@ -0,0 +1,513 @@
+# pi-browser-harness
+
+> **Full browser control for pi agents.** Navigate, click, type, screenshot, and extract data from a real Chrome browser — all through CDP, all from your coding agent.
+
+<p align="center">
+ <img alt="Version" src="https://img.shields.io/npm/v/@pi-browser-harness?style=flat-square&color=2563eb">
+ <img alt="License" src="https://img.shields.io/badge/license-MIT-blue?style=flat-square">
+ <img alt="Pi Package" src="https://img.shields.io/badge/pi-package-2563eb?style=flat-square">
+ <img alt="Node" src="https://img.shields.io/badge/node-%3E%3D18-339933?style=flat-square&logo=node.js&logoColor=white">
+</p>
+
+**pi-browser-harness** gives pi agents full control of a real Chrome browser. No headless mode, no emulation — your agent sees what you see, clicks where you'd click, and reads pages exactly as they render. Browser tools coexist seamlessly with all standard pi tools (`read`, `bash`, `edit`, `write`).
+
+---
+
+## Why pi-browser-harness?
+
+| | |
+|---|---|
+| 🖱️ **Real browser, real pixels** | Connects to your running Chrome via CDP. Compositor-level clicks work through iframes, shadow DOM, and cross-origin content. |
+| 🧩 **Seamless pi integration** | `browser_*` tools appear alongside `read`, `bash`, `edit` — no context switching, no separate daemon management. |
+| 🔧 **Self-extending harness** | The agent writes its own tools mid-task. Need a paginated scraper? Bulk CSV exporter? Register it at runtime, callable next turn. |
+| ⚡ **Fast data extraction** | `browser_http_get` bypasses the browser entirely for APIs — 10-50x faster than DOM scraping. `browser_execute_js` for rendered data. |
+| 🛡️ **Dialog-aware** | Auto-detects JS dialogs (alert, confirm, prompt, beforeunload) before they block your session. |
+| 📸 **Visual feedback** | Screenshots before and after every action. The agent can see exactly what it's doing. |
+
+---
+
+## Quick Start
+
+```bash
+# 1. Install the package
+pi install npm:pi-browser-harness
+
+# 2. Start Chrome with remote debugging
+# macOS:
+/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 &
+
+# Linux:
+google-chrome --remote-debugging-port=9222 &
+
+# 3. Run the guided setup inside pi
+/browser-setup
+```
+
+**That's it.** Your pi agent now has 20 browser control tools. Try:
+
+```
+> navigate to https://github.com and take a screenshot
+```
+
+---
+
+## Features
+
+### 🧭 Navigation & Tabs
+
+| Tool | What it does |
+|------|-------------|
+| `browser_navigate` | Navigate to a URL (safe: creates new tab on first call) |
+| `browser_new_tab` | Open a new tab, optionally navigate |
+| `browser_open_urls` | Open multiple URLs in parallel tabs (great after web search) |
+| `browser_go_back` / `browser_go_forward` | History navigation |
+| `browser_reload` | Reload the current page |
+| `browser_page_info` | Get URL, title, viewport, scroll position, or detect JS dialogs |
+| `browser_list_tabs` / `browser_current_tab` | Tab discovery and identification |
+| `browser_switch_tab` | Switch to a specific tab by targetId |
+
+### 🖱️ Interaction
+
+| Tool | What it does |
+|------|-------------|
+| `browser_click` | Click at viewport CSS-pixel coordinates (compositor-level) |
+| `browser_type` | Type text into the focused element |
+| `browser_press_key` | Press any key with modifier support (Ctrl, Alt, Meta, Shift) |
+| `browser_scroll` | Scroll the page by delta pixels |
+| `browser_handle_dialog` | Accept or dismiss JS dialogs |
+
+### 📸 Visual & Data
+
+| Tool | What it does |
+|------|-------------|
+| `browser_screenshot` | Capture a PNG screenshot of the current page |
+| `browser_execute_js` | Execute JavaScript and return the result |
+| `browser_http_get` | Direct HTTP GET (bypasses browser — 10-50x faster for APIs) |
+| `browser_wait` | Wait N seconds |
+| `browser_wait_for_load` | Wait for `document.readyState === 'complete'` |
+
+### 🔧 Self-Extending Harness
+
+| Tool | What it does |
+|------|-------------|
+| `list_dynamic_tools` | See what's already been registered |
+| `register_tool` | Inject a new tool (available immediately, next turn) |
+| `remove_tool` | Retire a tool that's no longer needed |
+
+> **Philosophy:** "The agent writes what's missing, mid-task." When the built-in tools aren't enough, the agent extends the harness itself — no reload, no restart.
+
+---
+
+## Installation
+
+### Prerequisites
+
+| Requirement | Version | Notes |
+|------------|---------|-------|
+| **pi** | Latest | The pi coding agent CLI |
+| **Node.js** | ≥ 18 | Runtime for the extension |
+| **Chrome / Chromium / Edge** | Any recent | Must support CDP (Chrome DevTools Protocol) |
+| **browser-harness daemon** | Latest | Installed automatically by `/browser-setup` |
+| **uv** (optional) | Latest | Python package manager; used for daemon installation |
+| **git** (optional) | Any | Fallback installation method |
+
+### Installing the package
+
+```bash
+# From npm (recommended)
+pi install npm:pi-browser-harness
+
+# From git
+pi install git:github.com/browser-use/browser-harness
+
+# Locally (for development)
+pi install ./pi-browser-harness
+```
+
+### Installing the browser-harness daemon
+
+The daemon (`daemon.py`) is what connects pi-browser-harness to Chrome. Run the guided setup:
+
+```
+/browser-setup
+```
+
+This will:
+1. Check for an existing browser-harness installation
+2. Auto-install via `uv tool install browser-harness` or `git clone`
+3. Verify Chrome is running with remote debugging
+4. Start the daemon and test the connection
+
+**Manual installation:**
+
+```bash
+# Option A: uv (recommended)
+uv tool install browser-harness
+
+# Option B: git clone
+git clone https://github.com/browser-use/browser-harness ~/Developer/browser-harness
+cd ~/Developer/browser-harness && uv sync
+```
+
+### Enabling Chrome Remote Debugging
+
+Start Chrome with the `--remote-debugging-port` flag:
+
+```bash
+# macOS
+/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
+ --remote-debugging-port=9222
+
+# Linux
+google-chrome --remote-debugging-port=9222
+
+# Windows
+"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
+```
+
+> **Edge / Chromium**: Works identically — just replace the binary path.
+
+---
+
+## Usage
+
+### Core Workflow
+
+The fundamental pattern: **screenshot → interact → screenshot → verify.**
+
+```
+browser_screenshot() → find the target → browser_click(x, y) → browser_screenshot()
+```
+
+Every interaction is verified visually. Never assume an action worked.
+
+### Navigation
+
+```bash
+# First navigation: creates a new tab (preserves user's active tab)
+browser_navigate("https://github.com/browser-use/browser-harness")
+browser_wait_for_load()
+browser_screenshot()
+```
+
+### Form Filling
+
+```bash
+browser_screenshot() # See the form
+browser_click(400, 200) # Click the search input
+browser_type("pi browser harness") # Type the query
+browser_press_key("Enter") # Submit
+browser_wait_for_load()
+browser_screenshot() # Verify results
+```
+
+### Data Extraction
+
+```bash
+# Fast: Direct HTTP for APIs
+browser_http_get("https://api.github.com/repos/browser-use/browser-harness")
+
+# DOM scraping: Execute JS in the rendered page
+browser_execute_js("document.querySelector('.price').innerText")
+
+# Structured: Extract arrays of data
+browser_execute_js(`
+ JSON.stringify(
+ Array.from(document.querySelectorAll('.result')).map(el => ({
+ title: el.querySelector('h3')?.textContent,
+ link: el.querySelector('a')?.href,
+ }))
+ )
+`)
+```
+
+### Research Workflow (Search + Tabs)
+
+```bash
+# Step 1: Search
+browser_navigate("https://google.com/search?q=chrome+devtools+protocol+reference")
+
+# Step 2: Open result links in parallel tabs
+browser_open_urls({ urls: [
+ "https://chromedevtools.github.io/devtools-protocol/",
+ "https://developer.chrome.com/docs/devtools",
+] })
+
+# Step 3: List all tabs to get target IDs
+browser_list_tabs()
+
+# Step 4: Switch to the tab you want
+browser_switch_tab({ targetId: "ABC123..." })
+
+# Step 5: Inspect
+browser_wait_for_load()
+browser_screenshot()
+browser_execute_js("document.querySelector('.main-content').innerText")
+```
+
+### SPAs (React, Vue, etc.)
+
+`browser_wait_for_load()` only checks `document.readyState === 'complete'`. SPAs often render content after this. Check for specific elements:
+
+```bash
+browser_navigate("https://my-spa.example.com")
+browser_wait_for_load()
+
+# Poll for the element to appear
+browser_execute_js("!!document.querySelector('.loaded-content')")
+```
+
+### Keyboard Modifiers
+
+`browser_press_key` supports modifier bitfield combinations:
+
+| Combo | Bitfield | Example |
+|-------|----------|---------|
+| Ctrl+C | 2 | `browser_press_key("c", { modifiers: 2 })` |
+| Cmd+V | 4 | `browser_press_key("v", { modifiers: 4 })` |
+| Ctrl+Shift+T | 10 (2\|8) | `browser_press_key("T", { modifiers: 10 })` |
+| Cmd+Shift+N | 12 (4\|8) | `browser_press_key("N", { modifiers: 12 })` |
+
+---
+
+## Self-Extending Harness
+
+When the built-in tools aren't enough, the agent writes its own:
+
+```
+ ● agent: needs to scrape 47 paginated search result pages
+ │
+ ● calls list_dynamic_tools() → empty
+ │
+ ● calls register_tool({
+ │ name: "scrape_paginated",
+ │ implementation: "..."
+ │ })
+ │
+ ✓ next turn: scrape_paginated() is available and callable
+```
+
+### Tool Lifecycle
+
+1. **`list_dynamic_tools`** — Check what's already registered
+2. **`register_tool`** — Inject a new tool with custom JavaScript
+3. **`remove_tool`** — Retire a tool you no longer need
+
+### Dynamic Tool Bindings
+
+Tools receive these bindings at runtime:
+
+| Binding | Description |
+|---------|-------------|
+| `params` | Tool arguments (as passed by the caller) |
+| `daemon` | Browser daemon — `daemon.cdp()`, `daemon.evaluateJS()`, `daemon.getPageInfo()` |
+| `require` | Node.js `require()` for builtins and installed packages |
+| `signal` | `AbortSignal` for cancellation |
+| `onUpdate` | Progress callback: `onUpdate({ content: [{ type: 'text', text: '...' }] })` |
+| `ctx` | `ExtensionContext` with `cwd`, `sessionManager`, `ui`, `signal` |
+| `console`, `fetch`, `JSON`, `Buffer`, `setTimeout`, `clearTimeout` | Standard globals |
+
+### Example: Structured Data Extractor
+
+```javascript
+// register_tool implementation:
+const info = await daemon.getPageInfo();
+if ("dialog" in info) throw new Error("Dialog is blocking: " + info.dialog.message);
+
+const data = await daemon.evaluateJS(`
+ JSON.stringify(
+ Array.from(document.querySelectorAll('${params.rowSelector}')).map(el => ({
+ title: el.querySelector('${params.titleSelector}')?.textContent?.trim(),
+ price: el.querySelector('${params.priceSelector}')?.textContent?.trim(),
+ link: el.querySelector('a')?.href,
+ }))
+ )
+`);
+
+const parsed = JSON.parse(data);
+return {
+ content: [{ type: 'text', text: `Extracted ${parsed.length} items:\n\n${JSON.stringify(parsed, null, 2)}` }],
+ details: { items: parsed, count: parsed.length }
+};
+```
+
+---
+
+## Architecture
+
+```
+┌─────────────────────────────────────────────────┐
+│ pi agent │
+│ │ │
+│ ├─ browser_navigate() │
+│ ├─ browser_screenshot() │
+│ ├─ browser_click(x, y) │
+│ ├─ browser_execute_js(...) │
+│ ├─ list_dynamic_tools() │
+│ ├─ register_tool(...) │
+│ └─ remove_tool(...) │
+│ │
+│ pi-browser-harness (TypeScript extension) │
+└────────────────────┬────────────────────────────┘
+ │ Unix socket
+ │ /tmp/bu-<namespace>.sock
+ ▼
+ ┌────────────────┐
+ │ daemon.py │
+ │ (Python) │
+ └───────┬────────┘
+ │ CDP WebSocket
+ │ ws://localhost:9222
+ ▼
+ ┌────────────────┐
+ │ Chrome / Edge │
+ │ (user's real │
+ │ browser) │
+ └────────────────┘
+```
+
+### Data Flow
+
+1. **pi agent** calls a `browser_*` tool (e.g., `browser_screenshot()`)
+2. **pi-browser-harness extension** translates the call into a CDP command
+3. **JSON-line request** sent over Unix socket to `daemon.py`
+4. **daemon.py** relays the command over CDP WebSocket to Chrome
+5. **Chrome** executes the command and returns the result
+6. Result flows back through the chain to the agent
+
+### Session Persistence
+
+- Tab history, daemon namespace, and preferences persist across session reloads and branch navigation
+- State is stored via `pi.appendEntry()` in the session's JSONL file
+- On `session_start`, state is restored by scanning the branch for the last `browser-harness-state` entry
+
+### Key Design Decisions
+
+- **One socket connection per request** — stateless, matches the daemon's internal `_send` pattern
+- **Session auto-recovery** — stale CDP sessions are automatically re-attached
+- **Compositor-level clicks** — `Input.dispatchMouseEvent` works through iframes, shadow DOM, and cross-origin content without selectors
+- **Daemon auto-restart** — if the daemon socket dies mid-request, it's restarted and the request is retried once
+
+---
+
+## Configuration
+
+### CLI Flags
+
+| Flag | Type | Default | Description |
+|------|------|---------|-------------|
+| `--browser-namespace` | `string` | auto-generated | Daemon namespace (`BU_NAME`). Use to run multiple instances. |
+| `--browser-debug-clicks` | `boolean` | `false` | Enable debug click overlay (saves annotated screenshots to `/tmp`). |
+
+### Commands
+
+| Command | Description |
+|---------|-------------|
+| `/browser-setup` | Guided setup wizard — installs browser-harness, connects to Chrome |
+| `/browser-status` | Show daemon health, current page URL/title/viewport |
+| `/browser-reload-daemon` | Restart the browser daemon |
+
+---
+
+## Troubleshooting
+
+| Symptom | Likely Cause | Fix |
+|---------|-------------|-----|
+| Daemon not starting | Chrome remote debugging not enabled | Start Chrome with `--remote-debugging-port=9222` |
+| "DevToolsActivePort not found" | Chrome didn't accept the debugging connection | Open `chrome://inspect/#remote-debugging`, tick the checkbox, click Allow |
+| Daemon starts but no tools work | Stale or dead CDP session | Run `/browser-reload-daemon` to restart |
+| Dialog blocking page | JS `alert`/`confirm`/`prompt` is open | Run `browser_page_info()` to detect it, then `browser_handle_dialog()` |
+| Page not fully loaded | SPA with async rendering | After `browser_wait_for_load()`, use `browser_execute_js()` to check for specific elements |
+| `uv` not found | Python package manager not installed | Install via `curl -LsSf https://astral.sh/uv/install.sh \| sh` or use the git fallback |
+| Socket permission denied | Stale socket file from previous run | `rm /tmp/bu-*.sock /tmp/bu-*.pid` and restart |
+| Windows: `ps` not found | `setup.ts` uses Unix commands | Windows detection is best-effort; see manual installation steps above |
+
+---
+
+## Security
+
+> **Warning:** This extension gives your pi agent full control over your real Chrome browser. It can see your open tabs, read page content, submit forms, and interact with authenticated sessions.
+
+- **No sandboxing** — the agent has access to whatever Chrome has access to
+- **Credentials** — if the agent hits an auth wall, it should stop and ask you. Never store credentials in agent prompts.
+- **Dynamic tools** — `register_tool` evaluates user-supplied JavaScript in the pi process with full `require` access. Review any dynamic tool implementations you didn't write yourself.
+- **Data handling** — Screenshots are saved to `/tmp`. HTTP responses and JS evaluation results may contain sensitive page data.
+- **Session persistence** — Tab history and daemon state are stored in pi's session file (`.jsonl`). These contain page URLs and titles.
+
+---
+
+## Contributing
+
+We welcome contributions! Here's how to get started:
+
+```bash
+# Clone the repository
+git clone https://github.com/browser-use/browser-harness
+cd browser-harness/pi-browser-harness
+
+# Install dependencies
+npm install
+
+# Type-check
+npm run typecheck
+
+# Test locally
+pi install ./ # Install from local path
+```
+
+### Development Guidelines
+
+- **TypeScript strict mode** — all code must pass `tsc --noEmit`
+- **Error handling** — tools must catch errors and return `isError: true` with a descriptive message
+- **Tool names** — use `snake_case` for consistency with pi conventions
+- **Parameters** — use `typebox` schemas for all tool parameters
+- **Prompt guidelines** — every tool must include `promptSnippet` and `promptGuidelines` for LLM context
+
+### Project Structure
+
+```
+pi-browser-harness/
+├── src/
+│ ├── index.ts # Extension entry point, lifecycle, flags, commands
+│ ├── daemon.ts # BrowserDaemon: spawns daemon.py, CDP transport
+│ ├── tools.ts # All browser_* tool registrations
+│ ├── dynamic-tools.ts # Self-extending harness (register_tool, etc.)
+│ ├── protocol.ts # Unix socket protocol types and low-level transport
+│ ├── prompt.ts # System prompt injection
+│ ├── renderers.ts # Custom TUI renderers
+│ ├── setup.ts # /browser-setup wizard
+│ └── state.ts # Session persistence
+├── skills/
+│ └── pi-browser-harness/
+│ └── SKILL.md # User-facing skill documentation
+├── package.json
+├── tsconfig.json
+├── LICENSE
+├── CHANGELOG.md
+└── README.md
+```
+
+---
+
+## Roadmap
+
+- [ ] Windows-native setup wizard (remove `ps`/`grep` dependency)
+- [ ] iframe-target evaluation support in `browser_execute_js`
+- [ ] Remote browser support (connect to Chrome running on another machine)
+- [ ] Screenshot annotations (click markers, element highlights)
+- [ ] Performance benchmarks and CI test suite
+- [ ] Configurable screenshot output directory
+- [ ] Recording/playback of interaction sequences
+- [ ] Better audio/video support for media-heavy pages
+
+---
+
+## License
+
+MIT — see [LICENSE](LICENSE) for details.
+
+---
+
+<p align="center">
+ <sub>Built with ❤️ for the pi ecosystem. Makes coding agents see the web.</sub>
+</p>