iframer-toolkit 0.10.8 → 0.11.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/README.md CHANGED
@@ -84,6 +84,7 @@ To update later:
84
84
  ```sh
85
85
  iframer-toolkit update # update via npm (also refreshes the extension if installed)
86
86
  iframer-toolkit update --check # just report whether a newer version exists
87
+ iframer-toolkit --version # print the installed version
87
88
  ```
88
89
 
89
90
  Your agent can also just run `iframer-toolkit install` for you; it figures out the rest.
@@ -92,7 +93,6 @@ Ships as:
92
93
  - **CLI** (`iframer-toolkit` / `iframer`): browse, screenshot, credentials, sessions, reverse-engineer APIs
93
94
  - **MCP server**: plugs into Claude Code or Codex so agents drive the browser themselves
94
95
  - **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
96
96
 
97
97
  ## Quick start
98
98
 
@@ -127,20 +127,18 @@ Claude / Codex (MCP) ──▶ iframer MCP server ──▶ shared local server
127
127
  and per-domain knowledge cache
128
128
  ```
129
129
 
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`).
130
+ Everything runs on your machine. 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`).
131
131
 
132
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.
133
133
 
134
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.
135
135
 
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.
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`) uses the same row.
137
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.
138
+ **Auto-escalation.** When a pipeline is blocked in `headless` (bot detection, captcha), iframer retries in `binary-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
139
 
140
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.
141
141
 
142
- For live remote viewing, multi-user, or Linux server deployments, see [Self-hosting with Docker](#self-hosting-with-docker) below.
143
-
144
142
  ## Extension mode: drive your real Chrome
145
143
 
146
144
  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.
@@ -176,15 +174,15 @@ Loading it from that exact path matters: it's what lets `iframer update` refresh
176
174
 
177
175
  ### Pairing (automatic)
178
176
 
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.
177
+ Once loaded, the extension pairs itself on macOS, Linux and Windows. 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. The install command also tests the host and starts the local server, and it tells you if either one fails.
180
178
 
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:
179
+ If auto-pairing ever fails, click the iframer icon in the toolbar and paste the output of this command, in any terminal:
182
180
  ```sh
183
- cat ~/.iframer/secret
181
+ iframer extension token
184
182
  ```
185
183
  then **Save & connect**.
186
184
 
187
- Either way, check the popup: the dot next to "iframer" turns green once it finds the running local server.
185
+ Either way, check the popup: the dot next to "iframer" turns green only once the running server has accepted the token. If it can't connect, the popup says why and keeps retrying.
188
186
 
189
187
  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
188
 
@@ -195,7 +193,7 @@ iframer-toolkit <command> [args]
195
193
 
196
194
  Pipeline:
197
195
  execute <pipeline.json|json> Run a pipeline of browser steps
198
- --mode <mode> Force browser mode (headless|binary-headful|docker-headful)
196
+ --mode <mode> Force browser mode (headless|binary-headful)
199
197
  --capture-api Record XHR/fetch requests during execution
200
198
  --continue-on-error Don't stop on step failure
201
199
  --timeout <ms> Stale-state timeout (default: 20000)
@@ -209,11 +207,28 @@ Quick actions:
209
207
  --wait-for <selector> Wait for element before extracting
210
208
  --sessionless Skip session persistence
211
209
  screenshot <url> Take a screenshot of a URL
210
+ --mode <mode> Browser mode (default: headless)
212
211
  --annotate Overlay element badges with refs
213
- -o, --output <path> Output file path
214
212
  reverse-engineer <url|file> Capture API calls a site makes
215
213
  --output <dir> Save directory
216
214
  --typed Generate TypeScript
215
+ --mode <mode> Browser mode
216
+
217
+ Capture in a browser iframer doesn't control (T3 Code, Playwright MCP, ...):
218
+ kit Write the in-page kit, print the agent's tool calls
219
+ --for <t3|playwright-mcp|any> Which browser tool's steps to print (default: t3)
220
+ --mode passive No patching: URLs + form posts only
221
+ --host-filter <regex> Only record matching hosts (e.g. 'discord\.com$')
222
+ --client <path> Also print steps to load a generated client.js
223
+ --print Print the kit source instead (tools without upload)
224
+ ingest <file|-|--latest> Capture -> api.json + client.js + knowledge cache
225
+ --latest Newest capture in T3 Code's downloads or ~/Downloads
226
+ --typed Also write client.d.ts
227
+ --out <dir> Output directory (default: ./<host>-api/)
228
+ --keep Keep the capture file (default: deleted)
229
+ --no-knowledge Don't update ~/.iframer/knowledge
230
+ --strict Refuse on any secret-looking value instead of replacing it
231
+ --json One-line JSON summary
217
232
 
218
233
  Browser windows:
219
234
  instances List live browser windows (instanceId → current page)
@@ -251,6 +266,7 @@ Setup:
251
266
  install mcp [--dev] Register MCP server in Claude Code and Codex
252
267
  install extension chrome Install the optional browser extension pairing host
253
268
  extension path Print the extension folder to load in chrome://extensions
269
+ extension token Print the pairing token (only needed to pair by hand)
254
270
  update [--check] Update iframer via npm (--check: report only)
255
271
  remove [chromium|mcp|extension] Remove everything, or one piece
256
272
 
@@ -267,15 +283,26 @@ Once the MCP is registered, the agent has access to:
267
283
 
268
284
  - **`status`**: system health, session state, stored credentials, available browser modes
269
285
  - **`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.
