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>
2.5 KiB
name, description, metadata
| name | description | metadata | ||
|---|---|---|---|---|
| reference_ff_firefox_driver | Drive Firefox via Playwright (.claude/scripts/ff.py) — Mike's preferred browser; replaces the disliked claude-in-chrome extension |
|
.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):
pyhonors a script's shebang. ff.py's#!/usr/bin/env pythonmakespy ff.pyresolvepythonvia PATH → Python 3.12, while barepy -cuses 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. IfModuleNotFoundError: playwrightrecurs after a Python upgrade, install playwright into whateverpy .claude/scripts/ff.py statusactually runs.- The detached daemon's stdio is redirected to
~/.claude/ff-daemon.log(NOT inherited) — otherwiselaunchnever returns control and startup crashes are invisible. Check that log iflaunchhangs.
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.