pire-browser
Cross-platform Pi extension and Firefox bridge for local browser automation
Package details
Install pire-browser from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pire-browser- Package
pire-browser- Version
0.2.2- Published
- Jun 4, 2026
- Downloads
- 364/mo · 27/wk
- Author
- ryenw
- License
- MIT
- Types
- extension, skill
- Size
- 313.7 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"pi/extensions/pire-browser.ts"
],
"skills": [
"skills"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pire-browser
Firefox automation for AI agents. pire-browser gives Pi and shell-based agents a local CLI for launching Firefox, inspecting pages, clicking and filling by stable refs, handling downloads/uploads, and reusing logged-in Firefox profiles.
It intentionally does not use BiDi or CDP. Firefox loads a WebExtension, the WebExtension talks to a native messaging host, and the CLI talks to that host through current-user IPC: Windows named pipes on Windows and Unix domain sockets on macOS/Linux.
Installation
Pi Package
Install the public Pi package:
pi install npm:pire-browser
If you previously installed from GitHub, the npm installer migrates the known legacy
git:github.com/ryenwang/pire-browser entry out of Pi settings so Pi does not load
two pire-browser tools. If you still see a conflict, run:
pi remove git:github.com/ryenwang/pire-browser
pi install npm:pire-browser
Then start Pi and ask it to use the pire-browser tool:
pi
Use pire-browser to open https://example.com and snapshot the page.
Global CLI
Install the command directly:
npm install -g pire-browser
pire-browser install
install registers the Firefox Native Messaging host for the current OS user. npm install also runs best-effort setup, but it is safe to run again. setup remains available as the lower-level setup command.
Project Install
For projects that want to pin the version:
npm install pire-browser
npx pire-browser install
If optional dependencies are disabled with --omit=optional, reinstall with optional dependencies enabled. The root package uses a small JS launcher plus one native optional package for your OS/architecture, such as @ryenw/pire-browser-win32-x64, @ryenw/pire-browser-darwin-arm64, or @ryenw/pire-browser-linux-x64.
From Source
Requires Node.js, npm, Rust, and Firefox.
git clone https://github.com/ryenwang/pire-browser
cd pire-browser
npm install
npm --prefix extension install
npm run build:extension
cargo build
cargo run -p pire-browser-cli -- setup
Build a platform package binary pair:
node scripts/build-platform.mjs win32-x64
Use the tuple for your platform: win32-x64, win32-ia32, win32-arm64, darwin-x64, darwin-arm64, linux-x64, or linux-arm64.
Requirements
- Firefox.
- Pi 0.75.4 or newer when installing as a Pi package.
- Supported public beta targets: Windows x64, Windows x86, Windows ARM64, macOS x64, macOS ARM64, Linux glibc x64, and Linux glibc ARM64.
- Alpine/musl Linux is not part of the beta.
On Linux, distro Firefox builds work best. Snap and Flatpak Firefox are detected, but sandboxed native messaging may require the WebExtensions portal or a non-sandboxed Mozilla Firefox build.
Custom Firefox Path
If Firefox is installed somewhere unusual:
pire-browser setup --firefox-path /path/to/firefox
PowerShell example:
$env:PIRE_BROWSER_FIREFOX_PATH = "D:\Apps\Mozilla Firefox\firefox.exe"
pire-browser setup --firefox-path $env:PIRE_BROWSER_FIREFOX_PATH
Quick Start
pire-browser open https://example.com
pire-browser snapshot -i --compact
pire-browser snapshot -d 3
pire-browser snapshot -i -c -d 5
pire-browser click '@e1'
pire-browser wait '@e1'
pire-browser fill '@e2' "hello@example.com"
pire-browser find role button --name "Submit" click
pire-browser wait --selector "#done"
pire-browser screenshot page.png
pire-browser close
PowerShell treats @ specially, so quote refs such as '@e1'.
Use semantic locators when you do not want to manage refs manually:
pire-browser find label "Email" fill "hello@example.com"
pire-browser find text "Continue" click
pire-browser find text "Save" --exact
pire-browser find role button --name "Submit" click
Use --json when another tool or agent needs structured output.
Commands
Setup And Diagnostics
pire-browser status
pire-browser status --json
pire-browser doctor
pire-browser doctor --json
pire-browser install
pire-browser install --firefox-path /path/to/firefox
pire-browser setup
pire-browser setup --firefox-path /path/to/firefox
status and doctor are observational. Browser commands that need auto-launch can run lazy setup when native host registration is missing or mismatched.
Configuration Defaults
# from a project that has ./agent-browser.json
pire-browser open https://example.com
pire-browser --config ./ci-config.json open https://example.com
AGENT_BROWSER_CONFIG=./ci-config.json pire-browser open https://example.com
pire-browser loads agent-browser-style JSON defaults from ~/.agent-browser/config.json, ./agent-browser.json, AGENT_BROWSER_CONFIG, and explicit --config, in that order. CLI flags override config defaults. Missing auto-discovered files are ignored; malformed auto-discovered files warn and continue. Explicit config paths must exist and contain a JSON object.
Supported camelCase defaults include json, profile, sessionName, session, allowedDomains, noAllowedDomains, actionPolicy, confirmActions, confirmInteractive, allowFileAccess, headed, headless, colorScheme, maxOutput, engine, provider, and model. Unknown keys are ignored for forward compatibility.
For editor autocomplete, add the packaged schema path:
{
"$schema": "./node_modules/pire-browser/schema/agent-browser.schema.json",
"json": true,
"sessionName": "work"
}
Browser Lifecycle
pire-browser launch
pire-browser launch --url https://example.com
pire-browser open https://example.com
pire-browser open --init-script ./before-load.js https://example.com
pire-browser --allow-file-access open file:///path/to/page.html
pire-browser open https://example.com --new-tab
pire-browser tab new https://example.com
pire-browser window new
pire-browser goto https://example.com
pire-browser navigate https://example.com
pire-browser close
launch starts a managed Firefox profile. open, goto, and navigate open a URL, auto-launching the managed Default profile when no live session exists. open --new and open --new-tab create a new tab. For a separate Firefox window, run pire-browser window new, then pire-browser open <url>. --allow-file-access supports opening local HTML file URLs; PDF local-file behavior is tracked separately. open --init-script <path> may be repeated and registers best-effort Firefox document-start scripts for that navigation.
The default launch engine is web-ext, including public packages. The direct Firefox/XPI path is release-validation-only for now:
PIRE_BROWSER_EXTENSION_MODE=xpi pire-browser launch
Unsigned XPI testing is local-only and requires Firefox Developer Edition or Nightly plus:
PIRE_BROWSER_EXTENSION_MODE=xpi PIRE_BROWSER_ALLOW_UNSIGNED_XPI=1 pire-browser launch
Inspect And Act
pire-browser snapshot -i
pire-browser snapshot -i -c -d 5
pire-browser click '@e1'
pire-browser fill '@e2' "hello"
pire-browser type '@e2' "hello"
pire-browser press Enter
pire-browser wait '@e1'
pire-browser wait --selector "#done"
pire-browser wait --text "Saved"
pire-browser wait --load networkidle
pire-browser mouse move 80 80
pire-browser mouse wheel 400
pire-browser drag '@e1' '@e2'
pire-browser auth save app --url https://example.com/login --username user --password pass --username-selector "#email" --password-selector "#password" --submit-selector "button[type=submit]"
pire-browser auth login app
pire-browser screenshot out.png
Use wait --load networkidle after navigation on dynamic apps when the next
step depends on fetch/XHR work settling before snapshot -i or screenshot.
Refs are short lived. Re-run snapshot -i after navigation, reloads, DOM changes, dialogs, downloads, uploads, or failed actions.
Batch Execution
pire-browser batch "open https://example.com" "snapshot -i" "screenshot result.png"
pire-browser batch --bail "open https://example.com" "click '@e1'" "screenshot result.png"
echo '[["open","https://example.com"],["snapshot","-i"],["click","@e1"]]' | pire-browser batch --json
Use batch to run short multi-step workflows with one CLI invocation. --bail stops and returns the first command error. With no inline commands, batch reads an agent-browser-style JSON array from stdin; entries can be command strings or arrays of args.
Responsive QA
pire-browser set viewport 1280 720
pire-browser snapshot -i --compact
pire-browser screenshot desktop.png
pire-browser set viewport 390 844 3
pire-browser snapshot -i --compact
pire-browser screenshot mobile.png
set viewport <w> <h> [scale] follows agent-browser's command shape, but Firefox WebExtensions can only resize the browser window to approximate the content viewport. The JSON result includes the requested size and measured viewport.page.innerWidth/innerHeight; use that measurement before relying on pixel-perfect screenshots. Device, geo, offline, and credentials remain unavailable on this backend.
pire-browser --color-scheme dark open https://example.com
pire-browser set media light
--color-scheme dark|light|auto and set media dark|light|auto apply Firefox's webpage content color-scheme override for the managed session.
Header Auth
pire-browser open https://api.example.com --headers '{"Authorization":"Bearer token"}'
pire-browser set headers '{"X-Custom-Header":"value"}'
pire-browser open https://api.example.com/dashboard
open --headers <json> applies headers to the opened URL's origin for the current managed Firefox session. set headers <json> applies headers to the active page's origin; pass {} to clear that origin. Header values are not echoed in command output, and origins are kept separate so headers for one host/port are not sent to another.
Semantic Find
pire-browser find role button --name "Submit"
pire-browser find role button --name "Submit" click
pire-browser find label "Email" fill "hello@example.com"
pire-browser find text "Sign in" click
pire-browser find text "Save" --exact
pire-browser find placeholder "Search" fill "pire-browser"
Supported locator families include role, label, text, placeholder, alt, title, testid, first, last, and nth. Use --exact when nearby text would otherwise create substring matches. Chained actions include click, fill, type, hover, focus, check, uncheck, and text.
Init Scripts
pire-browser open --init-script ./before-load.js https://example.com
pire-browser addinitscript "window.__flag = true"
pire-browser removeinitscript init1
open --init-script applies to one navigation. addinitscript registers a document-start script for future navigations in the current managed Firefox session and returns an id for removeinitscript. This is a best-effort Firefox WebExtension compatibility path; verify with a fresh snapshot or page state.
Tabs
pire-browser tabs list
pire-browser tabs select t1
pire-browser tabs close t1
pire-browser open https://example.com --label docs
Tab ids are stable strings such as t1, t2, and t3.
Sessions
pire-browser session list
pire-browser session list --json
pire-browser session attach <session-id>
pire-browser session cleanup
pire-browser --session <session-id> snapshot -i
pire-browser --profile Work open https://example.com
pire-browser profiles --json
pire-browser --session work open https://example.com
pire-browser --session-name work open https://example.com
pire-browser --session-name work snapshot -i
pire-browser --session-name work close
--profile <name-or-path> is the preferred agent-browser-style reusable profile spelling. It may launch or reuse a managed Firefox profile when the command can auto-launch. AGENT_BROWSER_PROFILE=<name-or-path> supplies the same default when no explicit profile/session flag is present. Path-like profile values such as ~/.myapp-profile are mapped to stable managed Firefox profile names under the pire-browser data directory; they are not used as raw Chrome profile directories.
--session <name> remains an agent-browser-style named-session alias for the same managed profile behavior, and AGENT_BROWSER_SESSION=<name> supplies that default. --session <uuid> targets a strict live session id from session list. --session-name <name> and AGENT_BROWSER_SESSION_NAME=<name> remain supported as explicit named-profile spellings.
Profile names may contain letters, numbers, internal spaces, _, -, and .. Empty names, path traversal, slashes, and : are rejected.
Downloads
pire-browser snapshot -i
pire-browser download '@e4' ./downloads/report.txt
pire-browser click '@e4'
pire-browser wait --download ./downloads/report.txt --timeout 60000
Firefox downloads are staged under the OS app-data pire-browser/downloads directory for managed profiles, then moved to the requested destination. Destinations must not already exist. Action policy and confirmation use the download category.
Uploads
pire-browser upload '#file' ./fixtures/example.txt
pire-browser upload '#multi-file' ./one.txt ./two.json --json
Uploads assign small local files to page file inputs. Total raw file bytes are capped at 512 KiB. This does not control native OS file-picker dialogs.
Clipboard
pire-browser clipboard read
pire-browser clipboard write "hello"
pire-browser clipboard copy
pire-browser clipboard paste
Active-Origin State
pire-browser --session-name work open https://app.example.com/dashboard
pire-browser --session-name work state save ./.pire-state/app.example.com-review.json
pire-browser --auto-connect state save ./.pire-state/app.example.com-review.json
pire-browser --state ./.pire-state/app.example.com-review.json open https://app.example.com/dashboard
pire-browser state list --json
pire-browser state show app.example.com-review --json
pire-browser state rename app.example.com-review app.example.com-ready
pire-browser state clear app.example.com-ready
pire-browser state clear --all
pire-browser state clean --older-than 7
pire-browser state inspect ./.pire-state/app.example.com-review.json
pire-browser state inspect --record ./.pire-state/app.example.com-review.json
pire-browser --session-name review state load --require-inspected ./.pire-state/app.example.com-review.json
State files are plaintext and contain active-origin cookies, localStorage, and sessionStorage. Do not commit or share them. The project gitignores .pire-state/. Bare state names in list, show, rename, clear, and clean resolve inside .pire-state; explicit paths remain supported for save, load, show, and rename.
Use --auto-connect state save <path> to save from the selected live managed Firefox session. Use --state <path> <browser-command> to preload that active-origin state before running the command, such as opening a dashboard page.
state show and state inspect are metadata-only. state inspect --record writes a 24-hour local receipt under the OS app-data directory. Set PIRE_BROWSER_REQUIRE_INSPECTED_STATE=1 to make normal state load require a fresh receipt; use --no-require-inspected only as an explicit one-command override.
This is active-origin state only. It does not export saved passwords, IndexedDB, browser cache, service workers, full profiles, auth vault entries, or cross-origin SSO state.
Skills
pire-browser skills list
pire-browser skills cat core
pire-browser skills cat core --json
Installed agents should use the bundled skill command for version-matched guidance instead of relying on stale cached instructions. The package also ships compact routing context under agent/, agent/workflows/, and agent/references/.
For local skill development, set AGENT_BROWSER_SKILLS_DIR to a directory of <name>/SKILL.md files. PIRE_BROWSER_SKILLS_DIR is also accepted as a project-specific alias.
Updates
pire-browser update check --json
pire-browser update apply
pire-browser update configure --mode off|notify|patch
Update checks run in a detached background process so browser launches do not wait on registry network calls. Patch auto-update is allowed only for global npm installs or confirmed Pi-managed installs, and only when no managed Firefox session is active. Local project installs and minor/major updates notify only.
On Windows, close managed Firefox sessions before replacing binaries. Windows can keep running executables locked.
Authentication
The simplest login flow is to use a persistent managed Firefox profile:
pire-browser launch --url https://example.com/login
# Sign in manually in Firefox.
pire-browser status --json
Firefox stores cookies, sessions, and saved passwords inside its managed profile. pire-browser stores launcher metadata, session files, confirmations, receipts, and download staging under the OS app-data directory, but it does not inspect cookies, saved passwords, session tokens, or one-time codes for diagnostics.
The default profile locations are:
Windows: %LOCALAPPDATA%\pire-browser\firefox-profiles\Default
macOS: ~/Library/Application Support/pire-browser/firefox-profiles/Default
Linux: $XDG_DATA_HOME/pire-browser/firefox-profiles/Default
or ~/.local/share/pire-browser/firefox-profiles/Default
Use named profiles to isolate projects:
pire-browser --profile github open https://github.com
pire-browser --profile app open https://app.example.com
pire-browser profiles --json
Deleting a managed profile folder clears that saved browser state.
Guardrails
Domain Allowlist
pire-browser --allowed-domains "app.example.com,*.example.com" open https://app.example.com/dashboard
AGENT_BROWSER_ALLOWED_DOMAINS="app.example.com,*.example.com" pire-browser snapshot -i
pire-browser --no-allowed-domains open https://example.net
The allowlist accepts host patterns such as example.com, *.example.com, localhost, and 127.0.0.1. This is a cooperative wrong-site guardrail, not a browser sandbox. It does not claim containment of redirects, subresources, WebSockets, EventSource, or races where a page navigates between check and action.
Action Policy
cat > policy-deny-eval.json <<'JSON'
{ "default": "allow", "deny": ["eval"] }
JSON
pire-browser --action-policy ./policy-deny-eval.json eval "document.title"
Policy files use optional default, allow, and deny fields. Categories include navigate, click, fill, eval, snapshot, scroll, wait, get, interact, state, network, download, and upload. deny wins over allow, and unknown keys fail closed.
Action Confirmation
pire-browser --confirm-actions eval eval "document.title" --json
pire-browser confirm c_8f3a1234
pire-browser deny c_8f3a1234
When confirmation is required, the command returns ConfirmationRequired with a short-lived id and the follow-up command to run. Agents should ask the user before running returned confirm <id> commands.
Confirmation records live under the OS app-data pire-browser/confirmations directory. They are plaintext, user-scoped, short-lived runtime metadata and may contain the original command arguments.
Security Model
pire-browser installs local native binaries, registers a Firefox Native Messaging host for the current OS user, and exposes a Pi extension. Pi extensions run with the current user's local permissions.
The Native Messaging host exposes only current-user IPC. On Windows, named pipes use a DACL restricted to the current Windows user plus required system/admin principals. On macOS/Linux, Unix domain sockets live in a short current-user runtime directory.
This protects against cross-user and remote access. It does not defend against malicious code already running as the same OS user.
Current Limits
- DOM-level automation only; no trusted OS input.
- File uploads, payment/auth flows, and browser-restricted pages can return
requires_user_activation. - Cross-origin frames are best-effort; inaccessible frames are opaque.
- Screenshots are visible-viewport only.
- Snap/Flatpak Firefox native messaging may require additional sandbox support or a non-sandboxed Firefox build.
Development
cargo build
npm --prefix extension install
npm --prefix extension run build
cargo run -p pire-browser-cli -- setup
npx --prefix extension web-ext run --source-dir extension --firefox "C:\Program Files\Mozilla Firefox\firefox.exe"
Common checks:
cargo test -q
npm test
npm run oracle:test
npm pack --dry-run --json
Run the local Windows smoke test:
.\scripts\smoke.ps1
Useful smoke variants:
npm run smoke:named-sessions
npm run smoke:state
npm run smoke:domain-policy
npm run smoke:downloads
npm run smoke:uploads
Package and packed-install checks:
node scripts/package-extension-xpi.mjs
node scripts/build-platform.mjs win32-x64
node scripts/package-platform.mjs win32-x64 --pack --pack-destination target/npm-artifact-smoke
node scripts/smoke-packed-package.mjs --no-browser --artifact-dir target/release-smoke-local
One-time npm trusted publishing setup:
npm run release:npm:trust
Run the printed npm trust github ... commands once for the root package and all seven @ryenw/* platform packages. Configure them for repository ryenwang/pire-browser, workflow npm-publish.yml, environment npm-production, and npm publish permission.
Before publishing, run the Platform Packages workflow in GitHub Actions. Its combined pire-browser-npm-artifacts artifact must contain the root npm tarball plus all seven optional native package tarballs, and the verifier must pass.
Then run the manual Release Smoke workflow with target=all and default web-ext mode. This is the packed-install publish gate for Windows x64, macOS ARM64, and Linux x64.
Publish through the manual Publish npm Package workflow from main. The workflow builds fresh root/platform tarballs, verifies them, publishes sidecar packages first through npm trusted publishing, then publishes the root package and creates the matching v<package.json version> GitHub release.
Signed-XPI smoke is separate. Run Release Smoke with run_signed_xpi=true only when AMO signing secrets are available and before claiming direct-XPI readiness. The public default remains web-ext.