286
+ - **`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, and `click` fails at 8s with Playwright's own reason (not visible, covered by another element). 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. See [Pipeline guardrails](#pipeline-guardrails).
271
287
  - **`browse`**: fast headless fetch with session persistence for pages that don't need a full pipeline
272
288
  - **`reverse-engineer`**: capture the APIs a site calls (feeds the knowledge cache so future runs can skip the browser)
273
289
  - **`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
290
  - **`tabs`**: list and target tabs in your real Chrome (requires the [extension](#extension-mode-drive-your-real-chrome))
275
291
  - **`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)
292
+ - **`session`**: `stop` (save state, close the browser), `clear` (wipe stored session data), `restart` (kill browsers and reset after a freeze or crash; credentials and knowledge are kept), `capture-start` / `capture-stop` (record XHR/fetch outside a pipeline), `get-cookies` (all cookies, including HttpOnly), `get-auth` (cookies, localStorage and sessionStorage together)
277
293
  - **`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.
278
294
 
295
+ ## Pipeline guardrails
296
+
297
+ Some calls are refused or cut short on purpose, so an agent gets a clear error instead of a hang, a stray window, or a tripped bot trap.
298
+
299
+ - **Honeypots.** `snapshot` leaves out fields no human can reach (pushed offscreen, clipped, or made transparent by an ancestor) and marks bait-looking ones (`website`, `fax`, `tabindex=-1`) as `[honeypot?]`. `fill` refuses an unreachable field with an explanatory error; pass `force: true` only when you're certain the field is real.
300
+ - **Selectors.** Use an `@e` ref from `snapshot`/`find`, an `@a:` anchor, or plain CSS. Playwright-only syntax (`text=`, `:has-text()`, `:text-is()`, `>>`) is rejected with a hint to `find` the element instead.
301
+ - **Frozen tabs.** Every page probe has a time budget, so a tab whose JS stops answering fails in about 30s. In extension mode, the watchdog names the step that hung and keeps the results of the steps that finished.
302
+ - **Stuck navigation.** If a page never commits to the new URL, `navigate` falls back to `location.assign`. `beforeunload` prompts are accepted.
303
+ - **No stray windows.** A pipeline with no `navigate` step and no live browser to reattach to is refused, as is `mode: "extension"` without a `tabId`. While the extension is connected, `session` `capture-start`, `capture-stop`, `get-cookies` and `get-auth` also refuse to open a new window unless you pass a `mode` or a matching browser is already open.
304
+ - **Keyboard in extension mode.** Cmd/Ctrl+A selects all in every mode. Other Cmd/Ctrl shortcuts are refused in extension mode.
305
+
279
306
  ## Session persistence
280
307
 
281
308
  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.
@@ -302,70 +329,47 @@ iframer-toolkit --clear-cache # wipe all cached knowledge
302
329
  iframer-toolkit --clear-cache figma.com # wipe one domain
303
330
  ```
304
331
 
332
+ ## Bring your own browser: T3 Code and other agent browsers
333
+
334
+ If your agent already has a browser (a T3 Code preview tab, Playwright MCP, Chrome DevTools MCP), iframer can reverse engineer the site inside it, on the session you're already logged into, without launching anything.
335
+
336
+ ```bash
337
+ iframer kit --for t3 # writes ~/.iframer/kit/iframer-kit.js, prints the agent's tool calls
338
+ # agent: upload the kit into the tab, eval it, use the site, then window.__ifk.dump()
339
+ iframer ingest --latest --typed # finds the capture in T3's downloads -> ./<host>-api/
340
+ ```
341
+
342
+ - **Small for the agent:** the kit and the capture move as files, so neither lands in the agent's context. On the 40-endpoint test site, the whole install-capture-export round was about 550 tokens of tool calls.
343
+ - **Shapes, not values:** paths are templated (`/users/{id}`), bodies and responses become type shapes, headers become names. `ingest` then swaps anything left that looks like a token, email or phone number for a placeholder, keeps the endpoint, and marks it with `privateValues`. `--strict` refuses the capture instead.
344
+ - **Identity, without the values:** the kit learns which auth headers the page sends and where it keeps each value (a localStorage key, a field inside it, a cookie, or page memory). api.json records that under `identity`, and `__ifk.call` rebuilds the headers from there for every replay, so the generated client acts as the logged-in user.
345
+ - **Output:** `api.json` (endpoint map with coverage), `client.js` (in-page client over `window.__ifk.call`), `client.d.ts` with `--typed`, and the domain's knowledge file.
346
+ - **Replay stays in the page:** HttpOnly cookies are invisible to page JS, so generated calls run through the tab. Same-origin only, GET unless approved, 50 calls per session, and a hard stop on 403, 429 or a captcha page.
347
+ - **Not complete:** worker requests, redirect hops, cross-origin iframes and Set-Cookie are invisible to the kit, and every report says so.
348
+ - **Survives the page:** after a full page load the agent re-runs one short `eval` and the capture continues. Works on sites that delete `window.sessionStorage` (Discord).
349
+ - **Other tools:** `--for playwright-mcp` or `--for any`. Tools without file upload can evaluate `iframer kit --print` instead, which costs about 17 KB per page load.
350
+
305
351
  ## Captcha solving
306
352
 
307
- iframer detects and solves reCAPTCHA and hCaptcha using Claude's vision API. Use the `solve-captcha` step in a pipeline:
353
+ iframer can try to solve reCAPTCHA and hCaptcha with Claude's vision API, in any browser mode. Treat it as best effort: it fails on many challenges, and when someone is at the screen it's more reliable to have them solve it in a `binary-headful` window. To try it, use the `solve-captcha` step in a pipeline:
308
354
 
309
355
  ```json
310
356
  { "type": "solve-captcha" }
311
357
  ```
312
358
 
313
- Requires `ANTHROPIC_API_KEY` in your environment.
359
+ Requires `ANTHROPIC_API_KEY` in the environment that starts the iframer server: your shell for the CLI, or the `env` block of your MCP config. If the server is already running, stop it first so it picks up the key. With a key set, `navigate` also tries automatically when it lands on a captcha, and each attempt uses API credit.
360
+
361
+ If it can't solve the captcha, the run fails with `captcha-unsolvable` and the reason.
314
362
 
315
363
  ## Environment variables
316
364
 
317
365
  | Variable | Required | Description |
318
366
  |---------------------|----------|-------------|
319
367
  | `ANTHROPIC_API_KEY` | For captcha | Used for vision-based captcha solving |
368
+ | `IFRAMER_CAPTCHA_MODEL` | No | Claude model the solver uses (default: `claude-haiku-4-5-20251001`). |
320
369
  | `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
370
  | `IFRAMER_TELEMETRY` | No | Set to `0` in the MCP env to disable the local token-telemetry log (`iframer telemetry` reads it). |
322
371
  | `IFRAMER_LOCAL_PORT`| No | Base port for the shared local server (default: `3022`, loopback only). |
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. |
324
- | `IFRAMER_MODE` | No | `local` (default) or `docker`. Force a mode regardless of what's running. |
325
- | `IFRAMER_URL` | No | Docker API URL when self-hosting (default: `http://localhost:3021`). |
326
-
327
- ## Self-hosting with Docker
328
-
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.
330
-
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.
332
-
333
- **1. Clone and configure**
334
-
335
- ```sh
336
- git clone https://github.com/EduardoFazolo/iframer-toolkit.git
337
- cd iframer-toolkit
338
- cp .env.example .env
339
- # Edit .env: set ANTHROPIC_API_KEY (for captcha) and IFRAMER_SECRET (for auth)
340
- ```
341
-
342
- **2. Start**
343
-
344
- ```sh
345
- bun run start:docker # docker compose up --build -d
346
- bun run logs:docker # tail container logs
347
- bun run stop:docker # stop containers
348
- ```
349
-
350
- **3. Point the MCP at it (remote host only)**
351
-
352
- If Docker runs on a remote machine and the MCP on a different one, install the MCP with the remote URL:
353
-
354
- ```sh
355
- IFRAMER_URL=https://your-host:3021 iframer-toolkit install mcp --dev
356
- ```
357
-
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.
359
-
360
- **4. Watch the browser live**
361
-
362
- When a `docker-headful` session is active, open noVNC:
363
-
364
- ```
365
- http://your-host:6080
366
- ```
367
-
368
- Or run `iframer-toolkit watch` to auto-open it.
372
+ | `IFRAMER_DATA_DIR` | No | Override the data directory. Default: `~/.iframer`. |
369
373
 
370
374
  ## Architecture
371
375
 
@@ -380,7 +384,6 @@ Or run `iframer-toolkit watch` to auto-open it.
380
384
  | Session persistence| Same SQLite file, cookies + localStorage re-injected across runs and modes |
381
385
  | Knowledge cache | Plain markdown at `~/.iframer/knowledge/<domain>.md` |
382
386
  | Captcha solving | Anthropic vision API (`@anthropic-ai/sdk`) |
383
- | Live viewing | Xvfb + x11vnc + noVNC + websockify (Docker mode only) |
384
387
  | MCP server | `@modelcontextprotocol/sdk` |
385
388
  | Runtime | Node.js ≥18 (Bun for development) |
386
389
 
@@ -416,10 +419,10 @@ bun run bin/cli.js status
416
419
  # Run the MCP server from source
417
420
  bun run src/mcp/server.ts
418
421
 
419
- # Run the Docker API server from source (no Docker)
422
+ # Run the local server from source
420
423
  bun run start # bun run index.ts
421
424
 
422
- # Rebuild the distributable bundles (dist/cli.cjs + dist/mcp-server.cjs)
425
+ # Rebuild the distributable bundles (dist/cli.js, dist/mcp-server.cjs, dist/local-server.cjs)
423
426
  bun run build
424
427
 
425
428
  # Install the locally-built package globally for testing