mcpField
C
codex-browser-fix

codex-browser-fix

github.com/vivswanAgent workflows159 installsUpdated 1d ago
Repository

About codex-browser-fix

Codex Browser Fix is a skill for diagnosing and restoring the ChatGPT extension connection used by Codex's desktop browser workflow. It synchronizes plugin files and settings, then selects the requested Chromium browser family without substituting another browser.

Key features

  1. 01Preflight sync and read-only check
  2. 02Repairs plugin cache and trust settings
  3. 03Overrides provider for app-server only
  4. 04Selects Chromium browsers by family
  5. 05Guides extension recovery and tab handoff

Use cases

  1. 01Fixing an unavailable Codex auth token
  2. 02Restoring extension discovery after a desktop update
  3. 03Connecting to Brave, Vivaldi, or Opera
  4. 04Checking browser setup without the desktop plugin

MCP support

The skill uses the installed Chrome plugin through its node_repl JavaScript tool. Its preflight check can run independently of an MCP host, but live browser work requires a desktop Codex session with the plugin.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/vivswan/skills --skill codex-browser-fix

After installing, type/codex-browser-fixin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

LICENSE.md
README.md
.codex-plugin/
plugin.json
agents/
openai.yaml
references/
recovery.md
scripts/
browser-auth-launcher.mts
browser-plugin-preflight.mts
codex-config-toml.mts

Details

From the project README

Codex Browser Fix

Codex only. The desktop app bundles a Chrome plugin that drives any Chromium browser through the ChatGPT extension. Two things break it, and the vendor skill covers neither:

SymptomCauseFix
Codex auth token is unavailable after the extension was discoveredconfig.toml sets a custom model_provider; the browser helper launches codex app-server and inherits it, so the ChatGPT sign-in is invisiblePreflight installs a launcher that overrides the provider for that one subprocess
Extension found yesterday, missing or erroring todayThe desktop app updated; ~/.codex/plugins/cache/openai-bundled/chrome still points at the old bundlePreflight re-syncs the cache and the trust hashes to the installed app
User asked for a Chromium browser other than Chrome or Edge (Brave, Vivaldi, Opera) and the agent picked ChromeThe vendor skill only names chrome and edge; other families need a list() matchSelect by family (below)

The installed Chrome plugin's own skill (skills/control-chrome/SKILL.md inside the app bundle) stays the authority for browser APIs. This skill owns local setup, recovery, and browser-family selection.

When to Apply

  • The user names Brave, Vivaldi, Opera, Edge, Chrome, or "my browser" for a task that needs their tabs or sign-in
  • The Chrome plugin errors with Codex auth token is unavailable
  • Browser discovery finds no extension connection, or fails right after a ChatGPT or Codex desktop update
  • "check the browser setup" / "fix the browser connection"

Workflow

1. Preflight the plugin

Run before importing browser-client.mjs or selecting a browser. Requires Bun and the ChatGPT or Codex desktop app. <skill-dir> is the installed skill folder (Codex default: ~/.codex/skills/codex-browser-fix).

bun "<skill-dir>/scripts/browser-plugin-preflight.mts"          # sync + verify
bun "<skill-dir>/scripts/browser-plugin-preflight.mts" --check  # read-only verify
usage: browser-plugin-preflight.mts [--check] [--plugin-dir <dir>]
  --check             verify only, nothing written; exit 1 on drift
  --plugin-dir <dir>  the bundled Chrome plugin directory of a non-standard install
the codex home is $CODEX_HOME or ~/.codex
exits: 0 synchronized, or verified current; 1 a missing file or a stale setting; 2 usage

It prints the app bundle version, the plugin path to import browser-client.mjs from, and which caches were synchronized. Re-run it after every desktop app update or restart.

A failure names the missing file or stale setting and exits 1. A missing config.toml, bundle, or executable is an error, never a pass, under --check too.

What it changes, and nothing else (<home> is the codex home):

  • <home>/plugins/cache/openai-bundled/chrome: every existing pinned version entry, the current version's entry, and the latest link follow the installed app bundle. <home>/plugins/cache/openai-bundled/browser: the current version's companion copy and its latest link only. Replaced stale copies move to <home>/plugin-rollbacks/.
  • <home>/config.toml, under [mcp_servers.node_repl.env]: CODEX_CLI_PATH, the app version, and the trusted code paths. Under [shell_environment_policy.set]: the browser-client.mjs hash. Each value must already be assigned there. The edit is parse-verified to change nothing else.
  • <home>/scripts/browser-codex: a generated launcher. Only its app-server subcommand gets -c 'model_provider="openai"'. Every other subcommand passes through unchanged. The main provider, CODEX_HOME, and credentials are untouched.
  • Each <home>/hosts/<host>/: its own plugins/cache/openai-bundled/browser companion cache, and, where it has a config.toml, the same config edits plus its own scripts/browser-codex. The Chrome cache is global only.
