-
Notifications
You must be signed in to change notification settings - Fork 37
Add agent-browser remote interop and browse-fleet-subagents skill #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 22 commits
ab68dc7
abe5f59
cf762a8
4444477
2764231
5ea8052
e75e7f8
5965eca
2cda0fa
1ada63a
f63168f
3fb2f49
6d020cf
5b74333
a2fdade
07ddb74
06fcff2
d1aa1f1
068b527
b4ea2f9
acc6cc3
909f675
63df3bc
9e5c1a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| MIT License | ||
|
|
||
| Copyright (c) 2026 Browserbase, Inc. | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| --- | ||
| name: agent-browser-remote | ||
| description: Use Agent Browser with Browserbase remote CDP sessions. Trigger this skill when users are driving browser tasks with agent-browser and encounter CAPTCHAs, anti-bot pages, IP-based blocking, JavaScript-heavy sites, geo restrictions, or request remote cloud browser execution. | ||
| compatibility: "Requires `agent-browser` and Node.js. Requires Browserbase credentials (`BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`) for remote sessions." | ||
| license: MIT | ||
| allowed-tools: Bash | ||
| metadata: | ||
| capabilities: | ||
| - agent-browser | ||
| - remote-browser | ||
| - cdp-interop | ||
| - stealth | ||
| - captcha-solving | ||
| - proxies | ||
| openclaw: | ||
| requires: | ||
| bins: | ||
| - agent-browser | ||
| - node | ||
| install: | ||
| - kind: node | ||
| package: "agent-browser" | ||
| bins: [agent-browser] | ||
| homepage: https://github.com/browserbase/skills | ||
| --- | ||
|
|
||
| # Agent Browser + Remote CDP | ||
|
|
||
| Use this skill when `agent-browser` local mode struggles on protected sites, or when the user explicitly wants remote cloud browsers. | ||
|
|
||
| ## Setup check | ||
|
|
||
| ```bash | ||
| which agent-browser || npm install -g agent-browser | ||
| agent-browser install | ||
| ``` | ||
|
|
||
| Set Browserbase credentials (or run `openclaw browserbase setup`): | ||
|
|
||
| ```bash | ||
| export BROWSERBASE_API_KEY="..." | ||
| export BROWSERBASE_PROJECT_ID="..." | ||
| ``` | ||
|
|
||
| ## Fast path | ||
|
|
||
| Create a Browserbase session, then point `agent-browser` at the returned CDP URL. | ||
|
|
||
| ```bash | ||
| eval "$(node scripts/browserbase-session.mjs create --proxies true --advanced-stealth true --format shell)" | ||
| agent-browser --cdp "$BROWSERBASE_CDP_URL" open https://example.com | ||
| agent-browser --cdp "$BROWSERBASE_CDP_URL" snapshot -i --json | ||
| ``` | ||
|
|
||
| When done: | ||
|
|
||
| ```bash | ||
| node scripts/browserbase-session.mjs close --session-id "$BROWSERBASE_SESSION_ID" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Script path unresolvable from user working directoryHigh Severity The SKILL.md instructs Claude to run |
||
| ``` | ||
|
|
||
| ## When to switch from local to remote | ||
|
|
||
| Switch to remote when any of these appear: | ||
| - CAPTCHA or challenge pages (reCAPTCHA, hCaptcha, Turnstile) | ||
| - bot checks ("checking your browser", "verify you are human") | ||
| - repeated `403` / `429` from sites that should be accessible | ||
| - empty DOM/snapshot on JavaScript-heavy pages that should have content | ||
| - geo-specific content requirements | ||
|
|
||
| Stay local for simple docs sites, localhost, and basic internal QA flows. | ||
|
|
||
| ## Command patterns | ||
|
|
||
| Per-command CDP (explicit, stateless): | ||
|
|
||
| ```bash | ||
| agent-browser --cdp "$BROWSERBASE_CDP_URL" open https://target.com | ||
| agent-browser --cdp "$BROWSERBASE_CDP_URL" snapshot -i --json | ||
| agent-browser --cdp "$BROWSERBASE_CDP_URL" click @e2 | ||
| ``` | ||
|
|
||
| Or connect once, then run normal commands: | ||
|
|
||
| ```bash | ||
| agent-browser connect "$BROWSERBASE_CDP_URL" | ||
| agent-browser open https://target.com | ||
| agent-browser snapshot -i --json | ||
| ``` | ||
|
|
||
| ## Notes | ||
|
|
||
| - `--proxies true` requires a Browserbase plan that includes proxies. | ||
| - `--advanced-stealth true` requires a plan that includes advanced stealth. | ||
| - Always close remote sessions explicitly when the task ends. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| const DEFAULT_API_BASE = process.env.BROWSERBASE_API_BASE_URL || "https://api.browserbase.com"; | ||
|
|
||
| function usage() { | ||
| console.error( | ||
| [ | ||
| "Usage:", | ||
| " node scripts/browserbase-session.mjs create [options]", | ||
| " node scripts/browserbase-session.mjs close --session-id <id> [options]", | ||
| "", | ||
| "Create options:", | ||
| " --api-key <key> Browserbase API key (or BROWSERBASE_API_KEY)", | ||
| " --project-id <id> Browserbase project ID (or BROWSERBASE_PROJECT_ID)", | ||
| " --proxies <true|false> Enable proxies", | ||
| " --advanced-stealth <true|false> Enable advanced stealth", | ||
| " --keep-alive <true|false> Keep session alive on Browserbase", | ||
| " --format <json|shell|url> Output format (default: json)", | ||
| " --api-base-url <url> API base URL (default: https://api.browserbase.com)", | ||
| "", | ||
| "Close options:", | ||
| " --session-id <id> Session ID to close (required)", | ||
| " --api-key <key> Browserbase API key (or BROWSERBASE_API_KEY)", | ||
| " --api-base-url <url> API base URL", | ||
| ].join("\n"), | ||
| ); | ||
| } | ||
|
|
||
| function parseArgs(argv) { | ||
| const out = { _: [] }; | ||
| for (let i = 0; i < argv.length; i += 1) { | ||
| const arg = argv[i]; | ||
| if (!arg.startsWith("--")) { | ||
| out._.push(arg); | ||
| continue; | ||
| } | ||
| const key = arg.slice(2); | ||
| const next = argv[i + 1]; | ||
| if (!next || next.startsWith("--")) { | ||
| out[key] = true; | ||
| continue; | ||
| } | ||
| out[key] = next; | ||
| i += 1; | ||
| } | ||
| return out; | ||
| } | ||
|
|
||
| function parseBool(value, name) { | ||
| if (value === undefined) return undefined; | ||
| if (value === true || value === false) return value; | ||
| const normalized = String(value).trim().toLowerCase(); | ||
| if (["1", "true", "yes", "on"].includes(normalized)) return true; | ||
| if (["0", "false", "no", "off"].includes(normalized)) return false; | ||
| throw new Error(`Invalid boolean for --${name}: ${value}`); | ||
| } | ||
|
|
||
| function shellQuote(value) { | ||
| return `'${String(value).replace(/'/g, `'\\''`)}'`; | ||
| } | ||
|
|
||
| async function createSession(args) { | ||
| const apiKey = args["api-key"] || process.env.BROWSERBASE_API_KEY; | ||
| const projectId = args["project-id"] || process.env.BROWSERBASE_PROJECT_ID; | ||
| const format = String(args.format || "json").toLowerCase(); | ||
| const apiBaseUrl = String(args["api-base-url"] || DEFAULT_API_BASE).replace(/\/$/, ""); | ||
|
|
||
| if (!apiKey) throw new Error("Missing API key. Set --api-key or BROWSERBASE_API_KEY."); | ||
| if (!projectId) throw new Error("Missing project ID. Set --project-id or BROWSERBASE_PROJECT_ID."); | ||
| if (!["json", "shell", "url"].includes(format)) { | ||
| throw new Error(`Invalid --format: ${format}`); | ||
| } | ||
|
|
||
| const proxies = parseBool(args.proxies, "proxies"); | ||
| const advancedStealth = parseBool(args["advanced-stealth"], "advanced-stealth"); | ||
| const keepAlive = parseBool(args["keep-alive"], "keep-alive"); | ||
|
|
||
| const payload = { projectId }; | ||
| if (proxies !== undefined) payload.proxies = proxies; | ||
| if (keepAlive !== undefined) payload.keepAlive = keepAlive; | ||
| if (advancedStealth !== undefined) { | ||
| payload.browserSettings = { advancedStealth }; | ||
| } | ||
|
|
||
| const response = await fetch(`${apiBaseUrl}/v1/sessions`, { | ||
| method: "POST", | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| "X-BB-API-Key": apiKey, | ||
| }, | ||
| body: JSON.stringify(payload), | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| const text = await response.text(); | ||
| throw new Error(`Failed to create session (${response.status}): ${text || response.statusText}`); | ||
| } | ||
|
|
||
| const data = await response.json(); | ||
| const sessionId = data.id; | ||
| const connectUrl = data.connectUrl; | ||
|
|
||
| if (!sessionId || !connectUrl) { | ||
| throw new Error("Browserbase response missing id or connectUrl."); | ||
| } | ||
|
|
||
| const output = { | ||
| sessionId, | ||
| connectUrl, | ||
| debuggerUrl: `https://www.browserbase.com/sessions/${sessionId}`, | ||
| }; | ||
|
|
||
| if (format === "url") { | ||
| console.log(output.connectUrl); | ||
| return; | ||
| } | ||
|
|
||
| if (format === "shell") { | ||
| console.log(`export BROWSERBASE_SESSION_ID=${shellQuote(output.sessionId)}`); | ||
| console.log(`export BROWSERBASE_CDP_URL=${shellQuote(output.connectUrl)}`); | ||
| console.log(`export BROWSERBASE_DEBUGGER_URL=${shellQuote(output.debuggerUrl)}`); | ||
| return; | ||
| } | ||
|
|
||
| console.log(JSON.stringify(output, null, 2)); | ||
| } | ||
|
|
||
| async function closeSession(args) { | ||
| const apiKey = args["api-key"] || process.env.BROWSERBASE_API_KEY; | ||
| const sessionId = args["session-id"] || args.sessionId; | ||
| const apiBaseUrl = String(args["api-base-url"] || DEFAULT_API_BASE).replace(/\/$/, ""); | ||
|
|
||
| if (!apiKey) throw new Error("Missing API key. Set --api-key or BROWSERBASE_API_KEY."); | ||
| if (!sessionId) throw new Error("Missing session ID. Set --session-id <id>."); | ||
|
|
||
| const response = await fetch(`${apiBaseUrl}/v1/sessions/${encodeURIComponent(sessionId)}`, { | ||
| method: "DELETE", | ||
| headers: { | ||
| "X-BB-API-Key": apiKey, | ||
| }, | ||
| }); | ||
cursor[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if (!response.ok) { | ||
| const text = await response.text(); | ||
| throw new Error(`Failed to close session (${response.status}): ${text || response.statusText}`); | ||
| } | ||
|
|
||
| console.log(JSON.stringify({ closed: true, sessionId }, null, 2)); | ||
| } | ||
|
|
||
| async function main() { | ||
| const argv = process.argv.slice(2); | ||
| if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) { | ||
| usage(); | ||
| process.exit(argv.length === 0 ? 1 : 0); | ||
| } | ||
|
|
||
| const [command, ...rest] = argv; | ||
| const args = parseArgs(rest); | ||
|
|
||
| if (command === "create") { | ||
| await createSession(args); | ||
| return; | ||
| } | ||
| if (command === "close") { | ||
| await closeSession(args); | ||
| return; | ||
| } | ||
|
|
||
| usage(); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| main().catch((error) => { | ||
| console.error(String(error?.message || error)); | ||
| process.exit(1); | ||
| }); | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New skills not registered in marketplace discovery catalog
High Severity
The two new skills (
agent-browser-remoteandbrowse-fleet-subagents) are added with fullSKILL.mdfiles and listed in theREADME.mdskills table, but neither is registered inmarketplace.json. Sincemarketplace.jsonis the discovery catalog that Claude Code uses to find and load skills, these skills won't be discoverable or installable through the plugin system. Thebrowseplugin'sskillsarray only contains./skills/browser.Additional Locations (1)
README.md#L11-L13