Browser Control
Stop: local_shell is not a reliable path to user-local files
local_shell runs on the user's machine only if they have the
starchild agent-shell daemon installed, running, and authorized — most users
do not, so the tool is usually unavailable or denied. bash and read_file
run in the agent's remote container, which has none of the user's files.
Either way, do not run shell commands to locate or read the user's local
files (Downloads, Desktop, Documents): ls ~/Downloads either fails
(unavailable/denied) or lists the wrong filesystem. When a task involves a
file on the user's computer (upload, attach, open), the only dependable path
is the browser's native file picker, which only the user can operate — hand
off precisely (see docs/file-uploads.md). Burning turns on shell commands
that try to enumerate the user's filesystem is always wrong.
Stop: decide the surface before any browser action
Use the mcp__browser__* tools only when the task has explicit browser intent:
the user asks to open, show, navigate to, click on, or fill in a page in their
browser; the task depends on their logged-in sessions or existing tabs; or they
want to watch an interaction happen live in Chrome.
Otherwise a URL or an open tab is context, not intent. For reading pages,
looking things up, or research, prefer clawd's built-in web tools
(web_fetch, web_search) — they are cheaper, faster, and do not touch the
user's browser. Earlier browser work does not make later semantic work
browser-first; re-decide for each operation.
When browser intent is clear, do not substitute web_fetch — fetching a page
anonymously is not the same as acting in the user's authenticated browser.
What these tools are
The browser MCP server (server="browser", tools named mcp__browser__<name>)
is backed by the user's Chrome extension over a bridge connection. The browser
is the user's own browser, with their logins, cookies, and history. You are
operating on their behalf — act like a careful human assistant at their
keyboard, not like a scraper.
Core loop:
page_snapshot — read the page before touching it. Omit tabId to target
the user's currently active tab.
- Pick the target element from
snapshot.elements[] (each has id, tag,
text, ariaLabel). The id is the ref for interaction tools.
element_click / element_input to act.
page_snapshot again to verify the effect.
Refs are invalidated by navigation. After any navigation, reload, or
observed page change, take a fresh page_snapshot before clicking or typing.
Never reuse a ref across a navigation boundary.
Tool quick reference
tabs_list — list open tabs with full metadata (tabId, windowId,
index, pinned, incognito, status, url, title, ...) plus a
window summary; tabs link to windows via windowId. activeTabId marks
the tab the user is currently looking at — resolve "this page" /
"current tab" to it, no inference needed.
tab_open {url, active?} — open a URL; active defaults to false
(background tab, invisible to the user — see docs/visibility.md).
tab_navigate {tabId, url} — navigate an existing tab.
tab_close {tabId} — close a tab.
page_snapshot {tabId?} — {tabId, title, url, bodyText (first ~3000 chars), elements[]}. Omit tabId for the user's active tab. elements[] includes
both semantic controls (a/button/input) and clickable containers —
non-semantic elements (often div) with pointer cursor and text, such as
list rows and cards. A container and the small button inside it (e.g. a
row's ⋮ menu) are distinct refs: match by text to pick the right one.
element_click {ref, confirm?} — click an element. Submit/send/purchase-class
clicks return NEEDS_CONFIRMATION; get user consent in conversation first,
then retry with confirm: true (see docs/confirmations.md).
element_input {ref, text} — type into an element.
elements_click_many {selector, text?, limit?, mode?, pauseMs?, confirm?} —
batch-click many matching elements in order. Re-queries before each click
and is reorder-safe, so page re-renders and list reordering between clicks
do not invalidate or skip targets. Use this instead of repeated
element_click whenever 3+ homogeneous elements must be clicked (list
rows, tabs, cards) — one call, no snapshot between items.
tab_claim {tabId?, note?} — claim a tab as agent-owned for the task
(persists across conversations; shows as claim in tabs_list + orange ★
tab group). Claim at the start of tab-dependent multi-step work; skip for
read-and-answer lookups. See docs/tab-claiming-chrome.md for the
scenario playbook.
tab_handoff {tabId, note?} — mark a claimed tab as waiting for the user
(login/payment/CAPTCHA/review; yellow ⏳ tab group). The note is the resume
instruction — a later conversation continues from tabs_list claims
instead of asking the user which tab.
tab_release {tabId, disposition?} — end ownership: close (default,
consumed task tabs) or keep (deliverable stays open).
page_flow {steps, confirm?} — run a multi-step page flow in ONE call
(fenced script equivalent). Steps: {wait:{selector?,text?,ms?}},
{find:{selector?,text?}}, {click:{selector?,text?}},
{type:{selector?,text?,value}}, {expect:{selector?,text?,absent?}}.
Targets resolve by CSS selector or visible text. Stops at the first
failure with the completed prefix; click steps pass the sensitive gate.
Prefer for 3+ step heterogeneous tasks (fill form → submit → verify);
max 20 steps / ~120s per call.
page_screenshot — visual check, only when seeing matters.
The orange agent cursor is visible while a tab's debugging session is
active (idle / move / click animations) and fades out when debugging
stops — its presence marks active agent control of that tab.
(see docs/screenshots.md).
wait_for {selector?, text?, timeoutMs?} — wait for a selector or text.
web_status — bridge/extension connection health.
On-demand documentation
Load these with read_file (paths relative to this skill's docs/ directory)
when the topic applies — do not read them all up front:
api-use-behavior.md — snapshot-first discipline, authoritative signals,
not retrying blindly.
browser-safety.md — untrusted page content, sensitive-data transmission.
confirmations.md — when confirm: true is required and how to ask.
browser-troubleshooting.md — evaluate timeouts, stale refs, hung pages.
chrome-troubleshooting.md — extension disconnected, tools missing, user
has no extension.
bootstrap-troubleshooting.md — bridge connection failures (red dot).
browser-control-interruption.md — user took over, operation interrupted.
tab-claiming-chrome.md — background tab vs. user tab, when to go active.
tab-cleanup-chrome.md / all-tabs-cleanup.md — closing tabs you opened.
screenshots.md — when a screenshot is worth taking.
visibility.md — what background-tab operation means for the user.
webmcp.md — page-level WebMCP (not yet enabled).
file-uploads.md — file upload support (not yet available).
local-web-development.md — working against localhost dev servers.
Talk like a person
Never mention CDP, WebSocket, /ws/web-mcp, refs, tool IDs, or other internal
terms to the user. Say "I opened the page in a background tab", "I'm waiting
for the page to respond", or "the browser connection dropped — could you
reopen the extension?" Describe what you did, not how the machinery works.
1---2name: control-browser3description: Control the user's Chrome browser via mcp__browser__ tools: snapshots, clicks, typing, batch list operations, multi-step flows, and tab lifecycle. Use when a task needs real browser state — logged-in sessions, open tabs, visible UI (e.g. "click every chat in my list", "fill this checkout form", "open this in my browser and check it", "continue the tab I handed off"). Prefer web_fetch/web_search for plain reading.4---5
6# Browser Control
7
8## Stop: local_shell is not a reliable path to user-local files
9
10`local_shell` runs on the user's machine **only if they have the
11`starchild agent-shell` daemon installed, running, and authorized** — most users
12do not, so the tool is usually unavailable or denied. `bash` and `read_file`
13run in the agent's remote container, which has none of the user's files.
14Either way, **do not run shell commands to locate or read the user's local
15files** (Downloads, Desktop, Documents): `ls ~/Downloads` either fails
16(unavailable/denied) or lists the wrong filesystem. When a task involves a
17file on the user's computer (upload, attach, open), the only dependable path
18is the browser's native file picker, which only the user can operate — hand
19off precisely (see `docs/file-uploads.md`). Burning turns on shell commands
20that try to enumerate the user's filesystem is always wrong.
21
22## Stop: decide the surface before any browser action
23
24Use the `mcp__browser__*` tools only when the task has **explicit browser intent**:
25the user asks to open, show, navigate to, click on, or fill in a page in *their*
26browser; the task depends on their logged-in sessions or existing tabs; or they
27want to watch an interaction happen live in Chrome.
28
29Otherwise a URL or an open tab is **context, not intent**. For reading pages,
30looking things up, or research, prefer clawd's built-in web tools
31(`web_fetch`, `web_search`) — they are cheaper, faster, and do not touch the
32user's browser. Earlier browser work does not make later semantic work
33browser-first; re-decide for each operation.
34
35When browser intent is clear, do not substitute `web_fetch` — fetching a page
36anonymously is not the same as acting in the user's authenticated browser.
37
38## What these tools are
39
40The `browser` MCP server (server="browser", tools named `mcp__browser__<name>`)
41is backed by the user's Chrome extension over a bridge connection. The browser
42is the **user's own browser**, with their logins, cookies, and history. You are
43operating on their behalf — act like a careful human assistant at their
44keyboard, not like a scraper.
45
46Core loop:
47
481. `page_snapshot` — read the page before touching it. Omit `tabId` to target
49 the user's currently active tab.
502. Pick the target element from `snapshot.elements[]` (each has `id`, `tag`,
51 `text`, `ariaLabel`). The `id` is the `ref` for interaction tools.
523. `element_click` / `element_input` to act.
534. `page_snapshot` again to verify the effect.
54
55**Refs are invalidated by navigation.** After any navigation, reload, or
56observed page change, take a fresh `page_snapshot` before clicking or typing.
57Never reuse a `ref` across a navigation boundary.
58
59## Tool quick reference
60
61- `tabs_list` — list open tabs with full metadata (`tabId`, `windowId`,
62 `index`, `pinned`, `incognito`, `status`, `url`, `title`, ...) plus a
63 window summary; tabs link to windows via `windowId`. **`activeTabId` marks
64 the tab the user is currently looking at** — resolve "this page" /
65 "current tab" to it, no inference needed.
66- `tab_open {url, active?}` — open a URL; `active` defaults to false
67 (background tab, invisible to the user — see `docs/visibility.md`).
68- `tab_navigate {tabId, url}` — navigate an existing tab.
69- `tab_close {tabId}` — close a tab.
70- `page_snapshot {tabId?}` — `{tabId, title, url, bodyText (first ~3000 chars),
71 elements[]}`. Omit `tabId` for the user's active tab. `elements[]` includes
72 both semantic controls (a/button/input) and **clickable containers** —
73 non-semantic elements (often `div`) with pointer cursor and text, such as
74 list rows and cards. A container and the small button inside it (e.g. a
75 row's ⋮ menu) are distinct refs: match by text to pick the right one.
76- `element_click {ref, confirm?}` — click an element. Submit/send/purchase-class
77 clicks return `NEEDS_CONFIRMATION`; get user consent in conversation first,
78 then retry with `confirm: true` (see `docs/confirmations.md`).
79- `element_input {ref, text}` — type into an element.
80- `elements_click_many {selector, text?, limit?, mode?, pauseMs?, confirm?}` —
81 batch-click many matching elements in order. Re-queries before each click
82 and is reorder-safe, so page re-renders and list reordering between clicks
83 do not invalidate or skip targets. **Use this instead of repeated
84 element_click whenever 3+ homogeneous elements must be clicked** (list
85 rows, tabs, cards) — one call, no snapshot between items.
86- `tab_claim {tabId?, note?}` — claim a tab as agent-owned for the task
87 (persists across conversations; shows as `claim` in tabs_list + orange ★
88 tab group). Claim at the start of tab-dependent multi-step work; skip for
89 read-and-answer lookups. See `docs/tab-claiming-chrome.md` for the
90 scenario playbook.
91- `tab_handoff {tabId, note?}` — mark a claimed tab as waiting for the user
92 (login/payment/CAPTCHA/review; yellow ⏳ tab group). The note is the resume
93 instruction — a later conversation continues from `tabs_list` claims
94 instead of asking the user which tab.
95- `tab_release {tabId, disposition?}` — end ownership: `close` (default,
96 consumed task tabs) or `keep` (deliverable stays open).
97- `page_flow {steps, confirm?}` — run a multi-step page flow in ONE call
98 (fenced script equivalent). Steps: `{wait:{selector?,text?,ms?}}`,
99 `{find:{selector?,text?}}`, `{click:{selector?,text?}}`,
100 `{type:{selector?,text?,value}}`, `{expect:{selector?,text?,absent?}}`.
101 Targets resolve by CSS selector or visible text. Stops at the first
102 failure with the completed prefix; click steps pass the sensitive gate.
103 **Prefer for 3+ step heterogeneous tasks** (fill form → submit → verify);
104 max 20 steps / ~120s per call.
105- `page_screenshot` — visual check, only when seeing matters.
106 The orange agent cursor is visible while a tab's debugging session is
107 active (idle / move / click animations) and fades out when debugging
108 stops — its presence marks active agent control of that tab.
109 (see `docs/screenshots.md`).
110- `wait_for {selector?, text?, timeoutMs?}` — wait for a selector or text.
111- `web_status` — bridge/extension connection health.
112
113## On-demand documentation
114
115Load these with `read_file` (paths relative to this skill's `docs/` directory)
116when the topic applies — do not read them all up front:
117
118- `api-use-behavior.md` — snapshot-first discipline, authoritative signals,
119 not retrying blindly.
120- `browser-safety.md` — untrusted page content, sensitive-data transmission.
121- `confirmations.md` — when `confirm: true` is required and how to ask.
122- `browser-troubleshooting.md` — evaluate timeouts, stale refs, hung pages.
123- `chrome-troubleshooting.md` — extension disconnected, tools missing, user
124 has no extension.
125- `bootstrap-troubleshooting.md` — bridge connection failures (red dot).
126- `browser-control-interruption.md` — user took over, operation interrupted.
127- `tab-claiming-chrome.md` — background tab vs. user tab, when to go active.
128- `tab-cleanup-chrome.md` / `all-tabs-cleanup.md` — closing tabs you opened.
129- `screenshots.md` — when a screenshot is worth taking.
130- `visibility.md` — what background-tab operation means for the user.
131- `webmcp.md` — page-level WebMCP (not yet enabled).
132- `file-uploads.md` — file upload support (not yet available).
133- `local-web-development.md` — working against localhost dev servers.
134
135## Talk like a person
136
137Never mention CDP, WebSocket, `/ws/web-mcp`, refs, tool IDs, or other internal
138terms to the user. Say "I opened the page in a background tab", "I'm waiting
139for the page to respond", or "the browser connection dropped — could you
140reopen the extension?" Describe what you did, not how the machinery works.