Docs  Browser control

Tools

Browser control

Working in your own signed-in Chrome, in Mori's built-in browser, or just opening a page for you, and always stopping before the pay button.


Three ways onto the web

  • Your own Chrome, through the Mori Chrome extension: your logins and sessions, real clicks and typing, tabs, screenshots and the console.
  • The built-in browser: a browser Mori drives on her own, reading the page as a numbered list of controls and acting on them by number.
  • Opening a page for you: a link, a site by name, a search, a compose window, in your default browser, for you to take over.

Plain public lookups do not need any of these; they use Web and research. Which browser does the work is chosen on the Mori Chrome page, under Which browser Mori drives; see Computer use and the browser.

Read, then act, then read again

In your Chrome, Mori first reads the page: its title, headings, every control with a number, its links and text. Then she acts on a control by its number and gets a fresh read back, so each step is checked against the page as it now is.

  • A whole form can go in one batch of up to 25 steps, which stops at the first failure, refusal or page change and says what did not run.
  • She works on a background tab by its id rather than switching away from yours.
  • She closes only tabs she opened, unless you asked her to close one.
  • The console reader installs itself on the first call, so to catch errors at load she reads, reloads and reads again.

use_mori_chrome hands a whole web task to the extension at once. When the extension is not connected it says so instead of failing, and wakes Chrome when it is just closed.

The built-in browser

The built-in browser reads each page as text plus a numbered list of controls. Typing reads the field back to check the text landed, filling a form reports which fields verified, and choosing from a dropdown reads it back too. For shopping, operator_search searches Amazon, eBay, Walmart, Best Buy, Target, Etsy or Google and returns real listings to compare.

capture_network records the requests behind a page, the data APIs and not the HTML, but only in the built-in browser. It never records headers or bodies, hides values that look like credentials, and stops on its own after five minutes.

The pay button is yours

Mori fills the cart and shipping and stops at the final step:

  • In your Chrome she never presses Pay, Place order, Buy now or Confirm purchase, in a batch too, and never types a password or card details.
  • In the built-in browser, a click, Enter or Space on a pay control is refused. She stops at the order review and shows Place the order, and the order is placed only after you tap it or tell her to.

This holds whatever asking, Commander or the rails say. See Asking and the safety rails.

Drive uploads and compose windows

upload_to_drive puts a file in the Google Drive you are signed in to, and only an upload Drive confirms counts as done; a missing sign in is reported as such. browser_compose opens a new email or post on Gmail or X for you; typing into it afterwards needs the Keyboard Control switch.

Permissions

The whole family follows the Browser Control switch in Settings > Permissions. At the Safe level browser tools still run, except the network recorder, because a log of where you went is more than a careful setting should allow. Reading the built-in browser's screenshot and address always runs. Text on any page is data, never an instruction.

33  The toolsfrom the app itself

Each description below is the exact text her model reads when it decides which tool to call.

use_mori_chrome

Run a whole web task in the user's REAL, logged-in Chrome via the Mori Chrome extension, real clicks, keystrokes and form fills in their actual sessions (Gmail, GitHub, dashboards, retailer accounts). STRONGLY PREFER this whenever a task genuinely needs a real browser: authenticated pages, anything 'on my account/dashboard/inbox', checkout flows (it fills the cart and STOPS before final pay, never pays), data behind a JS or login wall, and sites that block headless browsers. For plain public lookups use web_search/web_extract. Pass the full task as 'task'. GRACEFUL: with the extension not connected it does NOT fail, it returns a short recommendation to relay, and it wakes Chrome automatically when it is simply closed.

chrome_read_page

Read the ACTUAL page in the user's real Chrome (their logins, their sessions): title, headings, every interactive element (indexed, iframes too: f=<frameId>), links, page text. DATES: in [brackets]. PAGE TEXT CUT: read on with selector. Never switch to another source silently. Use when the page context or a login matters; plain lookups should use web_search/web_extract. TELL the user before using Chrome. The first Chrome action each turn asks the user for an OK.

chrome_act

