Migrating browser automation

September 21, 2026 ยท View on GitHub

Jev Browser is a functional alternative, not a drop-in alias for another package's JavaScript types, CLI flags or MCP schemas. The shared core is intentionally explicit about grounded data, ownership, authorization and verified completion.

Playwright MCP

Change the MCP executable to jev-browser-mcp or the installed dist/mcp-stdio.js. Standard operation names are exposed as browser_navigate, browser_snapshot, browser_click, browser_type, browser_fill_form, browser_tabs, browser_handle_dialog, browser_file_upload, browser_take_screenshot, and other documented native tools. Discovery uses the official MCP protocol and is tested with the official client.

Take a new snapshot and use this server's refs, not refs from an old Playwright MCP connection. Native methods accept the human-readable element field, but actual targeting uses ref or target. target is a Playwright selector supplied by a trusted caller. Snapshot results are structured JSON rather than Microsoft's exact text format.

Use browser_act for natural-language action selection and browser_assert for deterministic verification. Tool cancellation propagates to the shared core. A pending dialog is explicit and can be handled in the next call.

Page-side browser_evaluate is available only with --allow-evaluate, and currently accepts a page function rather than a target-bound function. Arbitrary Node-side browser_run_code is deliberately not provided; write that orchestration in the SDK using browser.page. Browser extensions and proprietary service integration are not included; use CDP or a Playwright WebSocket endpoint when attaching to another browser.

Playwright CLI

WorkflowJev Browser
Open a retained browseropen URL --session work
Read the pagesnapshot --session work
Click/type by refclick REF, fill REF TEXT, with --session work
Select/check/keyboardselect REF VALUE, check REF, uncheck REF, press Enter
Native arbitrary argumentsCOMMAND --args JSON or call COMMAND --args JSON
Bounded natural-language workflowrun INSTRUCTION --values JSON --max-steps N
Verify outcomeassert --args JSON; failure exits nonzero
Retain state over a pipesession with JSONL commands and optional request IDs
Inspect/close sessionssessions, close --session work

CLI output is always JSON (apart from help/version). Screenshots return image data and optionally save an artifact; use take_screenshot --args '{"filename":"page.png"}' to choose a file. Outputs stay inside the artifact directory. Flags and storage paths are not compatible with an existing Microsoft session descriptor. Retake snapshots during migration and close old sessions explicitly.

Stagehand

const browser = new JevBrowser({ page });
await browser.act('Fill email with email', { values: { email: 'user@example.invalid' } });
const plan = await browser.observe('Click Save');
if (plan) await browser.act(plan);
const { data, evidence } = await browser.extract('Read rows', schema, { recordsScope: 'tbody tr' });
const result = await browser.agent({ maxSteps: 8, until: verify }).execute({ instruction: goal, values });

Use the existing Playwright Page/fixtures and keep ordinary expect assertions. A browser constructed with a Page does not own it. Natural-language input variables use values, not upstream %variable% templating. Explicit values stay local, while literal quoted text is already visible in the prompt.

observe returns a single plan or null, rather than an array of reusable actions. Plans are single-use. extract returns data together with evidence, snapshot and decision metadata. Its contract is copying observed facts, not generating summaries. Nested objects, scalar roots and arrays of actual DOM rows/cards are available; record scopes preserve cross-field coherence within each row.

The goal runtime batches independent field questions and record extraction, executes browser writes serially, handles native-form transitions and ordinary confirmations, and checks fresh result records. A model's completion opinion still stays unverified. expect works in SDK/CLI/MCP; until is an additional SDK callback. See goal execution for default budgets and boundaries. Browserbase infrastructure, Stagehand's cache/replay service, cloud billing and arbitrary model-generated code are not included.

Visual-only pages and large pages

Screenshot and mouse-coordinate tools are available to an outer vision-capable agent. Jev itself is not an image model in this integration, so standalone autonomous Canvas/image interpretation is not claimed. Closed shadow roots are not inspectable by the DOM layer.

For large pages, explicit scope remains authoritative. Without one, a truncated page can be indexed into bounded real semantic regions (form/main/section/article/dialog/navigation) and Jev may select the region relevant to the current action/readback; ambiguous or still-truncated regions fail closed. recordsScope identifies repeated rows but is not a whole-page text filter. Very long native select lists are deferred rather than truncated, and standards-associated ARIA comboboxes use only their declared owned popup. The runtime never pretends an omitted candidate was observed.

Upstream references

Compare against the versions you actually deploy; upstream interfaces change independently of this project.

Upgrading to v0.7

compareSemantic remains a snapshot comparison. assertSemantic now re-reads the actual sources before returning and may fail inconclusive when the page changes while the model is running. Treat this as a stricter assertion, not a flaky outcome to retry blindly. Prefer known Playwright Locators for stable explicit target retrieval; otherwise keep the returned evidence and fresh/changed status in diagnostics.

SDK users can pass {actual:{locator:page.getByTestId('plan')},expected:'Professional annual plan'} or extend their existing Playwright expect with semanticMatchers(core) from @tontoko/jev-browser/playwright. No model key is required for an exact comparison. For CLI/MCP, the new semantic_compare_batch, semantic_assert_batch and semantic_locate_batch accept JSON descriptions/refs; Locator objects stay SDK-only.

Mixed model provenance is now reported in models; do not require a singular model when it is unknown or multiple models participated. Semantic failures now include error.semantic expected/results; treat logs as potentially sensitive UI data. Existing run, resume, native actions and deterministic assertions remain available without a new planner or backend service.