Skip to main content
Glama
README.md
<a id="readme-top"></a>

<div align="center">
  <img src="extension/icons/icon.svg" alt="Claude for Zen logo" width="80" height="80">

  <h1>Claude for Zen</h1>

  <p>
    Let <a href="https://claude.com/claude-code">Claude Code</a> see and drive your real <a href="https://zen-browser.app">Zen browser</a>:<br>
    tabs, clicks, typing, screenshots, page reading, forms, console and network logs.
  </p>

  <p>
    <a href="https://github.com/grapedjuice/claude-for-zen/releases/latest"><img alt="Latest release" src="https://img.shields.io/github/v/release/grapedjuice/claude-for-zen?color=d97757"></a>
    <a href="LICENSE"><img alt="MIT License" src="https://img.shields.io/github/license/grapedjuice/claude-for-zen?color=d97757"></a>
    <img alt="Zen and Firefox" src="https://img.shields.io/badge/browser-Zen%20%7C%20Firefox-d97757">
    <img alt="MCP server" src="https://img.shields.io/badge/MCP-server-d97757">
  </p>

  <p>
    <a href="#installation"><strong>Install</strong></a> ·
    <a href="#usage">Usage</a> ·
    <a href="#troubleshooting">Troubleshooting</a> ·
    <a href="https://github.com/grapedjuice/claude-for-zen/issues">Report a bug</a>
  </p>
</div>

> [!NOTE]
> This is an unofficial community project. It is not made by, affiliated with, or endorsed by Anthropic.

<details>
  <summary>Table of contents</summary>
  <ol>
    <li><a href="#about">About</a></li>
    <li><a href="#features">Features</a></li>
    <li>
      <a href="#getting-started">Getting started</a>
      <ul>
        <li><a href="#prerequisites">Prerequisites</a></li>
        <li><a href="#installation">Installation</a></li>
        <li><a href="#updating">Updating</a></li>
        <li><a href="#uninstalling">Uninstalling</a></li>
      </ul>
    </li>
    <li><a href="#usage">Usage</a></li>
    <li><a href="#tools">Tools</a></li>
    <li><a href="#how-it-works">How it works</a></li>
    <li><a href="#security">Security</a></li>
    <li><a href="#limitations">Limitations</a></li>
    <li><a href="#troubleshooting">Troubleshooting</a></li>
    <li><a href="#development">Development</a></li>
    <li><a href="#contributing">Contributing</a></li>
    <li><a href="#license">License</a></li>
  </ol>
</details>

## About

Anthropic's Claude in Chrome extension only works in Chromium browsers. Zen is built on Firefox, so this project rebuilds the same idea for Firefox-based browsers. A small extension runs inside Zen, a local bridge connects it to Claude Code, and Claude Code gets a set of `zen-browser` tools that work on the tabs you're already signed in to.

<p align="center">
  <img src="docs/overlay.png" alt="A sign-up page with an orange glow around it, an orange cursor dot on the Sign up button, and a 'Claude is working in this tab — Stop' bar at the bottom" width="720">
</p>

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Features

- **Full browser control.** Open and switch tabs, navigate, click, type, press keys, scroll, hover, and fill forms. It works with React and Vue apps and inside shadow DOM.
- **Sees the page the way Claude needs it.** It gives Claude an accessibility-style page tree with element references, a text search, readable page text, and screenshots that are scaled so the click coordinates line up.
- **Developer tools.** It can run JavaScript in the page and read console output and network requests.
- **You can see what it's doing.** While Claude works in a tab, the tab glows, a cursor dot shows each action, and a **Stop** button pauses Claude right away.
- **Live activity popup.** The popup shows your connected Claude Code sessions and every action as it happens, and has a single switch that pauses everything.
- **Several sessions at once.** Each Claude Code session gets its own connection, and all of them share the same browser.
- **Locked down.** Everything stays on your machine. The extension and the bridge both have to prove they hold your private pairing key before either side will trust the other.

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="docs/popup-dark.png">
    <img src="docs/popup-light.png" alt="The Claude for Zen popup listing two connected Claude Code sessions and recent actions" width="340">
  </picture>
</p>

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Getting started

### Prerequisites

