Skip to article
PlanToCodeDocsGet the app

HandbookBundled tools

Browser Bridge: your Chrome as a tool

A Manifest V3 extension, a native messaging host, and Chrome DevTools input let the agent search, read, click, type, upload, and screenshot in your own browser, visibly and within limits.

Checked against the source on 17 September 2026

On this page

How the bridge works

Browser commands wait on the desktop until Chrome asks for them
Browser commands wait on the desktop until Chrome asks for themTime runs left to right across the Codex child, the desktop runtime, the native host, the extension, and the page. The extension keeps asking for work through a native host that Chrome starts, and the desktop holds each question for up to 25 seconds. A Codex tool call is queued, handed to the waiting question, run in the page through the DevTools Protocol, and its result travels back up to resolve the call.
Chrome
Codex
Desktop runtime
Native hoststarted by Chrome
Extension
Web page
JSON-RPC over stdio
local socket or pipe, per-install secret
native messaging, origin checked
holds the question up to 25 s
tool call waits up to 60 s
attach debugger, act, detach
plantocode.next
command: null
command, up to 1 MiB
result, up to 64 MiB
use_user_browser
text, Markdown, screenshot path
click, type, capture
If Chrome is closed, nobody asks. After 60 s the command leaves the queue and Codex gets a tool error.
  • Tool callitem/tool/call

    Codex asks the desktop to run use_user_browser. The desktop checks upload paths, queues the command, and waits 60 seconds, or 5 seconds for status. Without a result in time, Codex gets a tool error that says to install the extension and keep Chrome open.

  • Long-pollplantocode.next

    The extension asks for one command at a time. The desktop answers command: null after 25 seconds, and the extension asks again at once. A 20-second keep-alive and a 30-second reconnect alarm keep it asking, so the desktop never listens on a network port.

  • Native hostplantocode-browser-bridge-host

    Chrome starts it for com.plantocode.browser_bridge. It refuses an extension origin outside the published and development IDs and PLANTOCODE_CHROME_EXTENSION_ORIGINS in its own environment, adds the per-install secret to every message, and opens one socket or pipe connection per message.

  • Resultplantocode.result

    Frames from Chrome may reach 64 MiB and frames to Chrome stop at 1 MiB, so large results fit on the way up and commands stay small on the way down. The desktop writes a screenshot to a file and gives Codex text, Markdown, and the path.

The desktop allows the published Chrome Web Store extension ID and the fixed development ID from the unpacked manifest, and PLANTOCODE_CHROME_EXTENSION_ORIGINS adds further trusted origins to that manifest. The host accepts them only when the same variable is set in its own environment. The per-install IPC secret lives in a file created with mode 0600. The host is registered when the Browser Bridge setting is on, which it is not by default, and PLANTOCODE_DISABLE_BROWSER_BRIDGE=1 forces it off. Chrome 120 is the minimum, and the extension spans incognito windows so research can run there.

DeadlineValue
Command60 seconds; status 5 seconds.
Extension long-poll for the next commandReturns empty after 25 seconds.
IPC connect / response5 seconds / 35 seconds.
Owned tab record30 minutes, refreshed on each use, swept by a 30-second alarm.

Every DevTools action attaches chrome.debugger (protocol 1.3) and detaches when it is done, so Chrome shows its debugging banner per command. A click first runs an injected locate script to find a document point and then dispatches a DevTools click there; typing focuses the target first and inserts text through the protocol. That is why they work on pages that ignore synthetic DOM events; inputMode=dom exists for the sites that need the legacy path, and select, check, and scroll stay injected DOM actions. Extraction waits for the page to load and for the DOM to go quiet, by default 800 milliseconds of quiet within an 8 second readiness window that can stretch to 30 seconds, then reads the rendered visible DOM including open shadow roots and frame content, and returns the title, URL, text, a reader view, Markdown, links, headings, frame metadata, and warnings.

Enable it

  1. Install the PlanToCode Browser Bridge extension from the Chrome Web Store. For development, load the desktop/browser-extension folder unpacked instead.
  2. In PlanToCode, open Settings → Connections → Browser Bridge and enable it. Saving starts the IPC server and registers the native messaging host at once; the restart hint in the UI is stale.

