Skip to content

fix(codex): drive BrowserOS tools instead of Codex's bundled in-app browser#1973

Merged
Dani Akash (DaniAkash) merged 4 commits into
mainfrom
fix/codex-disable-in-app-browser
Jul 22, 2026
Merged

fix(codex): drive BrowserOS tools instead of Codex's bundled in-app browser#1973
Dani Akash (DaniAkash) merged 4 commits into
mainfrom
fix/codex-disable-in-app-browser

Conversation

@DaniAkash

Copy link
Copy Markdown
Contributor

Problem

When BrowserOS drives Codex through the ACP chat path, Codex sometimes reaches for its own bundled in-app browser plugin (browser@openai-bundled, exposed as the control-in-app-browser skill and a node_repl bridge) instead of the BrowserOS MCP browser tools. It only falls back to mcp.browseros.* after that bridge fails. The behavior is intermittent: the plugin's own manifest instructs the model to use the in-app browser for "open, navigate, click, type, screenshot ... the current in-app browser tab", which competes directly with the BrowserOS tools.

Root cause: the chat path spawns Codex against the real ~/.codex, where that plugin is enabled, and the ACP prompt only steered Codex away from its "file, shell, or fetch tools", never its in-app browser.

Fix

Two layers so BrowserOS is the only browser Codex can reach:

  1. Spawn Codex with a CODEX_HOME overlay that disables the in-app browser plugin. The overlay symlinks every real ~/.codex entry except config.toml, which is regenerated with [plugins."browser@openai-bundled"] enabled = false. Verified with codex debug prompt-input: the in-app browser skill and node_repl bridge disappear from the model-visible prompt while every other plugin stays intact. The user's real ~/.codex is never modified.
  2. Reinforce the ACP system prompt to route every browser action through mcp.browseros.* and never fall back to an in-app browser, Playwright, chrome-devtools, or the system Chrome.

Resilience

The overlay is built to survive future changes to ~/.codex:

  • The symlink farm re-syncs on every session: entries added under ~/.codex are picked up automatically and removed ones are pruned, so there is no hard-coded file list.
  • The config.toml edit is validated by a real TOML round-trip (Bun.TOML.parse). It is written only when the parse proves the edit changed exactly the one plugin field and nothing else. If the config format ever changes in a way the edit cannot handle, the overlay is not written, an error is logged, and Codex falls back to the real home rather than crashing or writing a corrupt config.

Validation

  • New unit tests for the config transform and the round-trip verifier (including format-change and corruption-rejection cases), plus launcher extraEnv coverage. bun test tests/lib/agents/host-acp green.
  • apps/server typecheck clean.
  • Manual: materialized the overlay against a real ~/.codex and confirmed via codex debug prompt-input that the in-app browser is gone and other plugins remain.

Materialize a CODEX_HOME overlay that disables Codex's bundled in-app
browser plugin (browser@openai-bundled). Symlinks every real ~/.codex
entry except config.toml, which is regenerated with the plugin disabled.
Self-healing: the symlink farm re-syncs to ~/.codex each call, and the
config edit is committed only when a real TOML round-trip proves it
changed exactly that one field. resolveAcpSpawnCommand gains extraEnv to
carry CODEX_HOME into both the bundled-bun and npx-fallback commands.
On the acpx chat path, point Codex at the browserless CODEX_HOME overlay
so its in-app browser plugin is absent, and reinforce the ACP prompt to
route every browser action through mcp.browseros.* and never fall back to
an in-app browser, Playwright, chrome-devtools, or the system Chrome.
@github-actions github-actions Bot added the fix label Jul 22, 2026
@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR routes Codex browser work exclusively through BrowserOS. The main changes are:

  • Adds a CODEX_HOME overlay that disables the bundled browser plugin.
  • Passes the overlay to bundled-Bun and host-npx ACP launchers.
  • Strengthens the ACP prompt against alternate browser fallbacks.
  • Adds tests for TOML transformation and launcher environment injection.

Confidence Score: 4/5

The overlay failure paths need fixes before merging because they can launch Codex with missing user state.

  • Unreadable configuration is replaced with a valid but incomplete file.
  • Individual symlink failures do not invalidate the overlay.
  • The prompt and launcher environment changes otherwise follow the intended routing.

