Install
$ agentstack add skill-vanducng-skills-browser-profile ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
browser-profile
A thin profile registry on top of Chrome's --user-data-dir + --remote-debugging-port. Solves three problems at once:
- Persistent state per logical user. Cookies, localStorage, IndexedDB, disk cache survive across runs.
- Manual access. You open the profile in real Chrome and log in / poke around without Claude involved.
- Programmatic access on the same window. Claude attaches via CDP using the existing
browseCLI — no separate Chromium spawn, no SingletonLock collision.
Why not Playwright launchPersistentContext? Because that path requires Playwright to own the browser lifecycle — you can't have a normal Chrome window on the same user-data-dir simultaneously. The CDP-attach pattern here lets both of you share one window.
When to use
- Frontend tests where re-running the login flow on every iteration is wasteful or impossible (MFA, SSO).
- Long-lived debugging sessions where you want to come back tomorrow and have the same logged-in dashboards.
- Hand-off flows: you log in manually, then ask Claude to drive the rest.
Not for: cloud-only / anti-bot use cases (use Browserbase contexts via vd:browser --context-id instead) or one-shot ephemeral scraping (just use vd:browser directly).
Prerequisites
- macOS with Google Chrome at
/Applications/Google Chrome.app(override viaBROWSER_PROFILE_CHROMEenv var). vd:browserskill installed (browseCLI on PATH) — used byattach.- Optional:
jqfor prettyprofile listoutput.
Quick start
SKILL="${CLAUDE_SKILL_DIR:-$(for d in "$HOME/skills/skills/browser-profile" "$HOME/.claude/skills/browser-profile" "$HOME/.agents/skills/browser-profile"; do [ -d "$d" ] && { echo "$d"; break; }; done)}/scripts"
# 1. Open a fresh profile manually (you'll log in once)
"$SKILL/profile-open.sh" retell-staging
# 2. In another shell — let Claude attach to that same window
"$SKILL/profile-attach.sh" retell-staging
# → equivalent to: browse env local
# 3. List profiles and their status
"$SKILL/profile-list.sh"
# 4. When done
"$SKILL/profile-close.sh" retell-staging
Naming convention: -. Examples: retell-staging, goclaw-admin, cnb-snowflake-ui.
Command reference
| Script | Purpose | |---|---| | profile-open.sh | Launch headed Chrome with the profile's user-data-dir and deterministic debug port. Creates the dir on first run. Refuses if already open. | | profile-attach.sh | Run browse env local so the browse daemon points at this profile. Probes the CDP endpoint first; suggests open if nothing is listening. | | profile-list.sh | Show all profiles with status (open / closed), port, dir size. | | profile-close.sh | Send SIGTERM to the Chrome PID for that profile, clear stale lock files. | | profile-export.sh [] | Dump cookies + localStorage as Playwright-compatible storageState.json for CI replay. Requires the profile to be open. | | profile-reset.sh | Destructive. Wipe the profile dir. Asks for confirmation. |
How port allocation works
Ports are deterministic from the profile name so attach doesn't need a registry file:
port = 9300 + (cksum(name) % 100)
Range 9300–9399 avoids the conventional 9222. If two names hash to the same port, open will fail loudly — rename one.
Profile directory layout
$HOME/.claude/browser-profiles/
├── retell-staging/
│ ├── Default/ # Chrome user data (cookies.db, Local Storage/, IndexedDB/, Cache/, …)
│ ├── DevToolsActivePort # written by Chrome on launch; contains the actual port + WS path
│ ├── SingletonLock # dangling symlink to "-"; may be stale after a crash
│ └── .browser-profile.pid # PID of the Chrome process we launched (for `close`)
└── goclaw-admin/
└── ...
SingletonLock is Chrome's own collision marker — a dangling symlink whose target encodes - (so -f/-e tests see nothing; only -L does). The scripts treat a profile as open only when that PID is a live Chrome whose command line carries this --user-data-dir; stale locks left by crashed sessions are cleared automatically on open.
Security
- Profile dirs are created with
chmod 700. Storage cookies are tied to your user account. - Never commit
$HOME/.claude/browser-profiles/to any repo. - Same applies to
storageState.jsonexports — those are bearer credentials. - The skill never prints cookies / tokens to stdout.
Integration points
vd:cookflows that hit authenticated dashboards — start a step withprofile-attach.shso thebrowseCLI is pre-pointed at the right session.vd:browser-trace— attaches as a third CDP client on the same target, gets a full trace without interfering. Use the profile's deterministic port as the trace target.vd:web-e2e— project-aware full e2e on top of these profiles: boot/health checks, auth-state probing, flows, and reports. The e2e config'sprofilefield names a profile managed here.- Playwright
storageStatefixtures — exportstorageState.jsononce, then any Playwright test (local or CI) gets the same identity via{ storageState: '' }.
Troubleshooting
| Symptom | Cause | Fix | |---|---|---| | open refuses: "profile already open" | A live Chrome owns this profile | Run profile-close.sh first, or use profile-attach.sh if you intended to share | | list shows no-cdp | Chrome is running but not answering on the deterministic port (launched without the debug flag, or another Chrome took over) | profile-close.sh then profile-open.sh | | attach says "no CDP endpoint" | Chrome not running on that port | Run profile-open.sh first | | Cookies disappear after sleep/wake | Service-worker eviction by Chrome | Re-login. Chrome's call, not ours. Open issue if reproducible. | | Port collision between two profiles | cksum hash collision | Rename one of them (e.g., add a -2 suffix) | | Chrome won't launch (corrupted profile) | Crash during last session | profile-reset.sh and re-login — wipes the whole dir |
Future (deliberately out of scope for MVP)
- Cross-platform Chrome path resolution (Linux, Windows).
- Registry JSON with
last_used, custom port overrides, descriptions. - Auto-renew expired cookies via headless re-login.
- Headless mode for CI — use
profile-export.sh+ PlaywrightstorageStateinstead; persistent-context headless is flaky upstream.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: vanducng
- Source: vanducng/skills
- License: MIT
- Homepage: https://skills.vanducng.dev
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.