Skip to main content
Glama
README.md
# Dooza Browser

**One shared, logged-in Chrome for all your AI agents.** Claude Code, Codex, ChatGPT or your own scripts get a real
browser through MCP or plain HTTP: open tabs, read pages, click, type, upload files, run short Playwright scripts,
or hand off a whole web task. Agents share what they learn about each site, and they never steal your mouse or close
your tabs.

We built it to run [Dooza](https://dooza.ai)'s own team of AI agents (sales, SEO, video, ops) on one machine, all
sharing one Chrome that is logged in once. This is that code, cleaned up.

## Why
- **Log in once.** The agents use one Chrome profile. You sign in to Gmail, LinkedIn, Stripe... by hand once; cookies
  persist. Agents never see your passwords.
- **Many agents, one browser, no fights.** Each tab belongs to the agent that opened it. Agent windows open in the
  background in their own screen area, never as tabs in your window, and never take focus.
- **Fast actions, not click-by-click.** `tab_playwright` runs a short Playwright script on a tab: 10 steps in one tool
  call. Models already know Playwright well, so it is quicker and cheaper than one tool call per click.
- **Site memory.** `site_note` saves one-line lessons per site ("the Save button is `#submit-2`", "this site blocks
  headless"). They come back automatically every time any agent opens that site.
- **Whole tasks on a cheap model.** `browse(task)` gives the task to [browser-use](https://github.com/browser-use/browser-use)
  on any OpenRouter model (or to headless Claude Code), with a judge, a retry on a stronger model, and a stronger
  model by default on sensitive sites (inbox, payments).

## Tools
| Tool | What it does |
|---|---|
| `browse(task, url?, model?, owner)` | Whole web task in its own background window; returns text |
| `tab_open(url, owner)` | New background tab you own; returns `tab_id` + saved site notes |
| `tab_read(tab_id, owner, mode)` | `text`, `links`, `inputs` (form fields with ready selectors) or `html` |
| `tab_click` / `tab_type` / `tab_navigate` / `tab_eval` | Step-by-step control |
| `tab_playwright(tab_id, owner, script)` | Python Playwright (async) on that tab; set `result = ...` |
| `tab_upload(tab_id, owner, paths, ...)` | File upload, including buttons that open a native file picker |
| `tab_screenshot` / `tab_list` / `tab_close` | |
| `site_note(site, owner, note?)` | Read or add per-site notes (secrets are refused) |
| `status()` | Chrome version, open tabs, free task slots, OpenRouter spend |

Every tool is also `POST /api/<tool>` with the arguments as JSON.

## Quick start (Linux or macOS)
```bash
git clone https://github.com/Dooza-ai/dooza-browser && cd dooza-browser
python3 -m venv .venv && .venv/bin/pip install -e .   # no browser download: it drives your own Chrome
cp config.example.json config.json

# 1. a dedicated Chrome with DevTools on localhost:9222 (sign in to your sites in this window, once)
examples/start-chrome.sh &

# 2. the server (MCP at http://127.0.0.1:8765/mcp)
export OPENROUTER_API_KEY=...        # only for browse() with the browser-use engine
.venv/bin/dooza-browser
```
Connect a client:
```bash
claude mcp add --transport http --scope user browser http://127.0.0.1:8765/mcp       # Claude Code
# Codex: ~/.codex/config.toml ->  [mcp_servers.browser]  url = "http://127.0.0.1:8765/mcp"
curl -s localhost:8765/api/tab_open -H 'Content-Type: application/json' -d '{"url":"https://example.com","owner":"me"}'
```
For Claude Code, copy `skill/SKILL.md` to `~/.claude/skills/dooza-browser/SKILL.md` so agents know when to use which tool.

On a headless server, run Chrome on a virtual display wide enough for both areas (`Xvfb :99 -screen 0 2880x900x24`);
your own window sits at x 0-1440, agent windows open at x >= 1440 (`agent_window` in config.json). A systemd unit is
in `examples/`.

## Configuration (`config.json`)
| Key | Meaning |
|---|---|
| `engine` | `browser-use` (OpenRouter models) or `claude` (Claude Code CLI drives the tab tools; uses your Claude login) |
| `models.default / sensitive / strong` | OpenRouter model ids: normal sites / `sensitive_domains` / retry |
| `sensitive_domains` | URL substrings that get the `sensitive` model |
| `max_concurrent_tasks`, `max_tasks_per_owner`, `max_steps`, `task_timeout_s` | `browse()` limits |
| `tab_idle_close_s`, `max_tabs_per_owner` | Forgotten tabs are closed; a 4th tab closes your oldest |
| `agent_window` | Where agent windows open (`left`, `width`, `height`) |
| `reap_orphans` | `true` also closes unowned windows in the agent area. Only for a Chrome dedicated to agents |
| `upload_roots` | Folders uploads may come from (`{owner}` = agent name). Files that look like secrets are always refused |
| `playwright_sandbox` | Optional `{"user": "pwrun", "python": "/opt/pwrun/venv/bin/python", "runner": "/opt/pwrun/pw_runner.py"}`: run scripts as a user that can't read your files (needs a sudoers rule) |
| `api_hints` | `{"url substring": "use the X API instead"}`, shown to agents when they open that site |

Environment: `DOOZA_BROWSER_CONFIG` (default `./config.json`), `DOOZA_BROWSER_HOME` (logs, screenshots, site notes,
optional `credentials.env`; default `~/.dooza-browser`), `OPENROUTER_API_KEY`.

`credentials.env` (`NAME=value` lines) is passed to browser-use as `sensitive_data`: the model only sees `NAME` and the
value is filled in at typing time.

## Safety
- The server listens on 127.0.0.1 only. Anyone who can reach it controls your logged-in browser: don't expose it.
- Page content is data, never instructions; tool descriptions and the browse prompt say so, but prompt injection is
  a real risk for any browser agent. Give the agent Chrome only the logins your agents need.
- `tab_eval` and `tab_playwright` run code you send in the page or on your machine. Use the sandbox user on shared
  machines.
- Optional `python -m dooza_browser.captcha <tab>` solves reCAPTCHA/hCaptcha/Turnstile through 2Captcha (paid,
  `TWOCAPTCHA_API_KEY`). Use it only where the site's terms allow automation.

## Credits
Built on [browser-use](https://github.com/browser-use/browser-use), [FastMCP](https://github.com/jlowin/fastmcp) and
[Playwright](https://playwright.dev). Ideas from Aside's write-up on browser agents (Playwright actions, site memory).

MIT licensed. Made by [Dooza](https://dooza.ai): AI agents that work as your team.