pawbrowse 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pawbrowse contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,298 @@
1
+ <p align="center">
2
+ <img src="assets/hero.png" alt="PawBrowse — Claude Code drives your real Chrome" width="100%">
3
+ </p>
4
+
5
+ <h1 align="center">
6
+ <img src="extension/icons/icon-48.png" width="28" align="top" alt=""> PawBrowse
7
+ </h1>
8
+
9
+ <p align="center"><strong>Let Claude Code drive your real, logged-in Chrome — open source, no keys, no second model.</strong></p>
10
+
11
+ <p align="center">
12
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="MIT"></a>
13
+ <a href="CONTRIBUTING.md"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome"></a>
14
+ <a href="package.json"><img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" alt="Node >=18"></a>
15
+ <img src="https://img.shields.io/badge/deps-zero-brightgreen.svg" alt="zero dependencies">
16
+ <a href="https://claude.com/claude-code"><img src="https://img.shields.io/badge/for-Claude%20Code-8A63D2.svg" alt="for Claude Code"></a>
17
+ <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-server-blue.svg" alt="MCP"></a>
18
+ </p>
19
+
20
+ PawBrowse is a **Chrome MV3 extension + a tiny zero-dependency MCP server** that lets your local
21
+ AI coding agent (like **Claude Code**) read and act on your **actual, logged-in browser tabs** —
22
+ your profile, your sessions, your open pages — with **no remote-debug port, no browser relaunch,
23
+ and no separate AI model or API key.**
24
+
25
+ It's the open, self-owned answer to "I wish my agent could just use my real browser": the same
26
+ capability as the first-party Claude-in-Chrome extension, but **yours, auditable, MCP-native, and
27
+ faster per action** (see the [benchmark](#benchmark) below).
28
+
29
+ ```
30
+ Claude Code ──stdio (MCP)──▶ mcp/server.mjs ─┐
31
+ Cursor ──stdio (MCP)──▶ mcp/server.mjs ─┼─IPC─▶ broker ──ws://127.0.0.1:10577──▶ Chrome extension ──CDP──▶ your real tabs
32
+ VS Code ──stdio (MCP)──▶ mcp/server.mjs ─┘ │
33
+ each session ⇒ its own 🐾 tab group
34
+ ```
35
+
36
+ **Run as many sessions as you want.** The first one starts a shared *broker* that owns the port
37
+ and the extension; every other session just connects to it. Each session gets its **own tab group**
38
+ (named `🐾 PawBrowse`, its own color) and drives only its own tab, so several editors/agents can
39
+ automate the browser at once without fighting over a port or a tab. Close a session and its tabs are
40
+ cleaned up; the broker reaps itself when the last session ends. Nothing to configure — no ports, no
41
+ "already in use."
42
+
43
+ ---
44
+
45
+ ## Getting started
46
+
47
+ Two one-time steps, about 30 seconds. PawBrowse is a **Chrome extension** (the hands + eyes in
48
+ your browser) plus a tiny **local server** your AI client runs — both install with a click.
49
+
50
+ ### 1 — Add the extension to Chrome
51
+
52
+ [![Add to Chrome](https://img.shields.io/badge/Add%20to-Chrome-4285F4?logo=googlechrome&logoColor=white&style=for-the-badge)](https://chromewebstore.google.com/detail/ppfdoledneneiaflggcfogecfnhkmloe)
53
+
54
+ > Live on the **[Chrome Web Store](https://chromewebstore.google.com/detail/ppfdoledneneiaflggcfogecfnhkmloe)** — one click, done.
55
+ > Prefer to run from source (contributors, or the very latest)? Clone this repo, open
56
+ > `chrome://extensions`, turn on **Developer mode**, **Load unpacked**, and pick the `extension/` folder.
57
+
58
+ ### 2 — Connect your AI client (one time)
59
+
60
+ <p>
61
+ <a href="cursor://anysphere.cursor-deeplink/mcp/install?name=pawbrowse&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInBhd2Jyb3dzZUBsYXRlc3QiXX0="><img src="https://img.shields.io/badge/Add%20to-Cursor-000000?logo=cursor&logoColor=white&style=for-the-badge" alt="Add to Cursor"></a>
62
+ <a href="https://insiders.vscode.dev/redirect/mcp/install?name=pawbrowse&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22pawbrowse%40latest%22%5D%7D"><img src="https://img.shields.io/badge/Install%20in-VS%20Code-007ACC?logo=visualstudiocode&logoColor=white&style=for-the-badge" alt="Install in VS Code"></a>
63
+ <a href="https://github.com/ItaiZeilig/pawbrowse/raw/main/dist/pawbrowse.mcpb"><img src="https://img.shields.io/badge/Add%20to-Claude%20Desktop-D97757?logo=anthropic&logoColor=white&style=for-the-badge" alt="Add to Claude Desktop"></a>
64
+ </p>
65
+
66
+ **Claude Desktop** — click the button above to download `pawbrowse.mcpb`, then **double-click it**
67
+ (or drag it into **Settings → Extensions**) and click **Install**. No command, no config.
68
+
69
+ **Claude Code** — one line (the CLI has no click-to-install, so paste this):
70
+
71
+ ```bash
72
+ claude mcp add --scope user pawbrowse -- npx -y pawbrowse@latest
73
+ ```
74
+
75
+ Then **fully restart your client** and ask: *"use pawbrowse: what's my browser status?"* — you
76
+ should see `extension_connected: true`, and the extension badge turns **green ●**.
77
+
78
+ > Needs **Node.js ≥ 18**. Works with Claude Code, Cursor, VS Code, or any MCP client — the one
79
+ > button/line just tells your client to run `npx -y pawbrowse@latest`; nothing to clone or build.
80
+
81
+ <details>
82
+ <summary>From source (contributors, or before the Web Store listing is live)</summary>
83
+
84
+ ```bash
85
+ git clone https://github.com/ItaiZeilig/pawbrowse.git
86
+ ```
87
+ 1. **Load the extension:** `chrome://extensions` → **Developer mode** → **Load unpacked** → pick
88
+ the `pawbrowse/extension` folder.
89
+ 2. **Run Claude Code from the clone.** The repo ships a project [`.mcp.json`](.mcp.json), so Claude
90
+ Code offers to enable `pawbrowse` (running the local `mcp/server.mjs`) automatically — just
91
+ approve it. No npm, no manual `claude mcp add`.
92
+ Prefer to register it yourself? `claude mcp add --scope user pawbrowse -- node /full/path/to/pawbrowse/mcp/server.mjs`
93
+ 3. **Fully restart Claude Code** (not just `/mcp`), then run the status check above.
94
+ </details>
95
+
96
+ ## Using it
97
+
98
+ You don't call the tools yourself — you just **ask Claude Code in plain language**, and it uses
99
+ PawBrowse to drive whatever tab you point it at. Some things to try:
100
+
101
+ - *"Open news.ycombinator.com and give me the top 5 story titles."*
102
+ - *"On this tab, search for 'open source license' and open the first result."*
103
+ - *"Fill the signup form on the current page with my name and email, but don't submit."*
104
+ - *"Go to my GitHub notifications and tell me what's new."*
105
+
106
+ Tips:
107
+ - It acts on the **tab you have open and are logged into** — no separate window, no re-login.
108
+ - Point it at a specific tab by name, or it uses the active tab.
109
+ - It reads the page as a list of controls and clicks/types precisely — no screenshots needed.
110
+
111
+ ## Troubleshooting
112
+
113
+ | Symptom | Fix |
114
+ | --- | --- |
115
+ | Badge never turns green | The server isn't running — make sure you **fully restarted** Claude Code after `claude mcp add` (a `/mcp` reconnect alone won't relaunch it). |
116
+ | "No extension connected" | Reload the extension at `chrome://extensions`, then re-run `browser_status`. |
117
+ | "Another debugger is already attached" | That tab has DevTools open or another extension driving it — close DevTools or switch tabs. |
118
+ | A `chrome://` / Web Store page won't drive | Those are browser pages Chrome blocks from automation — use a normal web page. |
119
+ | Changed the port | Set the same port in the extension's **Options** and in `--env PAWBROWSE_PORT=…`. |
120
+
121
+ > Requires **Node ≥ 18** (≥ 22 to run the test suite). Works on Chrome, Edge, and Brave.
122
+
123
+ ---
124
+
125
+ ## Highlights
126
+
127
+ - **Your real browser.** Uses Chrome's built-in `chrome.debugger` (CDP) on tabs you already have
128
+ open and logged into — no `--remote-debugging-port`, no relaunch, no separate profile.
129
+ - **The agent is the policy.** No second model, no `TYPESAFE_API_KEY`, no OpenRouter — *you*
130
+ (Claude) decide every action. Page content flows to your agent as normal tool results and
131
+ **never leaves for any third-party server.**
132
+ - **Reads pages as an element table, not screenshots.** A compact, numbered list of the actionable
133
+ controls in view — cheap in tokens, fast to reason over, precise to act on.
134
+ - **Fast.** Stable element refs let it act in one round trip — **~2.2× faster per action** than the
135
+ closed alternative in testing.
136
+ - **Zero dependencies, MIT, extensible.** The whole server is one auditable `.mjs` file; the
137
+ extension is plain JS. Add a tool or an op in minutes.
138
+
139
+ ## Benchmark
140
+
141
+ <p align="center">
142
+ <img src="assets/pawbrowse-vs-claude-in-chrome.gif" alt="Real side-by-side recording: PawBrowse vs Claude-in-Chrome on the same task" width="100%">
143
+ </p>
144
+
145
+ <p align="center"><em>Real side-by-side screen recording — same task (3 Wikipedia section jumps), same brain (Claude). PawBrowse acts in one call per click and finishes first; Claude-in-Chrome perceives-then-clicks. Measured numbers below.</em></p>
146
+
147
+ Because PawBrowse keeps **stable element refs** and its `navigate`/`act` already return the fresh
148
+ table, the agent clicks a known target in **one** round trip. Screenshot/accessibility-tree drivers
149
+ do **perceive-then-act** — a read (or screenshot) *then* a click — paying an extra agent round trip
150
+ and a larger payload every action.
151
+
152
+ Measured task: click 5 different section links on the same Wikipedia page, averaged, same machine,
153
+ same agent (Claude):
154
+
155
+ | | PawBrowse | Claude-in-Chrome |
156
+ | --- | --- | --- |
157
+ | Calls per click | **1** (`act` by stable ref) | 2 (`read_page` → click) |
158
+ | Avg wall-clock per click | **~7.6 s** | ~17.0 s |
159
+ | Perception payload | compact, viewport-only | full a11y tree w/ URLs (up to 50 KB) |
160
+
161
+ > **Honest caveat:** with Claude as the shared brain, absolute wall-clock is dominated by agent
162
+ > latency and is noisy — treat the **~2.2× ratio** as the signal, not the exact seconds. The win is
163
+ > *structural* (fewer round trips + smaller payloads), which also means fewer tokens per step. It's
164
+ > **not** the sub-second speed of a small, dedicated click-picking model — PawBrowse trades that
165
+ > raw speed for a smart, general brain (Claude) with no keys and no per-click cost.
166
+
167
+ ## How it compares
168
+
169
+ | | Claude-in-Chrome | **PawBrowse** |
170
+ | --- | --- | --- |
171
+ | Drives your real, logged-in Chrome | ✅ | ✅ (`chrome.debugger`, no port) |
172
+ | Decision model | Claude | **Claude — no second model, no key** |
173
+ | Perception | screenshots + a11y tree | **compact element table** |
174
+ | Round trips per action | 2 (perceive → act) | **1** (stable refs) |
175
+ | Page data to a third party | no | **no** |
176
+ | Per-site permission gate | yes (allowlist) | no |
177
+ | Open source / self-owned | ❌ | **✅ MIT, zero-dep** |
178
+ | Works with any MCP client | ❌ | **✅** |
179
+
180
+ ## The element table
181
+
182
+ Every observation returns a compact, numbered table of the **in-viewport, actionable** controls —
183
+ with proper accessible names, current values, and state flags — instead of a screenshot:
184
+
185
+ ```
186
+ Web browser - Wikipedia — https://en.wikipedia.org/wiki/Web_browser
187
+ scroll 0/6361 · 83 controls
188
+ e2 fill "Search Wikipedia"
189
+ e6 click "Log in"
190
+ e10 click "2 History"
191
+ e13 click ▾ "Toggle Browser market subsection"
192
+ e9 click✓ "Remember me"
193
+ e3 select "Country" opts{US | UK | ...}
194
+ ```
195
+
196
+ Flags after the kind: `✓`/`·` checked/unchecked · `▾`/`▸` expanded/collapsed (open vs closed menu,
197
+ combobox, accordion) · `◉` selected (active tab/option). Refs like `e10` derive from a **stable node
198
+ identity**, so the agent can act on a control by ref in **one round trip**.
199
+
200
+ ## Tools
201
+
202
+ | Tool | Purpose |
203
+ | --- | --- |
204
+ | `browser_status` | Connection + attached-tab diagnostics. Call first if anything's off. |
205
+ | `browser_tabs` | List open tabs (`id`, `title`, `url`, `active`). |
206
+ | `browser_navigate` | `{ url, tabId? }` → element table after load. |
207
+ | `browser_observe` | `{ tabId? }` → the element table. |
208
+ | `browser_read` | `{ tabId?, max_chars? }` → the page's readable prose (articles, docs, rules). |
209
+ | `browser_act` | `{ ops: [...], tabId? }` → runs ops in order, returns a fresh table + a "page changed?" signal. |
210
+ | `browser_assert` | `{ contains? \| url_includes? \| ref_visible?, tabId? }` → prove an outcome (pass/fail). |
211
+
212
+ **Ops for `browser_act`:** `{op:"click",ref:"e12"}` · `{op:"click_text",text:"..."}` (for custom
213
+ widgets/menus not in the table) · `{op:"type",ref:"e7",text:"..."}` · `{op:"select",ref:"e8",value:"..."}`
214
+ · `{op:"key",key:"Enter"}` · `{op:"scroll",dy:600}` · `{op:"wait",ms:500}`.
215
+
216
+ ## Reliability & safety engineering
217
+
218
+ PawBrowse was hardened through two multi-agent code audits **and** live testing on real sites:
219
+
220
+ - **Hit-tested clicks.** Before every click it re-resolves the element live and verifies the center
221
+ isn't covered (`elementFromPoint`), so it never clicks a stale, moved, or occluded target.
222
+ - **Semantic freshness guard.** An element's role + accessible name is fingerprinted at observe time
223
+ and re-checked before acting — a silently relabeled target is rejected ("observe again") instead
224
+ of mis-clicked.
225
+ - **Robust fill.** Select-all + `insertText`, which works with React/controlled inputs; typed
226
+ comboboxes wait for their autocomplete options to actually render.
227
+ - **Background-tab safe.** Uses `Emulation.setFocusEmulationEnabled` and `setTimeout`-based waits
228
+ (never `requestAnimationFrame`, which Chrome pauses in background tabs) so driving a tab you aren't
229
+ looking at doesn't hang.
230
+ - **No double-execution.** If a post-action read fails because the page is navigating, the ops are
231
+ reported as executed ("call observe next") rather than surfaced as a failure to retry.
232
+ - **Serialized, unwedgeable command queue** — overlapping calls can't race the debugger, and one
233
+ hung command can't block the rest.
234
+
235
+ ## Security & privacy
236
+
237
+ - **No data leaves your machine.** There's no model and no API key; page content goes only to the
238
+ agent you run locally. `password`, `file`, and `hidden` inputs are excluded and never exposed.
239
+ (Other visible fields — e.g. text inputs — *are* part of the element table, so treat what's on
240
+ screen as visible to your agent.)
241
+ - **Local-only bridge.** The WebSocket binds to `127.0.0.1`, rejects non-`chrome-extension://`
242
+ origins (so a web page can't connect), trusts only the current extension socket, caps inbound
243
+ frame size, and rejects malformed/oversized frames. **Trust model:** the bridge trusts any
244
+ *local* process on `127.0.0.1` (there's no shared token yet), so it assumes other software on
245
+ your machine is trusted — the same assumption as most localhost dev tools. A per-pair token is
246
+ planned hardening.
247
+ - **One powerful permission, no host permissions.** The extension declares `debugger` (plus `tabs`,
248
+ `storage`, `alarms`) and **no** host permissions — `chrome.debugger` doesn't need them. That's the
249
+ same capability class as any real-browser agent; use it deliberately.
250
+ - **Fully auditable.** The server is one zero-dependency file; the extension is plain JS.
251
+
252
+ Found a vulnerability? See **[SECURITY.md](SECURITY.md)** — please don't open a public issue.
253
+
254
+ ## Privacy policy
255
+
256
+ PawBrowse is built to collect nothing. Full policy: **[PRIVACY.md](PRIVACY.md)**. In short:
257
+
258
+ - **Collection / use:** PawBrowse has no AI model, no account, no API key, and **no telemetry or
259
+ analytics**. Page content it reads (element tables, page text) is returned only to the local AI
260
+ client you run, to fulfill your request.
261
+ - **Storage:** the only thing stored is your **bridge port number**, in `chrome.storage.local` on
262
+ your machine. Page content is not persisted by the extension beyond the current operation.
263
+ - **Sharing:** nothing is sent to the developer or any third-party server. All traffic stays on
264
+ `127.0.0.1` (localhost) between the extension and the server on your own computer.
265
+ - **Retention:** none — there is no server-side data, so there is nothing to retain or delete.
266
+ - **Contact:** questions or requests via [GitHub issues](https://github.com/ItaiZeilig/pawbrowse/issues).
267
+
268
+ ## Notes & limits
269
+
270
+ - Attaching shows Chrome's "PawBrowse is debugging this browser" banner — expected.
271
+ - One debugger client per tab: a tab with DevTools open (or driven by another extension) can't be
272
+ attached — switch tabs or close DevTools.
273
+ - `chrome://`, the Chrome Web Store, and other browser pages can't be driven.
274
+ - **One active client at a time.** The bridge is a single localhost port, so PawBrowse can be driven
275
+ by one client at a time (e.g. Claude Code *or* Claude Desktop). A second client reports the port
276
+ is in use via `browser_status` rather than failing hard; set a different `PAWBROWSE_PORT` per
277
+ client if you need both.
278
+ - **Shadow DOM and same-origin iframes are enumerated** (v0.4.0): controls inside open shadow roots
279
+ (web components) and same-origin iframes appear in the element table and are clickable/typable by
280
+ ref. **Not yet:** cross-origin iframes (the browser blocks JS access to them), canvas, and file
281
+ uploads.
282
+
283
+ ## Contributing
284
+
285
+ Contributions welcome — see **[CONTRIBUTING.md](CONTRIBUTING.md)** for dev setup, tests (`npm test`),
286
+ and the PR process. By participating you agree to the **[Code of Conduct](CODE_OF_CONDUCT.md)**.
287
+ Questions? **[SUPPORT.md](SUPPORT.md)**.
288
+
289
+ ## Credits
290
+
291
+ Built with [Claude Code](https://claude.com/claude-code). Some of the page-perception and
292
+ action-execution techniques are adapted from
293
+ [browser-use/jev-ultrafast](https://github.com/browser-use/jev-ultrafast) (MIT); this credit is kept
294
+ as required by that project's license.
295
+
296
+ ## License
297
+
298
+ [MIT](LICENSE) © PawBrowse contributors.