Skip to content
Agentmart
Submit a tool

chrome-control

Invoke FIRST for blocked web access (Reddit, Instagram, Wirecutter/NYT, HTTP 403, bot checks, login/paywall stubs) and ANY browser task - Chrome, pages, tabs…

Skill by alexjmiller5

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/alexjmiller5-chrome-control

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Invoke FIRST for blocked web access (Reddit, Instagram, Wirecutter/NYT, HTTP 403, bot checks, login/paywall stubs) and ANY browser task - Chrome, pages, tabs, localhost, HTML, JS, clicks/forms, E2E tests, network, cookies, console, screenshots. Must load before any mcp__claude-in-chrome__* call; web-recon builds on it.

Use cases: frontend, testing, productivity

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Node.js package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/chrome-control

What's inside

Skill name
chrome-control
Description
Invoke FIRST for blocked web access (Reddit, Instagram, Wirecutter/NYT, HTTP 403, bot checks, login/paywall stubs) and ANY browser task - Chrome, pages, tabs, localhost, HTML, JS, clicks/forms, E2E tests, network, cookies, console, screenshots. Must load before any mcp__claude-in-chrome__* call; web-recon builds on it.
License
MIT
Instructions
576 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts
  • Instructions call the network

Agent Skills spec issues

  • body: 576 lines (spec recommends under 500)

Files (12)

  • SKILL.md
  • cdp-act.mjs · scripts/
  • cdp-allow · scripts/
  • cdp-eval.mjs · scripts/
  • cdp-group.mjs · scripts/
  • cdp-sniff.mjs · scripts/
  • click-target.mjs · scripts/
  • test-cdp-group-safety.mjs · scripts/
  • test-cdp-group.mjs · scripts/
  • test-cdp-output.mjs · scripts/
  • test-cdp-target.mjs · scripts/
  • test-click-target.mjs · scripts/

SKILL.md (first lines)

# Chrome Control

## When normal web access is blocked

If web search/open, fetch, curl, or another page reader returns a bot block,
HTTP 403, login/paywall stub, or empty JavaScript shell, open the exact URL
in the configured agent Chrome and read the rendered page before declaring
the source inaccessible or asking the user to paste it. For sites known to
block ordinary readers, such as Reddit, Instagram, and Wirecutter/NYT, go
directly to agent Chrome for page content; search tools can still find links.

Use the user's existing signed-in session and subscription access, with your
own session group and explicit target as described below. The persistent
browser can load content that anonymous fetches cannot. Verify the requested
article or post actually loaded; a challenge page is not source content.
If Chrome itself still needs login, MFA, a subscription, or a CAPTCHA,
follow the password-manager and human-handoff guidance below. Browser access
does not guarantee that every page will be available.

## The browser runs on the agent-Chrome host, not on this machine

