iframer-toolkit 0.7.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 +21 -0
- package/README.md +280 -0
- package/dist/cli.js +6175 -0
- package/dist/mcp-server.cjs +1498 -0
- package/package.json +70 -0
- package/skills/iframer.md +340 -0
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iframer-toolkit",
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "Browser access toolkit for AI agents — CLI and MCP server for headless/headful browsing, login flows, and pipeline execution.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"iframer",
|
|
7
|
+
"browser",
|
|
8
|
+
"automation",
|
|
9
|
+
"playwright",
|
|
10
|
+
"patchright",
|
|
11
|
+
"mcp",
|
|
12
|
+
"ai-agents",
|
|
13
|
+
"cli",
|
|
14
|
+
"scraping"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/EduardoFazolo/iframer-toolkit#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/EduardoFazolo/iframer-toolkit/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/EduardoFazolo/iframer-toolkit.git"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "Eduardo Verona",
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/",
|
|
31
|
+
"skills/",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"bin": {
|
|
36
|
+
"iframer": "dist/cli.js",
|
|
37
|
+
"iframer-toolkit": "dist/cli.js"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"start": "bun run index.ts",
|
|
41
|
+
"start:docker": "docker compose up --build -d",
|
|
42
|
+
"stop:docker": "docker compose down",
|
|
43
|
+
"logs:docker": "docker compose logs -f api",
|
|
44
|
+
"test:smoke": "node tests/smoke.js",
|
|
45
|
+
"test:login": "node tests/login-flows.js",
|
|
46
|
+
"test:crypto": "node tests/crypto.test.js",
|
|
47
|
+
"mcp:install": "node bin/cli.js install-mcp",
|
|
48
|
+
"mcp:remove": "node bin/cli.js remove-mcp",
|
|
49
|
+
"build:cli": "bun build bin/cli.js --target node --format cjs --outfile dist/cli.js --external better-sqlite3 --external patchright --external fingerprint-generator --external @anthropic-ai/sdk --external @modelcontextprotocol/sdk --external zod",
|
|
50
|
+
"build:mcp": "bun build src/mcp/server.ts --target node --format cjs --outfile dist/mcp-server.cjs --external better-sqlite3 --external patchright --external fingerprint-generator --external @anthropic-ai/sdk --external @modelcontextprotocol/sdk --external zod",
|
|
51
|
+
"build": "bun run build:cli && bun run build:mcp",
|
|
52
|
+
"prepublishOnly": "bun run build"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@anthropic-ai/sdk": "^0.80.0",
|
|
56
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
57
|
+
"better-sqlite3": "^12.8.0",
|
|
58
|
+
"fingerprint-generator": "^2.1.81",
|
|
59
|
+
"patchright": "^1.58.2",
|
|
60
|
+
"zod": "^4.3.6"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
64
|
+
"@types/express": "^5.0.6",
|
|
65
|
+
"@types/node": "^25.5.0",
|
|
66
|
+
"bun-types": "^1.3.11",
|
|
67
|
+
"express": "^4.18.2",
|
|
68
|
+
"typescript": "^6.0.2"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Use iframer to browse websites, login, take screenshots, reverse-engineer APIs, and manage browser sessions. Invoke with /iframer followed by what you want to do."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
You are an expert at using the iframer browser automation toolkit. The user wants you to do something with iframer. Parse their request and execute the right MCP tool calls with correctly-built pipelines.
|
|
6
|
+
|
|
7
|
+
## Available MCP tools
|
|
8
|
+
|
|
9
|
+
- `iframer.knowledge` — check cached domain knowledge (auth, endpoints, mode info)
|
|
10
|
+
- `iframer.credentials` — list or store login credentials (NEVER re-store as recovery)
|
|
11
|
+
- `iframer.execute` — run a browser pipeline (navigate, login, screenshot, snapshot, etc.)
|
|
12
|
+
- `iframer.browse` — fast headless page fetch (no pipeline needed)
|
|
13
|
+
- `iframer.session` — stop (save state) or clear session data
|
|
14
|
+
- `iframer.status` — system health, modes, stored credentials
|
|
15
|
+
- `iframer.reverse-engineer` — capture API calls a site makes
|
|
16
|
+
|
|
17
|
+
## Core rules
|
|
18
|
+
|
|
19
|
+
1. **ALWAYS check `knowledge get <domain>` before launching any browser.** If the cache has a direct-API path, use that instead — skip the browser entirely.
|
|
20
|
+
2. **NEVER guess CSS selectors.** Use `snapshot` to see what's on the page, then use `@e` refs from the snapshot for click/fill/etc.
|
|
21
|
+
3. **NEVER re-store credentials when login fails.** If credentials exist in `credentials list`, they are valid. Login failures are browser-mode or bot-detection problems, not credential problems. Retry with a stronger mode.
|
|
22
|
+
4. **NEVER pass explicit selectors to the login step** unless the auto-detect failed AND you took a snapshot to find the right ones. The login step auto-detects email, password, submit, and OTP fields.
|
|
23
|
+
5. **Let iframer handle mode escalation.** Don't hardcode modes. If you must pick one, prefer no mode (auto-select) or `binary-headful` for sites known to block headless.
|
|
24
|
+
|
|
25
|
+
## How to build pipelines
|
|
26
|
+
|
|
27
|
+
The `execute` tool takes a `steps` array. Each step is an object with a `type` field. Build the minimum pipeline for the task.
|
|
28
|
+
|
|
29
|
+
### Step types
|
|
30
|
+
|
|
31
|
+
| Type | Fields | Description |
|
|
32
|
+
|------|--------|-------------|
|
|
33
|
+
| `navigate` | `url`, `waitUntil?` | Go to URL |
|
|
34
|
+
| `login` | `domain` | Auto-detect form, fill stored credentials, handle 2FA. Handles email-first flows (Slack, Microsoft, Google) and standard email+password flows. |
|
|
35
|
+
| `snapshot` | — | Get interactive elements as structured list with @e refs. **Do this BEFORE interacting.** |
|
|
36
|
+
| `find` | `role?`, `name?`, `text?`, `placeholder?`, `label?` | Find a specific element, returns a ref |
|
|
37
|
+
| `screenshot` | `annotate?` | Take a screenshot. `annotate: true` overlays numbered badges. |
|
|
38
|
+
| `click` | `selector` | Click element (use @e refs from snapshot) |
|
|
39
|
+
| `fill` | `selector`, `value` | Fill input (use @e refs) |
|
|
40
|
+
| `human-click` | `selector` or `x`, `y` | Human-like click with random offset |
|
|
41
|
+
| `human-type` | `selector`, `value` | Human-like typing with variable delays |
|
|
42
|
+
| `scroll` | `deltaY?` | Scroll the page |
|
|
43
|
+
| `wait` | `ms` | Wait N milliseconds |
|
|
44
|
+
| `wait-for` | `selector`, `timeout?` | Wait for element to appear |
|
|
45
|
+
| `evaluate` | `expression` | Run JS, return result |
|
|
46
|
+
| `extract` | `expression` | Run JS, include result in response |
|
|
47
|
+
| `keyboard` | `key` | Press a key (Enter, Escape, Tab, etc.) |
|
|
48
|
+
| `solve-captcha` | — | Auto-detect and solve reCAPTCHA or hCaptcha |
|
|
49
|
+
|
|
50
|
+
### Pipeline options
|
|
51
|
+
|
|
52
|
+
| Option | Default | Description |
|
|
53
|
+
|--------|---------|-------------|
|
|
54
|
+
| `mode` | auto | `headless`, `binary-headful`, `docker-headful`. Omit for auto-select + auto-escalation. |
|
|
55
|
+
| `captureApi` | false | Record all XHR/fetch requests. Use for reverse-engineering. |
|
|
56
|
+
| `staleTimeoutMs` | 20000 | Per-step stale-state timeout |
|
|
57
|
+
| `continueOnError` | false | Don't abort pipeline on step failure |
|
|
58
|
+
| `screenshotAfterEach` | false | Screenshot after every step (expensive) |
|
|
59
|
+
|
|
60
|
+
## Workflows by task
|
|
61
|
+
|
|
62
|
+
### Login to a site
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
1. knowledge get <domain>
|
|
66
|
+
2. credentials list → if domain missing → credentials store <domain>
|
|
67
|
+
3. execute:
|
|
68
|
+
steps: [
|
|
69
|
+
{ type: "navigate", url: "https://<site>/login" },
|
|
70
|
+
{ type: "login", domain: "<domain>" }
|
|
71
|
+
]
|
|
72
|
+
// No mode needed — auto-escalation handles bot detection.
|
|
73
|
+
// login step handles: email+password, email-first (Slack/Google/Microsoft),
|
|
74
|
+
// TOTP from stored secret, OTP elicitation from user for email/SMS codes.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If the login step returns `emailSubmitted: true` but `loggedIn: false`, the site uses a magic-code flow. Tell the user to check their email and provide the code — then continue with:
|
|
78
|
+
```
|
|
79
|
+
steps: [
|
|
80
|
+
{ type: "fill", selector: "<code-input-ref>", value: "<code>" },
|
|
81
|
+
{ type: "click", selector: "<submit-ref>" }
|
|
82
|
+
]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Take a screenshot
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
execute:
|
|
89
|
+
steps: [
|
|
90
|
+
{ type: "navigate", url: "<url>" },
|
|
91
|
+
{ type: "screenshot" }
|
|
92
|
+
]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Add `annotate: true` to the screenshot step to get numbered element badges with @e refs.
|
|
96
|
+
|
|
97
|
+
### Extract data from a page
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
execute:
|
|
101
|
+
steps: [
|
|
102
|
+
{ type: "navigate", url: "<url>" },
|
|
103
|
+
{ type: "extract", expression: "document.querySelector('.price').textContent" }
|
|
104
|
+
]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Or for simpler cases, use `browse` directly:
|
|
108
|
+
```
|
|
109
|
+
browse: { url: "<url>", extract: "document.title" }
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Interact with a page (click, fill, etc.)
|
|
113
|
+
|
|
114
|
+
ALWAYS snapshot first to get refs:
|
|
115
|
+
```
|
|
116
|
+
execute:
|
|
117
|
+
steps: [
|
|
118
|
+
{ type: "navigate", url: "<url>" },
|
|
119
|
+
{ type: "snapshot" },
|
|
120
|
+
// read the snapshot output → find the ref you need
|
|
121
|
+
{ type: "click", selector: "@e5" },
|
|
122
|
+
{ type: "wait", ms: 2000 },
|
|
123
|
+
{ type: "screenshot" }
|
|
124
|
+
]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Split into two execute calls** if you need to read snapshot output before deciding what to click:
|
|
128
|
+
```
|
|
129
|
+
// Call 1: navigate + snapshot
|
|
130
|
+
execute: steps: [{ type: "navigate", url: "..." }, { type: "snapshot" }]
|
|
131
|
+
|
|
132
|
+
// Read the snapshot, find the right ref
|
|
133
|
+
|
|
134
|
+
// Call 2: interact using refs from call 1
|
|
135
|
+
execute: steps: [{ type: "click", selector: "@e3" }, { type: "screenshot" }]
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Reverse-engineer a site's API
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
1. Login first (if the site requires auth)
|
|
142
|
+
2. reverse-engineer:
|
|
143
|
+
steps: [
|
|
144
|
+
{ type: "navigate", url: "<target-page>" },
|
|
145
|
+
{ type: "wait", ms: 5000 },
|
|
146
|
+
{ type: "scroll", deltaY: 500 },
|
|
147
|
+
{ type: "wait", ms: 3000 }
|
|
148
|
+
]
|
|
149
|
+
outputDir: "<path-to-save>"
|
|
150
|
+
typed: true // generates TypeScript interfaces
|
|
151
|
+
options: { staleTimeoutMs: 60000, continueOnError: true }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The more interactions (scroll, click tabs, navigate sub-pages), the more API calls get captured. Results feed into the knowledge cache automatically.
|
|
155
|
+
|
|
156
|
+
### Handle captchas
|
|
157
|
+
|
|
158
|
+
Captcha handling depends on the browser mode:
|
|
159
|
+
|
|
160
|
+
**Binary-headful** (visible Chrome window on user's screen):
|
|
161
|
+
- The user can SEE the browser. Ask them to solve the captcha themselves in the open window.
|
|
162
|
+
- After they confirm it's solved, continue the pipeline with the next steps.
|
|
163
|
+
- Do NOT use `solve-captcha` step — it uses the vision API which is slower and less reliable than a human clicking the checkbox.
|
|
164
|
+
```
|
|
165
|
+
"A captcha appeared in the browser window on your screen. Please solve it, then let me know when you're past it."
|
|
166
|
+
// After user confirms:
|
|
167
|
+
execute: steps: [{ type: "screenshot" }] // verify captcha is gone, then continue
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Docker-headful** (remote browser via noVNC):
|
|
171
|
+
- Use the `solve-captcha` step — it auto-detects and solves reCAPTCHA/hCaptcha via vision AI.
|
|
172
|
+
```
|
|
173
|
+
execute: steps: [{ type: "solve-captcha" }, { type: "screenshot" }]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Headless**:
|
|
177
|
+
- Captchas can't be solved in headless. If you hit one, iframer auto-escalates to binary-headful.
|
|
178
|
+
- If it still fails, switch to docker-headful and use `solve-captcha`.
|
|
179
|
+
|
|
180
|
+
### Handle OTP / 2FA codes
|
|
181
|
+
|
|
182
|
+
If the login step encounters a code field and no TOTP secret is stored:
|
|
183
|
+
- The MCP will prompt the user via a form for the code
|
|
184
|
+
- If the form times out, tell the user to provide the code in chat
|
|
185
|
+
- Then fill it manually:
|
|
186
|
+
```
|
|
187
|
+
execute:
|
|
188
|
+
steps: [
|
|
189
|
+
{ type: "fill", selector: "<code-input>", value: "<code-from-user>" },
|
|
190
|
+
{ type: "click", selector: "<submit-button>" }
|
|
191
|
+
]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Restart a broken/frozen browser
|
|
195
|
+
|
|
196
|
+
When the browser crashes, freezes, or you get connection errors:
|
|
197
|
+
```
|
|
198
|
+
session: { action: "restart" }
|
|
199
|
+
```
|
|
200
|
+
This kills ALL running browser instances (local + Docker) and resets state. Credentials and knowledge cache are NOT affected. The next `execute` call launches a fresh browser automatically.
|
|
201
|
+
|
|
202
|
+
**The execute tool also auto-recovers:** if it detects a crash (connection closed, timeout, ECONNREFUSED), it automatically restarts the browser and retries once before reporting failure. If auto-recovery also fails, the agent should call `session restart` manually and try again.
|
|
203
|
+
|
|
204
|
+
### Manage credentials
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
// Check what's stored
|
|
208
|
+
credentials: { action: "list" }
|
|
209
|
+
|
|
210
|
+
// Store new (prompts user via secure form, falls back to CLI)
|
|
211
|
+
credentials: { action: "store", domain: "example.com" }
|
|
212
|
+
|
|
213
|
+
// Update existing (user explicitly asked to change password)
|
|
214
|
+
credentials: { action: "store", domain: "example.com", force: true }
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**NEVER call store as recovery from a failed login.** The tool will refuse and tell you why.
|
|
218
|
+
|
|
219
|
+
### Check/clear knowledge cache
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
knowledge: { action: "list" }
|
|
223
|
+
knowledge: { action: "get", domain: "example.com" }
|
|
224
|
+
knowledge: { action: "clear", domain: "example.com" }
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Handling a stalled/frozen pipeline
|
|
228
|
+
|
|
229
|
+
If an `execute` call takes a very long time (30s+), it's probably stuck on one of:
|
|
230
|
+
|
|
231
|
+
1. **Captcha blocking progress** — the login/navigate step can't proceed because a captcha appeared. In binary-headful mode, tell the user to solve it in the visible window. In docker-headful mode, add a `solve-captcha` step.
|
|
232
|
+
|
|
233
|
+
2. **Waiting for a page transition that never happens** — the site didn't redirect after form submission. Take a screenshot to see the current state, then decide what to do (wrong button clicked, error message on page, etc.).
|
|
234
|
+
|
|
235
|
+
3. **Stale-state timeout** — iframer's stale monitor will abort after `staleTimeoutMs` (default 20s). The error will say "stale-state" and include a screenshot. Read the screenshot to understand what the page looks like.
|
|
236
|
+
|
|
237
|
+
**Recovery pattern for all stalls:**
|
|
238
|
+
```
|
|
239
|
+
1. Take a screenshot to see the current page state
|
|
240
|
+
execute: steps: [{ type: "screenshot" }], options: { mode: "<same-mode>" }
|
|
241
|
+
|
|
242
|
+
2. If captcha visible:
|
|
243
|
+
- binary-headful → ask user to solve it in the visible window
|
|
244
|
+
- docker-headful → execute: steps: [{ type: "solve-captcha" }]
|
|
245
|
+
|
|
246
|
+
3. If the page shows an error or unexpected state:
|
|
247
|
+
- Take a snapshot to get element refs
|
|
248
|
+
- Interact with the page to fix the state (dismiss dialog, click retry, etc.)
|
|
249
|
+
|
|
250
|
+
4. Then continue where you left off (don't restart the entire flow from scratch)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**CRITICAL: Don't restart from scratch.** The browser session persists between execute calls (same daemon, same page context). If you were mid-login and hit a captcha, you don't need to navigate back to the login page — you're still there. Just solve the captcha and continue.
|
|
254
|
+
|
|
255
|
+
**Timeouts:** Docker-headful is slower than local modes — Xvfb + VNC + Chrome share one container. Heavy SPAs (Slack, Figma) can take 30+ seconds to load. If an execute call times out:
|
|
256
|
+
1. Use `staleTimeoutMs: 60000` or higher for heavy sites
|
|
257
|
+
2. Check `status` to confirm Docker is still running
|
|
258
|
+
3. Take a screenshot to see where the browser is — the session is likely still alive
|
|
259
|
+
4. If the container crashed, `docker compose up -d` restarts it; stored sessions/credentials survive since they're in the host's SQLite
|
|
260
|
+
|
|
261
|
+
## Multi-step flows (email → code, OAuth, etc.)
|
|
262
|
+
|
|
263
|
+
Many modern sites don't have email+password on one page. The login step handles these automatically:
|
|
264
|
+
|
|
265
|
+
- **Email-first (Slack, Microsoft, Google):** Login fills email, clicks submit, waits for next page. Returns `emailSubmitted: true`. If the next page has a password field, login fills that too. If it's a code page, the agent needs to ask the user for the code.
|
|
266
|
+
|
|
267
|
+
- **After login step returns with email submitted but not fully logged in:**
|
|
268
|
+
1. Take a screenshot to see what the site is showing
|
|
269
|
+
2. If it's asking for a code → ask the user for it → fill it
|
|
270
|
+
3. If there's a captcha → handle per the captcha rules above
|
|
271
|
+
4. If there's a "choose workspace" or similar → snapshot → click the right option
|
|
272
|
+
|
|
273
|
+
- **Keep the same mode across all steps.** If you started login in binary-headful, continue in binary-headful. Mode switches create new browser contexts and lose page state.
|
|
274
|
+
|
|
275
|
+
## Recovering from MCP disconnect
|
|
276
|
+
|
|
277
|
+
The iframer MCP server runs Chrome in-process. If Chrome crashes hard enough (native segfault, out of memory), the entire MCP server process dies and Claude Code shows "MCP disconnected."
|
|
278
|
+
|
|
279
|
+
**Recovery is simple — Claude Code auto-reconnects MCP servers.** Just wait 2-3 seconds and retry the tool call. Don't:
|
|
280
|
+
- Try to run `claude mcp` commands
|
|
281
|
+
- Try to inspect the toolkit source code
|
|
282
|
+
- Try to restart anything manually
|
|
283
|
+
- Give up and ask the user to restart Claude Code
|
|
284
|
+
|
|
285
|
+
Instead:
|
|
286
|
+
1. Wait a moment (the MCP server respawns automatically)
|
|
287
|
+
2. Call `iframer.status` to verify the connection is back
|
|
288
|
+
3. Call `iframer.session restart` to ensure the browser is in a clean state
|
|
289
|
+
4. Retry the original pipeline
|
|
290
|
+
|
|
291
|
+
**Your progress is NOT lost.** Credentials, sessions, and knowledge cache are in the SQLite database on disk — they survive MCP server restarts. You don't need to re-login or re-store anything.
|
|
292
|
+
|
|
293
|
+
If the MCP disconnects repeatedly on the same operation, the site is probably too heavy for the current mode. Switch to a lighter approach:
|
|
294
|
+
- If using `docker-headful` → switch to `binary-headful` (less overhead)
|
|
295
|
+
- If doing a complex multi-step pipeline → break it into smaller execute calls
|
|
296
|
+
- If just trying to capture APIs → you probably already have enough from previous runs. Check `knowledge get <domain>` before retrying.
|
|
297
|
+
|
|
298
|
+
## Common mistakes to avoid
|
|
299
|
+
|
|
300
|
+
| Mistake | Correct approach |
|
|
301
|
+
|---------|-----------------|
|
|
302
|
+
| Guessing CSS selectors like `button[data-qa='submit']` | Use `snapshot` → read refs → use `@e` refs |
|
|
303
|
+
| Passing `usernameSelector`/`passwordSelector` to login step | Omit them — auto-detect handles it |
|
|
304
|
+
| Re-storing credentials when login fails | Retry with stronger mode (`binary-headful` or `docker-headful`) |
|
|
305
|
+
| Launching browser without checking knowledge cache | Always call `knowledge get <domain>` first |
|
|
306
|
+
| Using `browse` for a page that needs interaction | Use `execute` with a pipeline |
|
|
307
|
+
| Running a huge pipeline without snapshots | Split into navigate+snapshot, then interact based on refs |
|
|
308
|
+
| Hardcoding `mode: "headless"` | Omit mode — auto-select + auto-escalation handles it |
|
|
309
|
+
| Calling `credentials list` and assuming results without reading the response | Read the response text LITERALLY |
|
|
310
|
+
| Using `solve-captcha` in binary-headful mode | Ask the user to solve it — they can see the window |
|
|
311
|
+
| Switching modes mid-flow (e.g. headless → binary-headful after login started) | Keep the same mode — mode switches lose page state |
|
|
312
|
+
| Restarting the entire login flow after a captcha/stall | The browser is still on the same page — just continue from where you are |
|
|
313
|
+
| Not passing `mode` consistently across execute calls in the same flow | Always pass the same `options.mode` for all steps in a multi-call flow |
|
|
314
|
+
| Panicking when MCP disconnects (running `claude mcp`, inspecting source, giving up) | Just wait 2-3 seconds, call `status` to verify reconnect, then `session restart` and retry |
|
|
315
|
+
|
|
316
|
+
## Mode selection guide
|
|
317
|
+
|
|
318
|
+
| Scenario | Recommended mode |
|
|
319
|
+
|----------|-----------------|
|
|
320
|
+
| Simple data extraction, no login | Omit mode (auto-select, starts headless) |
|
|
321
|
+
| Site with login | Omit mode (auto-escalation if headless is blocked) |
|
|
322
|
+
| Known bot-detection (Cloudflare, etc.) | `binary-headful` |
|
|
323
|
+
| Heavy SPA (Slack, Figma, Linear, etc.) | `binary-headful` — Docker often stalls on heavy pages |
|
|
324
|
+
| Interactive session (browsing, clicking around) | `binary-headful` — most stable for long flows |
|
|
325
|
+
| Need automated captcha solving | `docker-headful` (uses vision AI to solve) |
|
|
326
|
+
| Need to watch the browser remotely / headless server | `docker-headful` |
|
|
327
|
+
| Reverse-engineering after login | Same mode that login succeeded in |
|
|
328
|
+
|
|
329
|
+
**Prefer `binary-headful` over `docker-headful` for most tasks.** Binary-headful runs Chrome directly on the user's machine — it's faster, more stable for long sessions, and the user can solve captchas manually. Docker-headful adds overhead (Xvfb, VNC, container networking) and heavy SPAs frequently stall or timeout inside the container.
|
|
330
|
+
|
|
331
|
+
Use `docker-headful` only when: (a) automated captcha solving is needed, (b) the user asks for it explicitly, or (c) it's a remote/headless server with no display.
|
|
332
|
+
|
|
333
|
+
## Response handling
|
|
334
|
+
|
|
335
|
+
- **Screenshots are returned as file paths, NOT inline images.** When a screenshot step runs, the response includes `Screenshot saved: /path/to/file.jpg`. Use the **Read** tool on that path to view the image. This keeps screenshots out of the token budget.
|
|
336
|
+
- **`execute` results include per-step data** — extract values, snapshot text, error context
|
|
337
|
+
- **On failure**, the response includes: failed step index, error type, error message, page URL at failure, and a screenshot file path. Read ALL of it before deciding what to do. Use the Read tool on the screenshot path to see what the page looked like.
|
|
338
|
+
- **`knowledge` returns markdown** — read it for auth material, endpoints, and notes before running a pipeline
|
|
339
|
+
- After successful `execute`, the response includes a hint: "Knowledge cache updated for <domain>. Call `knowledge get <domain>` before the next run."
|
|
340
|
+
- **NEVER send or request images as base64.** All images are file paths. Read them with the Read tool.
|