Let an agent operate your app alongside the user
Give an AI assistant real control of your interface — without screen scraping.
The problem
You want an assistant that can actually do things in your product: fill the form, switch the tab, correct the entry. The usual answer is browser automation — point Playwright at your own app and have it hunt for buttons.
That works until it doesn't. Automation driving a real UI breaks on every markup change, cannot tell a disabled button from a missing one, and locks the human out while it runs. You end up maintaining a second, worse client for your own app.
The problem is the interface: the agent is on the outside, guessing. It should be a participant, with the same access to state the UI has.
What you are building
Live surfaces, not screenshots — every one composed from the same components you would install.
Agents in your app
Live presence over a real page — agents act through MCP tools on stable handles, not DOM scraping.
Agents act through MCP tools on stable handles — never Playwright, never DOM scraping.
Hand over a session
The share surface an operator uses to bring an external agent into the running app.
The code
// The adapter is the whole contract: getters and setters over the state the
// human is already looking at. Every mutation broadcasts an AgentActivity
// event, so presence, undo and coaching compose for free.
registerFormBridge(server, {
adapter: {
getFields: () => fields,
setField: (handle, value) => update(handle, value),
submit: () => form.submit(),
},
pendingMode: true, // destructive actions are PROPOSED, a human confirms
});// One session, one tool surface. Site tools are always present; a page's tools
// are contributed while it is mounted and withdrawn when it unmounts.
const { contributeBridges } = useCoBrowse();
useEffect(() => contributeBridges((server) =>
registerArtboardBridge(server, { adapter }).dispose), []);How to solve it
Make the surface controlled
An agent can only read what your app can hand it. Anything the agent should see or change needs to live in
value+onChangestate rather than inside the component. Most Fancy components are already controlled this way.Install the bridge layer
One package carries the MCP server and every per-surface bridge.
Run thisbash npm install @particle-academy/agent-integrationsRegister a bridge for each surface
A bridge is an adapter: getters and setters over your existing state. Registering one exposes MCP tools the agent can call —
form_*for forms,sheet_*for workbooks,flow_*for workflows,page_*to navigate the app itself. The agent calls a tool; youronChangefires exactly as if a human had typed.Show the human what the agent touched
Every mutation broadcasts an
AgentActivityevent. Wire it up and the element the agent is working on highlights in the live UI, so the human watches rather than wonders.Stage anything destructive
Mutations that a human would want to approve support a
pendingMode: the agent proposes, the change appears as pending, and a person confirms it. Use it for anything you would not want done silently.
