Content
# AgentReady.js
> **Add one JavaScript file. Make your website agent-ready.**
AgentReady.js is a progressive-enhancement layer for the existing web. Load it with a single
`<script>` tag and it turns your site's semantic HTML — forms, navigation, buttons, app state —
into safe, structured **[WebMCP](https://webmachinelearning.github.io/webmcp/)** tools that any
WebMCP-capable agent can call directly: ChatGPT's in-app browser, Chrome 149+, or in-page agents
using the standard `getTools()` / `executeTool()` shape.
Humans keep using the same interface. Agents get a reliable interface of their own.
```html
<script src="agentready.js" defer></script>
```
Built for the **WebMCP Challenge** (Sep 2026).
> 🌐 繁體中文版:[README.zh-tw.md](./README.zh-tw.md)
---
## Why this matters
WebMCP lets a website *declare* its capabilities to agents instead of leaving them to guess
through screenshots and DOM spelunking. But rewriting millions of existing websites isn't
realistic — so AgentReady.js derives the tool layer automatically:
| Level | What the site does | What agents get |
|---|---|---|
| **0 — one script tag** | Nothing. Just load `agentready.js` | 7 core semantic tools + auto-synthesized form tools |
| **1 — HTML metadata** | Add `data-agent-*` attributes | Precise tool names, descriptions, submit policies |
| **2 — native registration** | Call `AgentReady.register({...})` | Full domain-specific tools with your own logic |
The same page then works with **any** WebMCP agent — ChatGPT, an in-page agent, or a future
client — because everything is exposed through the standard `document.modelContext` API
(with a `navigator.modelContext` fallback for Firefox, and an identical in-page fallback for
browsers without it — including ChatGPT desktop's register-only client).
```
Human
│
┌─────┴─────┐
│ Website │
└─────┬─────┘
AgentReady.js (semantic discovery + policy + inspector)
│
document.modelContext ← native WebMCP when available
│
ChatGPT browser · Chrome 149+ · in-page agents (AskPage, …)
```
---
## Quick start
### Level 0 — drop it in
```html
<script src="https://cdn.jsdelivr.net/npm/@willh/agentready@latest/dist/agentready.js" defer></script>
```
Or install via npm: `npm install @willh/agentready` → serve `node_modules/@willh/agentready/dist/agentready.js`.
That's it. AgentReady discovers the page and registers:
| Tool | Type | Description |
|---|---|---|
| `get_page_context` | read | Semantic summary: title, headings, regions, forms, counts |
| `find_on_page` | read | Keyword / natural-language search over interactive elements **and visible page text** (any language, incl. CJK) → stable refs or text snippets; a miss explains what was searched and what to try next |
| `read_target` | read | Details of one ref: value, options, href, surrounding content |
| `activate_target` | write | Click buttons / links / tabs (destructive ones need human approval) |
| `set_field` | write | Set one input / select / checkbox / radio, firing real `input`+`change` events |
| `fill_form` | write | Fill a whole form by label; **never submits** |
| `submit_form` | write | Submit with **explicit human approval** in the on-page panel |
| `search_products`, `signup_form`, … | auto | One synthesized tool per semantic form, with a real JSON Schema |
Synthesized tools are derived from `aria-label` / headings / action URLs. A search form becomes
`search_products({ q, category, max_price })` — not twenty `set_input_17` primitives.
### Level 1 — add metadata (optional)
```html
<form
method="get"
aria-label="Product search"
data-agent-name="search_products"
data-agent-description="Search products in the catalog"
data-agent-submit="auto">
<input name="q" type="search" placeholder="Search…" />
<select name="category">…</select>
<button>Search</button>
</form>
```
- `data-agent-name` / `data-agent-tool` — tool name (else derived from labels/heading/action)
- `data-agent-description` — tool description
- `data-agent-submit="auto | confirm | never"` — override the submit policy
- `data-agent-hide` — exclude a field from agents entirely
- `data-agent-priority` — synthesize this form first (max 8 per page)
### Level 2 — register native tools (optional)
```html
<script>
window.AgentReadyConfig = { siteName: 'My Store' };
</script>
<script src="agentready.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.AgentReady.register({
name: 'add_to_cart',
description: 'Add a product to the shopping cart',
inputSchema: {
type: 'object',
properties: { productId: { type: 'string' }, quantity: { type: 'number' } },
required: ['productId'],
},
execute: ({ productId, quantity }) => cart.add(productId, quantity ?? 1),
});
});
</script>
```
`window.AgentReady` also exposes `getTools()`, `executeTool(name, argsJson)` and `inspect()` —
the same shapes as the WebMCP standard API — so **in-page agents work on every browser**,
even without the native API.
---
## Safety model (built in)
AgentReady treats everything on the page — and everything an agent might do — as untrusted by
default. All tools carry `untrustedContentHint`; read tools carry `readOnlyHint`. Tool output is
clamped to ~1,500 characters per call.
| Content / action | Policy |
|---|---|
| Reading page content, search, navigation | ✅ Allow — page-text search skips hidden content, `data-agent-hide` subtrees, scripts, form-control values, and the labels/hints of sensitive fields; text hits are read-only (`activate_target` / `set_field` refuse them) |
| Filling normal form fields | ✅ Allow |
| Hidden inputs, tokens, passwords, card fields (`cc-*`, CVV) | ⛔ Never exposed, never filled, values redacted |
| Form submission, checkout, delete/purchase-style buttons | 🙋 Human approval via the on-page panel |
| Arbitrary JavaScript execution | ⛔ Never provided |
The inspector (bottom-right badge) shows the live tool list, every agent action with its
arguments, highlights targets as the agent touches them, and pops an **Approve / Decline**
dialog for consequential actions. Sensitive fields are excluded from schemas *and* discovery,
so agents never see their existence or values.
Configuration:
```js
window.AgentReadyConfig = {
inspector: true, // on-page badge + activity + confirm dialogs (false: confirm-gated actions are auto-declined — fail-closed)
siteName: 'My Store', // badge label
maxResults: 8, // find_on_page result cap
};
```
### Hiding or customizing the inspector
The inspector badge is enabled by default (`inspector: true`). Depending on your needs, you can hide or customize it:
1. **Completely disable the inspector UI (Configuration):**
```html
<script>
window.AgentReadyConfig = {
inspector: false, // Disables badge, activity feed, and approval dialogs
};
</script>
<script src="agentready.js" defer></script>
```
> **Note:** AgentReady uses a fail-closed safety model. If `inspector` is set to `false`, any consequential actions requiring human confirmation (e.g., checkout, form submission) are **automatically declined** because there is no dialog UI for human approval.
2. **Hide the entire UI with CSS:**
The inspector host element has a `data-agentready-ui` attribute. You can hide it via global CSS:
```css
div[data-agentready-ui] {
display: none !important;
}
```
*(Note: This keeps the inspector logic running, but approval popups will also be visually hidden).*
3. **Hide ONLY the badge (keeping human confirmation dialogs active):**
Because the inspector UI uses an open Shadow DOM (`mode: 'open'`), you can hide just the floating `.badge` while keeping the **Approve / Decline** modal functional when an agent requests a sensitive action:
```html
<script>
window.addEventListener('DOMContentLoaded', () => {
const host = document.querySelector('div[data-agentready-ui]');
if (host?.shadowRoot) {
const style = document.createElement('style');
style.textContent = '.badge { display: none !important; }';
host.shadowRoot.appendChild(style);
}
});
</script>
```
---
## Development
Toolchain: **Bun** for installs/bundling/serving, **TypeScript 7** (strict) for all source.
```bash
bun install # or: make install
make ci # typecheck → lint → build → unit tests → size → E2E (real Chrome)
make demo # serve at http://localhost:8788
```
| URL | What it is |
|---|---|
| `http://localhost:8788/demo/store/` | Legacy Store demo — a deliberately ordinary storefront |
| `http://localhost:8788/demo/test-page/` | Verification page: status dashboard, fixtures, scenario console |
### Test layers
| Layer | Runner | Covers |
|---|---|---|
| Unit | `bun test tests/agentready.test.ts` (happy-dom) | Policy classification, semantic discovery/matching, control events, form synthesis, runtime shim |
| E2E | `bun test tests/e2e` (Playwright + real Chrome) | Boot, inspector UI, confirm gates approve/decline, synthesized tools, MutationObserver re-synthesis, output budgets, full shopping flow, zero console errors |
| Manual | `/demo/test-page/` | Live tool registry, redaction demos, anything from the DevTools console via `AgentReady.executeTool(...)` |
E2E uses your installed Chrome (`channel: 'chrome'`) and falls back to Playwright's Chromium.
### Project structure
```
src/
index.ts boot, MutationObserver, public API
runtime.ts document.modelContext adapter + in-page shim (getTools/executeTool)
semantic.ts DOM discovery, stable refs (WeakRef), natural-language matching
policy.ts exposure levels, output budgets, sensitive-field redaction
inspector.ts shadow-DOM activity UI + human approval dialog
env.ts shared types: AgentEnv, AgentReadyConfig, FormInfo, Activity
tools/ page.ts · interact.ts · forms.ts · controls.ts
demo/store/ Legacy Store demo (self-contained, deployable)
demo/test-page/ verification harness
tests/ bun:test unit + Playwright E2E
```
### Testing in a WebMCP browser
- **ChatGPT desktop app** — the in-app browser supports WebMCP by default (register-only client;
AgentReady detects it and keeps `getTools`/`executeTool` in-page).
- **Chrome 149+** — enable `chrome://flags/#enable-webmcp-testing`, restart, done.
- **Firefox** — AgentReady also detects `navigator.modelContext`.
- Without the native API, AgentReady runs its in-page shim: all tools still work through
`window.AgentReady` — useful for local dev (`http://localhost`) and non-WebMCP browsers.
### Website
The landing page lives in [`site/`](./site/) (plain HTML/CSS/JS, no build step) and is published
to **https://agentready.gh.miniasp.com/** by `.github/workflows/pages.yml` on every push to `main`
that touches `site/`, `demo/` or `src/`. The workflow assembles `site/` + `demo/store/` +
`demo/test-page/` into one GitHub Pages artifact, so the demo is reachable at `/demo/store/`.
Preview locally with `make demo` → `http://localhost:8788/site/` (the `demo/store/` link only
resolves on the deployed site).
### Deploying the demo
`demo/store/` is self-contained (bundle copied to `vendor/agentready.js` at build time) —
drag it into Netlify, `vercel deploy`, `npx wrangler pages deploy`, or any static host.
---
## License
[MIT](./LICENSE) © 2026 Will Huang
Connection Info
You Might Also Like
No recommendations available