cd /news/ai-agents/how-i-got-computer-use-and-browser-u… · home › topics › ai-agents › article
[ARTICLE · art-136977] src=gist.github.com ↗ pub= topic=ai-agents verified=true sentiment=· neutral

How I got Computer Use and Browser Use running with Codex in E2B

A developer documented a custom integration that runs OpenAI's first-party Computer Use and Browser Use runtimes inside an E2B sandbox, pairing the Codex CLI with a virtual Linux desktop built from Xvfb, Openbox, and Chromium. The setup extracts runtime artifacts from a pinned ChatGPT Linux package, registers cua_repl and node_repl as MCP servers, and relies on persistent kernels and installed skills to drive screenshots, OS input, and browser automation. The developer noted that Browser Use spawns a separate native Codex child for authentication that cannot inherit the main process's in-memory credentials.

by read5 min views20 publishedSep 9, 2026

I wanted my background coding agent to use the app it was building. Open Chromium, inspect the page, click through a flow, and see whether it actually works.

I got it running with codex app-server, OpenAI’s first-party computer/browser runtimes, and a Linux desktop inside E2B.

Here’s how I put it together, including the auth issues that took me a while to figure out.

My E2B image runs:

Xvfb :99
  └─ Openbox
      └─ Chromium + OpenAI's Chrome extension

Xvfb provides a virtual screen. Openbox manages the windows. Chromium runs as a desktop application on that screen.

The desktop and tool runtimes share:

DISPLAY=:99

I didn’t need XFCE or the ChatGPT Electron UI. The agent can capture screenshots and interact with the desktop without a human streaming it.

Installing the Codex CLI alone doesn’t give you the computer/browser stack.

I extracted the runtime artifacts from a pinned Linux ChatGPT package:

  • the bundled Node runtime and node_repl
  • the chrome andunified-computer-use plugins
  • the native messaging host
  • the first-party skills, including the Linux Sky instructions

I installed the matching Chrome extension separately and preserved its extension ID.

The combination I tested:

Artifact Version
ChatGPT Linux package 26.901.51231
Codex CLI 0.153.4
Chrome extension 1.26.901.11451

I verified the download hashes and checked that the bundled and canonical Codex versions matched.

This is a custom integration using the packaged runtime, not an official standalone installation recipe. I keep the images private; the runtime artifacts are proprietary.

codex app-server
  │
  ├─ cua_repl
  │    └─ Linux Sky helper
  │         └─ screenshots + keyboard/mouse input
  │
  └─ node_repl
       └─ first-party browser service
            └─ native messaging host
                 └─ Chrome extension
                      └─ Chromium

Computer Use works through screenshots and operating-system input.

Browser Use provides browser-specific APIs through the extension.

I also installed Playwright CLI as a separate tool. It isn’t Playwright MCP, and it doesn’t replace either first-party runtime.

I registered cua_repl and node_repl as MCP servers in the image’s Codex configuration.

The important settings are:

Computer Use:
  DISPLAY=:99
  CUA_REPL_ENABLED_SURFACES=computer

Browser Use:
  DISPLAY=:99
  BROWSER_USE_AVAILABLE_BACKENDS=chrome
  NODE_REPL_TRUSTED_SERVICES={"browser":"<plugin path>/scripts/browser-service.mjs"}

I kept the complete plugin directories at stable image-owned paths and copied their skills into:

/home/user/.agents/skills/
├─ computer-use/
└─ control-chrome/

The skills matter. They teach Codex how to initialize the runtimes and use the actual APIs.

For Computer Use, initialization happens inside cua_repl:

await cua.getState();

Then, in a later call in the same kernel:

var { sky } = await import("@oai/sky");

await nodeRepl.emitImage(
  (await sky.get_screenshot())[0].data_url
);

For Browser Use, the installed skill points to the browser client:

var { setupBrowserRuntime } = await import(
  "/opt/coding-agent/image/desktop/plugins/chrome/scripts/browser-client.mjs"
);

var agent = await setupBrowserRuntime();

nodeRepl.write(await agent.browsers.list());

That runs inside the first-party node_repl, not an ordinary Node shell.

One easy mistake: starting a fresh process for every snippet. These tools expect a persistent kernel, so the imported modules and browser handles survive between calls.

Use the installed skill for browser selection and method signatures. Don’t guess the APIs from another computer-use implementation.

This was the part I didn’t expect.

My main Codex process already received credentials through RPC. But Browser Use started a separate native Codex child for authentication and configuration reads.

That child couldn’t inherit the main process’s in-memory login.

The extension connected, but navigation failed with:

Codex auth token is unavailable

I didn’t want to write an auth.json into the sandbox, so I added a per-run Unix-socket broker:

Browser runtime
  → stdio bridge
  → private Unix socket
  → broker
  → real canonical Codex child

The broker initializes the child and authenticates it through RPC before returning the initialization response.

Browser Use can then request auth status and configuration from that child. Credentials still come from my existing control-plane callbacks.

The bridge keeps credentials out of an auth file. Its same-user socket is not a credential-isolation boundary.

Once the child was authenticated, I hit:

unsupported Codex auth method: chatgptAuthTokens

The pinned browser consumer expected "chatgpt". My external RPC login correctly returned "chatgptAuthTokens".

I added a narrow compatibility translation to the browser-facing auth-status response.

The native login stays external. The access token stays unchanged. Before translating the label, I check that the returned token and its account claim match the credentials installed in that child.

This is specific to the versions I tested. It doesn’t change credentials or remote authorization.

Another failure said:

admin-enforced policy could not be verified

The cause was in my bridge.

The native client sent:

{"id":"1","method":"configRequirements/read"}

I had required an explicit "params": null.

Rejecting that valid parameterless request broke the config read. Browser Use reported the failure as a policy-verification error.

Accepting the actual wire format fixed it. I didn’t need to bypass the policy check.

I install the desktop and runtime artifacts during image construction.

A systemd service starts Xvfb, Openbox, and Chromium before the image’s ready marker. E2B captures that running desktop in the snapshot.

Build image
  → install desktop + first-party runtimes
  → write Codex configuration
  → start desktop
  → capture ready snapshot

Create sandbox
  → attach to the existing desktop
  → authenticate Codex through RPC
  → run computer/browser tools

/resume preserves the desktop rather than rebuilding it for every prompt.

One detail worth remembering: changing the image only affects new sandboxes. Existing ones keep their image-baked tools.

That lets my background agent run its coding work and use Chromium in the same sandbox, through the same Codex session.

── more in #ai-agents 4 stories · sorted by recency
── more on @openai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-i-got-computer-u…] indexed:0 read:5min 2026-09-09 · —