The agent-readiness score
Send an AI assistant to a website and ask it to book a job. Either it can, or it cannot. The score is a measurement of that, out of 100, and this page is the whole method: what earns points, what the bands mean, and — just as importantly — what the instrument cannot see.
The score answers one question and nothing else: if a customer’s AI assistant arrives at this site and is told to book, quote or enquire, how much of what it needs is actually there?
It is five categories, 20 points each, 100 in total. Each category is capped at 20, so no single check can carry a site, and a category can only earn points for something the scanner positively found. There is no "nothing looked broken" route to a good score.
The three bands
| Score | Grade | What it means |
|---|---|---|
| 70–100 | agent-ready | An agent sent here to book, quote or enquire has a structured way in and can complete at least one job end to end. |
| 40–69 | partially ready | An agent can read the site. It cannot reliably finish a job — the ways in are built for a person with a mouse, not for software. |
| 0–39 | invisible to agents | An agent asked to book or enquire here has almost nothing to work with. It reads the page, finds no action it can complete, and moves to the next business. |
The five categories
1. Crawlability and discovery — 20 points
Before an agent reads a page it checks whether the site has published anything about itself at the addresses agents look at. This category is that check.
| Signal | Points | Note |
|---|---|---|
robots.txt present and not locking agents out | 5 | A robots.txt that disallows everything, or names an AI agent and disallows it, scores nothing here and is reported as a finding. |
No robots.txt at all | 3 | Open by default, but an agent cannot confirm intent. Recorded as a warning, not a pass. |
sitemap.xml found | 3 | |
/llms.txt present | 3 | A plain description of the site for language models. |
/.well-known/ai-catalog.json published | 5 | The Agent Readiness Discovery catalogue. |
| Canonical URL declared | 2 | |
Page not set to noindex | 2 | A noindex page scores nothing here. |
2. Structured data — 20 points
Whether the page tells a machine what this business is, in the format machines already read. With no structured data at all, an agent has to guess the business type, the hours and the address from prose.
| Signal | Points |
|---|---|
| Any parsable JSON-LD present | 6 |
A business entity type declared (LocalBusiness, Dentist, RealEstateAgent…) | 5 |
| Machine-readable opening hours | 3 |
| Phone in structured data | 2 |
| Address in structured data | 2 |
Service, Offer or Product entities | 2 |
3. Action affordances — 20 points
Is there anything on the page for an agent to do? A booking or quote form, a known booking widget, a clickable phone number, real buttons rather than clickable divs.
| Signal | Points |
|---|---|
| A known booking-widget signature detected | 6 |
| At least one booking, quote, callback or contact form that survives the non-action filter | 6 |
A tel: link | 3 |
Not overrun with clickable divs styled as buttons | 3 |
Real <button> or <a> elements present | 2 |
Two filters do most of the work here, and both exist because an earlier version of the scanner counted things that were not actions.
A form matching an action keyword is necessary but not sufficient. It is excluded — from the detected actions and from the form-quality score — when it carries a positive signature of being something else: a search box (role="search", a search input, a search/typeahead token in its attributes, or a field named s, q, query, search or keyword), a newsletter signup (a newsletter/subscribe/mailchimp token, or a lone email field, or newsletter wording when every field is an email or a checkbox), or a form with nothing to submit. A genuine enquiry form carrying a newsletter opt-in tick-box is not excluded, and a genuine one-field-plus-submit enquiry form still counts: the floor is structural, never field count alone.
Widget signatures are matched structurally, against URL-bearing attributes only, and each vendor pattern targets that vendor’s booking endpoint rather than its marketing site. A "powered by" credit in a footer, a blog paragraph naming a vendor, or a CRM script tag is not a booking widget. Under the earlier whole-page substring match, a test page that merely named four vendors in prose emitted four booking actions and gained six points.
4. Form quality — 20 points
Assessed over action forms only. A site’s form quality is not scored on the strength of its property-search box.
| Signal | Points |
|---|---|
| At least one action form exists | 4 |
| 80% or more of fields properly labelled | 4 |
90% or more of fields carry a name attribute | 3 |
Half or more of fields use a semantic input type (email, tel, date…) | 3 |
Any autocomplete attributes | 2 |
| A real submit control inside the form | 2 |
At least one field marked required | 2 |
| A CAPTCHA anywhere on the page | −2 |
5. Agent interface — 20 points
Whether the site declares what it can do to software, rather than leaving software to infer it from the layout.
| Signal | Points |
|---|---|
| WebMCP signals — the page declares its tools to the browser | 8 |
| A persistent MCP endpoint advertised, or an ARD catalogue published | 6 |
Semantic landmarks and at least one h1 | 3 |
| Images carry alt text (or there are no images) | 3 |
Agent-callable is a separate answer, and it is not part of the score
A site can have a contact form and still be a place no agent can finish a job. So each detected action carries its own verdict, computed from positive evidence only, and it deliberately does not feed the 0–100 number. The score describes a site; agentCallable describes one action.
The rule, as one exported string in the source
WebMCP tool declaration, advertised MCP endpoint, ARD catalog, known booking widget,
or a fully machine-completable form (every field labelled and named, an email/tel
reply channel, a real submit control, no CAPTCHA)AGENT_CALLABLE_RULE in packages/scanner/src/checks.ts. It is exported and imported by the benchmark so a report and its summary can never disagree about the rule they were scored under.| Route | What has to be true |
|---|---|
webmcp-tool-declaration | The form element itself carries mcp-tool, data-mcp-tool or toolname. |
mcp-endpoint | The page advertises a persistent endpoint — link[rel=mcp], meta[name=mcp-server]. |
ard-catalog | The site publishes /.well-known/ai-catalog.json. |
booking-widget | A known booking-widget signature. This is a weaker claim than the others: it is a path our own routing could drive natively, not proof that any agent could do it unaided today. |
machine-completable-form | Every field labelled and named, an email or tel reply channel, a real submit control inside the form, and no CAPTCHA on the page. |
false and carries a blockers list naming exactly what is missing. That list is the fix list. A tel: link is never agent-callable: it hands off to a human.What fifteen real sites scored
Fifteen Sydney service businesses — five trades, five clinics, five real estate agencies — scanned read-only on 25 August 2026. No business is named anywhere on this site.
| Vertical | Mean score | With a form or widget | With an agent-callable action |
|---|---|---|---|
| Trades | 58.0 | 4 of 5 | 1 of 5 |
| Clinics | 47.6 | 1 of 5 | 0 of 5 |
| Real estate | 31.4 | 0 of 5 | 0 of 5 |
| All fifteen | 45.7 | 5 of 15 | 1 of 15 |
15 of 15
published no WebMCP declaration, no MCP endpoint and no ARD catalogue. Every site in the sample scored zero on all three routes at once.
What the score does not claim
This section is published because an instrument that hides its error bars is not an instrument. Every item below is recorded in the scanner’s own repository, not discovered here.
- It reads one page, fetched once, and does not run JavaScript. A booking flow two clicks deep scores as if it were not there. That is the correct measurement of what an agent gets on arrival, and it is not a measurement of what the business can do.
- It understates most sites, and we know roughly by how much. Opening the same fifteen sites in a real browser — rendering, waiting for scripts, clicking, following links — reached 28 actions this pass did not see, on 14 of the 15 sites. Source:
packages/mapper/benchmark/results.json,comparison. - A file scan is not a URL scan. Scanning a saved HTML file skips the
robots.txt, sitemap,llms.txtand catalogue probes entirely, so the same page can score up to about 11 points higher as a live URL than as a fixture. Source:packages/scanner/README.md, "Notes for the fleet". - It is not a ranking. A category score is a direction; the fix list is the useful part. The scanner is version 0.1 and its known measurement defects are recorded in the repository rather than in a footnote.
- It says nothing about mappability or execution success. Those need a real browser and a sandbox, so the benchmark summary prints
n/afor both rather than substituting the detected-action rate as a proxy. The detected-action rate is mappability’s ceiling, not its stand-in. - A zero in the agent-callable column is a fact about those sites, not a property of the instrument. It is computed from positive evidence, and one site in fifteen did earn it.
How the measurement is made
Inside the repository
npm install
npm run scan -- https://somebusiness.com.au --html report.html --json report.json
npm run scan -- fixtures/bad-plumber.html # offline fixture mode
npm test # tsc --noEmit, then scoring, callability and publication assertions on 10 fixtures
npm run build:public # regenerate publish/public-reports.json from the committed benchmark reports
npm run build:public -- --check # fail if that bundle is stale (also asserted by npm test)packages/scanner/README.md, "Run".Written from
- Every check and every point
packages/scanner/src/checks.ts - The grade bands
packages/scanner/src/scan.ts - The scanner explainer and its known defects
packages/scanner/README.md - The committed 25 Aug 2026 run
packages/scanner/benchmark/reports/ - The published, anonymised bundle
packages/scanner/publish/public-reports.json