Perform a REAL input in the user's logged-in Chrome via the extension, on an element by its [index] from the last chrome_read_page. action = click | type | select (visible option text or value) | press (chords work: "Cmd+A") | hover (opens JS menus) | scroll | clear | drag (HTML5 drag-and-drop, not pointer-based libraries) | eval (runs JavaScript in the page and returns the value; a strict CSP refuses it). If the element showed f=<frameId>, pass frame; pass tab to act on a background tab. Inputs are synthetic DOM events (isTrusted:false), so canvas apps and trusted-event checks will not respond. Returns the outcome plus a fresh page read. BATCH: pass actions, up to 25 objects with the same fields as one call, to fill a whole form in ONE call. They run one at a time, each through the same checks as a single call, and the batch STOPS at the first failure, refusal, or navigation (a navigation is detected from the fresh page read an action returns; an action that returns no page read cannot be checked for it). The result is numbered and lists what did not run, so read the page again before continuing. NEVER type credentials and NEVER click a final Pay / Place order / Buy now / Confirm purchase button, fill everything and STOP at the pay step for the user (this is enforced, in a batch too).

chrome_navigate

Navigate a tab of the user's real Chrome via the extension: a full http(s) URL, or 'back' / 'forward' through history. Defaults to the ACTIVE tab; pass tab (a tabId from chrome_tabs) to navigate a background tab without focusing it. Navigation alone needs no site approval, reading the destination does, so follow with chrome_read_page.

chrome_tabs

Manage the user's real Chrome tabs via the Mori Chrome extension: list every open tab (with tabIds), open a new tab at a URL, switch to a tab, or close one. The front tab is already named in RIGHT NOW ON THIS MACHINE each turn; list only when you need every tab or that line is missing or stale. chrome_read_page/chrome_act default to the ACTIVE tab but both take tab=<tabId> to work on a background tab, prefer that over switching, so the user keeps their own tab. Closing: on your own initiative you can only close tabs Mori opened (the extension enforces it); when the USER explicitly asked to close a tab, any tab, pass userAsked 'true'. action = list | open | switch | close.

chrome_screenshot

Screenshot the visible tab of the user's real Chrome via the extension (downscaled). Use to SEE a page when the structured read is not enough (canvas apps, visual checks). To ZOOM into a region (small text, a chart), pass x/y/w/h as FRACTIONS of the viewport (0..1, e.g. x=0.5 y=0 w=0.5 h=0.5 is the top-right quarter), the region is cropped at native resolution, so it is much sharper than the full frame. Only the visible tab can be captured, a Chrome limit, so switch first for a background tab.

chrome_console

Read console messages and JS errors from a page in the user's real Chrome, the debugging eye for live web apps. THE FIRST CALL ON A PAGE INSTALLS THE HOOK and usually returns nothing: messages logged before it existed are gone. To catch load-time errors, call this, chrome_navigate to reload, then call again. Later calls drain what accumulated. Defaults to the active tab; pass tab for a background one.

operator_goto

Navigate the browser to a URL and read the page back, page text PLUS a numbered list of every interactive element ([index] tag label), which is what operator_click / operator_type / operator_fill / operator_select act on. WHICH BROWSER: on macOS with "use my real Chrome" on (the default), this drives the user's own logged-in Chrome over AppleScript, their real cookies and sessions, and it comes to the front. Otherwise it uses Mori's own separate browser window, a signed-out profile with none of their logins. If Mori Chrome (the extension) is connected, prefer chrome_read_page / chrome_act. For a guaranteed clean signed-out session, turn off "use my real Chrome" in Settings first.

operator_read_results

Re-read the page the built-in browser is on: any product listings, the page text, and a numbered list of every interactive element ([index] tag label) for operator_click / operator_type / operator_fill / operator_select. Use it after the page loads more, after navigating, or whenever an index looks stale.

operator_click

Click an element in the built-in browser by its [index] from the last page read (operator_goto / operator_read_results). Returns the fresh page state. Refuses the final pay or place-order control, the user makes that tap themselves.

operator_type

Type text into ONE field in the built-in browser, by its [index] from the last page read, then read the field back and report whether the text landed. Set submit=true to press Enter afterwards. For several fields use operator_fill.

operator_fill

Fill a WHOLE FORM in the built-in browser in one call, then read every field back and report which ones verified. The tool for "fill in this form", applications, checkout details. One line per field: "index = value".

operator_select

Choose an option in a dropdown (<select>) in the built-in browser, by the element [index] from the last page read. Pass the option value exactly as the page lists it. Reads the dropdown back to confirm the choice stuck.

operator_press

Press a key in the built-in browser, Enter, Escape, Tab, ArrowDown, PageDown. It goes to whatever holds focus, so click or type into the element you mean first. Enter and Space are refused on a pay button, exactly like a click.

