Agent skill

Open Web Bridge Browser Control

by woniu9524 in woniu9524/open-web-bridge

Lets the agent operate your own logged-in browser through the owb command to read pages, fill forms, audit sites and capture network traffic.

MITAuto-check passedProductivity & Automation

Install Open Web Bridge Browser Control

skills CLI
$ npx skills add woniu9524/open-web-bridge --skill owb -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install woniu9524/open-web-bridge owb --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/woniu9524/open-web-bridge.git skills-src && mkdir -p .claude/skills && cp -r skills-src/owb-skills/owb .claude/skills/owb && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
owb
GitHub stars
121
Token cost
~8.1k tokens
SKILL.md length
4,222 words
Files
6 (incl. references)
Skills in repo
1
Repo updated
First seen
Licence
MIT

At a glance

Lets the agent operate your own logged-in browser through the owb command to read pages, fill forms, audit sites and capture network traffic.

  • Reading or comparing pages that need your existing login
  • SKILL.md covers How to use this document, Before you start, The shape of a task and Your tabs and the user's tabs, plus 11 more sections
  • Calls npm and node; reaches news.ycombinator.com
  • Filling a form or walking a multi-step flow in your real browser

What it does

The owb command-line tool controls the browser you are using right now, with your logged-in accounts, settings and open tabs. That gives the agent access to pages behind a login and to actions that need your identity. Because every step lands on a real account, the skill tells the agent to read freely, ask before changing anything, and open pages in new tabs so your current view is not taken over.

Work starts with a self-check that confirms the daemon and the browser extension are connected, and the agent is told to stop and ask you when the extension is not. The main file covers a core loop, and five reference files are read on demand: commands, recipes, debugging and reverse-engineering, field notes, and relay mode for remote control. The tool has about 80 commands in 16 groups, and the agent is told to look names up with owb help rather than guess.

When your agent uses it

  • Reading or comparing pages that need your existing login
  • Filling a form or walking a multi-step flow in your real browser
  • Debugging a broken front end or auditing responsive and accessibility behavior
  • Capturing network traffic to see how a request is built or signed

Example prompts

  • “Open my billing dashboard with owb and list the invoices from this quarter.”
  • “The checkout page on my site breaks at narrow widths. Check it in my browser and tell me why.”
  • “Capture the network requests when I submit the search form and explain how the request is signed.”

Requirements

  • The owb CLI from the open-web-bridge npm package
  • The Open Web Bridge extension connected to your browser
  • The owb daemon, which the first command starts

What it can do on your machine

Read from SKILL.md and the folder at commit 27c9ebe. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npm
    • node

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • news.ycombinator.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Open Web Bridge Browser Control loads about 8.1k tokens when it runs, and up to ~27k if it reads all its reference files. Until then it costs about 163 tokens; SKILL.md has 4,222 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~163
When it runs · the whole SKILL.md, loaded when a task matches
~8.1k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~27k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from woniu9524/open-web-bridge at commit 27c9ebe, republished under its MIT licence (© woniu9524). 4,222 words, ~8,111 tokens.

Download SKILL.mdSave it as .claude/skills/owb/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.
name
owb
description
Open Web Bridge (OWB) — drive the user's own real browser with the `owb` command. Read pages behind their existing logins, gather and cross-check information, fill forms, walk multi-step flows, debug their site, audit responsive/accessibility behavior, and capture or reverse-engineer network traffic. Use this whenever the user mentions Open Web Bridge or OWB by name, or a task involves "go look at this page", "pull these pages together", "do this for me on that site", "my site's frontend is broken", "how is this request signed", or anything at all that needs a logged-in session or a real browser environment rather than a plain HTTP fetch.

owb (Open Web Bridge) — driving the user's real browser

owb, the Open Web Bridge CLI, operates the browser the user is using right now: their logged-in accounts, their settings, their open tabs. That is why you can reach content that exists only behind a login, and complete actions that require an identity.

For the same reason, every step lands on a real person's account and they may be using this browser beside you. Read freely; ask before changing anything; open pages in new tabs so you don't take over what they are looking at.

How to use this document

In a hurry? Read "Before you start" → "The shape of a task" → "The core loop". This file is the trunk; five reference files live in references/, read on demand:

