> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openbrowser.me/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI Daemon

> Execute browser automation code directly from Bash via a persistent daemon

## Overview

The CLI daemon provides a persistent browser session over a Unix socket. Use the `-c` flag to execute Python code directly from Bash -- no MCP server, no LLM, just code and a browser.

The daemon starts automatically on first use, persists variables across calls, and shuts down after 10 minutes of inactivity.

## Quick Start

```bash theme={null}
# Navigate to a page
uvx openbrowser-ai -c "await navigate('https://example.com')"

# Extract data
uvx openbrowser-ai -c "print(await evaluate('document.title'))"

# Multi-step interaction
uvx openbrowser-ai -c "
await navigate('https://news.ycombinator.com')
state = await browser.get_browser_state_summary()
print(state.title)
print(f'{len(state.dom_state.selector_map)} interactive elements')
"
```

## Variable Persistence

Variables set in one `-c` call are available in the next, as long as the daemon is running:

```bash theme={null}
uvx openbrowser-ai -c "await navigate('https://example.com')"
uvx openbrowser-ai -c "title = await evaluate('document.title')"
uvx openbrowser-ai -c "print(title)"  # still available
```

This enables incremental exploration -- navigate in one call, extract in the next, process in the third.

## Daemon Management

```bash theme={null}
uvx openbrowser-ai daemon start     # Start daemon (auto-starts on first -c call)
uvx openbrowser-ai daemon stop      # Stop daemon and close browser
uvx openbrowser-ai daemon status    # Show PID, init state, idle timeout
uvx openbrowser-ai daemon restart   # Restart with fresh browser session
```

The daemon runs in the background and communicates via a Unix socket at `~/.openbrowser/daemon.sock`. Logs are written to `~/.openbrowser/daemon.log`.

> **Windows**: On Windows, the daemon uses a localhost TCP connection on port 19222 instead of a Unix socket. This means any process on the same machine can connect. The Unix socket on macOS/Linux is restricted to the file owner (mode `0600`).

## Available Functions

All functions from the MCP `execute_code` tool are available in `-c` mode:

| Category        | Functions                                                                                                                     |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **Navigation**  | `navigate(url, new_tab)`, `go_back()`, `wait(seconds)`                                                                        |
| **Interaction** | `click(index)`, `input_text(index, text, clear)`, `scroll(down, pages, index)`, `send_keys(keys)`, `upload_file(index, path)` |
| **Dropdowns**   | `select_dropdown(index, text)`, `dropdown_options(index)`                                                                     |
| **Tabs**        | `switch(tab_id)`, `close(tab_id)`                                                                                             |
| **JavaScript**  | `evaluate(code)` -- run JS in page context, returns Python objects                                                            |
| **Downloads**   | `download_file(url, filename)`, `list_downloads()`                                                                            |
| **State**       | `browser.get_browser_state_summary()` -- page metadata and interactive elements                                               |
| **CSS**         | `get_selector_from_index(index)` -- CSS selector for an element                                                               |
| **Completion**  | `done(text, success)` -- signal task completion                                                                               |

**Pre-imported libraries**: `json`, `csv`, `re`, `datetime`, `asyncio`, `Path`, `requests`

Optional (imported on first use): `numpy`/`np`, `pandas`/`pd`, `matplotlib`/`plt`, `BeautifulSoup`, `PdfReader`, `tabulate`

## Multi-Action Batching

Batch multiple actions in a single call for efficiency:

```bash theme={null}
uvx openbrowser-ai -c "
await navigate('https://example.com/search')
await input_text(1, 'python automation')
await click(2)
await wait(2)
state = await browser.get_browser_state_summary()
print(f'Results page: {state.title}')
"
```

## Architecture

```mermaid theme={null}
graph LR
    CLI["CLI (-c flag)<br/><code>openbrowser-ai -c 'code...'</code>"]
    SOCK["Unix Socket<br/>~/.openbrowser/daemon.sock"]
    EXEC["CodeExecutor<br/>(persistent namespace)"]
    CHROME["Chrome<br/>(CDP)"]

    CLI -->|JSON request| SOCK
    SOCK --> EXEC
    EXEC -->|DevTools Protocol| CHROME

    subgraph Daemon Server
        SOCK
        EXEC
    end
```

* The **CLI** is a thin client (\~30ms startup) that sends code over the Unix socket
* The **daemon** holds the browser session, CodeExecutor, and persistent namespace in memory
* The **browser** connects via Chrome DevTools Protocol (CDP)

## Configuration

| Variable                 | Description                             | Default                      |
| ------------------------ | --------------------------------------- | ---------------------------- |
| `OPENBROWSER_HEADLESS`   | Run browser without GUI                 | `false`                      |
| `OPENBROWSER_MAX_OUTPUT` | Maximum output characters per execution | `10000`                      |
| `OPENBROWSER_SOCKET`     | Custom Unix socket path                 | `~/.openbrowser/daemon.sock` |

## Comparison with MCP Server

| Feature          | CLI Daemon (`-c`)                                 | MCP Server (`--mcp`)                |
| ---------------- | ------------------------------------------------- | ----------------------------------- |
| **Use case**     | Bash scripts, shell pipelines, manual exploration | AI assistants (Claude, Codex)       |
| **Intelligence** | You write the code                                | LLM writes the code                 |
| **Startup**      | \~30ms (thin client)                              | \~150ms (full MCP init)             |
| **Protocol**     | Unix socket (JSON lines)                          | MCP over stdio                      |
| **Persistence**  | Variables persist across `-c` calls               | Variables persist across tool calls |
| **Idle timeout** | 10 minutes                                        | Session-based                       |

Both use the same `CodeExecutor` engine and browser automation functions.

## Troubleshooting

**Daemon won't start**

* Check `~/.openbrowser/daemon.log` for errors
* Verify Chrome/Chromium is installed
* Remove stale files: `rm ~/.openbrowser/daemon.sock ~/.openbrowser/daemon.pid`

**"Daemon not running" on status**

* The daemon shuts down after 10 minutes of inactivity
* Run any `-c` command to auto-start it

**Socket permission errors**

* The socket is created with `0600` permissions (owner-only)
* Check that `~/.openbrowser/` is owned by your user

**Variables lost between calls**

* The daemon may have restarted (idle timeout or crash)
* Use `openbrowser-ai daemon status` to check if the daemon is running
