Chrome
GitHub通过持久化Node REPL控制Chrome浏览器,处理依赖现有标签页、登录状态或UI交互的任务。优先使用专用API,仅在无替代方案时启用此技能。
Trigger Scenarios
Install
npx skills add fanfan-de/anybox --skill Chrome -g -y
SKILL.md
Frontmatter
{
"name": "Chrome",
"description": "Control the user's Chrome browser through a persistent Node REPL when tasks depend on existing tabs, signed-in sessions, extensions, visible page state, or UI interaction. Prefer purpose-built connectors, APIs, or CLIs for semantic resource operations."
}
Chrome
Stop: choose the right surface before browser action
Explicit Chrome intent wins. If the user names Chrome or this plugin, asks to open or navigate to a page in Chrome, wants the page's visual or interactive state inspected, or requests UI interaction, continue with this skill and do not silently substitute another browser.
Otherwise, treat a URL or open tab as context rather than browser intent. Before each semantic operation on a linked resource, inspect available tools and use tool discovery when available to find an applicable connector, API, or CLI. Prefer that purpose-built surface when it can complete the operation. Use Chrome when no such surface exists, it lacks the required capability, existing Chrome state matters, or UI work remains.
Use this skill for navigating, inspecting visible page state, testing local web apps, clicking, filling, typing, scrolling, waiting for page changes, and taking screenshots.
Use only the persistent Node REPL
Control Chrome only through this plugin's js tool. Its full Anybox tool ID normally resembles mcp__plugin_chrome_node_repl__js. Do not use per-action browser_* MCP tools, Computer Use, standalone Playwright, or another browser-control plugin for this Chrome surface.
The js_reset tool only clears persistent JavaScript state. The js_add_node_module_dir tool only changes CommonJS module resolution. Do not call either helper while trying to expose js.
Keep setup details internal. Unless the user asks about implementation, describe progress naturally as connecting to Chrome, inspecting the page, or retrying the connection.
The runtime sends only operations advertised by the negotiated Browser Contract through the Anybox Agent policy gateway over authenticated local IPC. The client performs an early schema and capability check, and the Anybox Agent authoritatively validates the command again before it can reach Chrome. The isolated transport Worker holds the IPC credentials; do not attempt to discover or connect to its endpoint directly.
Bootstrap once
The Node REPL preloads setupBrowserRuntime, agent, and nodeRepl. Do not import an external or built-in browser-client package.
Initialize one persistent Chrome binding per fresh REPL session. Read its complete runtime documentation on first use:
if (globalThis.agent?.browsers == null) {
await setupBrowserRuntime({ globals: globalThis })
}
if (globalThis.chrome == null) {
globalThis.chrome = await agent.browsers.getDefault()
nodeRepl.write(await chrome.documentation())
}
Reuse globalThis.chrome across later calls and user turns. Do not initialize another browser runtime merely because the user sent a new message.
Check the extension connection when state is unclear:
return await chrome.status()
If Chrome is disconnected, retry chrome.status() once after a short interval. If it remains disconnected, ask the user to install or enable the Anybox Chrome extension, reconnect it, and tell you when it is ready.
Work with tabs
List tabs before opening a duplicate:
return (await chrome.tabs.list()).map(({ id, title, url, active }) => ({
id,
title,
url,
active,
}))
Bind the selected tab explicitly and persist it:
globalThis.tab = await chrome.tabs.get(123) // Replace 123 with a returned tab ID.
return await tab.snapshot()
For a new tab, persist the object returned by open:
globalThis.tab = await chrome.tabs.open("https://example.com/")
return await tab.snapshot()
An item returned by chrome.tabs.list() also contains a bound runtime property that can be used within the same call. Prefer an explicit tab binding across calls.
If a tab is missing, stale, or closed, discard only globalThis.tab and obtain or create a fresh tab from the existing chrome binding. An empty tab list does not invalidate the browser binding.
Inspect and interact
Prefer the highest-level operation that can complete the task:
- Inspect with
tab.snapshot(),interactiveSnapshot(),domTree(), oraccessibilityTree(). - Use
tab.interactiveSnapshot()before element actions, then pass a currentelementIdtotab.clickElement()ortab.fill(). - Use
tab.waitFor()with a concrete URL, text, selector, or element condition after navigation or page-changing actions. - Use
tab.click()for coordinates only when element-based interaction is unavailable. - Selector-driven click/fill adapters, page JavaScript, and CDP are disabled until Anybox can enforce permission at the command boundary. Bounded
waitForSelector()remains available.
Interactive element IDs can become stale after DOM changes. Take a new interactive snapshot instead of retrying an old ID.
To return a screenshot as an image, emit it instead of returning its base64 data:
await nodeRepl.emitImage(await tab.screenshot())
Available APIs include:
agent.browsers.list(),get("extension"),getDefault(), andgetForUrl(url)chrome.browserId,chrome.capabilities,chrome.status(), and capability-filteredchrome.documentation()chrome.tabs.list(),open(url, options),activate(tabId),get(tabId), andcurrent()tab.info(),activate(),snapshot(),interactiveSnapshot(),domTree(),accessibilityTree(), andscreenshot()tab.click(),clickElement(),fill(),type(),scroll(),waitFor(), andrelease()tab.playwright.screenshot(),waitForSelector(), keyboard typing, and coordinate mouse clicks
Authentication and privacy
Do not inspect cookies, local storage, session storage, browser profiles, passwords, tokens, or other credential stores. Never use raw JavaScript or CDP to bypass this rule.
If authentication blocks a task in explicitly requested Chrome, ask the user to sign in there and tell you when it is ready. Do not use web search, another site, or another browser merely to bypass sign-in.
Version History
- 374d7ca Current 2026-07-19 23:19


