dev-browser

repository·main·Indexed 27 days ago

https://github.com/sawyerhood/dev-browser

A CLI for controlling browsers with sandboxed JavaScript scripts, designed for AI agents and developers. It features a QuickJS WASM sandbox with a forked Playwright client, providing persistent page management and full Playwright API support. It includes specialized toolsets for AI interaction, such as pixel-based coordinates (page.cua), DOM-ID interaction (page.domCua), and AI-optimized page snapshots via page.snapshotForAI().

Tokens
9.5K
Snippets
19
Records
60
Agent score
91%

What's inside dev-browser

  1. Understand the Forked Playwright Client Architecture

    main

    The dev-browser uses a forked subset of Playwright's client-side code designed to run inside a QuickJS WASM sandbox. This allows sandboxed user scripts to use standard Playwright objects like Page, Frame, Locator, and ElementHandle without granting the sandbox direct access to the host filesystem, processes, or sockets.

    Execution Flow: User script $\rightarrow$ QuickJS sandbox $\rightarrow$ forked Playwright client $\rightarrow$ transport bridge $\rightarrow$ host Playwright dispatcher $\rightarrow$ real Playwright $\rightarrow$ browser

  2. Build the Sandbox Playwright Client Bundle

    main

    The sandbox client is built using esbuild from the bundle-entry.ts entry point. The resulting bundle is an IIFE that exposes the __PlaywrightClient global, which is then captured by the QuickJS sandbox.

    Build Configuration:

    • Entry point: bundle-entry.ts
    • Output: ../../../dist/sandbox-client.js
    • Format: IIFE
    • Global: __PlaywrightClient
    • Target: es2022
    • Platform: neutral (to ensure compatibility with the QuickJS environment)
    cd daemon && pnpm run bundle:sandbox-client
  3. Run browser automation scripts

    main

    You can run sandboxed JavaScript scripts using dev-browser. Use the --headless flag to launch a fresh Chromium instance.

    Linux/macOS

    dev-browser --headless <<'EOF'
    const page = await browser.getPage("main");
    await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
    console.log(await page.title());
    EOF

    Windows (PowerShell)

    @"
    const page = await browser.getPage("main");
    await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
    console.log(await page.title());
    "@ | dev-browser
  4. Use dev-browser for browser automation

    main

    Use the dev-browser CLI to control browsers using sandboxed JavaScript scripts. This tool is designed for tasks such as navigating websites, filling forms, taking screenshots, extracting web data, testing web applications, or automating browser workflows.

    To see all available commands and options, run:

    dev-browser --help
  5. Install dev-browser via npm

    main

    You can install dev-browser globally or run it using npx.

    Global Installation Installing globally via npm install -g dev-browser triggers a postinstall script that downloads the appropriate platform binary and patches shims to allow for zero Node.js startup time. After installation, you must run the install command to set up the necessary browser dependencies.

    One-off Execution You can run the tool without a permanent installation using npx. Note that this uses the Node.js wrapper, which results in a slightly slower startup compared to the global binary-patched version.

    # Global install (postinstall downloads binary, patches shims for zero Node startup)
    npm install -g dev-browser
    dev-browser install    # installs Playwright + Chromium
    
    # Or one-off via npx (uses Node wrapper, slightly slower startup)
    npx dev-browser --help
  6. Install dev-browser CLI

    main

    Install the dev-browser package globally via npm and then run the install command to set up Playwright and Chromium.

    Linux/macOS

    npm install -g dev-browser
    dev-browser install

    Windows (PowerShell)

    npm install -g dev-browser
    dev-browser install
  7. Pre-approve dev-browser in Claude Code

    main

    To prevent Claude Code from prompting for permission every time dev-browser is called, add it to the allow list in your settings.

    Per-project

    Add to .claude/settings.json in your project root:

    {
      "permissions": {
        "allow": [
          "Bash(dev-browser *)"
        ]
      }
    }

    Per-user (global)

    Add to ~/.claude/settings.json:

    {
      "permissions": {
        "allow": [
          "Bash(dev-browser *)",
          "Bash(npx dev-browser *)"
        ]
      }
    }
  8. Update the Forked Playwright Client

    main

    To update the forked Playwright client used in the sandbox, follow these steps to ensure upstream changes are correctly merged with sandbox-specific modifications:

    1. Clone Upstream: Clone the Playwright repository at the specific target tag or commit you wish to adopt. Avoid using version ranges in package.json; use a concrete revision.
    2. Diff Upstream Files: Compare the upstream files against the local directory. Focus on these paths:
      • packages/playwright-core/src/client/*
      • packages/playwright-core/src/protocol/*
      • packages/playwright-core/src/utils/isomorphic/*
      • packages/playwright-core/types/*
      • packages/protocol/src/channels.d.ts
    3. Reapply Local Changes: Manually reapply sandbox-specific edits. Be prepared for conflicts in files such as quickjs-platform.ts, bundle-entry.ts, and various files within src/client/ and src/protocol/.
    4. Rebuild: Rebuild the sandbox client bundle.
    5. Verify: Run the daemon test suite to ensure stability.
    6. Document: Update the version/provenance section in the README with the new upstream tag or commit.

    Practical Rules for Merging

    • Copy upstream code first, then reapply sandbox edits.
    • Explicitly stub new unsupported features instead of allowing them to fail silently.
    • If adding a new stubbed surface, use explicit runtime error messages to ensure sandbox users 'fail fast'.
    • Expect manual merge work if upstream changes affect screenshot path handling, Platform, or protocol type generation.
  9. Connect to a running Chrome instance

    main

    To control your existing Chrome browser, first enable remote debugging at chrome://inspect/#remote-debugging. Then use the --connect flag.

    Linux/macOS

    dev-browser --connect <<'EOF'
    const tabs = await browser.listPages();
    console.log(JSON.stringify(tabs, null, 2));
    EOF

    Windows (PowerShell)

    1. Start Chrome with the remote debugging port:
    chrome.exe --remote-debugging-port=9222
    1. Run the script:
    @"
    const page = await browser.getPage("main");
    console.log(await page.title());
    "@ | dev-browser --connect
  10. DOM-id workflow with page.domCua

    main

    The page.domCua workflow allows you to interact with elements using stable node_id values discovered via a snapshot.

    1. Snapshot: Call page.domCua.getVisibleDom() to get a list of visible interactive elements with their node_id.
    2. Act: Use page.domCua.click({ nodeId }) to interact with the specific ID.

    Important:

    • IDs are only valid for the current document snapshot. If the document changes or a navigation occurs, you must re-run getVisibleDom() to get fresh IDs.
    • The snapshot only includes elements currently in the viewport. Scroll to see more.

    Available page.domCua methods:

    • getVisibleDom(): Returns elements as node_id=N lines.
    • click({ nodeId, waitForNavigation? })
    • doubleClick({ nodeId })
    • scroll({ scrollX, scrollY, nodeId? })
    • type({ text }) (acts on focused element; click first)
    • keypress({ keys }) (acts on focused element; click first)
  11. Coordinate-based control with page.cua

    main

    The page.cua (Coordinate-based User Agent) workflow allows for visual, pixel-perfect interaction. This is useful when DOM selectors are unstable.

    1. Look: Take a screenshot using page.cua.screenshot() to get pixel coordinates and the image path.
    2. Act: Use the coordinates from the image to click, double-click, drag, or type.

    Note: Pixel coordinates on the saved image map 1:1 to page.cua coordinates. Always use a named page to ensure coordinates remain valid between scripts. Do not use full-page captures for coordinates; use viewport or clip screenshots and scroll if necessary.

    Available page.cua methods:

    • screenshot(options): Returns { path, width, height }. Options: { name?, fullPage?, clip? }.
    • click({ x, y, waitForNavigation? })
    • doubleClick({ x, y })
    • drag({ path: [{ x, y }, ...] })
    • move({ x, y })
    • scroll({ x, y, scrollX, scrollY })
    • keypress({ keys: string[] })
    • type({ text: string })
    // Script 1 - look
    const page = await browser.getPage("checkout");
    const shot = await page.cua.screenshot();
    console.log(JSON.stringify(shot));
    
    // Script 2 - act (using coordinates from Script 1)
    const page = await browser.getPage("checkout");
    await page.cua.click({ x: 412, y: 233 });
  12. Install dev-browser skills for AI agents

    main

    To allow AI agents (like Codex, Claude, or others) to use dev-browser effectively, install the embedded skill files.

    dev-browser install-skill --codex   # Installs to ~/.codex/skills/dev-browser/SKILL.md
    dev-browser install-skill --claude  # Installs to ~/.claude/skills/dev-browser/SKILL.md
    dev-browser install-skill --agents  # Installs to ~/.agents/skills/dev-browser/SKILL.md

    In non-interactive environments, running install-skill without flags updates all three locations.

    dev-browser install-skill --codex
    dev-browser install-skill --claude
    dev-browser install-skill --agents