2. Bootstrap the vendor way

Follow the installed control-chrome skill through its node_repl JavaScript tool. Import browser-client.mjs from the path the preflight printed, call setupBrowserRuntime() once, and reuse the agent and browser bindings across turns. Never reset a working session to repeat setup.

3. Select the browser family

Chrome and Edge have vendor selectors: agent.browsers.get("chrome") and agent.browsers.get("edge"). Every other Chromium family is matched from the list:

// Declared once per session; call it again with a profile name after asking.
async function selectExtension(family, profileName) {
  const label = (c) => c.profileName ?? c.name; // the name shown when asking
  const candidates = (await agent.browsers.list()).filter(
    (c) =>
      c.type === "extension" &&
      c.family === family &&
      (profileName === undefined || label(c) === profileName),
  );
  if (candidates.length === 0) throw new Error(`No connected ${family} extension`);
  if (candidates.length > 1) {
    const profiles = candidates.map(label).join(", ");
    throw new Error(`Several ${family} profiles connected (${profiles}); ask which one`);
  }
  return agent.browsers.get(candidates[0].id);
}
let browser = await selectExtension("<family>", undefined); // the family the user asked for; ("<family>", "Work") once the profile is known
nodeRepl.write(await browser.documentation());
  • No candidate: report the browser as unavailable in the user's words (the extension is missing or disconnected). Several: ask which profile, then call selectExtension again with that name and reassign browser. Never guess.
  • Family names follow the plugin's scripts/extension-ids.json: brave, chrome, edge, opera, vivaldi.
  • An explicit browser request is a hard constraint. Never substitute Google Chrome because the plugin is named Chrome, and never fall back to Computer Use or a fresh browser.
  • After selection, read the complete documentation() output as the vendor skill requires, name the session, then claim the exact tab object from browser.user.openTabs() that matches the task.
  • A stale or closed tab gets a fresh tab from the existing browser binding. Re-select a browser only after an explicit disconnection or a user-requested switch.
4. Work and hand off
  • Inspect the page before acting. Re-check state after each meaningful action. A completed click or upload is not a saved result: verify the fields, media, and saved state on the page before reporting success.
  • Read the vendor upload instructions before photo or document uploads.
  • Preserve tabs per the vendor's handoff rules. Never clear browser storage, since it holds local drafts and signed-in state.
  • Connection setup authorizes nothing else. Applications, messages, purchases, and publications still follow the current request and project approval rules.

Recovery

  • Codex auth token is unavailable, empty discovery, cache or trust failures: run the preflight, then read recovery.
  • Discovery or selection fails after a good bootstrap: await agent.documentation.get("bootstrap-troubleshooting").
  • Extension install or communication fails: await agent.documentation.get("chrome-troubleshooting").
  • A running browser helper keeps the environment it started with. A new launcher setting takes effect when that helper next starts. Do not kill a working connection to apply it.

Never: switch the main model_provider off and back on, copy tokens, patch app binaries, or reinstall components speculatively. Report a real sign-in requirement as the user's action.

Fallback Without the Desktop Plugin

The preflight --check runs from any terminal with Bun, independent of an MCP host, and reports which bundle, cache, or setting is missing. Prepare task material locally where useful.

Live browser work resumes only in a desktop Codex session with the Chrome plugin and the requested browser connection. Never substitute another browser or automation transport.

References

  • references/recovery.md: the auth incident specimen, what the preflight synchronizes, and the extension-versus-tab failure split
  • scripts/browser-plugin-preflight.mts: the sole setup implementation (sync and --check)
  • scripts/browser-auth-launcher.mts: the launcher generator, unit-tested upstream (https://github.com/Vivswan/skills, tests/skills/codex-browser-fix/browser-auth-launcher.test.ts)
  • scripts/codex-config-toml.mts: the config.toml edit, unit-tested upstream (https://github.com/Vivswan/skills, tests/skills/codex-browser-fix/codex-config-toml.test.ts)

Comments

Markdown supported