Sign inSign up

superbizon007/linux-chrome-agent

By superbizon007

Updated 5 months ago

Linux Chrome Agent

Image
Machine learning & AI
0

930

superbizon007/linux-chrome-agent repository overview

Linux Chrome Agent

A Docker image that runs a headless Chrome browser with a VLM-powered browser automation agent, exposed via A2A and OpenAI-compatible HTTPS APIs.

Implements an agent using the ReAct (Reasoning + Acting) pattern for intelligent Chrome orchestration.

Overview

The container bundles:

  • Chrome — runs headlessly with Chrome DevTools Protocol (CDP) access
  • VNC / noVNC — optional GUI desktop for visual debugging
  • Python agent server — FastAPI service that accepts tasks and autonomously controls Chrome using a Vision Language Model (VLM) via LangGraph

The agent observes the browser through screenshots, reasons about the next action, and executes it — repeating until the task is complete or the step budget is exhausted.


Features

FeatureDetails
Browser automationFull Chrome control via CDP — click, type, scroll, drag, keypress, and more
VLM-driven agentAny OpenAI-compatible VLM (GPT-4o, Claude, Gemini, local models)
Element detectionDOM-based interactive element detection with visual annotation
OmniParserOptional vision model for richer element detection (replaces DOM detection)
UI Locator modelOptional secondary model (UI-TARS / Fara-7B) resolves natural-language element descriptions to pixel coordinates
Popup detectionAutomatic detection of modals, dialogs, cookie banners, and overlays
New-tab handlingAutomatically follows links that open in a new tab and switches the CDP session
Network idle waitWaits for XHR/fetch to settle after clicks, keypresses, and JS evaluation
Loop detectionDetects repeated identical actions and warns the VLM to try a different strategy
Cookie exportExports browser cookies in Netscape cookies.txt format for sharing with other agents
Prior contextLoads prior task summary from trajectory when the same context_id is reused
Mid-task injectionOperator can inject instructions or pause/resume the agent mid-execution via A2A
Cost trackingTracks VLM token usage and cost per run; appended to trajectory summary
S3 workspaceOptional shared S3 workspace and blackboard for multi-agent coordination
A2A APIGoogle Agent-to-Agent JSON-RPC 2.0 protocol
OpenAI-compatible API/v1/chat/completions endpoint — drop-in for OpenAI clients
HTTPSSelf-signed TLS certificate generated at startup
Trajectory recordingSaves per-step screenshots, element lists, VLM requests/responses, and locator logs
Visual debuggingTigerVNC + noVNC web client for watching the agent live

Quick Start

Build
git clone <repo>
cd apps/linux_chrome_agent
docker build --build-context a2a_pkg=../../packages/a2a_agent -f Dockerfile.ubuntu -t linux_chrome_agent:ubuntu .
Run
docker run -d \
  --name chrome_agent \
  -p 443:443 \
  -p 6901:6901 \
  -p 5901:5901 \
  -p 9222:9222 \
  -e VLM_URL=https://api.openai.com/v1 \
  -e VLM_API_KEY=sk-... \
  -e VLM_MODEL=gpt-4o \
  linux_chrome_agent:ubuntu --wait
Dev mode

For development it is convenient to run the Docker image and the agent server separately.

Build the dev image:

docker build --build-context a2a_pkg=../../packages/a2a_agent -f Dockerfile.dev -t linux_chrome_agent_dev:ubuntu .

Run Chrome + VNC only:

docker run -d \
  --name chrome_agent_dev \
  -p 6901:6901 \
  -p 5901:5901 \
  -p 9222:9222 \
  linux_chrome_agent_dev:ubuntu --wait

Run the agent server locally:

VLM_URL=https://api.openai.com/v1 \
VLM_API_KEY=sk-... \
VLM_MODEL=gpt-4o \
CDP_HOST=localhost \
CDP_PORT=9222 \
uv run python -m app.server

With optional API auth:

API_KEY=your-token \
VLM_URL=https://api.openai.com/v1 \
VLM_API_KEY=sk-... \
VLM_MODEL=gpt-4o \
CDP_HOST=localhost \
CDP_PORT=9222 \
uv run python -m app.server
Access
ServiceURL / Address
Agent API (A2A + OpenAI)https://localhost/
noVNC web viewerhttp://localhost:6901/?password=vncpassword
VNC native clientlocalhost:5901 (password: vncpassword)
Chrome CDPhttp://localhost:9222

API

A2A — send a task
curl -sk -X POST https://localhost/ \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "message/send",
    "params": {
      "id": "task-1",
      "message": {
        "role": "user",
        "parts": [{"text": "Go to example.com and tell me the page title"}]
      }
    }
  }'
OpenAI-compatible
curl -sk -X POST https://localhost/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "browser-agent",
    "messages": [{"role": "user", "content": "Go to example.com and tell me the page title"}]
  }'
