# 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.json` keys, not by uninstalling the extension.** Flipping `claudeInChromeDefaultEnabled`/`cachedChromeExtensionInstalled` to false and dropping the `chromeExtension` pairing is the in-config switch; takes effect on next Claude Code restart.
- **Installed Playwright into both Python 3.12 and 3.14.** `py` honors a script shebang, so `py ff.py` resolves to a different interpreter than bare `py -c`; installing into both makes the tool interpreter-agnostic.
- **Scoped the commit to the four `.claude/` files only.** Excluded the `guru-rmm` submodule pointer change and the `guru-connect` untracked dir as unrelated. Bundled the pre-existing untracked `reference_antigravity_agy_not_headless.md` because 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: the `py` launcher reads a script's shebang. `ff.py`'s `#!/usr/bin/env python` made `py ff.py` resolve `python` via PATH → Python 3.12 (no playwright), while bare `py -c` used the default 3.14 (has playwright). The daemon inherited 3.12 via `sys.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.
- **`launch` never 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`, removed `chromeExtension` pairing. 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` (env `FF_PORT`).
- Firefox profile dir: `C:\Users\guru\.claude\ff-profile` (env `FF_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`, `py` default) and 3.12 (`...\Python312\python.exe`, selected by `py <shebang-script>`).

## Commands & Outputs

```bash
# 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.json` state), 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 `/rmm` or 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 of `reference_cdp_chrome_driver.md`).
- claude-in-chrome backup: `C:\Users\guru\.claude.json.bak-prechrome`.
- Playwright version: 1.60.0.