FileWhen to read it
references/commands.mdArguments, defaults, limits and return fields — check before writing a complex call instead of guessing argument names
references/recipes.mdLonger recipes for a specific job: extraction, clicking quirks, drag/canvas, downloads, site debugging, responsive audits, logins, flows
references/debugging.mdDebugging and reverse-engineering: capture, HAR processing, hooks, breakpoints, script patching, offline signature verification
references/field-notes.mdLong-tail oddities seen in the field (the "Reality check" table below is the symptom index — come here once a symptom matches)
references/relay.mdThe user asks about remote-controlling their browser, or daemon-status reports relay mode

For anything not documented here: this file cannot cover all 80 commands. owb help lists all 16 groups, owb help <group> expands one, and owb call <tool> --args '<json>' calls any underlying tool directly. Don't guess command names — look them up.

Before you start

bash
owb          # self-check
  • ✓ daemon + ✓ extension connected → go
  • ✗ extension not connected → stop and tell the user to click the extension icon in their toolbar and check its status. Hammering the tools will only produce NO_EXTENSION forever.
  • Command not found → npm i -g open-web-bridge, then owb setup
  • [owb] daemon not running, starting it… on stderr during the first command is not an error — the CLI is starting the daemon. Wait for it to connect; don't report it as a fault.

The self-check reports one of two modes: local (default; daemon and browser on one machine) and relay (browser on the user's machine, agent elsewhere, paired through a public relay). Local mode needs no configuration. Everything about relay mode — setup, capability differences, troubleshooting — is in references/relay.md.

The shape of a task

Read this section first. Individual commands are documented below, but if you don't know where a piece of work begins and ends, you will pile dozens of unrelated tabs into one place and have to close them one by one — measured: 25 tabs in a single session.

For multi-step work (anything beyond opening one page for a single look), the four steps are:

bash
owb task begin "competitor pricing research"  # ① open a task: creates a task group
owb open <url> --new-tab true                 # ② work: new tabs join that group
owb page / click / fill / wait                #    …normal operations
owb task end                                  # ③ close out: stop recording, archive, report tabs
owb tab close-group                           # ④ clean up: close every tab from this task

Each step earns its place:

StepWhat happens without it
task beginTabs pour into the shared scratch group, mixed with other tasks and with the user's own tabs
--new-tab trueYou navigate away from whatever the user is currently reading — this is a real person's browser, not yours
task endRecording keeps running and nothing is archived; flow save also fails with NEED_TASK
tab close-groupTabs accumulate without limit, and it gets progressively harder to tell whose is whose

⚠️ task end does not close tabs. It archives, clears task context and reports which tabIds were produced, but the pages stay open (sometimes you do want to keep the results visible). To actually clean up you must also run tab close-group. The word "end" does not mean what you would assume.

tab close-group closes the "OWB scratch" group plus every "task:" group; handoff groups are kept by default (that is the user's live workspace). To include them, pass --args '{"include_handoff":true}'. To close only the scratch group and keep task groups, pass --args '{"include_tasks":false}'.

A one-off look needs no task — owb open <url> --new-tab true is enough, and the tab lands in the "OWB scratch" group. The taskHint in the result tells you how many tabs are sitting there; a rising number is the signal to task begin.

⚠️ Losing task context has two consequences. Chrome reclaims idle MV3 service workers, and owb reload-ext or a daemon restart does the same; afterwards currentTask is gone. (1) The group survives but new tabs stop joining it and scatter into the scratch group — the symptom is tabs wandering off mid-task; just run task begin again (same title reuses the group). (2) task end reports NO_TASK and the task is never archived — though tab close-group still works, since it matches by group name. If you need the archive, confirm owb daemon-status still shows current_task before closing out.

🚨 Running several OWB missions at once (multiple agents/processes driving the same browser concurrently) is a different failure mode from the one above, and it's not idle recycling — it's contention. The daemon tracks "the current task" as one shared value, not one per caller. Whichever task begin runs last holds it; every earlier task's plain task end then either raises NO_TASK (if the pointer's since gone null) or — worse — returns ok:true while archiving someone else's task, with no error to catch it. New tabs opened in between two task begin calls get grouped under whichever task happened to be "current" at that exact moment, not the one that opened them — so tabs from different parallel missions end up scattered across each other's groups. Measured: 5 concurrent tasks, 5/5 hit this. What's fixed, and what still isn't:

  • task begin returns task_id — hold onto it, and pass it back as task end --task-id <id> instead of a bare task end. That reliably archives your task's metadata even if the pointer has moved on (the result carries ended_stale: true when it wasn't the live one) — but it does not retroactively fix which group your tabs already landed in.
  • task end's cleanup no longer reaches outside your task: it re-confirms ownership with the extension by task id before touching anything, and stops only the recorders on your task's tabs rather than every recorder in the browser. Tab ownership is tracked per task as you navigate, so it covers tabs you reused as well as ones you opened with --new-tab. If a recorder is running on a tab that genuinely isn't yours, task end leaves it alone and names it in recorders_not_archived — it is never silently dropped, but you do have to har save it yourself.
  • Still unfixed — skip tab close-group when other missions might be running. It closes by group name, and group membership is exactly what's unreliable under concurrency — it can just as easily close another mission's live tabs as your own. Track the tabIds you actually opened yourself and owb tab close --tab <id> each one individually (or batch them with owb seq) instead.
  • ⚠️ task end's result has group.cleared: true — that means the task context was cleared, not that any tab was closed (tabs_closed: false says so explicitly). Closing tabs is always a separate step.