Agent card
curl -sk https://localhost/.well-known/agent.json

Environment Variables

Core
VariableDefaultDescription
VLM_URLhttps://api.openai.com/v1Base URL of the VLM API
VLM_API_KEYAPI key for the VLM
VLM_MODELgpt-4oModel name
API_KEYBearer token to protect the agent API (optional)
PORT443HTTPS port for the agent server
AGENT_URLPublic URL published in the AgentCard (e.g. https://my-agent.example.com/). Defaults to https://localhost:{PORT}/
CDP_HOSTlocalhostChrome DevTools Protocol host
CDP_PORT9223Chrome DevTools Protocol port (internal)
VIEWPORT_WIDTH1920Browser viewport width in pixels
VIEWPORT_HEIGHT1080Browser viewport height in pixels
SEND_IMAGEtrueSet to false for text-only LLMs (uses element list only, no screenshot)
TRAJECTORY_DIRDirectory to save trajectory data; each run creates a YYYYMMDD_HHMMSS/ subdirectory
OmniParser (optional)

OmniParser is a visual element detection model. When configured, it replaces the default DOM-based element detection and returns richer UI element data.

VariableDefaultDescription
OMNIPARSER_URLBase URL of the OmniParser API (e.g. http://omniparser:8000)
OMNIPARSER_API_KEYBearer token for OmniParser API auth (optional)
UI Locator model (optional)

The locator is a secondary vision model (e.g. UI-TARS, microsoft/Fara-7B) specialised in resolving natural-language element descriptions to exact pixel coordinates. When configured, the agent describes elements by name (query) instead of guessing x/y coordinates, and the locator finds the exact click target.

Enabling the locator also disables the marked-screenshot annotation (since coordinates come from the locator, not visual inspection).

VariableDefaultDescription
LOCATOR_URLOpenAI-compatible API base URL for the locator model
LOCATOR_API_KEYBearer token for locator API auth (optional)
LOCATOR_MODELui-tarsModel name passed to the locator API
S3 Workspace (optional)

When configured, the agent writes a blackboard entry to S3 (or a local mount) so other agents can observe its status. Use with multi-agent orchestration workflows.

VariableDefaultDescription
WORKSPACE_IDLogical workspace name shared across agents (e.g. project-abc)
WORKSPACE_MOUNT_PATH/workspaceLocal filesystem path for the workspace (FUSE mount or local dir)
S3_BUCKETS3 bucket for direct S3 mode (skips FUSE mount)
S3_ENDPOINT_URLS3-compatible endpoint URL (omit for AWS S3)
S3_ACCESS_KEY_IDS3 access key
S3_SECRET_ACCESS_KEYS3 secret key
S3_REGIONus-east-1S3 region
S3_PREFIXOptional prefix prepended to workspace_id in the bucket
AGENT_IDlinux_chrome_agentUnique agent name written to the blackboard
Agent Metadata
VariableDefaultDescription
AGENT_NAMEweb.browser.chromeAgent name published in the A2A agent card
AGENT_VERSION0.1.0Agent version published in the agent card
AGENT_DESCRIPTION(built-in)Description published in the agent card
Container
VariableDefaultDescription
VNC_PWvncpasswordVNC password
VNC_RESOLUTION1920x1080Screen resolution

Trajectory Recording

When TRAJECTORY_DIR is set, each agent run creates a timestamped subdirectory containing one folder per step:

$TRAJECTORY_DIR/
  20260225_181523/              # run timestamp (YYYYMMDD_HHMMSS)
    summary.md                  # task, result, reusable plan, and cost summary
    turn_0000/
      screenshot.png            # browser state at start of step
      screenshot_marked.png     # annotated with detected elements (DOM mode)
      screenshot_annotated.png  # annotated with the proposed click target
      elements.json             # detected interactive elements
      llm_0_request.json        # messages sent to the VLM
      llm_0_response.json       # raw VLM reply + parsed action/args/reasoning
      locator.json              # locator model request + response (when LOCATOR_URL is set)
    turn_0001/
      ...
  20260225_182041/              # next run
    ...

Example:

docker run -d \
  -e VLM_URL=... -e VLM_API_KEY=... \
  -e TRAJECTORY_DIR=/data/trajectory \
  -v /tmp/agent-logs:/data/trajectory \
  linux_chrome_agent:ubuntu --wait

Element Detection

The agent detects interactive UI elements at each step and passes them to the VLM. Three modes are available:

DOM detection (default)

A JavaScript snippet scans the page for interactive elements (buttons, links, inputs, etc.) using checkVisibility() and elementFromPoint() reachability checks. Elements are deduplicated by a centre-point grid and annotated on the screenshot with numbered badges.

OmniParser

When OMNIPARSER_URL is set, the screenshot is sent to OmniParser instead of running DOM detection. OmniParser returns visual element bounding boxes with interactivity scores.

UI Locator model

When LOCATOR_URL is set, the agent describes elements in plain language (e.g. "Sign in button", "email input field") and sends the query + screenshot to the locator model. The locator returns the exact pixel coordinates, eliminating the need for the VLM to estimate positions.

Click strategy priority when locator is active:

  1. click with query — describe the element (always preferred)
  2. click with id — use element id from the detected list
  3. click_button / click_link — text-based fallback
  4. focus_element with query + type — for input fields
  5. evaluate_js — last resort

Popup Detection

The agent automatically detects popups, modals, dialogs, and cookie banners at each step using a combination of:

  • ARIA roles (role="dialog", role="alertdialog", aria-modal="true")
  • Class-name patterns (modal, popup, cookie, consent, gdpr, overlay)
  • Large fixed/sticky elements with high z-index

When a popup is detected, the VLM receives its role, label text, position, and whether it has a close button — and is instructed to dismiss it before continuing the main task.


Agent Tools

ToolDescription
navigate_toNavigate to a URL
screenshotCapture current page as base64 PNG
clickClick a UI element by query (locator), id, or (x, y)
double_clickDouble-click a UI element by query, id, or (x, y)
scrollScroll at (x, y); positive scroll_y = down, negative = up
typeType text via keyboard events
waitWait N milliseconds
moveMove mouse to (x, y)
keypressPress a key or modifier combo (e.g. ["Control","a"])
dragDrag along a path of coordinates
left_mouse_downPress and hold left mouse button
left_mouse_upRelease left mouse button
get_current_urlReturn current page URL
get_dimensionsReturn viewport width and height
get_page_infoPage title, URL, and DOM snippet
get_request_headersHeaders from last network request
get_response_headersHeaders from last network response
get_raw_htmlRaw HTML body of last response
get_all_page_requestsAll network requests since page load
evaluate_jsRun JavaScript and return result
click_buttonClick a button by CSS selector or visible text
click_linkClick a link by CSS selector, href, or visible text
focus_elementFocus an input by query, id, or (x, y)
focus_element_cssFocus an input by CSS selector
export_cookiesExport browser cookies in Netscape cookies.txt format; optionally filter by domain

Container Options

# Default — start Chrome, VNC, and API server, keep running
docker run linux_chrome_agent:ubuntu --wait

# Headless mode — no VNC, CDP + API only
docker run linux_chrome_agent:ubuntu --no-vnc

# Debug — verbose startup output
docker run linux_chrome_agent:ubuntu --debug

# Skip startup — run a custom command instead
docker run linux_chrome_agent:ubuntu --skip bash

Architecture

┌───────────────────────────────────────────────────┐
│                 Docker Container                   │
│                                                   │
│  Chrome (CDP :9223) ◄─ socat ◄─ :9222 (ext)      │
│         │                                         │
│  CDPClient          Network idle tracking         │
│         │           New-tab detection             │
│  Agent (browser.py)                               │
│         │                                         │
│  LangGraph (graph.py)                             │
│    take_screenshot                                │
│       │   OmniParser (optional)                   │
│       │   Popup detection                         │
│    call_vlm ──► VLM (OpenAI-compatible)           │
│    execute_action                                 │
│       │   Locator model (optional)                │
│       │   Network idle wait                       │
│       │   Loop detection                          │
│    check_updates ── drain TaskInbox               │
│       │             handle pause/resume           │
│       ├── (loop) → take_screenshot                │
│       ├── (done) → generate_summary ──► END       │
│       └── (max steps) ──► END                     │
│                                                   │
│  FastAPI Server (:443 HTTPS)                      │
│    ├── A2A router  (POST /)                       │
│    └── OpenAI router (/v1/...)                    │
└───────────────────────────────────────────────────┘

License

MIT

MCP tools

The agent image exposes an MCP (Model Context Protocol) server on the same port as A2A at /mcp. Any MCP client — Claude Desktop, Cursor, Windsurf, ChatGPT Connectors, OpenAI Agents SDK — can list and invoke these tools using the pod's API_KEY as Bearer.

In production, Core proxies https://linux-chrome-agent.agents.forfetch.ai/mcp → the worker pod's /mcp.

Tool (skill_id)Description
navigateNavigate the browser to a URL
clickClick on an element or coordinates
double_clickDouble-click on an element or coordinates
typeType text into a focused element
scrollScroll the page up, down, left, or right
screenshotTake a screenshot of the current page
extract_textExtract text content from a page or element
evaluate_jsExecute JavaScript in the browser
hoverHover over an element
select_optionSelect an option from a dropdown

Input schemas are authored in apps/agents_mcp/app/seed.py. Skills without an explicit schema advertise a single {task: str} freeform parameter.

Tag summary

Content type

Image

Digest

sha256:640816d2d

Size

727.1 MB

Last updated

5 months ago

docker pull superbizon007/linux-chrome-agent