packages/browseros-agent/apps/server/src/lib/agents/host-acp/codex-home.ts

Important Files Changed

Filename Overview
packages/browseros-agent/apps/server/src/lib/agents/host-acp/codex-home.ts Adds the overlay and TOML rewrite, but two suppressed filesystem failures can launch an incomplete Codex home.
packages/browseros-agent/apps/server/src/agent/provider-factory.ts Materializes the overlay and injects it into the built-in Codex launcher.
packages/browseros-agent/apps/server/src/lib/agents/host-acp/launcher.ts Adds optional environment variables to both supported ACP launch paths.
packages/browseros-agent/apps/server/src/agent/prompt.ts Requires ACP browser actions to use BrowserOS MCP tools.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Create ACP language model] --> B[Materialize browserless CODEX_HOME]
    B --> C[Mirror the real Codex home]
    C --> D[Disable and verify browser plugin config]
    D -->|Success| E[Set CODEX_HOME on Codex launcher]
    B -->|Failure| F[Leave CODEX_HOME unset]
    F --> G[Codex uses the real home]
    E --> H[Codex uses BrowserOS MCP tools]
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
packages/browseros-agent/apps/server/src/lib/agents/host-acp/codex-home.ts:191-193
**Unreadable Config Becomes Empty**

When `config.toml` exists but cannot be read because of permissions or an I/O error, this catch treats it as an empty file. Verification then succeeds and Codex starts with a minimal overlay that drops the user's model, provider, authentication, and other settings instead of falling back to the real home.

```suggestion
  let sourceText: string
  try {
    sourceText = await readFile(join(source, CONFIG_FILE), 'utf8')
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
    sourceText = ''
  }
```

### Issue 2 of 2
packages/browseros-agent/apps/server/src/lib/agents/host-acp/codex-home.ts:178-183
**Failed Links Still Mark Success**

When symlink creation is denied or races with another session using the shared overlay, this catch suppresses the failure and synchronization continues. The function can then return the incomplete directory as `CODEX_HOME`, leaving required files such as authentication state unavailable to Codex.

```suggestion
  } catch (error) {
    logger.warn('Failed to create a Codex home overlay symlink', {
      linkPath,
      error: error instanceof Error ? error.message : String(error),
    })
    throw error
  }
```

Reviews (1): Last reviewed commit: "fix(codex): drive BrowserOS tools, not t..." | Re-trigger Greptile

Comment thread packages/browseros-agent/apps/server/src/lib/agents/host-acp/codex-home.ts Outdated
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

✅ Tests passed — 1629/1633

Suite Passed Failed Skipped
agent 338/338 0 0
build 34/34 0 0
claw-app 185/185 0 0
⚠️ claw-mcp 0/0 0 0
⚠️ claw-onboard 0/0 0 0
⚠️ claw-server-rust-quality 0/0 0 0
⚠️ claw-server-rust 0/0 0 0
server-agent 314/314 0 0
server-api 147/147 0 0
server-browser 10/10 0 0
server-integration 10/10 0 0
server-lib 299/300 0 1
server-root 38/41 0 3
server-tools 254/254 0 0

View workflow run

Two edge cases in the overlay builder: an unreadable config.toml
(permissions/IO, not ENOENT) was treated as empty, producing a minimal
config that dropped the user's Codex settings; and a failed symlink was
swallowed, so a missing auth link could still be returned as CODEX_HOME.
Now a non-ENOENT config read rethrows to the fallback path, and
ensureSymlink reports success/failure (a concurrent EEXIST pointing at
the right target still counts as success) so the materializer returns
null and falls back to the real home when the overlay is incomplete.
Gate the browserless-home materialization on codex being the agent
actually spawned, so claude chats do not do the extra fs work (and the
workspace-mkdir assertion stays at one call). Import the overlay module
lazily inside codexBrowserlessEnv so its fs-heavy imports stay out of the
provider factory's static graph, which keeps the partial node:fs/promises
mock in the ACP factory tests intact.
@DaniAkash
Dani Akash (DaniAkash) merged commit fa34ee7 into main Jul 22, 2026
22 checks passed
@DaniAkash
Dani Akash (DaniAkash) deleted the fix/codex-disable-in-app-browser branch July 22, 2026 10:45
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