indrasvat/claude-code-skills · Archived

browsing-as-you

Drive ONE persistent, already-authenticated Chrome — the user's real logged-in sessions — over the DevTools Protocol, instead of spawning a fresh unauthenticated browser per task. Use when a task needs the browser SIGNED IN AS THE USER: screenshotting a logged-in page, filling a form, posting a comment, uploading a file, attaching an image to a GitHub PR, or driving an app whose API can't — Gmail, Google Docs/Drive, Cloudflare, X, GitHub, Devin, or any site the user is signed into. Prefer over …

First seen Jun 15, 2026

Installation

$ npx skills add indrasvat/claude-code-skills --skill browsing-as-you

Stronger alternatives

This repository is archived — consider an actively maintained alternative.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from indrasvat/claude-code-skills · top by installs.

npx skills add indrasvat/claude-code-skills

Browse all from indrasvat/claude-code-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 3
License LICENSE
Default branch main
Open issues 0
Status Archived

Skill metadata

Parsed from SKILL.md frontmatter.

Declared agents claude-code

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 9,413 B
  • docs SUMMARY.md 1,014 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 4 installs

SKILL.md

browsing-as-you

Run ONE long-lived, logged-in Chrome with remote debugging on; every agent and tool attaches to it. No per-task browser launches, no re-login, no macOS "Allow" prompts. Tabs and the window open in the background (open -g), never stealing focus.

Golden rule: never launch your own Chrome — attach to the shared instance at http://127.0.0.1:9222. Deep detail lives in reference/integration.md (setup, concurrency, triage) and reference/launchd.md (autostart).

1. Start (idempotent, concurrent-safe)

scripts/chrome-agent.sh start      # prints http://127.0.0.1:9222 when live

Triage: health → ok|down|wedged (exit 0|3|4) · doctor for diagnostics · recover a wedged one · stop/kill touch only the bridge profile (your real Chrome is safe). Full table + runbook: reference/integration.md.

Agent: bring it up yourself — don't bail, don't ask. If you land mid-task
and health is down/wedged, just run start (idempotent, concurrent-safe)
and, for a cookie site, seed (prompt-free — see §2); then carry on and
actually drive the browser. Reporting "the bridge was down" as a blocker, or
asking the user to start it, defeats the whole point of the skill. The user
should not be pinged for perms. The only human step is login (typing a
password), and only for the localStorage/SSO sites flagged in §2 — never for
plain cookie sites like GitHub.

2. Authenticate (the bridge starts logged out)

It uses a dedicated profile — it must, since Chrome 136 ignores the debug port on your default profile. Give it your sessions one of two ways:

scripts/cdp.py seed                     # import logins from your Default Chrome
scripts/cdp.py seed --filter github.com #   (cookies only; also --profile/--dry-run)
scripts/chrome-agent.sh login           # OR sign in once in the bridge (stop first)
Site type via seed durable answer
Normal cookie sites (GitHub, most SaaS, X) ✅ survives restart seed once
DBSC (Google, YouTube) live only — drops on restart login once
localStorage / SSO SPAs (Cloudflare, Devin) ❌ not covered — looks authed, renders sign-in login once