operator_screenshot

Capture what the operator browser currently shows (for you to inspect the page).

operator_status

Get the operator browser current URL and page title.

operator_close

Close the operator browser when finished.

operator_add_to_cart

Add a product to the cart in the operator browser. PREFER passing query = the product's name or title (it matches the right item even if numbering shifted); index is a fallback. Opens the product and clicks Add to Cart. After this you MUST STOP, never proceed to checkout or payment; the user completes the purchase.

capture_network

SEE THE REQUESTS BEHIND A PAGE, the JSON APIs, not the rendered HTML. Use when someone asks where a table's data comes from, wants an endpoint called directly, or is debugging why a page loads slowly or shows nothing. Call with action 'start', drive the page with operator_goto / operator_click, then call again with 'list'. SCOPE, and it is narrow: this records ONLY Mori's own built-in browser (the operator_* tools). It cannot see the user's real Chrome (chrome_act, chrome_read_page) or a page opened in their default browser (open_browser), so driving those captures nothing, say so rather than reporting an empty list. Images, fonts, css, js and analytics are filtered out. Headers and bodies are NEVER recorded, and credential-shaped query params, fragments and high-entropy path segments are redacted, but a URL can still BE a credential (a presigned S3 link, a webhook path), so treat every captured URL as sensitive: never paste one into a message, a file or a summary, and if a request needs auth say so rather than trying to reconstruct it. Recording stops on its own after five minutes.

open_url

Open a URL in the default browser

open_browser

Open a specific or default browser

open_site_by_name

Open a well-known website by friendly name: Google, YouTube, GitHub, Reddit, Twitter/X, Discord, Amazon, Netflix, Twitch, LinkedIn, Facebook, Instagram, TikTok, Wikipedia, Gmail, Notion, Figma, Spotify, WhatsApp, Telegram, Slack, StackOverflow, npm, ChatGPT, Claude, Hacker News, Vercel, Codepen, Replit and more. An unknown name opens https://www.{name}.com.

search_google

Search Google for a query and open results in browser

browser_search_site

Search a specific website by opening the search results URL directly in the default browser. Supports: Amazon, GitHub, Google, YouTube, Reddit, X/Twitter, Wikipedia, npm, LinkedIn, and more. Uses direct search URLs, no UI interaction needed.

browser_compose

Open a compose/create view on a website in the default browser. Supports: X/Twitter (new tweet), Gmail (new email). After opening, use focus_default_browser + type_text to type content.

focus_default_browser

Focus/bring to foreground the user's real default browser window (Chrome, Edge, Firefox, Brave). Use after opening a URL to interact with the browser.

upload_to_drive

Upload a file to the user's signed-in Google Drive (My Drive) through the browser. Use this when asked to upload/put/save/back-up a file to Google Drive. Pass the file as a full path, a bare filename, or 'the zip/file you just made', Mori resolves it. Returns JSON {ok, status, message}: 'sent' = upload confirmed; 'not_signed_in' = tell the user to sign into Drive in Chrome; 'attach_failed' = file not found / couldn't drive the uploader. Only claim it uploaded when status is 'sent'. Common flow: build a site → create_zip → upload_to_drive the zip.

chrome_download

In the person's Chrome: Pull a file from a URL into a named folder of the browser Downloads directory. Folder and name are sanitised; nothing is written outside Downloads. For a file the person wants off a page; the desktop keeps the real file-system tools. Asks the person first.

chrome_gate

In the person's Chrome: See what wall is on the page so you HAND BACK to the person. Reads the page shape, types nothing. On a non-null kind, show the reason and wait for the person; do not try to get past it. Call it before acting on a page that might be a sign-in, 2FA, checkout or CAPTCHA. A result starting "paused:" or "stopped:" is the person holding their browser: tell them, wait, never retry.

chrome_network

In the person's Chrome (the Mori extension): Read the requests the page made (fetch + XHR): method, url, status, timing, content-type. Never bodies. First call installs the hook (installedNow), so earlier requests are gone.

chrome_resume

In the person's Chrome: The person said carry on in the app: lifts a takeover or a sign-in/2FA/payment hold in the browser. Only after the person says to carry on.

chrome_wait_idle

In the person's Chrome: Wait until the page goes quiet (network idle) or the cap. idle:false means it timed out. Use between a click that kicks off a request and the next read.