Skip to content

Browser in runs

An agent building a web page cannot tell whether the page actually works by reading the code. The honest check is the same one you would do: start the dev server, open the page in a browser, click through it, and look.

The browser tool gives coding runs exactly that. When a run has it, the agent can drive a real headless Chromium: navigate to the app it just started, read the rendered page, click and type, and attach screenshots to the run.

A small, fixed set of tools, and nothing else:

  • navigate opens an http or https URL, such as a dev server on localhost.
  • snapshot reads the current page as text: title, visible text, and an outline of headings, links, buttons and form fields.
  • screenshot captures the page as a PNG and uploads it as a run artifact, so it shows up in the run’s output where you can see it.
  • click and type interact with elements by CSS selector.
  • wait_for waits for an element or text to appear.
  • evaluate runs a JavaScript expression in the page and returns the result.
  • console_messages reads what the page logged to its console.

There are no tabs, no downloads, no file uploads, and no way to sign in to anything on the agent’s behalf. The set is closed by design.

The agent itself works inside a strict sandbox, and a browser cannot live inside that boundary. So the runner starts Chromium outside the sandbox, as its own managed process, one per attempt:

  • a fresh, empty browser profile every time, created for the attempt and deleted with it;
  • no shared state between attempts, ever: no cookies, no cache, no history survives;
  • when the attempt ends, for any reason, the browser process is killed and its profile removed.

The agent reaches the browser only through the tools above. It never gets a browser binary, a profile path, or a debugging port of its own to keep.

A browser that can open file:// URLs is a window into the machine’s filesystem. The browser tool refuses that window twice:

  1. navigate only accepts http and https URLs. file://, data: and every other scheme are refused before the browser is even asked.
  2. The browser itself is instructed to fail every file:// request it sees, whatever produced it. A page that redirects to a file URL, or embeds one as an image or script, gets a failed request, not the file.

The second layer is the important one: it holds even when a page the agent visits tries to route around the first.

The browser tool is granted per run by the control plane, not switched on by the machine. Coding runs carry it by default; chat and huddle turns never do. A workspace admin can switch it off for the whole workspace in Settings, under AI Runtime.

The runner reads the capability the run was dispatched with and stages the tool only when it is present, and only when the machine can actually serve it.

The managed runner image ships with Chromium preinstalled. A self-hosted runner uses whatever the machine has:

  • Chromium or Google Chrome found on the PATH, or at the standard install location on macOS;
  • or an explicit path via the CC_CHROMIUM_PATH environment variable or the --chromium-path flag.

If no browser is found, nothing breaks: the run proceeds normally, just without the browser tool, and the runner logs why. commandchain-runner doctor reports the same answer up front, as a browser tool line next to the containment verdict. See doctor.

Browser activity shows up in the run’s timeline like any other tool call, and screenshots land in the attempt’s artifacts. When an agent says a page renders correctly, the screenshot it cites is the evidence.