When `$CHROME_CONTROL_HOST` is set (your machine config exports it), EVERY
browser task drives that host's shared agent Chrome - Tier 4 below: a
headed Chrome on its own data dir, fixed remote-debugging port, kept alive
as a login item, holding every login ever done in it. The Chrome on the
machine you are running on is off limits: driving it slows the user's own
laptop down. The ONE exception is a task literally about a tab the user
has open in front of them ("pull the HTML of this tab", "what does my
current tab say") - then Tier 1/2, locally, and nothing more.

```bash
H="$CHROME_CONTROL_HOST"; P="${CHROME_CONTROL_PORT:-9222}"
ssh -N -L 9223:127.0.0.1:$P "$H" &                 # once per session; 9223 locally so this machine's own Chrome (9222) is untouched
curl -s 127.0.0.1:9223/json/version | head -2      # alive?
S=~/.claude/skills/chrome-control/scripts
node $S/cdp-group.mjs "claude: <task>" https://example.com --port 9223         # your tabs (next section)
node $S/cdp-eval.mjs 9223 'document.title' --target <targetId>                  # = chrome-cli source/execute
node $S/cdp-eval.mjs 9223 --shot /path.png --target <targetId>                  # = screenshot
curl -s 127.0.0.1:9223/json/list | jq -r '.[]|select(.type=="page")|.id+" "+.url'   # = list tabs
```

When `$CHROME_CONTROL_HOST` is the literal `local`, the agent Chrome is on
this machine at `127.0.0.1:${CHROME_CONTROL_PORT:-9222}`: skip the ssh
forward, pass that port to every script, and expect no Allow sheet (that
Chrome runs on its own data dir). Everything else in Tier 4 applies
unchanged: own window and tab group per session, cleanup, no driving of any
other Chrome.

```bash
P="${CHROME_CONTROL_PORT:-9222}"
curl -s 127.0.0.1:$P/json/version | head -2
node $S/cdp-group.mjs "claude: <task>" https://example.com --port $P
```

If the configured host cannot be resolved or the SSH tunnel fails, diagnose
connectivity before declaring the host unavailable:

```bash
H="$CHROME_CONTROL_HOST"
tailscale status --json
ssh -G "$H" | rg '^hostname '
tailscale ping --c 1 --timeout 5s <resolved-hostname>
```

If the local Tailscale client is stopped or logged out, reconnect its existing
enrollment through its native UI or CLI, confirm `BackendState` is `Running`,
and retry the SSH tunnel once. Do not mint or reuse auth keys, change ACLs,
install or reconfigure Tailscale, or mutate the remote host from this skill.
If re-enrollment or other human authentication is required, stop and follow
the machine's documented recovery procedure. Do not fall back to the
laptop's local Chrome while the configured host is still unreachable.

There is no `chrome-cli` on the host - `cdp-eval.mjs --port` covers
source/execute/shot/trusted-click, `/json/list` covers tab listing. A dev
server on THIS machine is reachable from the host through a reverse
forward in the same ssh (`-R 5173:127.0.0.1:5173`, then open
`http://127.0.0.1:5173` there). A job that must outlive this session, or
the user stepping away, runs its driver on the host (Tier 4 rules). Human
steps (logins, CAPTCHAs) happen over Screen Sharing on the host, and stick.

## Every session gets its own window + tab group (MANDATORY)

Every tab you open lives in a window created for this session, inside a
tab group named after the session. Popups, OAuth redirects and
`target=_blank` pages spawned from those tabs land in the same window and
group (Chrome keeps a tab's children with it), so the user sees one
labelled cluster per agent session and never finds strays mixed into their
own windows. `scripts/cdp-group.mjs` does all of it:

```bash
G=~/.claude/skills/chrome-control/scripts/cdp-group.mjs   # add --port 9223 on the agent host; without it: local real profile (Tier 2)
node $G "claude: <task>" https://a.com https://b.com   # first call creates window + group, later calls add tabs to it
# -> window=<id> group=<id> tabs=<id,...> targets=<targetId,...>   tabs = Chrome/chrome-cli tab ids, targets = CDP ids, same order
node $G "claude: <task>"                                # no urls: sweep strays in the session window into the group
node $G "claude: <task>" --close                        # end of task: deletes the group, then closes its window and tabs
```

The name is `claude: <short task>`, the same string on every call. One
window per session is the rule; parallel drivers that genuinely need a
window each (several Maps windows at once) use one name per driver - that
is the only reason to have more than one.

**Group cleanup is part of finishing the task.** Keep every group name you
create and run `--close` for each before your final response, including when
a browser attempt fails or is abandoned. Follow "Close what you open" below.

How it works: CDP has no tab-group API, so the script opens a hidden
target on an installed extension's origin and calls `chrome.tabs` /
`chrome.tabGroups` from there. The profile needs an extension holding the
`tabGroups` permission - Claude in Chrome (the default `--ext`) does. A
dedicated agent profile gets it through Chrome policy (`ExtensionSettings`
in a root-owned plist under `/Library/Managed Preferences` on macOS, which
is Mandatory; the same key in the user's defaults domain is only
Recommended and ignored). Signing into the extension is a one-time human
step in that browser's window. Without `--port` the call goes through
the real profile (Tier 2, one auto-approved Allow sheet, ~2 s); with
`--port` it is prompt-free.

## Local tiers (the exception above, and the mechanics Tier 4 reuses)

From alexjmiller5/agent-config-public, MIT.

More from alexjmiller5/agent-config-public

Signals

Stars
0
Forks
0
Open issues
0
Last commit (this folder)
Oct 21, 2026 (7 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from alexjmiller5

Cite this page

chrome-control skill. Agent Mart. https://agentmart.dev/skills/alexjmiller5-chrome-control (last updated 2026-10-24)