Skip to content

feat: run BrowserOS inside OpenClaw container#655

Open
shivammittal274 wants to merge 2 commits intofeat/podman-migrationfrom
feat/browseros-in-container
Open

feat: run BrowserOS inside OpenClaw container#655
shivammittal274 wants to merge 2 commits intofeat/podman-migrationfrom
feat/browseros-in-container

Conversation

@shivammittal274
Copy link
Copy Markdown
Contributor

Summary

  • Adds a custom container image (ghcr.io/browseros/openclaw-runtime) that runs BrowserOS headless + BrowserOS server + OpenClaw together
  • When a user creates an agent, the container comes with full browser automation — no manual setup
  • OpenClaw uses browseros-cli to control BrowserOS inside the same container

What's in the container

Container starts → entrypoint.sh runs:
  1. BrowserOS headless (CDP on port 9000)
  2. BrowserOS server (MCP on port 9100, 60 browser tools)
  3. browseros-cli configured
  4. OpenClaw gateway starts

Changes

agents.ts

  • Image: ghcr.io/browseros/openclaw-runtime:latest
  • Port range 4000-4099 mapped for apps OpenClaw builds
  • shm_size: 256mb for headless browser
  • start_period: 60s for container health check
  • Auto-build image locally from Dockerfile if not found in registry
  • Health check timeout: 30 → 90 retries

openclaw-container/Dockerfile

  • Based on ghcr.io/openclaw/openclaw:latest
  • Installs BrowserOS ARM64 .deb
  • Installs browseros_server binary (needed because built-in server has a CDP port detection bug in headless mode)
  • Installs browseros-cli globally
  • Pre-installs browseros-agent skill

openclaw-container/entrypoint.sh

  • Launches BrowserOS headless with --disable-browseros-server (server runs separately)
  • Starts browseros_server with correct CDP/server ports
  • Configures browseros-cli
  • Starts OpenClaw gateway

Known issue

BrowserOS built-in server (--browseros-mcp-port) doesn't read --remote-debugging-port — it always tries CDP on the wrong port. This is why we run browseros_server separately. Same pattern used by BrowserOSAppManager and test helpers. TODO comment exists in browser.ts:86.

Tested e2e

  1. POST /agents/create → container starts with BrowserOS + server + CLI
  2. Chat: "search sensodyne toothpaste on Amazon"
  3. OpenClaw navigates to Amazon, fills search, extracts 533 results with prices

Prerequisites

  • browseros_server binary must be built and placed in openclaw-container/ dir before building the image
    NODE_ENV=production bun scripts/build/server.ts --target=linux-arm64 --compile-only
    cp dist/prod/server/.tmp/binaries/browseros-server-linux-arm64 apps/server/src/api/services/openclaw-container/browseros_server
  • Then build: podman build -t ghcr.io/browseros/openclaw-runtime:latest apps/server/src/api/services/openclaw-container/

🤖 Generated with Claude Code

- Custom container image (Dockerfile + entrypoint) that pre-installs:
  - BrowserOS ARM64 .deb (headless browser with custom CDP)
  - BrowserOS server binary (MCP server, 60 browser tools)
  - browseros-cli (CLI for browser automation)
  - browseros-agent skill (OpenClaw skill for browser control)

- Entrypoint automatically launches:
  1. BrowserOS headless (CDP on port 9000)
  2. BrowserOS server (MCP on port 9100, connects to CDP)
  3. Configures browseros-cli
  4. Starts OpenClaw gateway

- agents.ts changes:
  - Image: ghcr.io/browseros/openclaw-runtime:latest
  - Port range 4000-4099 for apps OpenClaw builds
  - shm_size 256mb for headless browser
  - Health check start_period 60s
  - Auto-build image locally if not found in registry
  - Health check timeout increased to 90s

Known issue: BrowserOS built-in server has a bug where it doesn't
read --remote-debugging-port, so the server must run separately.
This matches the pattern used by BrowserOSAppManager and test helpers.

Tested e2e: create agent → OpenClaw browses Amazon → extracts products
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 7, 2026

Greptile Summary

PR #655 adds a custom openclaw-runtime container image that bundles BrowserOS headless, BrowserOS server, and OpenClaw together, with auto-build fallback if the registry image is not found. Three P1 issues were identified that should be addressed before merging.

Confidence Score: 4/5

Three P1 issues should be resolved before merging: silent container failures in entrypoint.sh and an ARM64-only Dockerfile that breaks local builds on AMD64.

