# GrokBoy Playwright helper Install from this folder: `npm install && npx playwright install chromium`. JSONL stdin/stdout helper, one response per request with the same `id`. Rust owns one asynchronous helper per CLI session, checks IDs and a 60-second deadline, drains stderr and stops the process group on cancellation. A failed helper can be restarted. Modes: ```bash node browser_helper.mjs --self-test node browser_helper.mjs --cmd '{"op":"ping"}' node browser_helper.mjs # JSONL daemon ``` Operations: `ping`, `status`, `navigate`, `snapshot`/`dom`, `read_page`, `click`, `type`, `press`, `select`, `scroll`, `wait`, `tabs`, `upload`, `download`, `eval`, `handoff_prepare`, `close`. Use selectors or role/name, label, placeholder. `tab_id` selects a tab from `tabs`; `frame` identifies an iframe in that tab. `tabs` supports list/switch/close/new and popups get IDs automatically. `read_page` returns visible body text, source links and character pagination; snapshots expose controls and iframe selectors, omitting password values. `wait` waits on an element state or URL (default 10s, maximum 30s). `upload` targets a file input. `download` clicks a link and waits for the download to finish. Both check workspace paths; downloads require a new target path. Browser actions are DOM-based, not pixel automation. `GROKBOY_BROWSER_HEADED=1` launches visible Chromium. `handoff_prepare` opens/foregrounds a headed window; actual human input belongs to the CLI broker. `GROKBOY_BROWSER_PROFILE` is set by Rust to a session-specific directory. Profiles and a restricted-permission storage-state file retain login cookies (including session cookies); normal helper replies checkpoint this state. Existing context is re-observed on resume; in-flight effects after a crash remain uncertain. Run `python3 tests/browser_flow.py` from the repository root for real headless Chromium tests against local fixtures.