Your tabs and the user's tabs

owb runs inside the browser the user is using right now, so there are always two populations of tabs. Confusing them means closing the user's work at best, and reading the wrong page without noticing at worst.

GroupColorWhoseCreated when
task: <title>cyanyours--new-tab after task begin
OWB scratchblueyours--new-tab with no active task (staging area)
✋ OWB waiting for youorangehanded to the userafter owb handoff (captcha, login)
ungrouped—the user's ownthey opened it; never touch these

Guardrail: owb tab close only permits the first three. Closing an ungrouped tab raises FORBIDDEN. That is protection, not a fault — when you hit it, first ask yourself "did I grab the wrong tabId?" rather than reaching for --force true.

⚠️ Never assume a tab is still the one you left there. The user may have navigated it elsewhere, and other automation may reuse it. Measured: after a gap, an old tabId used with eval to read a chess position returned a completely unrelated search results page — every command "succeeded" and every piece of data was wrong, which is far harder to catch than an error. Before reusing a tabId across turns, confirm with owb tab list (or owb tab find --url-pattern "<regex>"), or just open a fresh one.

The core loop: look → point → act

owb page turns the page into a numbered list, one @eN per interactive element, so you act by number instead of guessing CSS selectors.

bash
owb open https://example.com --new-tab true   # ← don't skip this, see below
owb page                      # @e1 @e2 … each with role, text, href
owb fill @e3 "keyword"
owb keys --keys Enter         # submit with a real Enter key
owb wait --text "results"     # wait for readiness, never sleep
owb click @e5

⚠️ --new-tab true is not optional. Skipping it navigates the user's current tab away from what they were reading. Only skip it when you specifically intend to operate on the current page.

💡 --active false opens the new tab in the background, so you don't steal their screen focus. Especially worth it when opening several pages to read.

🚨 But a background tab is not the active tab, so every later command needs an explicit --tab. Without --tab, page/eval/wait/click act on the active tab — which is not the one you just opened; it is the page the user is looking at. Skipping --tab does not produce an error, it produces a silent read of the user's private page treated as your task data (measured: open returned tabId A, and the very next page read the user's internal admin system).

bash
owb open <url> --new-tab true --active false   # → note the tabId in the result
owb page --tab <that tabId>                    # ← carry it on every command

The open result includes backgroundTabHint naming the tabId to use. With an active task, forgetting --tab raises AMBIGUOUS_TAB — but without an active task there is no such protection, which is one more reason to task begin for multi-step work.

Keyboard: owb keys

fill only sets a value; it produces no key events. Submitting a search, dismissing a dialog, or using a shortcut all require keys:

bash
owb keys --keys Enter                 # submit
owb keys --keys Escape                # close a dialog / exit fullscreen
owb keys --keys "ArrowDown ArrowDown Enter"   # space-separated, pressed in order
owb keys --keys "Ctrl+a"              # modifiers (Ctrl|Alt|Shift|Meta)
owb keys --text "typed text"          # insertText — produces no per-key events

⚠️ --text and --keys are mutually exclusive; passing both raises BAD_ARGS. To type and then press Enter, call it twice. Named keys and the full list are in references/commands.md.

Reading a snapshot

One line carries more than you might expect:

