---
sidebar_position: 1
title: Browser
---

# Browser skill

Playwright-driven browser automation. Click, type, navigate, snapshot, record video. Used by `zibby test` and by any agent node that needs to drive a web UI.

- **ID:** `browser`
- **MCP server:** `playwright` (tools exposed as `mcp__playwright__*`)

## Tools provided

The Playwright MCP server exposes the full Playwright tool surface. Common tools:

| Tool | What it does |
|---|---|
| `browser_navigate` | Open a URL in the active tab |
| `browser_click` | Click an element by stable id or selector |
| `browser_type` | Type text into an input |
| `browser_press_key` | Press a key (Enter, Tab, etc.) |
| `browser_snapshot` | Accessibility snapshot of the current page (returns stable ids) |
| `browser_take_screenshot` | PNG screenshot saved to the session output dir |
| `browser_wait_for` | Wait for text, time, or selector |
| `browser_evaluate` | Run JS in the page context |
| `browser_fill_form` | Fill multiple fields in one call |
| `browser_select_option` | Pick a `<select>` option |
| `browser_hover` | Hover over an element |
| `browser_drag` | Drag from one element to another |
| `browser_tabs` | List, switch, or close tabs |
| `browser_close` | Close the browser |

Refer to `@zibby/mcp-browser` for the full list. All tools are gated by the `mcp__playwright__*` allowlist.

## Setup

No setup needed beyond a working `@zibby/cli` install — the cloud runner image and the global CLI install both pull `@zibby/mcp-browser` automatically.

For local dev outside the CLI, install it explicitly:

```bash
npm install @zibby/mcp-browser
```

Override the bin path with `MCP_BROWSER_PATH` if you need to point at a local checkout.

## Use in an agent

```js
import { WorkflowAgent, WorkflowGraph } from '@zibby/core';
import { SKILLS } from '@zibby/skills';

export class LoginCheck extends WorkflowAgent {
  buildGraph() {
    const graph = new WorkflowGraph();
    graph.addNode('login', {
      agent: 'claude',
      skills: [SKILLS.BROWSER],
      prompt: (state) => `Go to ${state.appUrl}, sign in as test@example.com / hunter2,
      then snapshot the dashboard and report whether the welcome banner is visible.`,
    });
    return graph;
  }
}
```

### Config knobs

Passed via the node's skill config or env:

| Knob | Where | Effect |
|---|---|---|
| `headless: true` | per-skill config or `ZIBBY_HEADLESS=1` | Launch headless instead of headed |
| `sessionPath` | passed by the runner | Output dir for videos + screenshots |
| Viewport / video | fixed | 1280x720 |

## Output example

`browser_snapshot` returns an accessibility tree with stable ids the agent can pass back to `browser_click`:

```json
{
  "url": "https://app.example.com/dashboard",
  "title": "Dashboard",
  "snapshot": [
    { "id": "e7a1", "role": "button", "name": "New project" },
    { "id": "e7b2", "role": "link", "name": "Settings" }
  ]
}
```

## Implementation notes

Resolves to `@zibby/mcp-browser/dist/bin/mcp-browser-zibby.js` via `require.resolve`. There is no fallback to `@playwright/mcp` — the upstream Microsoft binary lacks stable IDs and event recording, and silently looks for Chrome instead of Chromium, which broke cloud runs. If the bin can't be resolved, `skill.resolve()` throws with installation instructions.

The MCP server is spawned with `--isolated --save-video=1280x720 --viewport-size=1280x720 --output-dir=<sessionPath>`. Videos and screenshots land under the run's session directory and are uploaded with the rest of the artifacts.