What the agent can do

ActionBehavior
statusReturns the active tab and an inventory of every open tab in every window with URL and title, plus owned browser workspaces and windows, so later calls can target known IDs. Without a connected extension it returns bridge diagnostics instead: host name, IPC endpoint, allowed extension IDs, resolved host binary, and manifest install targets.
search, open, extractSearch opens a visible Google results page and returns classified result entries. Open and extract accept a URL and can use a new tab, the current tab, or an explicit tab ID, and extract can wait for a selector, text, or URL fragment before reading.
click, type, press, select, checkLocators accept a CSS selector, visible text, role plus accessible name, label, placeholder, a frame ID from extract or inspect, or coordinates in viewport or document space. Check is idempotent and reports the final checked state.
uploadAssigns up to 20 absolute local file paths to a located file input through the DevTools Protocol. The desktop first checks that each path is absolute, not a symlink, and a readable regular file, canonicalizes it, and rejects components such as .ssh, .gnupg, keychains, cookies, id_rsa, .env, .pem, .key, private_key, secret, and token. There is deliberately no byte limit, no file content enters the transcript, and protected Chrome pages can block it.
scroll, wait, inspectWait covers load, selector, text, role, label, placeholder, and URL conditions. Inspect lists interactive elements before a click when the page shape is unclear.
screenshotCaptures the full page through the DevTools Protocol by default, or the viewport or a clip rectangle, as JPEG at quality 70. A protected page returns full_page_screenshot_unavailable instead of a silent viewport image. The desktop writes the decoded image with mode 0600 under the cache directory in plantocode/browser-screenshots and returns the path; nothing deletes these files automatically.
closeCloses only extension-owned tabs and, with closeWorkspace, the owned windows; a window that still holds a tab the extension did not open is left alone. The extension has no history permission, so nothing is removed from Chrome history.

Workspaces, windows, and incognito

Tabs from one run share a window, and a search makes that window incognito
Tabs from one run share a window, and a search makes that window incognitoBrowser commands from one run in order, and the window each one lands in. A search creates the run’s window as incognito, and a later open joins it. A click with a tabId reaches that tab, but a click with neither tabId nor browserWorkspaceId lands in Chrome’s current window. An open with incognito: false starts a normal-profile window that takes over the run’s workspace, and later tabs follow it.
run:<runId>incognito window
run:<runId>normal window
Current windowpicked by Chrome
created unfocused, 1280×900
stays open, no longer the run’s
takes over run:<runId>
search
open
click tabId
click
open incognito: false
extract url
no tabId or browserWorkspaceId
  • WorkspacebrowserWorkspaceId

    Open, search, and extract with a URL put new tabs in the window of an explicit browserWorkspaceId, else run:<runId>, else session:<sessionId>, unless the call asks for the current window or tab. That window is created unfocused at 1280×900.

  • Profileincognito

    Only search asks for incognito, and open and extract join the workspace’s window whatever its profile. An explicit incognito value that the window does not match opens a new window that takes over the workspace, and incognito needs Allow in Incognito for the extension.

  • Page actionstabId

    Click, type, press, select, check, upload, scroll, wait, inspect, screenshot, and extract without a URL use tabId, else the active tab of an explicit browserWorkspaceId, else the active tab of Chrome’s current window. The run and session IDs do not steer them.

Research runs in a dedicated, unfocused 1280×900 Chrome window per browser workspace ID, so parallel research streams stay isolated. The ID comes from an explicit browserWorkspaceId, else the run, else the session, else the command. Only search asks for incognito, which keeps a search spree out of your history and requires the extension to be allowed in incognito windows. Open and extract ask for no profile and join the workspace’s existing window, so after a search they run incognito too. Pass incognito: false for signed-in work. When the workspace window is incognito, that opens a normal-profile window that takes over the workspace. Page actions ignore the run and the session. They use tabId, then an explicit browserWorkspaceId, and otherwise Chrome’s current window. Without an explicit wait condition, a readiness timeout does not fail the extraction. It returns the current content with a warning.