Files
claudetools/.claude/memory/reference_ff_firefox_driver.md
Mike Swanson 8a9759789f feat(scripts): add Firefox driver (ff.py) via Playwright; disable claude-in-chrome
Add .claude/scripts/ff.py, a Firefox browser driver built on Playwright and
the Firefox sibling of the existing cdp.py Chrome driver. It runs a small
background daemon holding one Playwright Firefox page on a persistent profile,
controlled over localhost:9333, with subcommands launch/status/nav/shot/click/
type/eval/console/network/stop. Verified end-to-end (real screenshot, network
and console capture). This is now the preferred browser-automation path because
Mike dislikes Chrome and the claude-in-chrome extension (that connector was
disabled in ~/.claude.json this session - not a repo change).

Add memory reference_ff_firefox_driver.md documenting the driver and an index
line in MEMORY.md. The MEMORY.md change also unavoidably includes a pre-existing
adjacent index line for reference_antigravity_agy_not_headless.md, so that memory
file is bundled in to keep the index consistent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 18:50:45 -07:00

38 lines
2.5 KiB
Markdown

---
name: reference_ff_firefox_driver
description: Drive Firefox via Playwright (.claude/scripts/ff.py) — Mike's preferred browser; replaces the disliked claude-in-chrome extension
metadata:
type: reference
---
`.claude/scripts/ff.py` drives **Firefox** over Playwright — the Firefox sibling of
[[reference_cdp_chrome_driver]]. Mike dislikes Chrome and the `claude-in-chrome` MCP
extension, so when he asks to "look at a website / interact / collect the logs", use this,
not Chrome. (The Chrome connector was disabled 2026-06-06: keys `claudeInChromeDefaultEnabled`,
`cachedChromeExtensionInstalled` set false and `chromeExtension` pairing removed in
`~/.claude.json`; backup at `~/.claude.json.bak-prechrome`. Re-toggle in the connectors UI if it
reappears.)
**Why a daemon, not stateless like cdp.py:** Firefox dropped most CDP support, so cdp.py's
"new WS per command" trick doesn't port. `ff.py launch` spawns a background daemon holding ONE
Playwright Firefox page on a **persistent profile** (`~/.claude/ff-profile`, logins survive);
every other subcommand is a thin HTTP client to it on `localhost:9333` (env `FF_PORT`). The page
persists between calls (nav now, shot later) and the daemon accumulates console + network logs.
**Commands:** `launch [url] [--headless]` · `status` · `nav <url>` · `shot <out.png>` (real PNG to
disk → feed to `agy image-analyze`/Grok) · `click <x> <y>` · `type <text>` · `key <Key>` ·
`eval <js>` · `console [--clear]` · `network [--clear]` · `stop`. Default headed (visible) so Mike
can log into authenticated apps once; Claude still must NOT type passwords.
**Gotchas (both bit during build, 2026-06-06):**
- **`py` honors a script's shebang.** ff.py's `#!/usr/bin/env python` makes `py ff.py` resolve
`python` via PATH → **Python 3.12**, while bare `py -c` uses the default **3.14**. Playwright is
installed in BOTH now (`<py312>\python.exe -m pip install playwright` + `... -m playwright install
firefox`), so it's interpreter-agnostic. If `ModuleNotFoundError: playwright` recurs after a
Python upgrade, install playwright into whatever `py .claude/scripts/ff.py status` actually runs.
- The detached daemon's stdio is redirected to `~/.claude/ff-daemon.log` (NOT inherited) — otherwise
`launch` never returns control and startup crashes are invisible. Check that log if `launch` hangs.
Verified end-to-end 2026-06-06: launch→status→eval→shot (26KB real render of example.com)→network
(200 captured)→console (caught an injected log). See [[reference_cdp_chrome_driver]].