chrome-bidi
Skill0 starsChanged 10 days agoMITView on GitHub
Use when a page must be opened, read, clicked, filled, screenshotted, printed or measured, checked at phone and desktop widths (/chrome-bidi), compared with its image files, or when a leftover Chrome or chromedriver must be closed.
In this repository12 other files it gives its agents.
- claude-model-effortSkill
- clean-codeSkill
- clean-commitsSkill
- drive-projectSkill
- limited-runSkill
- other-model-effortSkill
- progress-boardSkill
- resource-guardSkill
- stop-resume-agentsSkill
- strip-ai-tracesSkill
- using-git-worktreesSkill
- writing-skillsSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 26
Never stop a chrome.exe or chromedriver.exe whose command line lacks --remote-debugging-port=<your port> or --port=<your port + 1000>: it …
- Distinctive: line 31
Check free RAM, CPU and disk before a launch.
- Very specific: line 44
Read the result of shot rather than guessing from the DOM.
- Very specific: line 46
Check, replacing P and P1000 (empty output is the only good one):
- Very specific: line 62
Read each shot and the flagged image lines: blurry (file narrower than box times dpr), heavy (over twice the needed width), not loaded.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Chrome over WebDriver BiDi
The scripts start Chrome with a debugging port and a throwaway profile, a chromedriver of the same
version on port + 1000 (kept in bin/, downloaded from Chrome for Testing when the build differs),
and talk BiDi over a websocket. Call every script as
python -I "<skill dir>/scripts/<name>.py" with forward slashes. Stdlib only. A failure prints
chrome-bidi: <Type>: <message> and a by hand: line, exit 1.
Scripts: launch.py (start, prints the port), bidi.py (one action on a running Chrome),
measure_images.py (box of every displayed image per width, JSON), visual_test.py (the /chrome-bidi run).
Rules
These hold for every task, whatever the page.
- Pick the mode yourself and never ask about it.
--visiblewhen a person has to see or act in the window: a sign-in, a code or phone check, the user saying they want to watch. Headless for everything else (reading, checks, screenshots, /chrome-bidi). - One port per task, never shared. Profile
<temp>/claude-skills/chrome-<port>, downloads inchrome-<port>-downloads, session inchrome-<port>.session. Never the user's profile. - Never stop a
chrome.exeorchromedriver.exewhose command line lacks--remote-debugging-port=<your port>or--port=<your port + 1000>: it belongs to the user or another session. Never move, hide, resize or close a window you did not start. - Native input only (
input.performActions,input.setFiles, WebDriver element calls). JavaScript reads the page, it never clicks, types or scrolls. - Check free RAM, CPU and disk before a launch. One Chrome at a time per session.
- Close with
bidi.py close --port Pbefore the task ends, then check nothing is left.
Procedure
Three steps, from launch to reading the result.
python -I "$S/launch.py" --url "http://127.0.0.1:3000"withS=<skill dir>/scripts. Port picked in 9300-9899 when--portis missing; reuse a fixed port only to get back a signed-in profile. Options:--size 1280x720(content area),--profile <dir>,--prompt dismiss|accept|ignore(unanswered alert,dismissdefault),--visible,--desktop,--login.python -I "$S/bidi.py" <action> [value] --port P [--tab n] [--frame <url part>] [--timeout s]. Each call reconnects to the same session. One call at a time per port.- Read the result of
shotrather than guessing from the DOM. python -I "$S/bidi.py" close --port P.Check, replacing
PandP1000(empty output is the only good one):powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter \"Name='chrome.exe' or Name='chromedriver.exe'\" | ? { \$_.CommandLine -match 'remote-debugging-port=P(?!\d)|--port=P1000(?!\d)' } | Select ProcessId,Name"
/chrome-bidi
/chrome-bidi <url or local folder> [widths].
python -I "$S/visual_test.py" "<target>" 390,1440. Widths default to 390,1440, height 720 (--height),--visibleonly if the user wrote it. A local folder or file is served on 127.0.0.1 during the run.- Output goes to
<project>/.ia/chrome-bidi/<date-time>/(shot-<width>.png,images.json),.ia/added to.git/info/exclude. Project is the git root of the target, or of the current folder for a url; with none,<temp>/claude-skills/chrome-bidi/. - Read each shot and the flagged image lines:
blurry(file narrower than box times dpr),heavy(over twice the needed width),not loaded. - Answer in a few lines: what breaks at which width, images to resize, the folder. The script already closed Chrome; run step 5 with the port it printed.
Image measures alone
python -I "$S/measure_images.py" --url "<url or folder>" --widths 390,1440 --out "<file.json>"Per image and width: width, dpr, src, kind (img or background), box (content box for
<img>, padding box for a background, CSS px), natural, fit, selector. Empty boxes are
skipped; lazy images are made eager and awaited up to 5 s.
Sign-in a human has to type
Google and Microsoft refuse a driven browser: launch.py --port <p> --login --visible --url <page>,
no remote control. The user signs in and closes the window; start again on the same port without
--login, the profile keeps the session.
Window mode (--visible)
Chrome opens maximized on the virtual desktop of the host window when the VirtualDesktop
PowerShell module is there and that desktop can be found, else on the desktop shown now. Nothing to
ask. --desktop <n> forces one. Never call viewport or mobile in this mode.
Actions
Two-part values use |. A selector starting with / or ( is xpath, else CSS.
- Tabs:
nav <url>(reuses the tab on the same host, else a blank one, else a new one; prints the index for--tab),newtab [url],tabs,activate,closetab(refuses the last),url,back,forward,reload,close. - Reading:
wait <selector>(polls up to--timeout, 10) orwait <n>,find <css>,xpath <query>,text [selector],html [n chars],eval <expression>(read only),console [s](messages logged after the call),network [s] [all](reloads, failures only withoutall),cookies,clearcookies. - Input:
click <css>,clickxpath <xpath>,clickxy x,y,hover x,y,scroll [delta][@x,y],type [text](stdin when empty, for a password),key <name>[ xN](enter tab escape up down left right backspace delete ctrl shift, combos likectrl+a),upload <selector>|<path>,prompt accept|dismiss[|text],rejectcookies,fill <selector>|<text>(stdin when no text),select <selector>|<option text>.fillandselectare WebDriver element calls, top page only. - Capture:
shot <png>,fullshot <png>,elementshot <selector>|<png>,pdf <file>. - Emulation, then reload:
viewport WxH,mobile(390x844, ratio 3, Android UA),desktop,geo lat,lon|off(page origin only),locale <fr-FR|off>,timezone <Europe/Paris|off>.
Traps
Each of these has cost a run before.
- Git Bash rewrites an argument starting with
/: prefix withMSYS_NO_PATHCONV=1or write(//button)[1]. shotkeeps 720 px of height at most; a taller viewport is scaled down and the factor printed. Multiply coordinates read on the image by it beforeclickxyorhover.--prompt dismisscloses an alert beforepromptcan answer: launch with--prompt ignore.clickandfilltake the first match; a hidden duplicate gives "element not interactable". Narrow the selector, orclickxythentype.- A native
<select>menu and the Windows "Save as" dialog live outside the page: useselect; downloads land inchrome-<port>-downloads. - In a covered window
document.visibilityStateishiddenand keys get lost;fillstill works. - One
navper page.reloadrestarts loaders and can replay an expired sign-in: usewait <selector>orshotto see a change. - The profile refuses geolocation, notifications, camera, microphone and third-party cookies.
- The WebDriver HTTP API of the session stays open (id in
chrome-<port>.session, endpoints underhttp://127.0.0.1:<port+1000>/session/<id>/). Use it only for a missing action, neverDELETEthe session:closedoes it. - Web chat app: take the "open the app anyway" link, the "open in the browser tab" one can loop.
Ticket app: a
scrollplaced on the conversation panel moves it.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

