feat(domain-skills): add browser-use-cloud (REST + cleanup-zombies)#301
Conversation
Adds an operator-facing skill for cloud.browser-use.com / api.browser-use.com,
covering the same REST surface that the harness's own admin.py already
uses (X-Browser-Use-API-Key header, /browsers, /profiles), plus a
companion script for the most common automation -- stopping zombie
sessions older than N minutes.
Live-tested on 2026-05-05 with a real BROWSER_USE_API_KEY:
POST /browsers 201 - shape verified incl. liveUrl on live.browser-use.com
PATCH /browsers/{id} stop 200 - returns final cost
GET /browsers 200 - paginated {items, totalItems, ...}
GET /profiles 200 - same envelope
GET /profiles/{id} 200 - cookieDomains=None on fresh profiles
GET /usage 404 - no public endpoint, doc'd accordingly
GET / 404 - no root metadata
The cleanup-zombies.py companion is the regression artefact; running it
in dry-run mode is the cheapest smoke test, and a full E2E loop
(spawn -> list -> stop -> re-list) was confirmed end-to-end during
authoring.
Notable wire gotchas surfaced and documented:
- Cost / proxy fields (proxyCost, browserCost, proxyUsedMb) are returned
as JSON strings, not numbers; cast to float before arithmetic.
- liveUrl host is live.browser-use.com (different from cloud.browser-use.com),
with the cdp WebSocket encoded as a ?wss= query parameter.
- cookieDomains can be null on a freshly-created profile despite
list_cloud_profiles' docstring describing it as an array.
- GET /usage returns 404 -- per-session cost lives on each browser
record; aggregate billing only on the dashboard.
Style follows the claude-ai/share-export (browser-use#267) pattern of
markdown-skill-with-companion-py, sized at 222 + 161 LOC. Discovery
under helpers.py:163's current logic would resolve cloud.browser-use.com
to "cloud/" rather than "browser-use-cloud/" -- the skill folder name
mirrors the convention used by claude-ai/, vercel/, and tasksquad-ai/
which are also not auto-discoverable today; PR browser-use#165 is the broader fix
for that.
Refs: PR browser-use#300 (run.py precedence fix in the same area), PR browser-use#267
(claude-ai companion-script pattern), PR browser-use#288 (vercel dashboard skill
header style).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 84e7a2c0ae
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| except urllib.error.HTTPError as e: | ||
| record["action"] = f"stop_failed: HTTP {e.code}" |
There was a problem hiding this comment.
Handle network errors when stopping zombie sessions
When PATCH /browsers/{id} hits a transient network failure (e.g., timeout/DNS/socket reset), urlopen raises URLError, but this loop only catches HTTPError. That exception currently bubbles out, aborting the run before remaining zombies are processed, which can leave older sessions running and still accruing cost during exactly the cleanup workflow this script is meant to automate.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
3 issues found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="agent-workspace/domain-skills/browser-use-cloud/cloud.md">
<violation number="1" location="agent-workspace/domain-skills/browser-use-cloud/cloud.md:1">
P2: This skill is placed in a directory name that the current domain-skill resolver will never surface for `cloud.browser-use.com`/`api.browser-use.com`, so it is effectively undiscoverable through normal skill loading.</violation>
<violation number="2" location="agent-workspace/domain-skills/browser-use-cloud/cloud.md:181">
P1: Documentation recommends piping a remote script directly into `sh` without integrity verification, creating a supply-chain/code-execution risk for operators.</violation>
</file>
<file name="agent-workspace/domain-skills/browser-use-cloud/cleanup-zombies.py">
<violation number="1" location="agent-workspace/domain-skills/browser-use-cloud/cleanup-zombies.py:106">
P2: `stop_browser()` can raise `URLError`, but the PATCH path only catches `HTTPError`, so a transient network failure can abort the cleanup run mid-loop and skip remaining browsers.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| - **`_browser_use` has a 60s timeout** in `admin.py`; long-running ops | ||
| (large profile sync) need their own polling. | ||
| - **`profile-use` CLI is a separate install**: | ||
| `curl -fsSL https://browser-use.com/profile.sh | sh`. |
There was a problem hiding this comment.
P1: Documentation recommends piping a remote script directly into sh without integrity verification, creating a supply-chain/code-execution risk for operators.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At agent-workspace/domain-skills/browser-use-cloud/cloud.md, line 181:
<comment>Documentation recommends piping a remote script directly into `sh` without integrity verification, creating a supply-chain/code-execution risk for operators.</comment>
<file context>
@@ -0,0 +1,222 @@
+- **`_browser_use` has a 60s timeout** in `admin.py`; long-running ops
+ (large profile sync) need their own polling.
+- **`profile-use` CLI is a separate install**:
+ `curl -fsSL https://browser-use.com/profile.sh | sh`.
+- **`pageSize` caps at 100** silently — paginate via `pageNumber`.
+ `totalItems` in the envelope lets you size loops up front.
</file context>
| @@ -0,0 +1,222 @@ | |||
| # Browser Use Cloud — Programmatic Automation | |||
There was a problem hiding this comment.
P2: This skill is placed in a directory name that the current domain-skill resolver will never surface for cloud.browser-use.com/api.browser-use.com, so it is effectively undiscoverable through normal skill loading.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At agent-workspace/domain-skills/browser-use-cloud/cloud.md, line 1:
<comment>This skill is placed in a directory name that the current domain-skill resolver will never surface for `cloud.browser-use.com`/`api.browser-use.com`, so it is effectively undiscoverable through normal skill loading.</comment>
<file context>
@@ -0,0 +1,222 @@
+# Browser Use Cloud — Programmatic Automation
+
+`https://api.browser-use.com/api/v3` (REST). All five endpoints below were
</file context>
…n't abort the loop
A DNS/timeout/socket error during PATCH /browsers/{id} was bubbling out
of the loop, leaving remaining zombies running and still billing.
HTTPError is a subclass of URLError, so the existing clause stays first
and the URLError catch handles only the transport-level failures.
|
Thank you! |
Summary
Adds an operator-facing skill for the Browser Use cloud REST API
(
api.browser-use.com/api/v3) and a companioncleanup-zombies.pyscript. Covers the same wire surface
admin.pyalready speaks(
X-Browser-Use-API-Key,/browsers,/profiles), plus the mostcommon automation: stopping zombie sessions older than N minutes.
Why this style of skill
The README's contributor guidance says skills should be agent-generated.
This one takes a slightly different shape: it documents the
operator-facing REST surface that
admin.pyitself calls — there'sno browser DOM involved on the API path, so "what actually works in the
browser" partly doesn't apply. The provenance is still real:
cleanup-zombies.pyruns end-to-end(spawn → list → stop → re-list verified during authoring).
cloud.mdis from realresponses, not speculation.
I'm happy to follow up with an agent-driven complement (a
dashboard-navigation skill from real session capture) if you'd prefer
that style for this domain, or to scope this as
docs/instead ofdomain-skills/if the API-first framing isn't a fit.Live verification log (2026-05-05)
/profiles?pageSize=100&pageNumber=1/profiles/{id}cookieDomains=Noneobserved on a fresh profile/browsersliveUrlhost islive.browser-use.com(notcloud.browser-use.com)/browsers/{id}({action:"stop"})/browsers{items, totalItems, pageNumber, pageSize}/usage/Wire gotchas surfaced and documented
proxyCost,browserCost,proxyUsedMbneedfloat()cast before arithmetic.liveUrlhost islive.browser-use.com, separate fromcloud.browser-use.com; the cdp WebSocket is encoded as a?wss=query parameter.
cookieDomainscan beNoneon freshly-created profiles,contradicting
admin.py:list_cloud_profiles's docstring.GET /usagereturns 404 — per-session cost lives on each browserrecord; aggregate billing only on the dashboard.
Companion script live demo
--dry-runmode is the cheapest smoke test (noPATCH /stopcalls).Tests
The skill is a markdown + utility script; no harness code is touched.
Style refs
claude-ai/share-export).helpers.py:163's current logic resolvescloud.browser-use.comtocloud/rather thanbrowser-use-cloud/;the dirname here mirrors the hyphenated convention used by
claude-ai/,vercel/,tasksquad-ai/which are also notauto-discoverable today. fix(helpers): resolve domain skills for subdomains and hyphenated hosts #165 is the broader fix for that pattern.
Refs
run.pyprecedence fix in the sameBU_CDP_*/BROWSER_USE_API_KEYarea; the trap aboutBU_CDP_WSoverwrite iscross-referenced.
claude-ai/share-exportcompanion-script pattern thisfollows.
Summary by cubic
Adds an operator-facing Browser Use Cloud skill and a
cleanup-zombies.pyutility to stop stale cloud browsers. Documents the/browsersand/profilesREST surface used byadmin.py, with live-verified wire shapes.browser-use-cloud/cloud.mdforhttps://api.browser-use.com/api/v3:POST/GET/PATCH /browsers,GET /profiles,GET /profiles/{id};GET /usageis not public (404).cleanup-zombies.pyto stop sessions older than N minutes; supports--older-than,--dry-run,--json; continues on transient network errors during stop calls.X-Browser-Use-API-KeyfromBROWSER_USE_API_KEY.liveUrlhost islive.browser-use.com;cookieDomainsmay benull.Written for commit 3de7fe0. Summary will update on new commits.