localStorage/SSO dashboards: prefer login, not seed. Cloudflare and
similar SPAs keep part of their auth in localStorage or a device-bound SSO key
that cookie-only seed can't carry. The catch: seed reports success, cookies
are injected, and location.href still reads as authed — but the SPA quietly
renders its sign-in screen (no redirect, so a URL check is fooled). Don't
trust a URL heuristic; confirm with a DOM probe:
cdp.py probe https://dash.cloudflare.com --front → `login-wall |
likely-authed. (--front` matters: CF's dash is visibility-gated and renders
blank in a hidden tab, which reads as unknown.) A login-wall after seed
means: run chrome-agent.sh login for that site.

seed is cookies-only and reads your real profile locally (nothing leaves the machine, nothing is written back). login creates the device key inside the bridge profile, so Gmail, Docs/Drive, X, and Cloudflare stay authed across restarts and reboots — verified. Adding a new site later: seed --filter <host> if you're already signed in there, else one login. At most one login per site, then it persists; an agent can't type your password — that's the only human step.

3. Drive it

Preferred: chrome-devtools-mcp pointed at the browser (--browser-url http://127.0.0.1:9222; setup in reference/integration.md). Or scripts/cdp.py:

Need Command
open background tab, wait for load cdp.py open <url> -w → prints targetId
open + foreground a visibility-gated SPA cdp.py open <url> --front -w
eval JS · screenshot · navigate cdp.py eval '<js>' -t <id> · shot out.png -t <id> · nav <url> -t <id>
trusted click (coords or selector) cdp.py click '#submit' -t <id> · click 240,180 -t <id>
trusted type (into focused / a selector) cdp.py type 'hello' -t <id> · type 'us-east' --into '[role=combobox]' --enter -t <id>
trusted key (Enter/Tab/Arrow…) cdp.py key ArrowDown -t <id> · key Enter -t <id>
auth probe (is it really logged in?) cdp.py probe <url> --front → `login-wall \ likely-authed \ unknown`
upload files to a GitHub issue/PR (no submit click) cdp.py --json gh-attach --repo o/r --pr 19 -f a.png -f b.log → asset URLs
foreground · close · sweep blanks cdp.py front -t <id> · close <id> · gc
isolated context cdp.py ctx new → open <url> --context <id> → ctx close <id>

Trusted verbs (click/type/key) use the CDP Input domain — real isTrusted events — so they drive react-select dropdowns, role=combobox widgets, and native checkboxes that ignore synthetic eval-dispatched events. click/type --into take a CSS selector (scrolled into view) or x,y coords.

--json (before the subcommand) for machine-readable output. Concurrency: each agent owns its targetId and passes -t; set CHROMEAGENTSTRICT=1 to make eval/nav refuse an implicit tab. Full rules: reference/integration.md.

GitHub attachments — safe two-phase upload

To attach local files (screenshots, logs, any file type) to a GitHub issue or PR without committing binaries to the repo, never drive the page's submit button: GitHub puts Close / Merge / Delete / Reopen / Submit-review controls right next to the comment box, and a broad "first enabled submit" selector can click a destructive one after the upload. Split it in two:

Phase 1 — upload only (browser), prints the user-attachments URLs:

cdp.py --json gh-attach --repo OWNER/REPO --pr 19 -f ./shot-1.png -f ./trace.log
#   --issue N for issues · --url <full link> · -t <tab already on the page>

gh-attach sets the files on GitHub's hidden file input over CDP and reads the URL(s) back from the composer — it issues zero clicks, so destructive controls are unreachable by construction. It fails closed: if the comment box isn't found (logged out / no permission) or a URL never appears, it restores the composer, leaves the page untouched, and exits non-zero. It uploads any file type (assets/<uuid> for images, files/<n>/<name> otherwise); it never posts.

Phase 2 — post the comment yourself via the API (no page button). gh-attach prints the ready line; it uses the issues endpoint (PR comments included):

gh api repos/OWNER/REPO/issues/19/comments -f body="$(...uploaded markdown...)"

Posting through the browser is intentionally unsupported — --allow-submit is
refused. Treat PR Close/Merge/Reopen/Delete as out of scope unless the user
explicitly asks. Self-test the helper logic with make test-browsing.

Guardrails

  • Be a good citizen. Human pace, not machine-gun. A CAPTCHA / "unusual

traffic" / interstitial is a STOP sign, not a retry trigger — back off and tell the user. Prefer official APIs for bulk work. A blank/stuck SPA is usually just a hidden background tab → --front, not bot detection.

  • Trusted input is not for CAPTCHA. click/type/key are for app forms,

not human-verification. click refuses any target inside a reCAPTCHA / hCaptcha / Cloudflare Turnstile widget (exit 2) — solving a challenge stays a human step. Don't try to coordinate-click around the guard.

  • Dedicated profile, loopback only. seed reads your real profile but never

writes to it; the debug port binds to 127.0.0.1 — never expose it. stop/ kill/recover only ever touch the bridge profile.

  • Real keychain by default so login is durable (one "Always Allow" at

most). CHROMEAGENTMOCK_KEYCHAIN=1 gives a prompt-free, seed-only browser.

  • Clean up tabs you open (gc / close).

Setup & autostart (human, once)

seed or login to authenticate, wire up chrome-devtools-mcp (reference/integration.md), and for hands-free use scripts/chrome-agent.sh autostart on — a self-pathing login LaunchAgent (Linux: systemd, see reference/launchd.md). Needs uv; chrome-devtools-mcp needs Node 22+; seed is macOS-only.