dsh-codex-chrome
Manifest validDeepSeek Harness plugin: migrates OpenAI Codex's chrome@openai-bundled plugin into DSH as native mcp__chrome__* tools — drive your own Chrome (tabs, logged-in sessions, accessibility trees, screenshot
dsh-codex-chrome
English · 简体中文
Control your own Chrome from DeepSeek Harness by
migrating OpenAI Codex's chrome@openai-bundled plugin into DSH. The agent gets a set of native
mcp__chrome__* tools and can reuse the browser state you already have — open tabs, cookies,
logged-in sessions — to navigate, read pages, click, type and take screenshots.

Above: a DSH session calling chrome_observe { mode: "screenshot", fullPage: true } and getting a
capture of the page open in the user's own Chrome.
What the Codex "plugin" actually is
It is enabled in ~/.codex/config.toml as:
[plugins."chrome@openai-bundled"]
enabled = true
But it is not an MCP server. It is three things:
| Part | Location | Role |
|---|---|---|
| Skill | ~/.codex/plugins/cache/openai-bundled/chrome/<ver>/skills/control-chrome/SKILL.md | Tells the model to select a browser, observe with ax.write(), then act |
| Hooks | plugin.json → Stop / Interrupt / SubagentStop | Call the node_repl tool turn_ended each turn to release browser control |
| Runtime | scripts/browser-client.mjs + scripts/browser-service.mjs | The actual browser control, hosted by Codex's node_repl MCP server as a trusted service |
browser-client.mjs drives the work through globalThis.nodeRepl.rpc("browser", …), and that service
only runs inside the Codex node_repl host: it depends on privileged capabilities that exist
nowhere else (nativePipe, addTurnEndedHandler, createElicitation, host-injected turn metadata).
This migration therefore does not rewrite browser control — it reuses the vendor runtime exactly as
shipped.
Why there is an extra bridge process
Every browser call must carry Codex turn metadata:
{ "_meta": { "x-codex-turn-metadata": { "session_id": "…", "turn_id": "…", "call_id": "…" } } }
The browser service reads it from nodeRepl.requestMeta and hard-fails without it:
Missing required Codex turn metadata: session_id, turn_id
@deepseek-ai/dsh-mcp-client has no per-call _meta support — its only call site is
client.callTool({ name, arguments }, { … }) — so bin/chrome-mcp.mjs fronts node_repl, injects the
metadata, and republishes the browser API as native DSH tools:
DSH ──mcp-client(stdio)──▶ bin/chrome-mcp.mjs ──MCP(stdio) + _meta──▶ Codex node_repl
│ │
│ trusted service browser-service.mjs
│ │
└────────── native tools ◀────── ChatGPT browser extension ◀▶ Chrome
Install
DSH Desktop
Open the plugin manager and install the bundle from this directory, or from a registry once
published. Desktop profiles are managed exclusively by the app, so
dsh plugin --profile desktop add … is refused by design.
CLI profiles
dsh plugin --profile web add /absolute/path/to/dsh-codex-chrome
Either way the profile's package.json ends up with the dependency and the bundle entry; doing it by
hand is equivalent:
"dependencies": { "dsh-codex-chrome": "link:/path/to/dsh-codex-chrome" }
"dsh": { "profile": { "bundles": [ "…", "dsh-codex-chrome" ] } }
then run pnpm install in the profile directory. After a restart the model sees the eleven
mcp__chrome__* tools and the control-chrome skill.
Tools
| Tool | Purpose |
|---|---|
chrome_status | List connected browsers, the current binding, and open tabs |
chrome_select | Bind a browser: chrome / edge / brave / vivaldi / opera / iab / extension / default / auto |
chrome_tabs | list / new / select / close / user_tabs (your own tabs) / claim (take one over) |
chrome_navigate | goto / back / forward / reload |
chrome_observe | state (accessibility tree, preferred) / dom / visible_dom / screenshot / both |
chrome_act | via:"ax": click, setValue, typeText, pressKey, paste, scroll, selectText, performSecondaryAction, dragvia:"locator": Playwright locator click, fill, press, selectOption, check, waitFor, … |
chrome_read | innerText / textContent / allTextContents / attribute / count / isVisible / isEnabled |
chrome_evaluate | Evaluate a read-only expression in the page |
chrome_wait | Wait for url / load / timeout / selector |
chrome_js | Escape hatch: run JS inside the Codex runtime with agent / browser / tab in scope |
chrome_end_turn | Release browser control for this turn (Codex's Stop hook equivalent) |
The model-facing workflow, documented in the bundled control-chrome skill, is
observe → act → observe: prefer accessibility element indices over coordinates, and re-derive the
indices after every action.
Implementation notes
- State lives on
globalThis, not in module scope. Everyjscall innode_replis evaluated in a fresh realm that re-evaluates the sameimport(); module-level bindings reset, whileglobalThisis shared for the life of the kernel. - Screenshots cannot be written to disk. Once the browser service is active the kernel filesystem
turns read-only (even
/tmpand$CODEX_HOMEreturnEROFS), so images go out throughnodeRepl.emitImage; the bridge spools a copy on the host side. - Accessibility indices are bound to the call that produced them.
chrome_actre-readstab.ax.get("state")before acting so an index returned bychrome_observeis usable. - The
_metainjection is the whole point. Without it every browser call fails. - The vendor capture path labels JPEG as PNG. Both the sandbox and the bridge re-derive the type from magic bytes, because DSH rejects an image whose declared type disagrees with its payload.
Self-checks
node scripts/check-package.mjs # static package consistency, no browser needed
node --test # 13 tests: unit checks + a real MCP handshake
node scripts/doctor.mjs # assets, extension, native host, node_repl
node scripts/doctor.mjs --deep # …plus one real browser round trip
node scripts/smoke.mjs # end to end: open a tab, observe, screenshot, evaluate, close
Requirements
- Linux (developed and verified on Arch with Chrome 154, on both Wayland and X11).
- The ChatGPT/Codex desktop app must have run at least once, so it materialises
~/.codex/plugins/cache/openai-bundled/{chrome,browser}/…(scripts/browser-client.mjs,browser-service.mjs,extension-host). - The ChatGPT browser extension installed in the target browser, with the
com.openai.codexextensionnative messaging host registered (~/.config/google-chrome/NativeMessagingHosts/). - The target browser running.
Environment overrides:
| Variable | Meaning |
|---|---|
CODEX_HOME | Codex home directory, defaults to ~/.codex |
DSH_CODEX_CHROME_NODE_REPL | Absolute path to the node_repl executable |
BROWSER_USE_AVAILABLE_BACKENDS | Backends handed to node_repl, defaults to chrome,iab,mcpapps |
Licence and provenance
This package is MIT licensed. It ships no OpenAI code: it calls
browser-client.mjs / browser-service.mjs from your local Codex installation at runtime, and those
proprietary files are not redistributed. See THIRD_PARTY.md.
Comments
Loading…
Similar plugins
by ZSeven-W
DeepSeek Harness plugin for browser automation, headless first. Every agent gets its own throwaway Chrome/Edge/Chromium profile, short-lived semantic references instead of CSS selectors, scoped subtre
★ 1
MIT
JavaScript
Sep 24, 2026
dsh plugin --profile web add @zseven-w/dsh-browserby stuarthu
DeepSeek Harness (dsh) browser companion: Chrome side panel embedding the full dsh web UI + host plugins for page reading, HTTP capture, and browser control.
★ 9
↓ 382/wk
MIT
JavaScript
Aug 22, 2026
dsh plugin --profile web add dsh-chromeby chaserchan
DSH plugin: drive a real Chrome from your dsh agent via the browser-use Browser Harness (local, no API key).
★ 0
MIT
JavaScript
Sep 25, 2026
dsh plugin --profile web add dsh-browser-harnessChrome DevTools Protocol Plugin for DeepSeek Harness. Use chrome-remote-interface to connect to and control Chrome via CDP. The connection includes a graphical interface.
★ 0
dsh plugin --profile web add dsh-chrome-cdpby yzd6552-commits
browser-use style browser automation plugin for DeepSeek Harness: drives a dedicated Chrome instance (persistent profile) via playwright-core — fine-grained tools, autonomous tasks, scheduling, danger
★ 3
MIT
JavaScript
Aug 30, 2026
dsh plugin --profile web add dsh-browseruseby lirui1024k
Browser automation for DeepSeek Harness: agent-driven real-browser control (managed Chrome with an isolated persistent profile, or attach to your daily Chrome over CDP) with snapshot, click, fill and
★ 0
MIT
JavaScript
Sep 6, 2026
dsh plugin --profile web add dsh-browser-ops