Vyre / Computer / Chrome control, architecture
How Chrome control is built.
Driving a site the way the site drives itself.
Vyre for Chrome does not click pixels when the site already has a call that does the job. It calls the site’s own API from inside your signed-in page, remembers how each site works, plans before it acts, holds anything that sends, and stops when you press Esc. This page explains each mechanism and names the file that holds it.
The path of a call.
One extension, one connector, a module that decides.
Decision record: ADR 0049. No debugging port and no browser relaunch. The extension attaches Chrome’s debugger to a tab once and keeps it.
chrome_snapshot, chrome_api, chrome_act and the rest.local/hands-chrome-mac/index.js and oversight.js.Through the site’s own API.
A call is cheaper and surer than a click.
A page is a front end for calls to a back end. Vyre Computer watches those calls, learns their shapes and makes the same call itself, from inside the page, so your cookies sign it.
1. Capture
The extension keeps a bounded ring buffer of the tab’s network events, from every frame including a cross-origin iframe such as GoHighLevel’s workflow builder. Reading the buffer costs no round trip.
2. Learn
chrome_api learn reduces the buffered XHR and fetch traffic to a catalog: method, path template, query and body shape, the kind of credential (cookie, bearer or a named header), and a sample status. Values are never stored. Each entry records the frame it was learned in.
3. Route
chrome_api route takes a hint such as “contacts” and picks the best matching GET entry. It calls it from inside the page and checks for a 2xx. The reply says which way it went:
{ "route": "api", "entryId": "...", "pathTemplate": "/contacts/{id}", "status": 200, ... }
{ "route": "ui", "why": "no learned read matches the hint" }
On "ui" the agent drives the page as before. A tie between two entries, a missing path parameter, a held or refused call and an answer that is not 2xx all return "ui" with the reason. An entry that fails twice is dropped, so a changed app stops being tried.
4. Call
chrome_api call runs one entry inside the page, in the frame it was learned in unless you name another, so that frame’s cookies and auth sign it. For a bearer or header credential, the worker takes the value from the newest captured request and hands it to the page’s own fetch. It is never returned or logged, and the response comes back through the redactor.
5. Writes ask
A GET passes. A write passes only when the person asked for that call or a plan they approved covers it. A request that sends something as you (a message, a post, a payment, judged by method and endpoint) waits for approval whatever else is true.
When the API route does not answer
Each tool has a rung: API 1, page controls 2, DevTools 3, accessibility tree 4, screenshot and point 5. A failure says which rung it was on and what the next is. When the same target fails twice on rungs 2 to 4 in one chain, the error carries a small fresh screenshot and names chrome_point, so the model does not have to remember the ladder.
The control loop.
Plan, call, check, remember.
Each pass through the loop leaves the next one cheaper. The highlight moves through the stages as the loop runs.
- 01AgentAsks in words: “list the contacts tagged renewal.” A named agent must hold your grant.
- 02PlanPosts its steps first. You see them, can interject, and can stop it.
- 03Site API callThe best learned read, called from inside your page with your login.
- 04ResultChecked for a 2xx and redacted. If it fails, the page is driven instead.
- 05MemoryThe endpoint’s confidence moves up or down. What worked is kept for next time.
It remembers how each site works.
Structure is kept. A value never is.
This is how it does long, complex tasks without relearning a site every time. Memory has three layers, from short-lived to lasting.
Session memory
The API catalog and the recipes live in the browser’s session storage and are gone when it closes. A recipe is a flow that worked: chrome_batch with saveAs and every step succeeding. Only its parameters are kept. What you typed never is. chrome_recipe run replays it as one call with no model turn between steps.
The site record
One record per origin: the frame layout, stable controls and how to find them, the site’s API endpoints, how to tell the page is ready or that you must sign in, and the operations you taught. Learning is on by default and one setting turns it off. In Vyre you see and forget a record under Memory, Sites; each forget can be undone for a day. Standalone, a record is a file at ~/.vyre-chrome/sites/<hash>.json, mode 0600.
Taught operations
chrome_op turns a page’s request into a named, typed call. It runs the trigger twice with two different example inputs, diffs the traffic and drafts the operation. A read is kept only after it answers on an input that was not an example. Credentials are stored as references such as cookie:name and resolved inside the worker. A drift is repaired once and kept only if a replay answers. Each kept version can be rolled back.
- An allowlist, failing closedOnly named fields survive, with types and length limits. A string shaped like a credential, a pairing code or a key, or carrying an email, makes the whole patch refused. The refusal names the field and never the text.
- Labels need two visitsA control’s label is stored only when it was seen on two separate visits, outside a row or list of records, without an email, phone or long number. Otherwise the control is found by identifier or by structure.
- Facts healA stored fact that worked moves its confidence up. One that missed moves it down and is quarantined after repeated misses, so a redesigned page stops being trusted instead of failing silently.
- Arrival cardsOn a revisit the extension has a small card for the origin from memory, never waiting on a server, and the same record format serves Vyre Memory and the standalone files.
Long and complex tasks.
One round trip for a whole job.
- Batch inside the browser
chrome_batchruns its steps in the extension’s worker with no hop to the host between steps. It halts at the first failure, on stop, or on a floor refusal, and says which step. - Waits that match the pageEvery step waits for spinners, drawers and toasts, and a page counts as settled when there is no spinner, a quiet DOM and a quiet network in every readable frame.
- Stale controls retriedA control that went stale is looked up again inside a retry budget. Harmless popups (what’s new, tours, cookies) are closed. Anything else, such as unsaved changes or a confirm, stops the run rather than guessing.
- Saves verifiedA save is confirmed by a toast, a disabled Save, a URL change or a list item. One that cannot be confirmed is an error that names the step.
- Frames are first classSnapshot, act, fill and wait look in every readable frame, top first. A frame it cannot read is listed with its origin and the reason, and never left out silently.
- One approval for many changes
chrome_approvelists what a job will create, edit or publish. You approve it once. That many creates and edits then go through, and the page shows “step N of M”. A delete, a message to a contact and a payment are never covered. A publish is covered only when your own words asked for it. The plan ends after an hour or when you stop it.
Holds for sends, posts and payments.
Nothing leaves until you say yes.
An agent can ask for a send and cannot approve it. The extension decides what counts as outward from the page itself, not from a label an agent chose.
- 01Agent actsPresses a control, or makes an API write, that might send.
- 02Extension decidesA real submit, or a Send, Pay or Post control read from the DOM. For an API write, the method and endpoint.
- 03HeldNothing is sent. The agent gets
held: true, an id, the field values and a signature of the page. - 04You see itA card in Needs you, or a question from Claude Code, with the site, the button and the fields.
- 05You approveOnly a person’s yes releases it. The server asks you itself when your client can show a question.
- 06ReleasedThe page is hashed again. Same signature: it runs. Changed: refused, nothing done.
Approved, page unchanged
The act runs once, with the page’s own login.
Page changed since the hold
Refused with code changed. Look again and ask again.
Declined, or no answer
Nothing is sent. A held act with no answer yet stays held and can be asked again.
Four layers decide what is held
The send classifier (extension/shared/outbound.js) judges an API write by method and endpoint: messages, campaigns, invoices and payments, social posts, and any write to an endpoint whose name says it sends, posts or pays. GraphQL and RPC bodies are read for the action.
The write gate holds every other change made with your login (a create, an edit, a delete) unless you asked for that call or a plan you approved covers it. The request function refuses a write that did not pass through it.
The page act holds an outward control chosen from the DOM. The held result carries the form’s non-secret values and a signature of the page. The release re-hashes the page and refuses with changed on any difference.
The script guard wraps a script an agent runs with chrome_eval. It may read with your login and cannot write. A send it tries is held, and it cannot reach a site the page does not already talk to. The browser enforces that for HTTP and HTTPS requests, navigation, WebSockets and beacons, in every frame of the tab, and CI proves it in a real Chrome.
Esc stops everything.
You press it. Only you undo it.
While an agent works in a tab, a dark pill in that tab says “Step 12 of 20”, the step in plain words, and “Esc to stop”.
- Four ways inEsc in the tab, the Stop button on the pill, the shortcut Cmd+Shift+E (Ctrl+Shift+E elsewhere), and the toolbar icon. A person’s stop and an agent’s
chrome_stopare the same state. - Set before anything is awaitedThe stopped flag is set first, so the very next call is refused with code
stopped. The extension is told in the same breath, so a running batch halts within a step. Each stop’s latency is recorded. - It waits for youNothing continues until the person answers and
chrome_resumeis called. A model cannot lift your stop. In the standalone version the server asks you itself before it carries on, and if the client cannot ask, the resume is refused. - Pause and interjectYou can pause from the panel, which holds exactly like Esc, or tell the agent something by typing or voice. It reaches the agent on its very next call, once, so it can change course.
The floor, redaction and logs.
Some pages are off limits. Everything is written down.
The URL floor
One list, checked by the module before anything is sent and again in the worker. Blind pages return nothing and refuse every operation: banks, password-manager web vaults, sign-in pages, Vyre’s own surfaces, the browser’s own pages and the Web Store. Hands-only pages are readable and not actable. A hostname that says “bank” is caught too, and you can add your own entries.
Redaction
Cookies, tokens, session ids, CSRF tokens, API keys and passwords are removed before the model sees them. Names and lengths stay, values never. It runs in the extension on every result and again in the module. There is no argument that asks for a raw value. A page with a visible password field never runs a script, in any frame.
Logs
Every session writes one trace file on your computer only. Each call records its masked arguments, queue, run and page time, success, the failing step, retries, which selector strategy matched, the page’s host and path without the query, the rung used, and a small masked snippet of the page on failure. Typed values are logged as their length, except on GoHighLevel builder pages. Old logs are removed to stay under 100 MB. vyre-chrome report bundles the last sessions, masked.
Tests: the Chrome control suite runs against a fake extension on every change, and a real-Chrome job installs the connector with its own install command, starts the server and drives it like Claude Code on macOS, Windows and Linux.
Connects to
- Vyre ComputerChrome control is one of three places an agent can work.
- Install Vyre for ChromeThe two ways to run this, step by step.
- Vyre architectureThe Gate and Needs you that hold a send, and the Vault.
- ADR 0049: Deep Chrome controlThe decision record with the frame model and the speed design.
- GoHighLevel playbookHow the flows, waits and verified saves apply to one real product.