iframer-toolkit 0.10.1 → 0.10.6

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/README.md CHANGED
@@ -1,16 +1,62 @@
1
- # iframer-toolkit
1
+ <div align="center">
2
2
 
3
- Browser access for AI agents when normal fetching fails. Give Claude, Codex, or any MCP-compatible agent a real browser — with session persistence, stealth fingerprinting, encrypted credential storage, and automatic captcha solving, and most af all, API Reverse Engineering.
3
+ <img src="docs/logo.svg" width="104" alt="iframer">
4
4
 
5
- ## Example:
6
- <img width="2962" height="1116" alt="image" src="https://github.com/user-attachments/assets/c937b39c-5dba-4d6a-892d-71243ecf8146" />
7
- Resulting rev API example:
8
- <img width="2141" height="1173" alt="image" src="https://github.com/user-attachments/assets/19a27904-ebe0-4e65-8a44-a8cfb3756ed8" />
5
+ # iframer
9
6
 
10
- Ships as:
11
- - **CLI** (`iframer-toolkit` / `iframer`) — browse, screenshot, credentials, sessions, reverse-engineer APIs
12
- - **MCP server** — plugs directly into Claude Code or Codex so agents can drive the browser themselves
13
- - **Self-hosted Docker server** (optional) — adds live headful browsing over noVNC for remote/multi-user setups
7
+ **Give an AI agent a real browser, get an API back.**<br>
8
+ Drive a site once and iframer hands the agent the actual request behind it, no devtools, no HAR file.
9
+
10
+ ![npm](https://img.shields.io/npm/v/iframer-toolkit?color=6D5EF0&label=npm)
11
+ ![license](https://img.shields.io/badge/license-MIT-6D5EF0)
12
+ ![node](https://img.shields.io/badge/node-%E2%89%A518-6D5EF0)
13
+ ![CLI](https://img.shields.io/badge/-CLI-6D5EF0)
14
+ ![MCP](https://img.shields.io/badge/-MCP-6D5EF0)
15
+ ![extension](https://img.shields.io/badge/-extension-6D5EF0)
16
+
17
+ <img src="docs/example/demo.gif" width="760" alt="left: a demo page being clicked. right: the terminal, running iframer reverse-engineer, showing the captured endpoint">
18
+
19
+ </div>
20
+
21
+ Most agent-driven browsers only replay clicks. Every visit to the same page means rendering the whole thing again, screenshot after screenshot, just to read one field off it.
22
+
23
+ iframer drives a real, stealth-patched Chromium, or your own logged-in Chrome through the extension, and while it does:
24
+
25
+ - Records the fetch and XHR calls the page makes while it drives it (not static assets), no manual devtools work
26
+ - Hands back the real request behind a login form or a button click: method, headers, auth, a working curl
27
+ - Generates typed functions ready to `import`, when an agent is doing the driving
28
+ - Caches the domain after the first run, so the next visit skips the browser and hits the endpoint directly, seconds down to milliseconds
29
+
30
+ ## Example
31
+
32
+ The left side of the GIF above is [`docs/example/site/index.html`](docs/example/site/index.html): one button, one hidden API call. The right side is a real terminal, only the typing pace was staged for the recording; the command and its output are exactly what running it produces. Capturing it for real:
33
+
34
+ ```sh
35
+ cd docs/example/site && python3 -m http.server 8934 &
36
+ iframer-toolkit reverse-engineer '[
37
+ {"type":"navigate","url":"http://localhost:8934/index.html"},
38
+ {"type":"click","selector":"#load"},
39
+ {"type":"wait","ms":1000}
40
+ ]' --output docs/example/api
41
+ ```
42
+
43
+ That produced [`docs/example/api/captured-api.json`](docs/example/api/captured-api.json): the exact request, headers, response body, and a curl command, all automatic, no agent required.
44
+
45
+ The rest of `docs/example/api/` (`getTodos.ts`, `transport/rest.ts`, `types.ts`, `README.md`) is what an agent writes from that capture: iframer tells it the endpoint's protocol, verb, and function name, and the agent turns that into a typed function. That's what happened here, driven by Claude through the MCP `reverse-engineer` tool.
46
+
47
+ The whole round trip, one click to one typed endpoint, cost about 590 tokens back to the agent. This is the whole thing you get: no HAR file, no manual devtools work, a function you can call.
48
+
49
+ ## Token cost
50
+
51
+ Most of iframer's savings come from the snapshot it hands back: capped and filtered, instead of the full accessibility tree other tools dump into context. Measured with the same tokenizer, same steps, on the same three tasks:
52
+
53
+ | Task | iframer (MCP) | iframer (CLI) | agent-browser | Playwright MCP |
54
+ |------|---------------|----------------|----------------|-----------------|
55
+ | Wiki link chase (6 hops, Everest → Gojo) | 517 | 721 | 913 | 1,405 |
56
+ | Store purchase (login → sort → cart → checkout) | 552 | 697 | 851 | 2,739 |
57
+ | Heavy-page recon (GitHub: look + pull 4 facts) | 986 | 1,058 | 8,433 | 19,906 |
58
+
59
+ The gap grows with how much DOM the page has. On the GitHub page, iframer spent about 986 tokens where Playwright MCP spent about 19,900, roughly 20x. That's per-task cost. It doesn't include the roughly 5.1k tokens of MCP tool-definition overhead loaded once per session, not per task.
14
60
 
15
61
  ## Install
16
62
 
@@ -21,23 +67,36 @@ npm install -g iframer-toolkit
21
67
  Then pull in the runtime dependencies (Chrome for Testing + MCP registration):
22
68
 
23
69
  ```sh
24
- iframer-toolkit install deps
70
+ iframer-toolkit install
25
71
  ```
26
72
 
27
73
  This is shorthand for:
28
74
 
29
75
  ```sh
30
76
  iframer-toolkit install chromium # downloads Chrome for Testing to ~/.iframer
31
- iframer-toolkit install-mcp # registers the MCP server in ~/.claude.json and ~/.codex/config.toml
77
+ iframer-toolkit install mcp # registers the MCP server in ~/.claude.json and ~/.codex/config.toml
32
78
  ```
33
79
 
34
80
  Restart Claude Code or Codex and the `iframer` tools will be available.
35
81
 
36
- > **Note:** If you prefer, your agent can run `iframer-toolkit install deps` for you — it'll figure the rest out.
82
+ To update later:
83
+
84
+ ```sh
85
+ iframer-toolkit update # update via npm (also refreshes the extension if installed)
86
+ iframer-toolkit update --check # just report whether a newer version exists
87
+ ```
88
+
89
+ Your agent can also just run `iframer-toolkit install` for you; it figures out the rest.
90
+
91
+ Ships as:
92
+ - **CLI** (`iframer-toolkit` / `iframer`): browse, screenshot, credentials, sessions, reverse-engineer APIs
93
+ - **MCP server**: plugs into Claude Code or Codex so agents drive the browser themselves
94
+ - **Browser extension** (optional): lets the agent drive tabs in your real Chrome, on your real logged-in session
95
+ - **Self-hosted Docker server** (optional): adds live headful browsing over noVNC for remote or multi-user setups
37
96
 
38
97
  ## Quick start
39
98
 
40
- Once installed, you can either drive the browser via the CLI directly, or ask your agent (Claude Code / Codex) to do it for you via the MCP.
99
+ Once installed, drive the browser via the CLI directly, or ask your agent (Claude Code / Codex) to do it through the MCP.
41
100
 
42
101
  **CLI:**
43
102
 
@@ -46,37 +105,89 @@ iframer-toolkit status # system + browser m
46
105
  iframer-toolkit browse https://example.com --extract 'document.title'
47
106
  iframer-toolkit screenshot https://news.ycombinator.com -o /tmp/hn.png
48
107
  iframer-toolkit credentials add github.com # interactive masked prompt
49
- iframer-toolkit reverse-engineer https://some-spa.com # capture the APIs it calls
108
+ iframer-toolkit reverse-engineer https://some-spa.com # capture the APIs it calls
50
109
  iframer-toolkit --cache # list cached domains
51
110
  ```
52
111
 
53
- **From Claude Code or Codex** (after `install-mcp`):
112
+ **From Claude Code or Codex** (after `install mcp`):
54
113
 
55
114
  > "Log into my account on example.com and extract the latest invoice."
56
115
 
57
- The agent will call `knowledge` first (to see if a direct-API path is cached), fall back to `credentials` + `execute` if not, auto-escalate browser modes if a site blocks headless, and return the result. No copying cookies, no proxies, no manual login.
116
+ The agent calls `knowledge` first to check for a cached direct-API path, falls back to `credentials` + `execute` if there isn't one, auto-escalates browser modes if a site blocks headless, and returns the result. No copying cookies, no proxies, no manual login.
58
117
 
59
118
  ## How it works
60
119
 
61
120
  ```
62
- Claude / Codex (MCP) ──→ iframer MCP server ──→ Iframer (local)
63
- ├─ patchright (stealth Chromium)
64
- ├─ Chrome for Testing
65
- └─ SQLite at ~/.iframer — one file for
66
- encrypted credentials, session state,
67
- and per-domain knowledge cache
121
+ Claude / Codex (MCP) ──▶ iframer MCP server ──▶ shared local server (127.0.0.1)
122
+ ├─ patchright (stealth Chromium)
123
+ ├─ Chrome for Testing
124
+ ├─ your real Chrome (optional, via extension)
125
+ └─ SQLite at ~/.iframer: one file for
126
+ encrypted credentials, session state,
127
+ and per-domain knowledge cache
68
128
  ```
69
129
 
70
- By default, `install-mcp` runs in **local mode**: no Docker needed. The MCP spawns a stealth-patched Chromium (via [patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright)) on your machine. `install-mcp` registers the server in both Claude Code (`~/.claude.json`) and Codex (`~/.codex/config.toml`).
130
+ By default, `install mcp` runs in **local mode**, no Docker needed. Both the MCP clients and the `iframer execute` CLI talk to one shared local server (discovered via `~/.iframer/server.json`, loopback only) that keeps a stealth-patched Chromium warm between calls, tracks every browser it spawns in an on-disk PID registry so nothing leaks, and idle-exits when no one needs it. `install mcp` registers the server in both Claude Code (`~/.claude.json`) and Codex (`~/.codex/config.toml`).
71
131
 
72
- **One credential store for every browser mode.** Stored credentials, session cookies/localStorage, and the knowledge cache all live in a single SQLite file at `~/.iframer/iframer.db`. Store a password once (via CLI or MCP) and every mode — `headless`, `binary-headful`, `docker-headful` — uses the same row. No split-brain between modes.
132
+ **Warm CLI.** `iframer execute` routes to that shared daemon instead of launching a cold browser per invocation, so after the first call it's as fast as the MCP (pass `--in-process` to force a private throwaway browser). Each agent gets its own browser instance, keyed off `CLAUDE_CODE_SESSION_ID` / `TERM_SESSION_ID` or `IFRAMER_INSTANCE`, so concurrent agents never share a window, while all CLI calls share one login session.
73
133
 
74
- **Auto-escalation.** When a pipeline is blocked in `headless` (bot detection, captcha), iframer transparently retries in `binary-headful` and then `docker-headful` without a round-trip to the agent. The mode that worked is recorded in `~/.iframer/domain-modes.json` so the next run on that domain starts at the right mode.
134
+ **Resuming a task.** The browser and its page persist in the daemon between calls and survive an interrupt (Ctrl-C). Name a multi-step or human-in-the-loop task's browser with a stable `instanceId`, and to resume, run `execute` again with the same `instanceId` and act on the current page (`snapshot` / `read` / `find`). Don't navigate again; that reloads the page and loses state like an OTP screen. `iframer instances` lists the live windows and which page each is on.
75
135
 
76
- **Knowledge cache.** After every successful run, iframer writes a per-domain markdown file at `~/.iframer/knowledge/<domain>.md` recording which cookies / localStorage keys / headers the site uses for auth, plus any API endpoints observed along the way. Next time the agent needs data from that domain, it reads the cache first — if there's a direct-API path, it skips the browser entirely. See [Knowledge cache](#knowledge-cache) below.
136
+ **One credential store for every browser mode.** Stored credentials, session cookies/localStorage, and the knowledge cache all live in one SQLite file at `~/.iframer/iframer.db`. Store a password once, from the CLI or the MCP, and every mode (`headless`, `binary-headful`, `docker-headful`) uses the same row.
137
+
138
+ **Auto-escalation.** When a pipeline is blocked in `headless` (bot detection, captcha), iframer retries in `binary-headful` and then `docker-headful` without a round trip to the agent. The mode that worked is recorded in `~/.iframer/domain-modes.json`, so the next run on that domain starts at the right mode.
139
+
140
+ **Knowledge cache.** After every successful run, iframer writes a per-domain markdown file at `~/.iframer/knowledge/<domain>.md` recording which cookies, localStorage keys, and headers the site uses for auth, plus any API endpoints seen along the way. The next time an agent needs data from that domain, it reads the cache first; if there's a direct-API path, it skips the browser entirely. See [Knowledge cache](#knowledge-cache) below.
77
141
 
78
142
  For live remote viewing, multi-user, or Linux server deployments, see [Self-hosting with Docker](#self-hosting-with-docker) below.
79
143
 
144
+ ## Extension mode: drive your real Chrome
145
+
146
+ The optional browser extension lets the agent drive a tab you already have open in your real Chrome. No relaunch, no remote-debugging port, your real logged-in session. The extension dials out to iframer's local server and relays the CDP protocol via `chrome.debugger`, so your live tab is driven by the exact same pipeline engine (find, click, snapshot, obstacle handling, API capture) as every other mode, with real trusted input. While a run is active, Chrome shows its yellow "started debugging" bar.
147
+
148
+ There's no Chrome Web Store listing. You load it as an unpacked, developer-mode extension, straight from the files npm just installed on your machine.
149
+
150
+ ### Installing it
151
+
152
+ 1. Run:
153
+ ```sh
154
+ iframer install extension chrome
155
+ ```
156
+ This installs a small pairing host and prints a folder path. That folder is the extension itself.
157
+
158
+ 2. Open `chrome://extensions` in Chrome.
159
+ 3. Turn on **Developer mode**, the toggle is top right.
160
+ 4. Click **Load unpacked**.
161
+ 5. In the file picker, paste the folder path from step 1 and select it.
162
+
163
+ Chrome loads the extension and pins its icon to the toolbar. That's the whole install, one time only.
164
+
165
+ ### Finding the path again
166
+
167
+ Lost the path, or setting up a second machine? Run:
168
+ ```sh
169
+ iframer extension path
170
+ ```
171
+ It prints the same folder every time.
172
+
173
+ That folder lives inside wherever npm put `iframer-toolkit` globally, not inside a git checkout of this repo. On most machines that's something like `/usr/local/lib/node_modules/iframer-toolkit/extension` or, with nvm, a path under `~/.nvm/versions/node/<version>/lib/node_modules/iframer-toolkit/extension`. Run the command above instead of guessing, the exact path depends on your Node setup.
174
+
175
+ Loading it from that exact path matters: it's what lets `iframer update` refresh the extension files in place, then tell Chrome to reload it, no repeating the install steps after every update.
176
+
177
+ ### Pairing (automatic)
178
+
179
+ Once loaded, the extension pairs itself. The pairing host installed in step 1 hands it the same local token the CLI and MCP already use, straight from `~/.iframer/secret`. Nothing to copy, nothing to type.
180
+
181
+ If that ever fails (host not installed, or you're on a platform it doesn't support), click the iframer icon in the toolbar and paste the token yourself:
182
+ ```sh
183
+ cat ~/.iframer/secret
184
+ ```
185
+ then **Save & connect**.
186
+
187
+ Either way, check the popup: the dot next to "iframer" turns green once it finds the running local server.
188
+
189
+ You can repeat this whole install on more than one Chrome profile, or in Brave, Edge, or another Chromium-based browser, at the same time. Each one pairs under its own profile name, and iframer routes each task to whichever profile actually has the tab. Once paired, the agent lists your open tabs with the `tabs` tool and drives the one you mean. See [`extension/README.md`](extension/README.md) for how the pipeline and multi-profile routing work under the hood.
190
+
80
191
  ## CLI reference
81
192
 
82
193
  ```
@@ -88,6 +199,8 @@ Pipeline:
88
199
  --capture-api Record XHR/fetch requests during execution
89
200
  --continue-on-error Don't stop on step failure
90
201
  --timeout <ms> Stale-state timeout (default: 20000)
202
+ --json Print raw PipelineResult JSON (default: compact agent-readable text)
203
+ --in-process Skip the shared warm daemon; run a private in-process browser
91
204
 
92
205
  Quick actions:
93
206
  browse <url> Headless fetch with JS rendering
@@ -102,8 +215,12 @@ Quick actions:
102
215
  --output <dir> Save directory
103
216
  --typed Generate TypeScript
104
217
 
218
+ Browser windows:
219
+ instances List live browser windows (instanceId → current page)
220
+ windows Alias of instances
221
+
105
222
  Session:
106
- session stop Stop and save cookies/localStorage
223
+ session stop Save state + close idle browsers on the shared daemon
107
224
  session clear Wipe stored session data
108
225
  session status Check session state
109
226
 
@@ -124,16 +241,22 @@ Knowledge cache:
124
241
  knowledge get <domain> Same as --cache <domain>
125
242
  knowledge clear [domain] Same as --clear-cache [domain]
126
243
 
244
+ Telemetry:
245
+ telemetry Report estimated session tokens consumed by MCP tool calls
246
+ telemetry --clear Wipe the telemetry log
247
+
127
248
  Setup:
249
+ install Install everything (Chromium + MCP)
128
250
  install chromium Download Chrome for Testing
129
- install mcp Register MCP server in Claude Code and Codex
130
- install deps Run both of the above
131
- install-mcp [--dev] Same as `install mcp`
132
- remove-mcp [--dev] Remove iframer MCP from Claude Code and Codex
251
+ install mcp [--dev] Register MCP server in Claude Code and Codex
252
+ install extension chrome Install the optional browser extension pairing host
253
+ extension path Print the extension folder to load in chrome://extensions
254
+ update [--check] Update iframer via npm (--check: report only)
255
+ remove [chromium|mcp|extension] Remove everything, or one piece
133
256
 
134
257
  Browser:
135
258
  modes Show available browser modes
136
- status Show system status
259
+ status Show system status
137
260
  ```
138
261
 
139
262
  The binary is available as either `iframer-toolkit` (full name) or `iframer` (short alias). `npx iframer-toolkit ...` also works without a global install.
@@ -142,30 +265,33 @@ The binary is available as either `iframer-toolkit` (full name) or `iframer` (sh
142
265
 
143
266
  Once the MCP is registered, the agent has access to:
144
267
 
145
- - **`status`** — system health, session state, stored credentials, available browser modes
146
- - **`knowledge`** — read / list / clear the per-domain knowledge cache. Agents are told to check this **before** every `execute` or `browse` — if the cache has a direct-API path for the data, the browser doesn't launch at all.
147
- - **`execute`** — run a pipeline of browser steps (navigate, click, fill, human-click, human-type, scroll, wait, evaluate, extract, keyboard, login, solve-captcha, screenshot, snapshot, find). Each step has a 20s stale-state timeout. On failure, returns the exact step, error type, and a screenshot of the page at the point of failure. Auto-escalates browser modes transparently on bot-block.
148
- - **`browse`** — fast headless fetch with session persistence for pages that don't need a full pipeline
149
- - **`reverse-engineer`** — capture the APIs a site calls (feeds into the knowledge cache so future runs can skip the browser)
150
- - **`session`** — `stop` (save state) or `clear` (wipe)
151
- - **`credentials`** — `store` (secure form via MCP elicitation), `list`. The `store` action will **refuse to overwrite** existing credentials unless explicitly told to (`force: true`) — this blocks the common "login failed, re-ask for password" anti-pattern when the real problem is browser mode / bot detection.
268
+ - **`status`**: system health, session state, stored credentials, available browser modes
269
+ - **`knowledge`**: read/list/clear the per-domain knowledge cache. Agents are told to check this before every `execute` or `browse`; if the cache already has a direct-API path, the browser never launches.
270
+ - **`execute`**: run a pipeline of browser steps (navigate, click, right-click, fill, select, human-click, human-type, type-code, read, evaluate, extract, wait, wait-for, scroll, keyboard, upload, paste, download, login, solve-captcha, recaptcha, screenshot, snapshot, find). Each step has a 20s stale-state timeout. On failure, it returns the exact step, error type, and a screenshot of the page at the point of failure. Auto-escalates browser modes on bot-block.
271
+ - **`browse`**: fast headless fetch with session persistence for pages that don't need a full pipeline
272
+ - **`reverse-engineer`**: capture the APIs a site calls (feeds the knowledge cache so future runs can skip the browser)
273
+ - **`remember`**: per-domain element anchors. Save a selector once under a name, then target it as `@a:<name>` in any later pipeline, no re-finding the element on every visit. Anchors self-heal (a failed anchor triggers re-discovery, not blind retries) and the tool also records per-site quirks.
274
+ - **`tabs`**: list and target tabs in your real Chrome (requires the [extension](#extension-mode-drive-your-real-chrome))
275
+ - **`clipboard`**: read/write the machine's clipboard, the same one your Chrome uses: read a code a site just copied, or stage text to paste into a field via the `paste` step
276
+ - **`session`**: `stop` (save state) or `clear` (wipe)
277
+ - **`credentials`**: `store` (secure form via MCP elicitation), `list`. `store` refuses to overwrite existing credentials unless told to (`force: true`), which blocks the common "login failed, re-ask for password" mistake when the real problem is browser mode or bot detection.
152
278
 
153
279
  ## Session persistence
154
280
 
155
- Session data (cookies + localStorage) and credentials are stored in SQLite at `~/.iframer/iframer.db` and encrypted with AES-256-GCM. Data is automatically re-injected on the next `execute` or `browse` so agents stay logged in across restarts — and across browser modes: a session captured in `binary-headful` will transparently load into `headless` on the next run.
281
+ Session data (cookies + localStorage) and credentials are stored in SQLite at `~/.iframer/iframer.db` and encrypted with AES-256-GCM. Data is automatically re-injected on the next `execute` or `browse` so agents stay logged in across restarts, and across browser modes: a session captured in `binary-headful` will load into `headless` on the next run.
156
282
 
157
- The encryption key lives at `~/.iframer/secret` (0600 permissions), generated on first `install-mcp`. Set `IFRAMER_SECRET` in your environment to override it — useful if you want to synchronize the key across multiple machines.
283
+ The encryption key lives at `~/.iframer/secret` (0600 permissions), generated on first `install mcp`. Set `IFRAMER_SECRET` in your environment to override it, useful if you want to sync the key across machines.
158
284
 
159
285
  ## Knowledge cache
160
286
 
161
- Every successful `execute` run updates a plain markdown file at `~/.iframer/knowledge/<domain>.md` — human-readable, grep-able, and editable. Each file captures:
287
+ Every successful `execute` run updates a plain markdown file at `~/.iframer/knowledge/<domain>.md`, human-readable, grep-able, editable. Each file captures:
162
288
 
163
- - Which cookies, localStorage keys, and headers are load-bearing for authentication (names only — values stay encrypted in the session store)
164
- - Which API endpoints the site called during the run (with method, path, example curl, and status code)
289
+ - Which cookies, localStorage keys, and headers are load-bearing for authentication (names only; values stay encrypted in the session store)
290
+ - Which API endpoints the site called during the run, with method, path, example curl, and status code
165
291
  - Which browser mode last worked for the domain
166
- - Notes about captcha/bot-detection behavior
292
+ - Notes about captcha or bot-detection behavior
167
293
 
168
- The MCP `knowledge` tool exposes this to the agent with `get`, `list`, and `clear` actions. Agents are instructed to call it **before** every browser-touching tool — if the cache already knows a direct-API path for the data the user is asking about, the agent hits the API directly and never launches a browser. First request takes seconds; repeat requests on the same domain take milliseconds.
294
+ The MCP `knowledge` tool exposes this with `get`, `list`, and `clear` actions. Agents are instructed to call it before every browser-touching tool; if the cache already has a direct-API path for the data, the agent hits the API directly and never launches a browser. First request takes seconds, repeat requests on the same domain take milliseconds.
169
295
 
170
296
  Inspect the cache yourself:
171
297
 
@@ -178,7 +304,7 @@ iframer-toolkit --clear-cache figma.com # wipe one domain
178
304
 
179
305
  ## Captcha solving
180
306
 
181
- iframer auto-detects and solves reCAPTCHA and hCaptcha using Claude's vision API. Use the `solve-captcha` step in a pipeline:
307
+ iframer detects and solves reCAPTCHA and hCaptcha using Claude's vision API. Use the `solve-captcha` step in a pipeline:
182
308
 
183
309
  ```json
184
310
  { "type": "solve-captcha" }
@@ -191,16 +317,18 @@ Requires `ANTHROPIC_API_KEY` in your environment.
191
317
  | Variable | Required | Description |
192
318
  |---------------------|----------|-------------|
193
319
  | `ANTHROPIC_API_KEY` | For captcha | Used for vision-based captcha solving |
194
- | `IFRAMER_SECRET` | No | Encryption key for sessions & credentials. Defaults to the value at `~/.iframer/secret` (auto-generated on first `install-mcp`). Override in the shell or in `.env` to pin a specific key. |
320
+ | `IFRAMER_SECRET` | No | Encryption key for sessions & credentials. Defaults to the value at `~/.iframer/secret` (auto-generated on first `install mcp`). Override in the shell or in `.env` to pin a specific key. |
321
+ | `IFRAMER_TELEMETRY` | No | Set to `0` in the MCP env to disable the local token-telemetry log (`iframer telemetry` reads it). |
322
+ | `IFRAMER_LOCAL_PORT`| No | Base port for the shared local server (default: `3022`, loopback only). |
195
323
  | `IFRAMER_DATA_DIR` | No | Override the data directory. Default: `~/.iframer`. The Docker container sets this to `/iframer-data` so a bind mount makes host and container share one database. |
196
324
  | `IFRAMER_MODE` | No | `local` (default) or `docker`. Force a mode regardless of what's running. |
197
325
  | `IFRAMER_URL` | No | Docker API URL when self-hosting (default: `http://localhost:3021`). |
198
326
 
199
327
  ## Self-hosting with Docker
200
328
 
201
- The Docker server adds a live headful browsing mode over noVNC (watch the agent drive the browser in real time) and lets multiple clients share one browser pool. The Docker path is only used when the pipeline explicitly requests `mode: "docker-headful"` — `headless` and `binary-headful` always run directly on the host even when Docker is up, so host-stored credentials are always visible.
329
+ The Docker server adds a live headful browsing mode over noVNC (watch the agent drive the browser in real time) and lets multiple clients share one browser pool. The Docker path only runs when a pipeline explicitly requests `mode: "docker-headful"`; `headless` and `binary-headful` always run directly on the host even when Docker is up, so host-stored credentials stay visible.
202
330
 
203
- The `docker-compose.yml` bind-mounts `~/.iframer` from the host into the container as `/iframer-data` and sets `IFRAMER_DATA_DIR=/iframer-data`, so **container and host share the same SQLite file**. Credentials stored via the CLI or MCP on the host are immediately visible to `docker-headful` without any copy step.
331
+ `docker-compose.yml` bind-mounts `~/.iframer` from the host into the container as `/iframer-data` and sets `IFRAMER_DATA_DIR=/iframer-data`, so container and host share the same SQLite file. Credentials stored via the CLI or MCP on the host are immediately visible to `docker-headful`, no copy step.
204
332
 
205
333
  **1. Clone and configure**
206
334
 
@@ -208,7 +336,7 @@ The `docker-compose.yml` bind-mounts `~/.iframer` from the host into the contain
208
336
  git clone https://github.com/EduardoFazolo/iframer-toolkit.git
209
337
  cd iframer-toolkit
210
338
  cp .env.example .env
211
- # Edit .env — set ANTHROPIC_API_KEY (for captcha) and IFRAMER_SECRET (for auth)
339
+ # Edit .env: set ANTHROPIC_API_KEY (for captcha) and IFRAMER_SECRET (for auth)
212
340
  ```
213
341
 
214
342
  **2. Start**
@@ -221,13 +349,13 @@ bun run stop:docker # stop containers
221
349
 
222
350
  **3. Point the MCP at it (remote host only)**
223
351
 
224
- If you're running Docker on a remote machine and the MCP on a different machine, install the MCP with the remote URL:
352
+ If Docker runs on a remote machine and the MCP on a different one, install the MCP with the remote URL:
225
353
 
226
354
  ```sh
227
- IFRAMER_URL=https://your-host:3021 iframer-toolkit install-mcp --dev
355
+ IFRAMER_URL=https://your-host:3021 iframer-toolkit install mcp --dev
228
356
  ```
229
357
 
230
- When Docker is on the same host as the MCP, no extra setup is needed — the local MCP server will auto-detect the Docker API on `localhost:3021` and route only `docker-headful` requests through it.
358
+ When Docker is on the same host as the MCP, no extra setup is needed; the local MCP server auto-detects the Docker API on `localhost:3021` and routes only `docker-headful` requests through it.
231
359
 
232
360
  **4. Watch the browser live**
233
361
 
@@ -245,15 +373,36 @@ Or run `iframer-toolkit watch` to auto-open it.
245
373
  |--------------------|------------|
246
374
  | Browser engine | [patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright) (stealth-patched Playwright fork) |
247
375
  | Browser binary | Chrome for Testing (downloaded to `~/.iframer/chrome/`) |
376
+ | Local server | One shared warm server per machine (loopback only, discovered via `~/.iframer/server.json`), on-disk browser PID registry, idle auto-exit |
377
+ | Extension mode | Chrome extension relaying CDP over WebSocket (`chrome.debugger` → `connectOverCDP`), drives tabs in your real Chrome |
248
378
  | Stealth | Fingerprint injection, WebRTC leak prevention, worker patching |
249
379
  | Credential store | SQLite at `~/.iframer/iframer.db`, AES-256-GCM encrypted, shared by every browser mode |
250
- | Session persistence| Same SQLite file — cookies + localStorage re-injected across runs and modes |
380
+ | Session persistence| Same SQLite file, cookies + localStorage re-injected across runs and modes |
251
381
  | Knowledge cache | Plain markdown at `~/.iframer/knowledge/<domain>.md` |
252
382
  | Captcha solving | Anthropic vision API (`@anthropic-ai/sdk`) |
253
383
  | Live viewing | Xvfb + x11vnc + noVNC + websockify (Docker mode only) |
254
384
  | MCP server | `@modelcontextprotocol/sdk` |
255
385
  | Runtime | Node.js ≥18 (Bun for development) |
256
386
 
387
+ ## Repo layout
388
+
389
+ ```
390
+ src/lib/ core: pipeline executor, actions, auth, screenshot, knowledge cache
391
+ src/mcp/ MCP server + tool definitions
392
+ bin/cli.js CLI entry point
393
+ extension/ Chrome extension (manifest v3, CDP relay)
394
+ docs/example/ the demo in this README: site/ + captured api/
395
+ benchmark/ token-cost benchmark harness vs agent-browser and Playwright MCP (gitignored, local only)
396
+ ```
397
+
398
+ ## What's not done yet
399
+
400
+ - Stealth fingerprinting is injected right after the page loads, not at browser-context creation, so a site checking for it in the first tick of navigation can still catch it. This is the main remaining cause of false bot-blocks.
401
+ - The knowledge cache's markdown merge can drop an endpoint's description or example fields when the same domain is captured a second time.
402
+ - Consent banners rendered inside a cross-origin iframe (common with some CMPs) aren't recognized as an obstacle yet.
403
+ - Element anchors (`remember`) still have to be saved by hand after a successful run; auto-saving the selectors that worked isn't wired up.
404
+ - A few internal modules (the SQLite adapter, the stealth/humanize helpers) still carry loose `any` types.
405
+
257
406
  ## Development
258
407
 
259
408
  ```sh
@@ -261,7 +410,7 @@ git clone https://github.com/EduardoFazolo/iframer-toolkit.git
261
410
  cd iframer-toolkit
262
411
  bun install
263
412
 
264
- # Run the CLI from source (no build needed — bun runs .ts directly)
413
+ # Run the CLI from source (no build needed, bun runs .ts directly)
265
414
  bun run bin/cli.js status
266
415
 
267
416
  # Run the MCP server from source