browser-automation-skill 0.71.0
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 +144 -0
- package/SECURITY.md +39 -0
- package/SKILL.md +206 -0
- package/bin/cli.mjs +55 -0
- package/install.sh +143 -0
- package/package.json +54 -0
- package/references/adapter-candidates.md +40 -0
- package/references/browser-mcp-cheatsheet.md +132 -0
- package/references/browser-stats-cheatsheet.md +155 -0
- package/references/chrome-devtools-mcp-cheatsheet.md +232 -0
- package/references/midscene-integration.md +359 -0
- package/references/obscura-cheatsheet.md +103 -0
- package/references/playwright-cli-cheatsheet.md +64 -0
- package/references/playwright-lib-cheatsheet.md +90 -0
- package/references/recipes/add-a-tool-adapter.md +134 -0
- package/references/recipes/agent-workflows/README.md +37 -0
- package/references/recipes/agent-workflows/cache-driven-bulk-operation.md +110 -0
- package/references/recipes/agent-workflows/flow-record-and-replay.md +102 -0
- package/references/recipes/agent-workflows/incremental-pattern-discovery.md +125 -0
- package/references/recipes/agent-workflows/login-then-scrape.md +100 -0
- package/references/recipes/anti-patterns-tool-extension.md +182 -0
- package/references/recipes/body-bytes-not-body.md +139 -0
- package/references/recipes/cache-write-security.md +210 -0
- package/references/recipes/fingerprint-rescue.md +154 -0
- package/references/recipes/model-routing.md +143 -0
- package/references/recipes/path-security.md +138 -0
- package/references/recipes/privacy-canary.md +96 -0
- package/references/recipes/visual-rescue-hook.md +182 -0
- package/references/stats-prices.json +42 -0
- package/references/stats-schema.json +77 -0
- package/references/tool-versions.md +8 -0
- package/scripts/browser-add-site.sh +113 -0
- package/scripts/browser-assert.sh +106 -0
- package/scripts/browser-audit.sh +68 -0
- package/scripts/browser-baseline.sh +135 -0
- package/scripts/browser-click.sh +100 -0
- package/scripts/browser-creds-add.sh +254 -0
- package/scripts/browser-creds-list.sh +67 -0
- package/scripts/browser-creds-migrate.sh +122 -0
- package/scripts/browser-creds-remove.sh +69 -0
- package/scripts/browser-creds-rotate-totp.sh +109 -0
- package/scripts/browser-creds-show.sh +82 -0
- package/scripts/browser-creds-totp.sh +94 -0
- package/scripts/browser-do.sh +630 -0
- package/scripts/browser-doctor.sh +365 -0
- package/scripts/browser-drag.sh +90 -0
- package/scripts/browser-extract.sh +192 -0
- package/scripts/browser-fill.sh +142 -0
- package/scripts/browser-flow.sh +316 -0
- package/scripts/browser-history.sh +187 -0
- package/scripts/browser-hover.sh +92 -0
- package/scripts/browser-inspect.sh +188 -0
- package/scripts/browser-list-sessions.sh +78 -0
- package/scripts/browser-list-sites.sh +42 -0
- package/scripts/browser-login.sh +279 -0
- package/scripts/browser-mcp.sh +65 -0
- package/scripts/browser-migrate.sh +195 -0
- package/scripts/browser-open.sh +134 -0
- package/scripts/browser-press.sh +80 -0
- package/scripts/browser-remove-session.sh +72 -0
- package/scripts/browser-remove-site.sh +68 -0
- package/scripts/browser-replay.sh +206 -0
- package/scripts/browser-route.sh +174 -0
- package/scripts/browser-select.sh +122 -0
- package/scripts/browser-show-session.sh +57 -0
- package/scripts/browser-show-site.sh +37 -0
- package/scripts/browser-snapshot.sh +176 -0
- package/scripts/browser-stats.sh +522 -0
- package/scripts/browser-tab-close.sh +112 -0
- package/scripts/browser-tab-list.sh +70 -0
- package/scripts/browser-tab-switch.sh +111 -0
- package/scripts/browser-upload.sh +132 -0
- package/scripts/browser-use.sh +60 -0
- package/scripts/browser-vlm.sh +707 -0
- package/scripts/browser-wait.sh +97 -0
- package/scripts/install-git-hooks.sh +16 -0
- package/scripts/lib/capture.sh +356 -0
- package/scripts/lib/common.sh +262 -0
- package/scripts/lib/credential.sh +237 -0
- package/scripts/lib/fingerprint-rescue.js +123 -0
- package/scripts/lib/flow.sh +448 -0
- package/scripts/lib/flow_record.sh +210 -0
- package/scripts/lib/mask.sh +49 -0
- package/scripts/lib/memory.sh +427 -0
- package/scripts/lib/migrate.sh +390 -0
- package/scripts/lib/migrators/README.md +23 -0
- package/scripts/lib/migrators/memory/v1_to_v2.sh +15 -0
- package/scripts/lib/migrators/recent_urls/README.md +13 -0
- package/scripts/lib/migrators/stats/README.md +24 -0
- package/scripts/lib/node/chrome-devtools-bridge.mjs +1812 -0
- package/scripts/lib/node/mcp-server.mjs +531 -0
- package/scripts/lib/node/mcp-tools.json +68 -0
- package/scripts/lib/node/playwright-driver.mjs +1104 -0
- package/scripts/lib/node/totp-core.mjs +52 -0
- package/scripts/lib/node/totp.mjs +52 -0
- package/scripts/lib/node/url-pattern-cluster.mjs +102 -0
- package/scripts/lib/node/url-pattern-resolver.mjs +77 -0
- package/scripts/lib/output.sh +79 -0
- package/scripts/lib/router.sh +342 -0
- package/scripts/lib/sanitize.sh +107 -0
- package/scripts/lib/secret/keychain.sh +91 -0
- package/scripts/lib/secret/libsecret.sh +74 -0
- package/scripts/lib/secret/plaintext.sh +75 -0
- package/scripts/lib/secret_backend_select.sh +57 -0
- package/scripts/lib/session.sh +153 -0
- package/scripts/lib/site.sh +126 -0
- package/scripts/lib/stats.sh +419 -0
- package/scripts/lib/tool/.gitkeep +0 -0
- package/scripts/lib/tool/chrome-devtools-mcp.sh +349 -0
- package/scripts/lib/tool/obscura.sh +249 -0
- package/scripts/lib/tool/playwright-cli.sh +155 -0
- package/scripts/lib/tool/playwright-lib.sh +106 -0
- package/scripts/lib/verb_helpers.sh +222 -0
- package/scripts/lib/visual-rescue-default.sh +145 -0
- package/scripts/regenerate-docs.sh +99 -0
- package/uninstall.sh +51 -0
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "browser-automation-skill",
|
|
3
|
+
"version": "0.71.0",
|
|
4
|
+
"description": "MCP server + bash CLI that drives a real browser from Claude Code by routing across chrome-devtools-mcp, playwright-cli, playwright-lib, and obscura adapters. 42 verbs covering site/session/credential management, snapshot+ref interaction, capture pipelines, declarative flows, and a per-archetype memory cache.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"claude-code",
|
|
7
|
+
"mcp",
|
|
8
|
+
"model-context-protocol",
|
|
9
|
+
"browser-automation",
|
|
10
|
+
"playwright",
|
|
11
|
+
"chrome-devtools-mcp",
|
|
12
|
+
"anthropic",
|
|
13
|
+
"skill",
|
|
14
|
+
"agent"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/xicv/browser-automation-skill#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/xicv/browser-automation-skill/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/xicv/browser-automation-skill.git"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "Nick Cao <nick.cao@avcrm.com>",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"browser-automation-skill": "bin/cli.mjs",
|
|
29
|
+
"browser-mcp": "bin/cli.mjs"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"bin/",
|
|
33
|
+
"scripts/",
|
|
34
|
+
"references/",
|
|
35
|
+
"SKILL.md",
|
|
36
|
+
"SECURITY.md",
|
|
37
|
+
"install.sh",
|
|
38
|
+
"uninstall.sh",
|
|
39
|
+
"LICENSE",
|
|
40
|
+
"README.md"
|
|
41
|
+
],
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"os": [
|
|
46
|
+
"darwin",
|
|
47
|
+
"linux"
|
|
48
|
+
],
|
|
49
|
+
"scripts": {
|
|
50
|
+
"mcp": "bash scripts/browser-mcp.sh serve",
|
|
51
|
+
"test:smoke": "printf '%s\\n' '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{}}' '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\",\"params\":{}}' | bash scripts/browser-mcp.sh serve",
|
|
52
|
+
"prepublishOnly": "npm run test:smoke >/dev/null && echo 'smoke OK'"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Adapter candidates
|
|
2
|
+
|
|
3
|
+
Browser-automation tools we have considered for the adapter roster but have **not** committed to. This file is a holding pen so candidates survive handoffs and don't get re-discovered from scratch every six months.
|
|
4
|
+
|
|
5
|
+
The shipped roster lives in `references/tool-versions.md` (autogenerated from each adapter's `tool_metadata`). The planned roster lives in the parent spec Appendix B routing matrix. Candidates here are **neither shipped nor planned** — they're "we looked, we declined, here's why, here's what would change our mind."
|
|
6
|
+
|
|
7
|
+
## Format
|
|
8
|
+
|
|
9
|
+
Each candidate gets one short section: what it is, why we declined now, and the concrete trigger that would flip the decision.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## pinchtab — `https://github.com/pinchtab/pinchtab`
|
|
14
|
+
|
|
15
|
+
**What:** Standalone Go HTTP server (~16MB binary) controlling Chrome via CDP. User-installed daemon model (`pinchtab daemon install`). HTTP API at `127.0.0.1:9867` plus a `pinchtab` CLI with subcommands (`nav`, `snap`, `click`, `fill`, `text`, `press`). First-class profile model, multi-instance, token-efficient text extraction (~800 tokens/page). Local-first security posture (loopback bind, IDPI allowlist).
|
|
16
|
+
|
|
17
|
+
**Considered:** 2026-05-02.
|
|
18
|
+
|
|
19
|
+
**Declined now because:**
|
|
20
|
+
- **No empty roster slot.** Inspect/audit/extract → chrome-devtools-mcp (Phase 5 part 1c). Stealth-scrape → obscura (Phase 8). Navigation primitives → playwright-cli/lib. PinchTab competes in occupied lanes without a knockout differentiator.
|
|
21
|
+
- **Daemon-ownership conflict.** Skill invariant: skill manages all process lifecycle. PinchTab inverts this — daemon is user-installed, persists across sessions, has its own update cadence. Adapting requires a new "attach-to-external-daemon" abstraction we don't have.
|
|
22
|
+
- **Architectural duplication.** PinchTab's HTTP-daemon overlaps with our already-shipped IPC daemon (Phase 4 part 4b). Two daemon models would split the contributor mental model.
|
|
23
|
+
- **Maturity risk.** Brand-new project (~2026 H1), single-org. Roster incumbents (Microsoft Playwright, Chrome team's chrome-devtools-mcp) are bets the ecosystem already made.
|
|
24
|
+
- **Token-efficiency overlap.** Our token-efficient-output spec (`docs/superpowers/specs/2026-05-01-token-efficient-adapter-output-design.md`) already captures the `eN` refs + capture files + summary-only-on-stdout discipline. Marginal pinchtab gain ≈ small.
|
|
25
|
+
|
|
26
|
+
**Triggers that would flip the decision:**
|
|
27
|
+
| Trigger | Action |
|
|
28
|
+
|---|---|
|
|
29
|
+
| Phase 8 obscura design surfaces and pinchtab's multi-instance model is a viable non-stealth scrape alternative | reconsider as alt-path for `extract --scrape` |
|
|
30
|
+
| User has a pinchtab daemon running for *other* agents and wants browser-skill to share it | add as 5th adapter targeting the running daemon (requires "attach-to-external-daemon" abstraction first) |
|
|
31
|
+
| PinchTab matures (~12mo), gets community adapters, or Anthropic ships an MCP wrapper for it | re-evaluate against then-current roster |
|
|
32
|
+
| Need a no-node, no-300MB-browser footprint adapter (e.g. CI minimal images) | pinchtab's ~16MB Go binary becomes attractive |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## How to add a new candidate
|
|
37
|
+
|
|
38
|
+
Copy the section template above. Keep it short — what / why-declined / triggers. The point is to make the next consideration a 30-second decision, not a 30-minute re-research.
|
|
39
|
+
|
|
40
|
+
If a trigger fires and a candidate becomes shippable, follow [`recipes/add-a-tool-adapter.md`](recipes/add-a-tool-adapter.md) Path A and remove the section from this file.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# browser-mcp — cheatsheet
|
|
2
|
+
|
|
3
|
+
`scripts/browser-mcp.sh serve` starts an MCP (Model Context Protocol) server
|
|
4
|
+
that exposes our verbs as MCP tools. Spawn it from any MCP-capable client
|
|
5
|
+
(Claude Code, Continue, Cline, agent-browser, midscene, Stagehand,
|
|
6
|
+
browser-use, etc.) to drive our cache + telemetry + secrets vault without
|
|
7
|
+
re-implementing them.
|
|
8
|
+
|
|
9
|
+
Phase 14 origin: midscene research showed midscene publishes its own MCP
|
|
10
|
+
server so upper-layer agents can call it via natural language. We mirror that
|
|
11
|
+
pattern so anything that speaks MCP can reuse our entire skill — turning us
|
|
12
|
+
into the shared middleware browser agents delegate to.
|
|
13
|
+
|
|
14
|
+
## Wire format
|
|
15
|
+
|
|
16
|
+
- Transport: stdio (NDJSON — one JSON object per line)
|
|
17
|
+
- Protocol: MCP 2024-11-05 (matches our existing chrome-devtools-bridge client)
|
|
18
|
+
- Envelope: JSON-RPC 2.0
|
|
19
|
+
|
|
20
|
+
## Tools exposed (Stage 1 + Stage 2)
|
|
21
|
+
|
|
22
|
+
| Tool | Wraps | Required inputs | Optional |
|
|
23
|
+
|---|---|---|---|
|
|
24
|
+
| `browser_open` | `scripts/browser-open.sh` | `url` | `site`, `tool` |
|
|
25
|
+
| `browser_snapshot` | `scripts/browser-snapshot.sh` | _none_ | `site`, `tool`, `capture` |
|
|
26
|
+
| `browser_click` | `scripts/browser-click.sh` | one of `ref` / `selector` | `site`, `tool` |
|
|
27
|
+
| `browser_fill` | `scripts/browser-fill.sh` | `text` + one of `ref` / `selector` | `site`, `tool` |
|
|
28
|
+
| `browser_extract` | `scripts/browser-extract.sh` | one of `selector` / `eval` | `site`, `tool` |
|
|
29
|
+
|
|
30
|
+
Each `tools/call` response carries `content: [{type: "text", text: "<summary JSON>"}]`
|
|
31
|
+
where `<summary JSON>` is the verb's last stdout line (per the token-efficient
|
|
32
|
+
output spec §3.1). `_meta.exitCode` and `_meta.stderr` are surfaced for
|
|
33
|
+
diagnostics.
|
|
34
|
+
|
|
35
|
+
### Secrets discipline (AP-7)
|
|
36
|
+
|
|
37
|
+
`browser_fill` deliberately has NO `secret` field. MCP has no stdin channel
|
|
38
|
+
and putting secrets in tool arguments lands them in the request transcript.
|
|
39
|
+
For real secret values, call `scripts/browser-fill.sh --secret-stdin`
|
|
40
|
+
directly (the secret is piped via stdin and never reaches argv). Phase 14
|
|
41
|
+
unit-tests this contract: `tests/browser-mcp.bats` asserts the schema does
|
|
42
|
+
not expose any "secret" property and rejects unknown props via
|
|
43
|
+
`additionalProperties: false`.
|
|
44
|
+
|
|
45
|
+
### Env-var passthrough (whitelist)
|
|
46
|
+
|
|
47
|
+
The MCP server does NOT inherit the client's full env. Only these prefixes
|
|
48
|
+
+ POSIX essentials pass through to spawned bash verbs (see
|
|
49
|
+
`scripts/lib/node/mcp-server.mjs::ENV_WHITELIST_PREFIXES`):
|
|
50
|
+
|
|
51
|
+
| Prefix | Purpose |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `BROWSER_SKILL_*` | skill internals (`BROWSER_SKILL_HOME`, trace ID, etc.) |
|
|
54
|
+
| `BROWSER_STATS_*` | post-condition contract + model-name injection |
|
|
55
|
+
| `CLAUDE_*` | `CLAUDE_MODEL`, `CLAUDE_USAGE_*`, `CLAUDE_SESSION_ID` |
|
|
56
|
+
| `MIDSCENE_MODEL_*` | local-VLM endpoint config (one envvar block reaches BOTH our skill AND midscene) |
|
|
57
|
+
| `PLAYWRIGHT_*` | adapter knobs + test injection |
|
|
58
|
+
| `CHROME_DEVTOOLS_*` | cdt-mcp adapter knobs |
|
|
59
|
+
| `OBSCURA_*` | obscura adapter knobs |
|
|
60
|
+
| `STUB_*` / `FIXTURES_*` | test-only seams |
|
|
61
|
+
| `MCP_*` | reserved for future MCP overrides |
|
|
62
|
+
|
|
63
|
+
Everything else (e.g. arbitrary `OPENAI_API_KEY` or unknown secrets in the
|
|
64
|
+
client process) is filtered out. This is the AP-7-aligned default — opt-in
|
|
65
|
+
later via expanding the whitelist, not via removing it.
|
|
66
|
+
|
|
67
|
+
## Smoke test
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
printf '%s\n%s\n' \
|
|
71
|
+
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
|
|
72
|
+
'{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
|
|
73
|
+
| bash scripts/browser-mcp.sh serve
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Expected output (two NDJSON lines): an `initialize` reply with
|
|
77
|
+
`protocolVersion: "2024-11-05"` + a `tools/list` reply enumerating
|
|
78
|
+
`browser_open` and `browser_snapshot`.
|
|
79
|
+
|
|
80
|
+
## Wiring from Claude Code
|
|
81
|
+
|
|
82
|
+
Add to `~/.claude/config.json` (or per-project):
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"mcpServers": {
|
|
87
|
+
"browser-skill": {
|
|
88
|
+
"command": "bash",
|
|
89
|
+
"args": ["/abs/path/to/scripts/browser-mcp.sh", "serve"]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
After Claude Code restart, the `browser_open` / `browser_snapshot` tools
|
|
96
|
+
appear in the tool list. They run against the same `~/.browser-skill/` state
|
|
97
|
+
(sites, sessions, captures, memory) as the bash entry points — one cache,
|
|
98
|
+
two surfaces.
|
|
99
|
+
|
|
100
|
+
## Why this exists
|
|
101
|
+
|
|
102
|
+
- **Cache reuse**: `browser-do` archetype cache + Phase 13 fingerprint rescue
|
|
103
|
+
apply automatically when called via MCP — the bash verb is the same entry
|
|
104
|
+
point either way.
|
|
105
|
+
- **Telemetry parity**: every MCP `tools/call` results in one `stats.jsonl`
|
|
106
|
+
event (same as a direct bash call), so `browser-stats report` shows MCP
|
|
107
|
+
and direct calls in one table.
|
|
108
|
+
- **Secrets stay local**: the MCP server spawns the same `scripts/browser-*.sh`
|
|
109
|
+
verbs, which honour AP-7 (no secrets in argv). MCP clients NEVER see
|
|
110
|
+
credentials.
|
|
111
|
+
|
|
112
|
+
## Limitations (Stage 1 + 2)
|
|
113
|
+
|
|
114
|
+
- 5 verbs exposed (open + snapshot + click + fill + extract). The other ~37
|
|
115
|
+
verbs (site / session / credential management, flow runner, capture mgmt,
|
|
116
|
+
stats, baseline, schema migration) are reachable only via direct bash.
|
|
117
|
+
Stage 3 candidates: `browser_wait`, `browser_press`, `browser_select`,
|
|
118
|
+
`browser_assert`.
|
|
119
|
+
- No streaming progress events — request/response only. MCP supports
|
|
120
|
+
`notifications/progress`; wiring it is a Stage 3 task.
|
|
121
|
+
- No tool-side authorization. Anything that can spawn the server can call any
|
|
122
|
+
verb. The skill's existing per-verb typed-phrase confirmations (e.g.
|
|
123
|
+
`--yes-i-know` on destructive ops) still apply at the bash boundary.
|
|
124
|
+
- `browser_extract` does NOT expose `--scrape` (multi-URL batch mode) — too
|
|
125
|
+
many args and the output shape changes. Use `scripts/browser-extract.sh`
|
|
126
|
+
directly for that.
|
|
127
|
+
|
|
128
|
+
## Environment
|
|
129
|
+
|
|
130
|
+
| Var | Meaning | Default |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `BROWSER_SKILL_NODE_BIN` | Node binary used by `browser-mcp.sh serve` | `node` |
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# browser-stats — telemetry / audit / tuning surface
|
|
2
|
+
|
|
3
|
+
Per-action JSONL audit log under `${BROWSER_SKILL_HOME}/memory/stats.jsonl`
|
|
4
|
+
plus a lazy-built SQLite mirror at `memory/stats.db`. JSONL is the source of
|
|
5
|
+
truth; SQLite is regenerated from cursor (`memory/stats.db::stats_cursor`).
|
|
6
|
+
|
|
7
|
+
## Mental model — balance triangle
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
tokens
|
|
11
|
+
\
|
|
12
|
+
\
|
|
13
|
+
\____ accuracy
|
|
14
|
+
/
|
|
15
|
+
/
|
|
16
|
+
latency
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Every adapter invocation emits one event. `browser-stats report` rolls events
|
|
20
|
+
up by (route × verb × outcome) and surfaces:
|
|
21
|
+
|
|
22
|
+
- success rate (and post-condition hit-rate — the *real* accuracy signal)
|
|
23
|
+
- p50/avg token proxies (`stdout_bytes`, `stderr_bytes`, `argv_bytes`)
|
|
24
|
+
- avg duration_ms
|
|
25
|
+
- $/event when `CLAUDE_USAGE_*` env vars present (priced via
|
|
26
|
+
[`stats-prices.json`](stats-prices.json))
|
|
27
|
+
- failure-mode histogram (13-value enum — see schema)
|
|
28
|
+
- **`oblivious_success`** count: adapter reported `outcome=success` but
|
|
29
|
+
the post-condition assertion failed. This is the audit's killer signal —
|
|
30
|
+
without it, naive self-reported success rates lie.
|
|
31
|
+
|
|
32
|
+
## Verbs
|
|
33
|
+
|
|
34
|
+
| Verb | What it does |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `browser-stats rebuild` | Tail `stats.jsonl` from cursor → upsert into `stats.db`. Idempotent. Builds schema on first run. |
|
|
37
|
+
| `browser-stats report [--days N] [--route R] [--verb V] [--pareto]` | Human-readable summary. `--pareto` adds a per-route composite efficiency score. |
|
|
38
|
+
| `browser-stats mark <span_id> success\|fail[:reason]` | Record a user override on one event. Audit-report applies overrides over self-reported outcomes. |
|
|
39
|
+
| `browser-stats tune [--days N] [--route R]` | Surface worst-performing (verb, route) candidates for `/autoresearch` handoff. Human-in-loop — never auto-mutates the skill. |
|
|
40
|
+
|
|
41
|
+
## Examples
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Daily summary (last 7 days, all routes):
|
|
45
|
+
bash scripts/browser-stats.sh report
|
|
46
|
+
|
|
47
|
+
# Per-route Pareto frontier (success_rate × output-byte efficiency):
|
|
48
|
+
bash scripts/browser-stats.sh report --pareto --days 30
|
|
49
|
+
|
|
50
|
+
# Just one route:
|
|
51
|
+
bash scripts/browser-stats.sh report --route chrome-devtools-mcp --days 14
|
|
52
|
+
|
|
53
|
+
# Override an event (e.g. you know the audit miscategorized this):
|
|
54
|
+
bash scripts/browser-stats.sh mark a1b2c3d4e5f6a7b8 fail:wrong_element_acted
|
|
55
|
+
|
|
56
|
+
# Find tuning candidates:
|
|
57
|
+
bash scripts/browser-stats.sh tune --days 30
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Wiring an adapter call site
|
|
61
|
+
|
|
62
|
+
Every verb script that invokes an adapter should emit one stats event per
|
|
63
|
+
invocation. Pattern (see `scripts/browser-open.sh` for a real example):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
source "${SCRIPT_DIR}/lib/stats.sh"
|
|
67
|
+
|
|
68
|
+
stats_t0="$(now_ms)"
|
|
69
|
+
set +e
|
|
70
|
+
adapter_out="$(invoke_with_retry open "${verb_argv[@]}")"
|
|
71
|
+
adapter_rc=$?
|
|
72
|
+
set -e
|
|
73
|
+
|
|
74
|
+
# Phase 12 part 2: post-condition contract via env vars (keeps the helper
|
|
75
|
+
# call-site readable — 6 positional args instead of 10). Verb script sets
|
|
76
|
+
# OBSERVED to the verb-specific signal (URL for open, adapter_out for
|
|
77
|
+
# click/extract). End-user sets EXPECT_* via env to assert specific values.
|
|
78
|
+
BROWSER_STATS_OBSERVED="${url}" \
|
|
79
|
+
stats_run_adapter_emit \
|
|
80
|
+
"open" "${tool_name}" "${stats_t0}" "${adapter_rc}" \
|
|
81
|
+
"${adapter_out}" "" \
|
|
82
|
+
-- "${verb_argv[@]}"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Post-condition env vars (caller sets before invoking the verb)
|
|
86
|
+
|
|
87
|
+
| Env var | Values | Default |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `BROWSER_STATS_EXPECT_TYPE` | `url`, `element_path`, `element_value` | (none — disables check) |
|
|
90
|
+
| `BROWSER_STATS_EXPECT_MATCH` | `exact`, `include`, `semantic` | `include` |
|
|
91
|
+
| `BROWSER_STATS_EXPECT_VALUE` | any string | (none — disables check) |
|
|
92
|
+
| `BROWSER_STATS_OBSERVED` | any string | set by verb script |
|
|
93
|
+
|
|
94
|
+
Example:
|
|
95
|
+
```bash
|
|
96
|
+
BROWSER_STATS_EXPECT_TYPE=url \
|
|
97
|
+
BROWSER_STATS_EXPECT_MATCH=include \
|
|
98
|
+
BROWSER_STATS_EXPECT_VALUE='/devices/42' \
|
|
99
|
+
bash scripts/browser-open.sh --url https://example.com/devices/42
|
|
100
|
+
# → event will carry post_condition_hit:true; oblivious_success detected on mismatch
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Contract
|
|
104
|
+
|
|
105
|
+
- Helper is best-effort — failure never taints caller's exit code (warns to stderr).
|
|
106
|
+
- `parent_span_id` is null unless caller exported `BROWSER_SKILL_PARENT_SPAN_ID`
|
|
107
|
+
(used by `browser-flow` to nest step spans inside a run span).
|
|
108
|
+
- `model` + `gen_ai_usage_*` fields populate only when `CLAUDE_USAGE_*` /
|
|
109
|
+
`CLAUDE_MODEL` env vars are set. Outside Claude Code → null.
|
|
110
|
+
- `stats_random_id` is fork-free `$RANDOM` by default (~60 bits, fine for
|
|
111
|
+
correlation). Set `STATS_USE_CRYPTO_ID=1` if you need `openssl rand` strength.
|
|
112
|
+
- Requires **bash 5.0+** (`$EPOCHREALTIME`). Falls back to second precision
|
|
113
|
+
on legacy bash; the skill's other bash-isms already require Homebrew bash
|
|
114
|
+
on macOS.
|
|
115
|
+
|
|
116
|
+
## Schema
|
|
117
|
+
|
|
118
|
+
See [`stats-schema.json`](stats-schema.json) for the full JSON Schema. Field
|
|
119
|
+
names follow OpenInference + OTel GenAI v1.40 conventions (snake_case
|
|
120
|
+
flattening) for direct compatibility with Langfuse / Phoenix / Jaeger via an
|
|
121
|
+
OTLP exporter.
|
|
122
|
+
|
|
123
|
+
Failure-mode enum (13 values, sourced from WAREX + Agent-E + WebVoyager
|
|
124
|
+
taxonomies):
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
element_not_found element_ambiguous wrong_element_acted
|
|
128
|
+
stale_ref action_timeout navigation_mismatch
|
|
129
|
+
js_not_ready network_error captcha_blocked
|
|
130
|
+
auth_required popup_intercept extraction_mismatch
|
|
131
|
+
oblivious_success
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Privacy
|
|
135
|
+
|
|
136
|
+
- All writes are local (`memory/` mode 0700, files mode 0600).
|
|
137
|
+
- chrome-devtools-mcp opt-out of upstream Clearcut telemetry recommended:
|
|
138
|
+
pass `--no-usage-statistics` in the adapter wrapper (or set
|
|
139
|
+
`CDT_MCP_NO_USAGE_STATISTICS=1`).
|
|
140
|
+
- `selector_value` and `post_condition_observed` may contain user data.
|
|
141
|
+
No remote sink ever. Future `--redact` mode can hash these.
|
|
142
|
+
|
|
143
|
+
## Doctor integration
|
|
144
|
+
|
|
145
|
+
`browser-doctor` surfaces:
|
|
146
|
+
- `ok: stats events recorded: N` (or `warn: stats.jsonl absent`)
|
|
147
|
+
- `ok: stats SQLite indexed: N (delta from JSONL: K)`
|
|
148
|
+
- `warn: stats has N oblivious_success in last 7 days` (when > 0)
|
|
149
|
+
|
|
150
|
+
## Schema migrations
|
|
151
|
+
|
|
152
|
+
`stats.jsonl` starts at `schema_version: 1`. Future shape changes ship a
|
|
153
|
+
migrator under `scripts/lib/migrators/stats/v1_to_v2.sh` (same pattern as
|
|
154
|
+
`memory/`); `browser-migrate run` applies it. SQLite is rebuilt from JSONL
|
|
155
|
+
on the first `rebuild` after a bump.
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# chrome-devtools-mcp — cheatsheet
|
|
2
|
+
|
|
3
|
+
The browser-skill's chrome-devtools-mcp adapter is the **inspection / audit /
|
|
4
|
+
extract** path. Upstream is the `chrome-devtools-mcp` MCP server
|
|
5
|
+
(`npx chrome-devtools-mcp@latest`) which exposes the rich set of CDP-backed
|
|
6
|
+
tools — console messages, network requests, lighthouse audits, performance
|
|
7
|
+
traces — that the playwright-* adapters do not.
|
|
8
|
+
|
|
9
|
+
## Status — Path A introduction (phase-05 part 1) + bridge scaffold (part 1b)
|
|
10
|
+
|
|
11
|
+
This adapter ships **opt-in** via `--tool=chrome-devtools-mcp`. Router
|
|
12
|
+
promotion (Path B — making it the default for capture-flag verbs and for
|
|
13
|
+
`audit` / `inspect` per parent spec Appendix B) is deferred to phase-05
|
|
14
|
+
part 1d after a soak window.
|
|
15
|
+
|
|
16
|
+
Phase-05 part 1b shipped the **node bridge scaffold** at
|
|
17
|
+
`scripts/lib/node/chrome-devtools-bridge.mjs`. The adapter shells to that
|
|
18
|
+
bridge (mirrors `playwright-lib`'s shape: adapter → node bridge → upstream).
|
|
19
|
+
|
|
20
|
+
**Phase-05 part 1c shipped the real MCP stdio transport** for stateless
|
|
21
|
+
verbs. With `${CHROME_DEVTOOLS_MCP_BIN}` pointing at a real
|
|
22
|
+
`chrome-devtools-mcp` (e.g. `npx chrome-devtools-mcp@latest`), the bridge:
|
|
23
|
+
1. spawns the upstream MCP server with stdio piped,
|
|
24
|
+
2. sends the `initialize` handshake (protocol version `2024-11-05`),
|
|
25
|
+
3. translates the verb → MCP `tools/call`,
|
|
26
|
+
4. shapes the response into the skill's single-line summary JSON,
|
|
27
|
+
5. exits cleanly.
|
|
28
|
+
|
|
29
|
+
`uid → eN` translation happens at the adapter boundary (per token-efficient-
|
|
30
|
+
output spec §5) for snapshot output. The original `uid` is kept on each ref
|
|
31
|
+
for traceability.
|
|
32
|
+
|
|
33
|
+
| Verb | Real-mode behavior |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `open` | `navigate_page {url}` — works (one-shot, or via daemon when running) |
|
|
36
|
+
| `snapshot` | `take_snapshot` — works; refs translated to `eN`. When daemon is running, refMap is cached server-side so subsequent `click` / `fill` resolve `eN → uid` |
|
|
37
|
+
| `eval` | `evaluate_script {script}` — works |
|
|
38
|
+
| `audit` | `lighthouse_audit` — works (60s timeout) |
|
|
39
|
+
| `click`, `fill` | works **via daemon** (phase-05 part 1c-ii) — `daemon-start` first, then `snapshot`, then `click eN` / `fill eN ...`. Without daemon → exit 41 with hint |
|
|
40
|
+
| `inspect` | works real-mode (phase-05 part 1e-ii). Multi-flag aggregation: `--capture-console` → `list_console_messages`; `--capture-network` → `list_network_requests`; `--screenshot` → `take_screenshot`; `--selector CSS` → `evaluate_script` with querySelectorAll. One-shot or daemon-routed |
|
|
41
|
+
| `extract` | works real-mode (phase-05 part 1e-ii). `--selector CSS` → evaluate_script with querySelectorAll → text join; `--eval JS` → raw evaluate_script. One-shot or daemon-routed |
|
|
42
|
+
|
|
43
|
+
### Daemon mode (phase-05 part 1c-ii)
|
|
44
|
+
|
|
45
|
+
`daemon-start` spawns a detached node child that holds ONE long-lived MCP
|
|
46
|
+
server child + the `eN ↔ uid` ref map + a TCP loopback IPC server. Verb
|
|
47
|
+
clients connect over loopback (Unix sun_path 104-char cap on macOS bats temp
|
|
48
|
+
paths — TCP loopback with ephemeral port sidesteps it). State written to
|
|
49
|
+
`${BROWSER_SKILL_HOME}/cdt-mcp-daemon.json` (mode 0600, dir 0700).
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node scripts/lib/node/chrome-devtools-bridge.mjs daemon-start
|
|
53
|
+
node scripts/lib/node/chrome-devtools-bridge.mjs open https://example.com
|
|
54
|
+
node scripts/lib/node/chrome-devtools-bridge.mjs snapshot
|
|
55
|
+
node scripts/lib/node/chrome-devtools-bridge.mjs click e1
|
|
56
|
+
node scripts/lib/node/chrome-devtools-bridge.mjs daemon-stop
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`daemon-status` reports `daemon-running` / `daemon-not-running`. `daemon-stop`
|
|
60
|
+
when none is a no-op success. Idempotent `daemon-start` returns
|
|
61
|
+
`daemon-already-running`. Daemon stderr lands at
|
|
62
|
+
`${BROWSER_SKILL_HOME}/cdt-mcp-daemon.log` (mode 0600).
|
|
63
|
+
|
|
64
|
+
Stub mode (`BROWSER_SKILL_LIB_STUB=1`) still works exactly as part-1b — used by the bats suite + CI for adapter contract tests without spawning anything.
|
|
65
|
+
|
|
66
|
+
## When the router picks this adapter
|
|
67
|
+
|
|
68
|
+
After Phase 5 part 1d, four routing rules promote chrome-devtools-mcp to a default for verbs and flags where it's the only sensible adapter (per parent spec Appendix B):
|
|
69
|
+
|
|
70
|
+
| Verb / flag | Default? | Why |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `open` (no flags) | no | router default is playwright-cli |
|
|
73
|
+
| `click` (no flags) | no | playwright-cli |
|
|
74
|
+
| `fill` (no flags) | no | playwright-cli (or playwright-lib for `--secret-stdin`) |
|
|
75
|
+
| `snapshot` (no flags) | no | playwright-cli |
|
|
76
|
+
| `--capture-console` / `--capture-network` (any verb) | **YES** (part 1d) | `rule_capture_flags` — only adapter with console + network MCP tools |
|
|
77
|
+
| `--lighthouse` / `--perf-trace` (any verb) | **YES** (part 1d) | `rule_audit_or_perf` — only adapter with `lighthouse_audit` + `performance_*` |
|
|
78
|
+
| `audit` (any flags) | **YES** (part 1d) | `rule_audit_or_perf` |
|
|
79
|
+
| `inspect` | **YES** (part 1d) | `rule_inspect_default` |
|
|
80
|
+
| `extract` | **YES** (part 1d) | `rule_extract_default`. With `--scrape <urls...>` → obscura (when Phase 8 lands) |
|
|
81
|
+
| `eval` | no — opt-in | playwright-cli/lib both support it |
|
|
82
|
+
|
|
83
|
+
`session_required` (storage-state loaded) still wins above all capture-flag rules; that path keeps routing through playwright-lib, so flag combos like `--site app --capture-console` route to playwright-lib (capture flags silently ignored). Limitation tracked for part 1f (Chrome `--user-data-dir` lets cdt-mcp do session loading too).
|
|
84
|
+
|
|
85
|
+
## Capabilities declared
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"verbs": {
|
|
90
|
+
"open": { "flags": ["--headed", "--url"] },
|
|
91
|
+
"click": { "flags": ["--ref"] },
|
|
92
|
+
"fill": { "flags": ["--ref", "--text", "--secret-stdin"] },
|
|
93
|
+
"snapshot": { "flags": ["--depth"] },
|
|
94
|
+
"inspect": { "flags": ["--capture-console", "--capture-network", "--screenshot"] },
|
|
95
|
+
"audit": { "flags": ["--lighthouse", "--perf-trace"] },
|
|
96
|
+
"extract": { "flags": ["--selector", "--eval"] },
|
|
97
|
+
"eval": { "flags": ["--expression"] }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
All eight verbs are declared so `--tool=chrome-devtools-mcp` makes the full
|
|
103
|
+
surface reachable today (the capability filter in `pick_tool` admits any
|
|
104
|
+
declared verb regardless of router precedence).
|
|
105
|
+
|
|
106
|
+
## Architecture
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
bash adapter node bridge upstream MCP server
|
|
110
|
+
┌─────────────────┐ ┌──────────────────────┐ ┌─────────────────────┐
|
|
111
|
+
│ chrome-devtools-│───▶│ chrome-devtools- │───▶│ chrome-devtools-mcp │
|
|
112
|
+
│ mcp.sh │ │ bridge.mjs │ │ (npx, JSON-RPC over │
|
|
113
|
+
│ (8 tool_* fns) │ │ - stub mode │ │ stdio) — part 1c │
|
|
114
|
+
│ │ │ - real mode (1c) │ │ │
|
|
115
|
+
└─────────────────┘ └──────────────────────┘ └─────────────────────┘
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This mirrors the `playwright-lib → playwright-driver.mjs → real Playwright`
|
|
119
|
+
shape. The bridge is the translation boundary between skill verb argv and
|
|
120
|
+
the MCP `tools/call` JSON-RPC envelope (real mode) OR fixture lookup (stub
|
|
121
|
+
mode).
|
|
122
|
+
|
|
123
|
+
## Doctor check
|
|
124
|
+
|
|
125
|
+
Verifies `node` is on PATH and the bridge file is present (mirror
|
|
126
|
+
`playwright-lib::tool_doctor_check`). Reports node version and the
|
|
127
|
+
`mcp_server_bin` name. Includes a `note` field stating real-mode MCP
|
|
128
|
+
transport is deferred to part 1c.
|
|
129
|
+
|
|
130
|
+
To install (real-mode, once part 1c lands):
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npm i -g chrome-devtools-mcp
|
|
134
|
+
# or run via npx (no global install):
|
|
135
|
+
# CHROME_DEVTOOLS_MCP_BIN='npx chrome-devtools-mcp@latest' \
|
|
136
|
+
# bash scripts/browser-<verb>.sh --tool=chrome-devtools-mcp ...
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Version pin
|
|
140
|
+
|
|
141
|
+
- `version_pin: "0.x"` — the upstream package is pre-1.0; capabilities are
|
|
142
|
+
expected to drift. The pin will move once a stable major lands.
|
|
143
|
+
|
|
144
|
+
## Override
|
|
145
|
+
|
|
146
|
+
Force this adapter even when the router would pick another:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
bash scripts/browser-<verb>.sh --tool=chrome-devtools-mcp ...
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
This is the **Path A entry point** — it works without router edits and is
|
|
153
|
+
how every new adapter is introduced (see
|
|
154
|
+
[references/recipes/add-a-tool-adapter.md](recipes/add-a-tool-adapter.md)).
|
|
155
|
+
|
|
156
|
+
## Stub mode
|
|
157
|
+
|
|
158
|
+
Set `BROWSER_SKILL_LIB_STUB=1` to make the bridge perform a fixture lookup
|
|
159
|
+
instead of spawning the upstream MCP server (which the bridge doesn't yet do
|
|
160
|
+
anyway — that's part 1c). The bridge hashes argv (`sha256` of args
|
|
161
|
+
joined+terminated by NUL — matches `printf '%s\0' "$@" | shasum -a 256`) and
|
|
162
|
+
echoes the corresponding `tests/fixtures/chrome-devtools-mcp/<sha>.json`.
|
|
163
|
+
Misses exit 41 with a JSON error line.
|
|
164
|
+
|
|
165
|
+
To regenerate fixture filenames after changing the adapter's argv translation:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
printf '%s\0' inspect --capture-console | shasum -a 256 | awk '{print $1}'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The same digest in node (the bridge's path):
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
node -e "const{createHash}=require('crypto'); \
|
|
175
|
+
console.log(createHash('sha256') \
|
|
176
|
+
.update(['inspect','--capture-console'].map(a=>a+'\0').join('')) \
|
|
177
|
+
.digest('hex'))"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Environment variables
|
|
181
|
+
|
|
182
|
+
| Var | Meaning | Default |
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| `BROWSER_SKILL_LIB_STUB` | When `=1`, bridge skips MCP transport and reads fixtures | unset |
|
|
185
|
+
| `BROWSER_SKILL_NODE_BIN` | Node binary the adapter invokes | `node` |
|
|
186
|
+
| `CHROME_DEVTOOLS_MCP_BIN` | Upstream MCP server binary the bridge spawns in real mode (part 1c) | `chrome-devtools-mcp` |
|
|
187
|
+
| `CHROME_DEVTOOLS_MCP_FIXTURES_DIR` | Override fixture directory in stub mode | `tests/fixtures/chrome-devtools-mcp` (relative to bridge file) |
|
|
188
|
+
| `STUB_LOG_FILE` | When set, bridge in stub mode appends each invocation's argv (one line per arg) here | unset |
|
|
189
|
+
| `CHROME_USER_DATA_DIR` | When set (phase-5 part 1f), bridge forwards `--user-data-dir DIR` to the spawned upstream MCP child. Chrome reuses the profile (cookies, localStorage, extensions persist). | unset |
|
|
190
|
+
|
|
191
|
+
## Session loading (phase-5 part 1f)
|
|
192
|
+
|
|
193
|
+
cdt-mcp's session mechanism is **Chrome's native `--user-data-dir`**, NOT
|
|
194
|
+
playwright-lib's `storageState` JSON. To reuse a logged-in profile:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# 1. Log in once with real Chrome at a known directory:
|
|
198
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
|
|
199
|
+
--user-data-dir=/tmp/my-profile https://app.example.com
|
|
200
|
+
|
|
201
|
+
# 2. Now point cdt-mcp at it:
|
|
202
|
+
export CHROME_USER_DATA_DIR=/tmp/my-profile
|
|
203
|
+
bash scripts/browser-snapshot.sh --capture-console
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
The bridge forwards the directory as `--user-data-dir DIR` to the upstream
|
|
207
|
+
MCP server child. If upstream chrome-devtools-mcp accepts the flag (most
|
|
208
|
+
versions do — it's a standard Chrome arg), Chrome reuses the profile.
|
|
209
|
+
|
|
210
|
+
**Limitations:**
|
|
211
|
+
- User provides the directory. Capture / automation of user-data-dir creation is out of scope (no `bash scripts/browser-login.sh --user-data-dir-mode` yet).
|
|
212
|
+
- Concurrent runs sharing the same profile dir → Chrome lock conflicts. Serialize.
|
|
213
|
+
- Upstream chrome-devtools-mcp version dictates whether the flag is honored.
|
|
214
|
+
|
|
215
|
+
## Limitations (current state)
|
|
216
|
+
|
|
217
|
+
- **No router promotion.** Per anti-pattern AP-4, this PR ships dark only.
|
|
218
|
+
Promotion is part 1d.
|
|
219
|
+
- **No `inspect` / `extract` verbs yet.** `scripts/browser-audit.sh` and
|
|
220
|
+
`scripts/browser-extract.sh` don't exist; `tests/browser-inspect.bats` is
|
|
221
|
+
still skipped. Verb-side wiring (and daemon dispatch for these two) is
|
|
222
|
+
phase-05 part 1e.
|
|
223
|
+
- **No session loading.** Chrome's `--user-data-dir` mechanism (different
|
|
224
|
+
from playwright-lib's `storageState`) is phase-05 part 1f.
|
|
225
|
+
|
|
226
|
+
## See also
|
|
227
|
+
|
|
228
|
+
- Parent spec: [`docs/superpowers/specs/2026-04-27-browser-automation-skill-design.md`](../docs/superpowers/specs/2026-04-27-browser-automation-skill-design.md) — Appendix B routing matrix.
|
|
229
|
+
- Add-a-tool-adapter recipe: [`references/recipes/add-a-tool-adapter.md`](recipes/add-a-tool-adapter.md).
|
|
230
|
+
- Anti-patterns: [`references/recipes/anti-patterns-tool-extension.md`](recipes/anti-patterns-tool-extension.md).
|
|
231
|
+
- Token-efficient output spec: [`docs/superpowers/specs/2026-05-01-token-efficient-adapter-output-design.md`](../docs/superpowers/specs/2026-05-01-token-efficient-adapter-output-design.md).
|
|
232
|
+
- Phase 5 part 1b plan: [`docs/superpowers/plans/2026-05-02-phase-05-part-1b-cdt-mcp-bridge.md`](../docs/superpowers/plans/2026-05-02-phase-05-part-1b-cdt-mcp-bridge.md).
|