bunwv


Headless browser automation CLI for Bun, powered by Bun.WebView. Cross-platform: WebKit on macOS (default, zero dependencies), Chrome on macOS/Linux/Windows.
A persistent daemon keeps a browser instance alive so page state — DOM, modals, forms, auth, cookies — survives across commands. Designed agent-first: every action verb is silent on success, errors are JSON on stderr with stable exit codes, and event/console buffers are cursor-pulled. Built for AI coding assistants (Claude Code, Cursor, etc.) driving the browser through discrete tool calls.
Install
bun install -g @naticha/bunwv
Requires Bun v1.3.14+. On macOS, uses the native WebKit engine by default (zero dependencies). On Linux and Windows, automatically uses Chrome/Chromium (must be installed).
AI Coding Assistant Skill
bunx skills add naticha/bunwv
# or
npx skills add naticha/bunwv
Or install directly in Claude Code:
/plugin marketplace add naticha/bunwv
/plugin install bunwv@bunwv
This installs the skill file that teaches AI assistants how to use bunwv for browser testing.
Quick Start
bunwv start # start the daemon
bunwv navigate http://localhost:3000 # go to a page
bunwv screenshot # writes /tmp/bunwv-screenshot-<session>.jpg (JPEG @ q80), prints the path
bunwv screenshot --max-width 1024 # bound the longest side; aspect preserved
bunwv screenshot --metadata # {"width","height","format"} instead of pixels
bunwv click --selector "button.submit" # click an element (auto-waits)
bunwv type "hello world" # type into focused element
bunwv evaluate "document.title" # run JS in the page, JSON-literal result
bunwv close # stop the daemon
Agent-first contract
- Successful action verbs print nothing on stdout and exit 0.
click, type, navigate, press, scroll, scroll-to, clear, submit, resize, back/forward/reload, close, exists, wait-for, wait-for-gone, cdp-subscribe, cdp-unsubscribe are all silent. Read verbs (status, evaluate, events, console, cdp, cdp-subscriptions, screenshot, sessions) print their result.
- Stable exit codes:
0 ok, 1 generic, 2 usage, 3 timeout, 4 element-not-found, 5 daemon-unreachable, 6 batch-partial.
- Errors are JSON on stderr:
{ok:false, error, exitCode}. Branch on the exit code, not stderr text.
- Error-level console auto-surfaces. If the page logs
console.error/console.warn while a verb runs, {"console":[…]} is written to stderr alongside the verb's response.
--json global flag wraps any command's output as {ok, data?, error?, exitCode}.
- Flexible flags:
--flag value, --flag=value, repeated flags (e.g. --mod Shift --mod Control), and flags before or after the command all work.
BUNWV_SESSION env var replaces --session <name> when set.
Commands
Session
| Command | Description |
|---|
start [--width N] [--height N] [--data-store PATH] [--idle-timeout ms] [--backend webkit|chrome] [--chrome-path PATH] [--chrome-argv '[json]'] [--chrome-url <ws>] [--chrome-stdout inherit|ignore] [--chrome-stderr inherit|ignore] [--webkit-stdout inherit|ignore] [--webkit-stderr inherit|ignore] [--url <initial>] | Start the daemon (default 1920x1080, 30min idle timeout) |
close [--all] | Stop this session, or every running session with --all |
status | Terse: <url> | <title> | <idle|loading> | pending=<n>. --json for loading, pendingEvents, cursor, cdpSubscriptions |
sessions | List all running sessions |
Navigation
| Command | Description |
|---|
navigate <url> | Navigate to a URL (silent) |
back / forward / reload | History + refresh (silent) |
Interaction