Score reduced from 5 due to two P1 logic bugs in entrypoint.sh that produce zombie-healthy containers, and one P1 Dockerfile issue that breaks the auto-build fallback on non-ARM64 hosts.

entrypoint.sh (both wait loops need exit-on-failure guards) and Dockerfile (arch detection for .deb URL)

Important Files Changed

Filename Overview
packages/browseros-agent/apps/server/src/api/services/openclaw-container/entrypoint.sh Both CDP and server wait loops silently swallow timeouts, allowing OpenClaw to start with a broken browser automation stack
packages/browseros-agent/apps/server/src/api/services/openclaw-container/Dockerfile Hardcoded ARM64 .deb URL will break local auto-builds on AMD64 machines
packages/browseros-agent/apps/server/src/api/routes/agents.ts Well-structured agent lifecycle management; stale '30 seconds' error message and unchecked app port range are minor issues
packages/browseros-agent/apps/server/src/api/services/openclaw-container/.gitignore Correctly ignores the browseros_server binary that must be supplied manually before building the image

Sequence Diagram

sequenceDiagram
    participant Client
    participant AgentsRoute
    participant Podman
    participant Container
    participant BrowserOS
    participant BrowserOSServer
    participant OpenClaw

    Client->>AgentsRoute: POST /agents/create
    AgentsRoute-->>Client: 201 {id, status: creating}
    AgentsRoute->>Podman: ensureReady()
    AgentsRoute->>Podman: image exists? / pull / build
    AgentsRoute->>Podman: compose up -d
    Podman->>Container: start entrypoint.sh
    Container->>BrowserOS: launch --headless --disable-browseros-server
    Container->>Container: wait loop (30s) for CDP:9000
    Note over Container: ⚠️ No exit on timeout
    Container->>BrowserOSServer: launch browseros_server
    Container->>Container: wait loop (30s) for :9100/health
    Note over Container: ⚠️ No exit on timeout
    Container->>OpenClaw: exec node dist/index.js gateway
    AgentsRoute->>AgentsRoute: poll /healthz (90 retries)
    OpenClaw-->>AgentsRoute: 200 OK
    AgentsRoute->>AgentsRoute: updateStatus('running')
Loading

Comments Outside Diff (1)

  1. packages/browseros-agent/apps/server/src/api/routes/agents.ts, line 501 (link)

    P2 Only the gateway port is probed; the 100-port app range is never verified

    findAvailablePort(18789) finds a free gateway port, but the compose file maps host ports gatewayPort+1000 through gatewayPort+1099 for OpenClaw app ports. Those ports are never checked for availability, so a second agent created while the first is running risks a compose up failure due to port conflicts.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: packages/browseros-agent/apps/server/src/api/routes/agents.ts
    Line: 501
    
    Comment:
    **Only the gateway port is probed; the 100-port app range is never verified**
    
    `findAvailablePort(18789)` finds a free gateway port, but the compose file maps host ports `gatewayPort+1000` through `gatewayPort+1099` for OpenClaw app ports. Those ports are never checked for availability, so a second agent created while the first is running risks a `compose up` failure due to port conflicts.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/services/openclaw-container/entrypoint.sh
Line: 31-38

Comment:
**Silent failure if CDP never becomes ready**

The wait loop exits after 30 iterations without signaling failure. If BrowserOS never starts, `browseros_server` still launches and the container reports healthy with broken browser automation.

Add `exit 1` after the loop:
```suggestion
echo "[entrypoint] Waiting for BrowserOS CDP on port $CDP_PORT..."
READY=0
for i in $(seq 1 30); do
  if curl -sf http://localhost:$CDP_PORT/json/version > /dev/null 2>&1; then
    echo "[entrypoint] CDP ready"
    READY=1
    break
  fi
  sleep 1
done
if [ "$READY" -eq 0 ]; then
  echo "[entrypoint] ERROR: BrowserOS CDP did not become ready in time" >&2
  exit 1
fi
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/services/openclaw-container/entrypoint.sh
Line: 50-57

Comment:
**Server wait loop also swallows failure silently**

Same issue as the CDP loop: if `browseros_server` never becomes healthy, the script silently continues and starts the OpenClaw gateway, producing a healthy-looking container with broken automation.

```suggestion
echo "[entrypoint] Waiting for BrowserOS server on port $SERVER_PORT..."
READY=0
for i in $(seq 1 30); do
  if curl -sf http://localhost:$SERVER_PORT/health > /dev/null 2>&1; then
    echo "[entrypoint] Server ready"
    READY=1
    break
  fi
  sleep 1