- [Zen browser](https://zen-browser.app). It also works in Firefox Developer Edition, Nightly, or ESR (see [Limitations](#limitations)).
- [Claude Code](https://claude.com/claude-code)
- [Node.js](https://nodejs.org) 18 or newer
- [Git](https://git-scm.com)

### Installation

**1. Install the bridge and connect it to Claude Code**

```bash
git clone https://github.com/grapedjuice/claude-for-zen.git
cd claude-for-zen
npm install
npm run setup
```

`npm run setup` registers the `zen-browser` MCP server with Claude Code for every project. It also prints your **pairing key**, which you'll need in step 3.

> [!TIP]
> Want it in one project only? Run `npm run setup -- --no-register`, then in that project run the `claude mcp add --scope local …` command it prints.

**2. Install the extension in Zen**

The extension isn't on the Mozilla add-ons store, so Zen has to be told to accept it:

1. Open `about:config` in Zen, accept the warning, and set `xpinstall.signatures.required` to **`false`**.
2. Download **[claude-for-zen.xpi](https://github.com/grapedjuice/claude-for-zen/releases/latest/download/claude-for-zen.xpi)** from the latest release.
3. Open `about:addons`, click the gear icon, choose **Install Add-on From File…**, and pick the downloaded `.xpi`.
4. Optional: right-click the toolbar, choose **Customize Toolbar**, and pin the ✷ button.

**3. Pair them**

Click the ✷ button in Zen, paste the pairing key from step 1, and click **Pair**. To see the key again, run `npm run pair` in the `claude-for-zen` folder.

**4. Restart Claude Code**

Open a new Claude Code session. The popup should say **Connected to 1 Claude Code session**.

### Updating

```bash
cd claude-for-zen
git pull
npm install
```

Then download the latest `.xpi` and install it over the old one. Your pairing carries over.

### Uninstalling

```bash
claude mcp remove --scope user zen-browser
```

Remove the extension from `about:addons`, delete the `claude-for-zen` folder, and delete `~/.claude-for-zen` (which holds the pairing key). If you want signature checks back on, set `xpinstall.signatures.required` to `true` again.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Usage

Ask Claude Code to do things in the browser in plain language:

```text
> open my GitHub notifications in Zen and summarize what needs my attention
> fill out the sign-up form on localhost:3000 with test data and tell me what breaks
> check the console on the current tab for errors and find the cause in this repo
> compare the prices on these three open tabs
```

Claude starts by listing your tabs, then reads pages and acts on elements by reference. It takes screenshots when the layout matters.

- **Pause or stop.** Click **Stop** on the in-page bar, or turn off the switch in the popup. Claude gets a clear "paused" error until you turn it back on.
- **Choose the tab.** Claude acts on whatever tab you tell it to. If you don't name one, it uses the active tab in the focused window.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Tools

| Tool | What it does |
| --- | --- |
| `tabs_context` | List tabs (id, title, URL, active). Tabs in other Zen workspaces are flagged. |
| `tabs_create` · `tabs_select` · `tabs_close` | Open, focus, and close tabs. |
| `navigate` | Go to a URL, or `back` / `forward`, and wait for the page to load. |
| `screenshot` | Capture the visible tab as an image. |
| `computer` | `left_click`, `right_click`, `double_click`, `triple_click`, `hover`, `type`, `key`, `scroll`, `scroll_to`, `wait`, `screenshot`, `zoom`. Targets elements by `ref` or by coordinate. |
| `read_page` | Accessibility-style tree. Interactive elements are tagged `[ref_N]`. |
| `find` | Find elements by role, name, or text. |
| `form_input` | Set text fields, selects, checkboxes, radios, and contenteditables by `ref`. |
| `get_page_text` | Readable text of the page. |
| `javascript` | Run JavaScript and return the last expression. Top-level `await` works. |
| `read_console_messages` | Console output and uncaught errors for a tab. |
| `read_network_requests` | Requests the tab made since it loaded. |
| `resize_window` | Resize the browser window. |

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## How it works

```text
Claude Code ──MCP over stdio──▶ bridge (server/index.js) ◀──WebSocket on 127.0.0.1:47321–47330──▶ Zen extension ──▶ your tabs
```

- **The bridge.** Claude Code starts one bridge per session. Each bridge takes the first free port between 47321 and 47330.
- **The extension.** It checks those ports, connects to every bridge it finds, and carries out the tool calls.
- **Why not native messaging?** Chrome extensions normally talk to Claude through native messaging. Here, the bridge is the process Claude Code launches, so a localhost socket with mutual authentication is simpler and works the same way on Windows, macOS, and Linux.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Security

- **Mutual authentication.** The bridge and the extension each prove they hold the pairing key with an HMAC-SHA256 challenge–response that uses fresh nonces in both directions. The extension ignores commands from any bridge that can't prove the key. The bridge drops any extension that can't, within 5 seconds. Other extensions, other local programs, and other users on the same machine can't pose as either side.
- **The key stays private.** It lives in `~/.claude-for-zen/pairing-key`, inside your user profile.
- **Websites can't reach it.** The bridge listens on `127.0.0.1` only. It accepts WebSocket connections only from `moz-extension://` origins with a loopback `Host` header, which blocks DNS-rebinding tricks. Its HTTP probe returns only `{bridge, version}`.
- **Page scripts can't change settings.** Pairing and settings can only be changed from the popup. Code running in the page, including code from the `javascript` tool, can only press Stop.
- **Passwords are masked.** `read_page` shows password fields as `••••`.
- **Nothing leaves your machine except through Claude Code.** The extension only talks to localhost. What Claude reads is sent to Anthropic through Claude Code, as with any other tool output.
- **Page content is untrusted.** A web page can contain text written to manipulate an AI (prompt injection). Claude is told to treat page content as data, not instructions. Still, keep an eye on what it does on sites you don't trust, and use **Stop** if anything looks off.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Limitations

- **Synthesized input.** Firefox has no `chrome.debugger` API, so clicks and keys are generated inside the page and have `event.isTrusted = false`. Most sites don't care, but some captchas and anti-bot checks ignore this kind of input.
- **Native dropdowns.** `<select>` dropdowns can't be opened by clicking. Claude uses `form_input` for them instead.
- **Iframes.** The extension only works in a page's top-level frame, so it can't type into fields inside iframes.
- **Browser pages.** `about:` pages and addons.mozilla.org are off-limits to all extensions.
- **Console capture.** Capture starts while a Claude Code session is connected. For tabs that were opened before that, reload the tab to capture its logs.
- **Firefox release builds.** Regular Firefox ignores `xpinstall.signatures.required`. In release Firefox, load the extension temporarily from `about:debugging` (it's removed when the browser restarts), or use Developer Edition, Nightly, or ESR.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Troubleshooting

<details>
<summary><strong>The popup says "Waiting for Claude Code…"</strong></summary>

- Restart Claude Code after running `npm run setup`.
- Run `claude mcp list` and check that `zen-browser` shows **Connected**.
- Make sure nothing else is using all of ports 47321–47330.
</details>

<details>
<summary><strong>The popup says "Needs pairing", or Claude reports the extension "isn't paired"</strong></summary>

Run `npm run pair` in the `claude-for-zen` folder and paste the key into the popup. If you deleted `~/.claude-for-zen`, a new key was created and you need to pair again.
</details>

<details>
<summary><strong>"This add-on could not be installed because it appears to be corrupt"</strong></summary>

`xpinstall.signatures.required` is still `true`. Set it to `false` in `about:config` and try again.
</details>

<details>
<summary><strong>Screenshots fail or time out</strong></summary>

The browser can't capture a minimized window. Claude brings the window forward and tries again, but if Zen stays minimized the capture fails.
</details>

<details>
<summary><strong>A session I don't expect shows up in the popup</strong></summary>

`npm run setup` registers the bridge for every project, so each open Claude Code session connects. To limit it to certain projects, see the tip in [Installation](#installation).
</details>

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Development

```text
extension/        Firefox WebExtension (Manifest V2)
  background.js   connections, pairing, tool dispatch, screenshots, network log
  content.js      page reading, synthetic input, in-page overlay
  console-hook.js console capture, registered only while a session is connected
  popup/          toolbar popup
server/index.js   MCP server + localhost WebSocket bridge
scripts/setup.mjs one-time setup (register + pair)
```

```bash
npm install
npm run lint           # web-ext lint
npm run build          # writes dist/claude-for-zen.xpi
```

To try local changes, load `extension/manifest.json` from `about:debugging#/runtime/this-firefox` → **Load Temporary Add-on**.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Contributing

Issues and pull requests are welcome.

1. Fork the repo and create a branch: `git checkout -b fix/something`
2. Make your change, run `npm run lint`, and try it in Zen.
3. Commit and open a pull request that describes what changed and how you tested it.

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## License

Distributed under the MIT License. See [`LICENSE`](LICENSE) for details.

<p align="right">(<a href="#readme-top">back to top</a>)</p>