Start with a narrow contract
A useful browser agent does not need unrestricted access to the web. It needs a small set of tools with clear inputs, outputs, and limits. I define the allowed domains, action types, data fields, and stopping conditions before I give the model control.
This changes the engineering problem. Instead of hoping the model behaves, the application decides what behavior is possible.
- Separate read actions from write actions.
- Require confirmation before purchases, messages, downloads, or account changes.
- Set maximum steps, retries, runtime, and spend per task.
Treat the page as changing state
Browser automation breaks when it assumes the interface is static. A click can trigger navigation, replace a component, open a modal, or invalidate every selector captured one second earlier.
The agent should observe after every meaningful action. It should compare the expected state with the actual state and stop when they do not match.
observe()
-> identify_target()
-> validate_action()
-> execute_once()
-> observe_again()
-> compare_expected_state()Keep evidence with every decision
For research agents, a final answer is only as good as the trail behind it. Store the page URL, extracted value, timestamp, and the exact element or text that supported the result.
When two sources disagree, preserve both values and make the conflict visible. Silent conflict resolution makes a polished answer look more certain than the evidence allows.
- Attach sources to individual claims.
- Record failed attempts and blocked pages.
- Keep raw evidence separate from the model summary.
Design recovery before scale
The first production milestone is not completing every task. It is failing in a way that is understandable and recoverable.
A good run can pause for approval, retry a transient page load, switch to a known fallback, or hand the task to a person with the current state attached. That is much more useful than an agent that starts over or guesses.