done
if [ "$READY" -eq 0 ]; then
  echo "[entrypoint] ERROR: BrowserOS server did not become ready in time" >&2
  exit 1
fi
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/services/openclaw-container/Dockerfile
Line: 6-9

Comment:
**Hardcoded ARM64 `.deb` — local builds on AMD64 will install the wrong binary**

The PR adds an auto-local-build fallback when the registry image is missing, so this Dockerfile will run on user machines of any architecture. The default `BROWSEROS_DEB_URL` points to the `arm64` package, causing `dpkg` to fail or install an unusable binary on AMD64 hosts. Detect arch at build time instead:

```suggestion
ARG BROWSEROS_VERSION=0.44.0.2
RUN ARCH=$(dpkg --print-architecture) && \
    curl -fsSL -o /tmp/BrowserOS.deb \
      "http://cdn.browseros.com/releases/${BROWSEROS_VERSION}/linux/BrowserOS_v${BROWSEROS_VERSION}_${ARCH}.deb" && \
    apt-get update -qq && \
    apt-get install -y -qq --fix-broken /tmp/BrowserOS.deb && \
    rm /tmp/BrowserOS.deb && \
    npm install -g browseros-cli && \
    rm -rf /var/lib/apt/lists/*
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/routes/agents.ts
Line: 639

Comment:
**Error message says 30 s but the loop now waits 90 s**

The retry count was bumped to 90 in this PR but the thrown error message wasn't updated.

```suggestion
            throw new Error('Gateway did not become healthy within 90 seconds')
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/routes/agents.ts
Line: 501

Comment:
**Only the gateway port is probed; the 100-port app range is never verified**

`findAvailablePort(18789)` finds a free gateway port, but the compose file maps host ports `gatewayPort+1000` through `gatewayPort+1099` for OpenClaw app ports. Those ports are never checked for availability, so a second agent created while the first is running risks a `compose up` failure due to port conflicts.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "feat: run BrowserOS inside OpenClaw cont..." | Re-trigger Greptile

Comment on lines +31 to +38
echo "[entrypoint] Waiting for BrowserOS CDP on port $CDP_PORT..."
for i in $(seq 1 30); do
if curl -sf http://localhost:$CDP_PORT/json/version > /dev/null 2>&1; then
echo "[entrypoint] CDP ready"
break
fi
sleep 1
done
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Silent failure if CDP never becomes ready

The wait loop exits after 30 iterations without signaling failure. If BrowserOS never starts, browseros_server still launches and the container reports healthy with broken browser automation.

Add exit 1 after the loop:

Suggested change
echo "[entrypoint] Waiting for BrowserOS CDP on port $CDP_PORT..."
for i in $(seq 1 30); do
if curl -sf http://localhost:$CDP_PORT/json/version > /dev/null 2>&1; then
echo "[entrypoint] CDP ready"
break
fi
sleep 1
done
echo "[entrypoint] Waiting for BrowserOS CDP on port $CDP_PORT..."
READY=0
for i in $(seq 1 30); do
if curl -sf http://localhost:$CDP_PORT/json/version > /dev/null 2>&1; then
echo "[entrypoint] CDP ready"
READY=1
break
fi
sleep 1
done
if [ "$READY" -eq 0 ]; then
echo "[entrypoint] ERROR: BrowserOS CDP did not become ready in time" >&2
exit 1
fi
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/services/openclaw-container/entrypoint.sh
Line: 31-38

Comment:
**Silent failure if CDP never becomes ready**

The wait loop exits after 30 iterations without signaling failure. If BrowserOS never starts, `browseros_server` still launches and the container reports healthy with broken browser automation.

