πŸ¦€ Gajae Code

Tool guide

browser tool

Open, reuse, close, and script Puppeteer tabs against headless Chromium, a CDP-attached app, or a saved Chrome profile. Tabs live in a process-global map and are reused by name across later calls and in-process subagents until closed.

How to use it

There is no separate gjc browser subcommand. Start a normal GJC session and ask the agent to use the browser tool. The agent drives three actions β€” open, run, and close β€” against named tabs.

# Launch GJC from your repo/workspace
gjc

# Then prompt the agent, e.g.
"Use the browser tool to open example.com and extract the main article text."

For static pages (articles, docs, JSON, PDFs), prefer the read tool. Reach for the browser when you need JS execution, authentication, or interactive actions.

Actions

  • open β€” acquire or reuse a named tab (defaults to "main"). Optional url navigates after the tab is ready; viewport, wait_until, and dialogs ("accept"/"dismiss") tune the page. The app field selects the browser kind.
  • run β€” execute an async JS body with page, browser, tab, display, assert, and wait in scope. display(value) calls and the return value become tool output.
  • close β€” release one tab, or every tab with all: true. kill: true also terminates a spawned-app process tree (and only a GJC-launched Chrome profile process).

Browser kinds

  • Headless (no app) β€” local Chromium with stealth patches applied; a fresh page per tab. Default viewport is 1365Γ—768 at deviceScaleFactor 1.25.
  • Spawned app (app.path) β€” reuses an existing CDP-enabled process for that executable when possible, otherwise spawns it with remote debugging. No stealth patches.
  • Connected browser (app.cdp_url) β€” attaches to an existing CDP endpoint. No process ownership; close only disconnects.
  • Saved Chrome profile (app.browser: "chrome" + path + user_data_dir + profile_directory) β€” automate with cookies and login state without risking the daily Chrome process.

The tab helper API

Inside run, prefer the structured tab helpers over raw Puppeteer; drop to page only when needed.

  • tab.goto(url, { waitUntil? }), tab.url(), tab.title()
  • tab.observe({ includeAll?, viewportOnly? }) β€” accessibility snapshot with stable numeric element ids; tab.id(n) resolves an id to an ElementHandle.
  • tab.click, tab.type, tab.fill, tab.press, tab.select, tab.scroll, tab.drag, tab.scrollIntoView, tab.uploadFile
  • tab.waitFor(selector), tab.waitForUrl(pattern), tab.waitForResponse(pattern), tab.evaluate(fn, …args)
  • tab.screenshot({ selector?, fullPage?, save?, silent? }) β€” attaches an image unless silent; tab.extract(format = "markdown") returns Readability content.

Selectors accept CSS plus Puppeteer query handlers such as aria/Sign in, text/Continue, xpath/…, and pierce/…. After a tab.goto() or any navigation, re-run tab.observe() β€” prior element ids are invalidated.

Saved Chrome profile example

{
  "action": "open",
  "name": "work-browser",
  "app": {
    "browser": "chrome",
    "path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
    "user_data_dir": "~/Library/Application Support/Google/Chrome",
    "profile_directory": "Profile 10",
    "background": true,
    "no_focus": true,
    "target": "example.com"
  }
}
  • CDP binds to 127.0.0.1; never expose a logged-in profile's CDP port publicly β€” a CDP client has full browser-account access.
  • A matching already-running profile is reused only when its localhost CDP endpoint responds; a profile running normally without CDP is refused rather than killed or relaunched.
  • kill: true terminates only the Chrome profile process that GJC launched.

Limits

  • Tool timeout: default 30s, clamped to the browser range (max 30s).
  • Headless first run may download Chromium into the Puppeteer cache; launch prefers a detected system Chrome, then PUPPETEER_EXECUTABLE_PATH, then download.
  • Stealth patches apply to headless mode only; spawned and externally connected browsers are left untouched.
  • Screenshots sent to the model are downscaled (max 1024Γ—1024); save or browser.screenshotDir persists full resolution.