@e17 link "Technology" href=https://example.com/lists/65.html
@e2  textbox "Search models, datasets, users..."
@e48 textbox "< 1B 6B 12B" type=range
@e86 textbox "Filter by name" type=search
      checkbox "Subscribe to newsletter" checked
      link "Next page" href=... disabled
  • Links always carry href — even when the name is empty, the URL tells you where it goes. This is an underrated fallback.
  • Inputs carry type= (range/search/date/email…), and required, checked, disabled are all marked; <select> lists its values=[...].
  • iframes lists the page's iframes and shadowRoots reports how much content comes from Web Components (snapshots descend into open shadow roots). To act inside an iframe: owb frames for the list, then owb eval --frame-pattern <regex>; contextId:null frames are cross-origin and cannot be evaluated.
⚠️ Refs expire

After a navigation or re-render, old numbers stop working and report REF_STALE. Run owb page again for fresh numbers — don't retry with the old ones.

⚠️ Notice when a snapshot was truncated

Roughly a quarter of sites hit the cap on the first screen (default 20000 chars / 400 nodes); the result then carries truncated: true and omittedNodes. Either raise the cap or narrow the scope:

bash
owb page --max-nodes 1200 --max-chars 60000    # full detail (max-nodes caps at 2000)
owb page --mode article                         # article body only

Dense text-heavy sites hit the cap especially easily.

Saving tokens: incremental snapshots

After acting, do not re-read the whole page. Use --since-last to get only what changed:

bash
owb fill @e86 "qwen3"
owb wait --network-idle true
owb page --since-last true
# → added=54 changed=6 removed=62 unchanged=340

Only 54 new entries enter your context instead of 400 elements. Whether a long session survives comes down to this one habit.

Three ways to read — pick the right one

ModeUse forMain field
owb page (default snapshot)Acting on a page: finding buttons, filling forms, clicking linkslines
owb page --mode articleReading the body of an article page as clean markdowncontent
owb page --mode textList pages, irregular structures, when you want all the texttext

💡 All three modes also expose text as an alias for that mode's main field, so scripts can read text without switching field names per mode.

⚠️ List pages and forum front pages return 0 characters in article mode — they have no "article body"; that is correct, not a failure. The reason field on an empty result explains why.

💡 Body reads as 0 characters while hiddenContentNote says the DOM holds thousands → switch to --mode text, which falls back to textContent automatically and marks the result textSource: "textContent-fallback" (measured: article 3 chars → text 25161). ⚠️ That fallback is DOM order, not visual order, and includes navigation chrome — fine for reading, not for judging layout. Why it happens: references/field-notes.md, symptom C.

💡 Body nearly empty and the DOM really is empty too (title renders, content doesn't — typical of client-side-rendered pages): the result carries a _hint that says which case you are in — still loading (→ wait --network-idle), a bot-check interstitial (→ handoff), an SPA shell whose data never arrived (→ check net list), or content behind interaction / inside an iframe. Follow the hint instead of re-reading in a loop.

Waiting and timeouts

bash
owb wait --selector ".result-item"      # wait for an element
owb wait --text "128 results"           # wait for text
owb wait --url-pattern "search"         # wait for navigation
owb wait --network-idle true            # wait for requests to settle (best for SPAs)

Exactly one of the four; passing two raises BAD_ARGS. Never sleep.

⚠️ On SPAs, open returning loadCompleted:true does not mean the content has rendered. Measured: one news site returned complete in 2.3 seconds with only 6 elements in the snapshot. When a snapshot looks suspiciously small, run owb wait --network-idle true and read again.

⚠️ Three layers of timeout — the most common source of wasted effort
LayerArgumentDefaultCap
CLI waiting for the ctl result--timeout <seconds>120300
Tool-internal waiting--timeout-ms <ms>open 30000 / wait 10000 / wait-user 280000wait 110000
A single CDP callnone30 secondshardcoded, no argument changes it
  • ⚠️ --timeout is not forwarded to the tool; it only relaxes the CLI's wait for a result. To let owb open wait more than 30 seconds on a slow site, write --timeout-ms 60000. Writing --timeout 60 does nothing.
  • ⚠️ owb wait waits only 10 seconds by default, not indefinitely. For slow sites pass --timeout-ms 60000 explicitly.
  • ⚠️ When tool-internal waiting exceeds 110 seconds you must also raise --timeout, or you hit the 120-second envelope first (ctl call timeout). wait-user is the one exception — the CLI relaxes it automatically.
  • ⚠️ The 30 seconds that owb shot and owb eval can hit is the CDP hard limit; no argument helps. That is a different problem — see the Reality check table.

Common tasks

Longer recipes — structured extraction, live-data provenance, click vs click --mouse, dragging and canvas, rich text editors (ProseMirror-style), speeding up slow sites, downloads and uploads, debugging a site, responsive/accessibility audits, saving logins, recording flows, high-frequency step sequences (owb seq) — live in references/recipes.md. The few below are either used constantly or easy to get wrong.

Reading content that requires a login

The user's session is already in the browser, so just open it:

bash
owb open <article URL> --new-tab true
owb page --mode article

For multiple pages: owb page to find the "next page" number → owb click @eN → owb wait → read again.

Reading comment threads and forum discussions

Comments and replies are not article body — --mode article doesn't recognize them and returns 0 characters, while the default snapshot only draws structure (who posted how long ago, upvote/reply links) and never shows what was said. Skip snapshot and article for threads; go straight to text:

bash
owb open https://news.ycombinator.com/item?id=<id> --new-tab true
owb page --mode text        # measured: the whole thread is here; snapshot/article are empty

The same applies to Reddit posts, forum replies, and Q&A answer lists.

Cross-site synthesis and verification

The genuinely valuable pattern: pull a repository link from a paper page → open GitHub to read stars and recent commits → conclude whether the code actually exists and whether the project is alive. That conclusion requires more than one site; no single-site scrape produces it. Pair it with task begin to keep the whole chain in one group.

Show full SKILL.md (1,720 more words)Show less
Hitting a captcha, QR login, or a password prompt

Don't try to get around it, and don't fill in credentials. Hand it back:

bash
owb handoff --reason "Please complete the QR login on this page, then tell me"
owb wait-user --condition text --text "Sign out"    # ← wait for a post-login marker

⚠️ A bare owb wait-user waits for a URL change (condition: url_change by default) with a 280-second timeout. QR logins and SPA logins often don't change the URL — a bare call will silently wait almost five minutes and then time out. For logins, always pass an explicit condition: --condition text --text "<text that only appears after login>" or --condition selector --selector "<avatar or username selector>".

Then tell the user plainly what you need them to do. When they are done, confirm with owb page before continuing.

Debugging the user's own site

⚠️ net start must come before navigation, or you get orphan records with no URL. 🚨 But don't write it as bare owb net start then owb open <url> — without --tab, capture binds to the user's active tab and the open then navigates their page away. Get your own blank tab first:

bash
owb open about:blank --new-tab true --active false   # ① your own tab, note the tabId
owb net start --tab <id>                             # ② bind capture to it
owb open http://localhost:3000 --tab <id>            # ③ then navigate

⚠️ har save is the only command that stops AND keeps the recording. har discard also stops but throws the data away — it exists for abandoning a recording, never as a step before save (that reports NOT_RECORDING and the data is permanently lost).

The full ladder — HAR to replay scripts, HAR diffing, assertions, hooks, breakpoints, script search and patching, offline signature verification, TLS replay — is in references/debugging.md. Go there for "how is this parameter computed" questions. The rest of the recipe is in references/recipes.md.

Arguments and output

  • --foo-bar <value> → tool argument foo_bar; JSON-parsed when possible (--new-tab true is a boolean)
  • --tab <id> selects a tab; without it, the active tab is used
  • --out <file> is the on-disk path for screenshots and PDFs
  • --args '<json>' passes anything the flat aliases don't cover (highest priority)
  • Escape hatches: --raw for the full result envelope, --compact for single-line JSON, --no-autostart to skip starting the daemon, owb call <tool> --args '<json>' for any tool, owb cdp for raw CDP
  • owb seq "<step>" "<step>" … runs several steps over one process and connection — reach for it when a stretch of mechanical steps (game moves, multi-field forms) would otherwise pay ~100–200ms of spawn overhead each. Recipe in references/recipes.md, flags in references/commands.md
  • ⚠️ PowerShell: a bare @e3 is splatting syntax and silently vanishes before owb runs (symptom: a confusing BAD_ARGS) — always quote refs there: owb fill '@e3' 'x'. And Windows hosts that spawn processes without a shell can't execute the owb.ps1/owb.cmd shims — invoke node "<npm root -g>\open-web-bridge\owb-daemon\src\cli.js" instead. Both are detailed in references/commands.md under "PowerShell"

Success prints data JSON to stdout; failure prints one line error CODE: message to stderr with a non-zero exit code (2 for usage errors).

⚠️ Screenshots and PDFs always go to disk; stdout returns only {savedTo, bytes} rather than flooding your context with base64. For a full-page capture add --full-page true.

Full argument tables, return fields and the underscore-prefixed CLI metadata fields are in references/commands.md.

Reality check: symptom → judgment

These are not malfunctions; they are what a real browser does. The table indexes by symptom, with details in references/field-notes.md — go read the details once a symptom matches, rather than pulling all of it into context up front.

SymptomJudgment in one line
Floating buttons unrelated to the page (translate / bookmark / quick settings)Injected by another extension the user installed; extensionUiHidden only filters some. Don't click them
Animation frozen / video stuck at readyState:0 / game unresponsiveThe whole Chrome window lacks OS focus (not the tab being inactive). Run the focus diagnostic below
owb shot hangs the full 30 secondsFirst add owb eval "1+1" to fork: also times out = the tab is genuinely dead (close and reopen); instant = the window lacks focus (reopening won't help)
Empty snapshot with renderNoteThe tab isn't rendering; already auto-foregrounded and retried. renderNote says whether it is a content problem or window focus
403 / empty snapshot / httpErrorHintAnti-scraping refusal. Change approach; don't keep analyzing an empty snapshot
Everything reports FORBIDDEN and the page looks differentThe tab was replaced wholesale by an extension like OneTab. Confirm with tab list, reopen in a new tab
FORBIDDEN mentioning cannot be scripted, a chrome-extension:// URL, or an interstitialChrome structurally forbids debugging these (Web Store, chrome://, devtools://, other extensions' pages, security interstitials). Not a fault, retrying won't help — find another route, or have the user handle it in the browser
A PDF URL yields no body text in any modeChrome's PDF viewer lives in a separate sandboxed view — architecturally out of reach. Find an HTML version, or screenshot it
Garbage words like derosnopS in search resultsAnti-scraping decoy text (invisible to humans). Skip it as noise
Navigating to docs.google.com/**/create⚠️ Merely visiting creates a real file in the user's account, and a brand-new empty file cannot be trashed. Don't navigate to these URLs
stderr shows extension unreachable … retrying in N sThe MV3 worker was recycled. Normal — the command retries itself (about 35 seconds total) to success
Still NO_EXTENSION after the backoff finishesThis is not idle recycling; the script itself crashed and the heartbeat cannot wake it. Stop waiting and tell the user
Navigation is just slowMeasured across 219 sites: p50 4.7s / p90 15s / p99 30s. Beyond 30s it is usually the site — widen with --timeout-ms or use domcontentloaded

Window focus diagnostic (check both signals; one alone will misdiagnose):

bash
owb eval 'document.visibilityState + " hasFocus=" + document.hasFocus()'
  • Frozen rAF/animation/video → follow visibilityState (measured: hasFocus() true while visibilityState was still hidden, and rAF never fired)
  • shot hanging the full 30s → follow hasFocus() (measured: the page was visible while hasFocus() was false and the compositor produced no frames)

If either looks wrong, ask the user to bring the whole browser window to the foreground, rather than retrying or concluding the tool is broken. This is Chrome's power-saving design; there is no CDP-level workaround (Emulation.setFocusEmulationEnabled was tried and does not help — don't go down that road).

When something errors

ErrorMeaningWhat to do
NO_EXTENSIONExtension not connectedThe CLI already retried with backoff for ~35s; if it still fails, stop waiting (the script crashed and the heartbeat can't wake it) and ask the user to check the extension
REF_STALENumbers expiredRun owb page again
AMBIGUOUS_TABSeveral tabs match, or you gave no --tab and the active tab is the user's own pageowb tab list for ids, then pass --tab. The latter usually means you used --active false without --tab — use the tabId open returned
BAD_ARGSWrong or duplicated argumentsThe message lists the valid values; if unsure of an argument name, check references/commands.md
PAUSEDThe page is stopped at a breakpointowb debug resume
FRAME_NOT_FOUNDiframe not foundowb frames for the list; contextId:null frames are cross-origin and can't be evaluated
TIMEOUTBusy main thread (most common) / breakpoint / modalTry owb wait --network-idle true and retry; to wait longer use --timeout-ms (not --timeout). When even shot times out, first add owb eval "1+1" to fork the diagnosis
ctl call timeoutYou hit the CLI envelopeYou raised tool-internal waiting past 110s — also pass --timeout <seconds>
NEED_TASKNo active taskowb task begin "<title>" and retry
NOT_RECORDINGThe recorder was destroyedYou called har discard first; discard throws the recording away, and the data is gone — record again, then finish with har save alone
FORBIDDEN + interstitialChrome security pageNo workaround; the user must deal with the certificate warning
FORBIDDEN + not in an OWB-managed groupYou are closing a user's own tabThis is the guardrail, not a fault. Check the tabId with owb tab list; only consider --force true if it really should be closed

Command map

16 groups, 80 commands — names only, so you know what exists. Arguments are in references/commands.md, or run owb help <group>.

GroupCommands
coreopen back forward reload page shot click (--mouse for real mouse events) fill keys scroll eval wait frames status cdp
tabtab list / find / close / close-group
netnet start / stop / list / detail / initiator / capture
harhar start / save / discard / status / to-replay / diff / assert
hookhook preset / fn / remove / status / logs
debugdebug break-xhr / break-fn / break-remove / stack / step / resume / console; oracle is top-level (owb oracle, not owb debug oracle)
scriptscript list / source / search / patch / unpatch / watch / watch-remove
verifyverify signer / replay / evidence
cookiecookie get / set / delete
statestate save / load / list / delete (raw primitives: owb call export_state / import_state)
envenv set / reset / compare
filedownload, upload, pdf are top-level; only file fetch takes the file prefix
tasktask begin / end / list
flowflow save / run / list
humanhandoff, wait-user
daemondaemon-status, daemon-stop, reload-ext

The net/har/hook/debug/script/verify groups are the debugging ladder — see references/debugging.md.

Staying current

Versions iterate quickly, and a stale install is a real source of avoidable failures (this document itself is an installed copy that only updates on reinstall). After the session's main task is finished — once per session, not after every command — run:

bash
owb update check

This is a background chore, silent by default. Don't announce that you are about to check, and don't narrate the result — the only outcome worth a sentence to the user is an actual update. Three outcomes:

  • ✓ up to date → say nothing at all (no "already on the latest version", no mention that a check happened).
  • ? could not reach the npm registry → say nothing; never retry or troubleshoot this on your own.
  • ⬆ update available → the output lists the exact upgrade steps (npm i -g open-web-bridge@latest, then owb skill install to refresh this skill, then owb daemon-stop so the new daemon starts on the next command; a store-installed extension updates itself, a Load-unpacked one needs owb reload-ext). Tell the user a new version exists and offer to run the upgrade — run the steps only after they agree, then run owb to confirm both ✓s before reporting success.

Boundaries

These actions land on a real person's account, and many cannot be undone.

Ask the user first: sending messages, posting, commenting, sending email, submitting forms, placing orders or paying, deleting content, changing account settings, authorizing third parties.

Never do: enter passwords, verification codes or payment details (hand off instead), bypass human-verification challenges, open private pages unrelated to the task (direct messages, mail, billing).

Reverse-engineering and traffic analysis are for the user's own sites, or sites the user has explicitly asked you to investigate. Circumventing anti-abuse controls or breaking into someone else's system is out of scope.

Reading and browsing: just do it. For anything that changes state, say what you intend to do and wait for a yes.

© woniu9524, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 5 other files (references) in owb-skills/owb of woniu9524/open-web-bridge.

  • SKILL.md
  • references/commands.md
  • references/debugging.md
  • references/field-notes.md
  • references/recipes.md
  • references/relay.md

Open the folder on GitHubat commit 27c9ebe

Compare with similar skills

Open Web Bridge Browser Control next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Open Web Bridge Browser Control compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Open Web Bridge Browser Control this skillwoniu9524/open-web-bridge121—~8.1kAutomated safety check: PassMIT
Chrome Cdpaiguicai/MCP-Gateway158—~2.1kAutomated safety check: PassMIT
Dev Browser AutomationMemTensor/MemOS12k3 repos~1.7kAutomated safety check: PassApache-2.0
OpenCLI Adapter Authorjackwener/OpenCLI30k1 repos~3.4kAutomated safety check: PassApache-2.0
Skyvern Browser AutomationSkyvern-AI/skyvern23k1 repos~2.9kAutomated safety check: PassAGPL-3.0
OpenCLI Browser Controljackwener/OpenCLI30k2 repos~7.3kAutomated safety check: PassApache-2.0

Similar skills

  • Chrome Cdp

    aiguicai/MCP-Gateway

    Browser automation and debugging through bundled Chrome DevTools Protocol.

    158 GitHub stars~2.1k tokensUpdated 4 mo ago
    Productivity & AutomationAuto-check passed
  • Dev Browser Automation

    MemTensor/MemOS

    Automates a real browser through short TypeScript scripts that keep page state between runs, for navigating, filling forms, taking screenshots and extracting data.

    12k GitHub starsUsed in 3 repos~1.7k tokens
    Productivity & AutomationAuto-check passed
  • OpenCLI Adapter Author

    jackwener/OpenCLI

    Walks through writing an OpenCLI adapter for a new site or a new command on an existing one, from first recon and field decoding to coding and verification.

    30k GitHub starsUsed in 1 repo~3.4k tokens
    DevelopmentAuto-check passed
  • Skyvern Browser Automation

    Skyvern-AI/skyvern

    Picks the right Skyvern CLI command for a web task, from quick yes/no checks to reusable multi-page workflows, instead of falling back to plain page fetching.

    23k GitHub starsUsed in 1 repo~2.9k tokens
    Productivity & AutomationAuto-check passed
  • OpenCLI Browser Control

    jackwener/OpenCLI

    Drives a real Chrome window through the opencli CLI to inspect pages, fill forms, click through logged-in flows and extract data from structured command responses.

    30k GitHub starsUsed in 2 repos~7.3k tokens
    Productivity & AutomationAuto-check passed
  • Cloudflare Browser Rendering

    cloudflare/moltworker

    Official

    Drives headless Chrome through Cloudflare Browser Rendering over a CDP WebSocket to take screenshots, navigate and scrape pages, and record multi-page videos.

    10k GitHub stars~742 tokensUpdated 5 mo ago
    Productivity & AutomationAuto-check passed

Questions about Open Web Bridge Browser Control

What does Open Web Bridge Browser Control do?

Lets the agent operate your own logged-in browser through the owb command to read pages, fill forms, audit sites and capture network traffic. The owb command-line tool controls the browser you are using right now, with your logged-in accounts, settings and open tabs. That gives the agent access to pages behind a login and to actions that need your identity.

When should I use Open Web Bridge Browser Control?

Open Web Bridge Browser Control fits situations like: reading or comparing pages that need your existing login; filling a form or walking a multi-step flow in your real browser; debugging a broken front end or auditing responsive and accessibility behavior; capturing network traffic to see how a request is built or signed.

How do I install Open Web Bridge Browser Control in Claude Code?

Run `npx skills add woniu9524/open-web-bridge --skill owb -a claude-code`. Or copy the skill folder (owb-skills/owb in woniu9524/open-web-bridge) into .claude/skills/owb in your project. Claude Code loads it when a task matches its description.

How do I install Open Web Bridge Browser Control in Codex?

Run `npx skills add woniu9524/open-web-bridge --skill owb -a codex`. Or copy the skill folder (owb-skills/owb in woniu9524/open-web-bridge) into .agents/skills/owb in your project. Codex loads it when a task matches its description.

Can I use Open Web Bridge Browser Control in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add woniu9524/open-web-bridge --skill owb -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/owb, .gemini/skills/owb, .github/skills/owb and .opencode/skills/owb in your project.

What does Open Web Bridge Browser Control need to run?

Going by SKILL.md and its folder, Open Web Bridge Browser Control needs the command-line tools its instructions call (npm and node). Our summary lists: The owb CLI from the open-web-bridge npm package; The Open Web Bridge extension connected to your browser; The owb daemon, which the first command starts.

Does Open Web Bridge Browser Control access the network?

SKILL.md names 1 domain. In commands or code: news.ycombinator.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Open Web Bridge Browser Control safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Open Web Bridge Browser Control use?

Open Web Bridge Browser Control is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Open Web Bridge Browser Control use?

About 8.1k tokens (SKILL.md is roughly 32k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 19k tokens, read only when the agent opens those files.

What are the alternatives to Open Web Bridge Browser Control?

Skills that share tags, products or a category with Open Web Bridge Browser Control: Chrome Cdp (aiguicai/MCP-Gateway, 158 stars), Dev Browser Automation (MemTensor/MemOS, 12k stars), OpenCLI Adapter Author (jackwener/OpenCLI, 30k stars) and Skyvern Browser Automation (Skyvern-AI/skyvern, 23k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Open Web Bridge Browser Control?

woniu9524 (a GitHub user) maintains it in woniu9524/open-web-bridge, which has 121 GitHub stars. The repository was last updated on August 23, 2026.

Source: woniu9524/open-web-bridge on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.