Add `exit 1` after the loop:
```suggestion
echo "[entrypoint] Waiting for BrowserOS CDP on port $CDP_PORT..."
READY=0
for i in $(seq 1 30); do
  if curl -sf http://localhost:$CDP_PORT/json/version > /dev/null 2>&1; then
    echo "[entrypoint] CDP ready"
    READY=1
    break
  fi
  sleep 1
done
if [ "$READY" -eq 0 ]; then
  echo "[entrypoint] ERROR: BrowserOS CDP did not become ready in time" >&2
  exit 1
fi
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +50 to +57
echo "[entrypoint] Waiting for BrowserOS server on port $SERVER_PORT..."
for i in $(seq 1 30); do
if curl -sf http://localhost:$SERVER_PORT/health > /dev/null 2>&1; then
echo "[entrypoint] Server ready"
break
fi
sleep 1
done
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Server wait loop also swallows failure silently

Same issue as the CDP loop: if browseros_server never becomes healthy, the script silently continues and starts the OpenClaw gateway, producing a healthy-looking container with broken automation.

Suggested change
echo "[entrypoint] Waiting for BrowserOS server on port $SERVER_PORT..."
for i in $(seq 1 30); do
if curl -sf http://localhost:$SERVER_PORT/health > /dev/null 2>&1; then
echo "[entrypoint] Server ready"
break
fi
sleep 1
done
echo "[entrypoint] Waiting for BrowserOS server on port $SERVER_PORT..."
READY=0
for i in $(seq 1 30); do
if curl -sf http://localhost:$SERVER_PORT/health > /dev/null 2>&1; then
echo "[entrypoint] Server ready"
READY=1
break
fi
sleep 1
done
if [ "$READY" -eq 0 ]; then
echo "[entrypoint] ERROR: BrowserOS server did not become ready in time" >&2
exit 1
fi
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/services/openclaw-container/entrypoint.sh
Line: 50-57

Comment:
**Server wait loop also swallows failure silently**

Same issue as the CDP loop: if `browseros_server` never becomes healthy, the script silently continues and starts the OpenClaw gateway, producing a healthy-looking container with broken automation.

```suggestion
echo "[entrypoint] Waiting for BrowserOS server on port $SERVER_PORT..."
READY=0
for i in $(seq 1 30); do
  if curl -sf http://localhost:$SERVER_PORT/health > /dev/null 2>&1; then
    echo "[entrypoint] Server ready"
    READY=1
    break
  fi
  sleep 1
done
if [ "$READY" -eq 0 ]; then
  echo "[entrypoint] ERROR: BrowserOS server did not become ready in time" >&2
  exit 1
fi
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +6 to +9
ARG BROWSEROS_DEB_URL=http://cdn.browseros.com/releases/0.44.0.2/linux/BrowserOS_v0.44.0.2_arm64.deb
RUN apt-get update -qq && \
curl -fsSL -o /tmp/BrowserOS.deb "$BROWSEROS_DEB_URL" && \
apt-get install -y -qq --fix-broken /tmp/BrowserOS.deb && \
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hardcoded ARM64 .deb — local builds on AMD64 will install the wrong binary

The PR adds an auto-local-build fallback when the registry image is missing, so this Dockerfile will run on user machines of any architecture. The default BROWSEROS_DEB_URL points to the arm64 package, causing dpkg to fail or install an unusable binary on AMD64 hosts. Detect arch at build time instead:

Suggested change
ARG BROWSEROS_DEB_URL=http://cdn.browseros.com/releases/0.44.0.2/linux/BrowserOS_v0.44.0.2_arm64.deb
RUN apt-get update -qq && \
curl -fsSL -o /tmp/BrowserOS.deb "$BROWSEROS_DEB_URL" && \
apt-get install -y -qq --fix-broken /tmp/BrowserOS.deb && \
ARG BROWSEROS_VERSION=0.44.0.2
RUN ARCH=$(dpkg --print-architecture) && \
curl -fsSL -o /tmp/BrowserOS.deb \
"http://cdn.browseros.com/releases/${BROWSEROS_VERSION}/linux/BrowserOS_v${BROWSEROS_VERSION}_${ARCH}.deb" && \
apt-get update -qq && \
apt-get install -y -qq --fix-broken /tmp/BrowserOS.deb && \
rm /tmp/BrowserOS.deb && \
npm install -g browseros-cli && \
rm -rf /var/lib/apt/lists/*
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/browseros-agent/apps/server/src/api/services/openclaw-container/Dockerfile
Line: 6-9

Comment:
**Hardcoded ARM64 `.deb` — local builds on AMD64 will install the wrong binary**

The PR adds an auto-local-build fallback when the registry image is missing, so this Dockerfile will run on user machines of any architecture. The default `BROWSEROS_DEB_URL` points to the `arm64` package, causing `dpkg` to fail or install an unusable binary on AMD64 hosts. Detect arch at build time instead:

```suggestion
ARG BROWSEROS_VERSION=0.44.0.2
RUN ARCH=$(dpkg --print-architecture) && \
    curl -fsSL -o /tmp/BrowserOS.deb \
      "http://cdn.browseros.com/releases/${BROWSEROS_VERSION}/linux/BrowserOS_v${BROWSEROS_VERSION}_${ARCH}.deb" && \
    apt-get update -qq && \
    apt-get install -y -qq --fix-broken /tmp/BrowserOS.deb && \
    rm /tmp/BrowserOS.deb && \
    npm install -g browseros-cli && \
    rm -rf /var/lib/apt/lists/*
```

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant