8.5 KiB
Session Log — Firefox Browser Driver + claude-in-chrome Removal
User
- User: Mike Swanson (mike)
- Machine: GURU-5070
- Role: admin
Session Summary
Mike wanted out of Chrome-based browser automation: he dislikes Chrome and considers the claude-in-chrome MCP extension garbage. Two deliverables came out of the session — disable the Chrome connector across his Claude Code sessions, and build a Firefox-driven equivalent so that "look at a website / interact with it / collect the logs" requests run against his preferred browser.
Investigation showed claude-in-chrome is not a JSON mcpServers entry; it is a built-in Claude Code browser connector toggled by four top-level keys in ~/.claude.json (claudeInChromeDefaultEnabled, cachedChromeExtensionInstalled, hasCompletedClaudeInChromeOnboarding, and a chromeExtension paired-device record named "Browser 1"). The repo already contained a non-extension Chrome driver — .claude/scripts/cdp.py (DevTools Protocol) — built specifically because the extension had invisible windows and screenshots that never landed on disk. The task was therefore to add a Firefox sibling, not to fix the extension.
Built .claude/scripts/ff.py, a Playwright-based Firefox driver modeled on cdp.py's CLI. Because Firefox dropped most CDP support, the stateless "new connection per command" approach cdp.py uses against Chrome's debug port does not port. Instead ff.py launch spawns a small background daemon that holds one Playwright Firefox page on a persistent profile (~/.claude/ff-profile, so logins survive); the other subcommands are thin HTTP clients to it on localhost:9333. The daemon accumulates console and network logs for retrieval — directly serving the "collect the logs" use case. Commands: launch [url] [--headless], status, nav, shot, click, type, key, eval, console [--clear], network [--clear], stop.
Installed Playwright + the Firefox browser binary, then debugged two real bugs (see Problems). Verified end-to-end headless against example.com: launch, status, eval (returned "Example Domain"), screenshot (26 KB real PNG render confirmed visually), network capture (200 response logged), and console capture (caught an injected console.log). Disabled the Chrome connector in ~/.claude.json (backup saved) and documented the driver in a new memory reference. Finally committed and pushed the four .claude/ files via the Gitea Agent, deliberately excluding the unrelated guru-rmm submodule bump and guru-connect untracked dir.
Key Decisions
- Daemon architecture instead of cdp.py's stateless model. Firefox dropped most CDP support, so a long-lived Playwright page behind a local HTTP control port is the robust way to preserve the "nav now, screenshot later, page persists" UX and to accumulate console/network logs.
- Headed (visible) by default, persistent profile. Lets Mike log into authenticated apps once and keeps sessions. The standing rule that Claude never types passwords still holds regardless.
- Disable the connector via
~/.claude.jsonkeys, not by uninstalling the extension. FlippingclaudeInChromeDefaultEnabled/cachedChromeExtensionInstalledto false and dropping thechromeExtensionpairing is the in-config switch; takes effect on next Claude Code restart. - Installed Playwright into both Python 3.12 and 3.14.
pyhonors a script shebang, sopy ff.pyresolves to a different interpreter than barepy -c; installing into both makes the tool interpreter-agnostic. - Scoped the commit to the four
.claude/files only. Excluded theguru-rmmsubmodule pointer change and theguru-connectuntracked dir as unrelated. Bundled the pre-existing untrackedreference_antigravity_agy_not_headless.mdbecause its MEMORY.md index line was already interleaved in the same file edit — keeps the index non-dangling.
Problems Encountered
- Daemon died with
ModuleNotFoundError: No module named 'playwright'despite the launcher having it. Root cause: thepylauncher reads a script's shebang.ff.py's#!/usr/bin/env pythonmadepy ff.pyresolvepythonvia PATH → Python 3.12 (no playwright), while barepy -cused the default 3.14 (has playwright). The daemon inherited 3.12 viasys.executable. Fixed by installing Playwright + Firefox into Python 3.12 as well; both interpreters now work. A no-shebang probe script worked, which initially masked the cause. launchnever returned control / startup crashes were invisible. The detached daemon inherited the parent's stdout pipe, so the caller hung and any crash went unseen. Fixed by redirecting the detached child's stdio to~/.claude/ff-daemon.log(stdin=DEVNULL,stdout/stderr=logfile).- Push raced a Howard auto-sync commit. origin/main advanced (
5a9fe1bc) between commit and push; the Gitea Agent rebased the single commit on top (no content change) and pushed cleanly.
Configuration Changes
Created:
.claude/scripts/ff.py— Playwright Firefox driver (daemon + CLI)..claude/memory/reference_ff_firefox_driver.md— memory reference documenting ff.py.
Modified:
.claude/memory/MEMORY.md— added index line for the Firefox driver (and carried a pre-existing index line for the antigravity reference).~/.claude.json(machine-local, NOT in repo) —claudeInChromeDefaultEnabled=false,cachedChromeExtensionInstalled=false, removedchromeExtensionpairing. Backup:~/.claude.json.bak-prechrome.
Committed alongside (pre-existing untracked, bundled for index consistency):
.claude/memory/reference_antigravity_agy_not_headless.md
Installed (machine-local):
- Playwright 1.60.0 + Firefox browser binary into Python 3.14 and Python 3.12.
Credentials & Secrets
None created or discovered this session. The Firefox driver uses a dedicated persistent profile (~/.claude/ff-profile) and the standing rule remains: Claude does not type passwords; Mike logs into authenticated apps in the visible window himself.
Infrastructure & Servers
- Firefox driver control port:
localhost:9333(envFF_PORT). - Firefox profile dir:
C:\Users\guru\.claude\ff-profile(envFF_PROFILE). - Daemon log:
C:\Users\guru\.claude\ff-daemon.log. - Existing Chrome driver (cdp.py) debug port:
localhost:9222— unchanged. - Python interpreters on GURU-5070: 3.14 (
C:\Users\guru\AppData\Local\Programs\Python\Python314\python.exe,pydefault) and 3.12 (...\Python312\python.exe, selected bypy <shebang-script>).
Commands & Outputs
# Install Playwright + Firefox (run for BOTH interpreters)
py -m pip install playwright && py -m playwright install firefox
"/c/Users/guru/AppData/Local/Programs/Python/Python312/python.exe" -m pip install playwright
"/c/Users/guru/AppData/Local/Programs/Python/Python312/python.exe" -m playwright install firefox
# Driver usage
py .claude/scripts/ff.py launch example.com # visible (default); add --headless to hide
py .claude/scripts/ff.py status
py .claude/scripts/ff.py nav rmm.azcomputerguru.com
py .claude/scripts/ff.py shot D:/tmp/page.png
py .claude/scripts/ff.py eval "document.title"
py .claude/scripts/ff.py console # collected console/pageerror msgs (JSON)
py .claude/scripts/ff.py network # collected responses (JSON)
py .claude/scripts/ff.py stop
Verification output (headless example.com): status returned {"ok":true,"url":"https://example.com/","title":"Example Domain"}; shot wrote a 26303-byte PNG (confirmed a real render); network logged a 200; console caught an injected hello-from-ff.
Pending / Incomplete Tasks
- claude-in-chrome disable applies on the next Claude Code restart; the Chrome tools are still loaded in the current session. If they reappear after restart (the app re-persists
~/.claude.jsonstate), toggle off in the connectors UI or re-run the key edit after fully quitting. - Headed mode was not visually exercised this session (headless path proved Playwright Firefox works; headed is the same code with
headless=False). Worth a quick visible-window smoke test next time a real site is requested. - Optional: teach the
/rmmor site-review flows to prefer ff.py over cdp.py.
Reference Information
- Commit:
8a975978—feat(scripts): add Firefox driver (ff.py) via Playwright; disable claude-in-chrome(4 files, +330). - Push:
5a9fe1bc..8a975978 main -> main(origin). - Memory:
.claude/memory/reference_ff_firefox_driver.md(peer ofreference_cdp_chrome_driver.md). - claude-in-chrome backup:
C:\Users\guru\.claude.json.bak-prechrome. - Playwright version: 1.60.0.