The open standard for agent readiness
Agents are a new class of user. Many protocols now serve them (MCP, A2A, x402, llms.txt, Web Bot Auth, and more), but there is no shared definition of what it means to be ready for them. Scanners, badges, and readiness grades exist, and none of them agree.
AgentReady is a community-driven standard for the agentic web: an open specification of the protocols, standards, and conventions a product should implement to be usable by AI agents, from discovery to completion. It does not promote any specific protocol or vendor, and it does not prescribe how builders should score compliance.
The agentic web moves faster than a traditional standards process. The guide below is based on measured agent behavior, and its recommendations are revised as that behavior and the protocols around it change.
§ the guide
Make your site readable by AI agents
A practical guide to making your website work for the agents that now read it, based on real agent runs and a controlled experiment.
Developed by ora.ai and Vercel · v1.0 · last updated August 2026
AI agents visit websites on users’ behalf to answer questions, integrate APIs, and complete tasks. Together with the ora.ai research lab, we measured which site features help them succeed.
In the studies, two changes caused agents to fail: hiding answers behind JavaScript and blocking access. Other practices shaped where agents went and which pages their answers were built from. This guide follows the order in which agents encounter a site: find, read, then act. Each stage depends on the previous one, and unlinked files are unlikely to be discovered.
All recommendations in this guide share one prerequisite: the agent must be able to reach the page and find the answer in the returned HTML.
§ find
Be reachable and citable
Agents can cite only pages they can discover and fetch. They may receive or recall a URL, follow a link, or find a page through a crawl-built search index. Pages blocked from crawlers do not appear in those indexes at all. Blocking can also stop an agent from fetching a page while answering a user.
| practice | what it does | what the runs show | |||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Publish the answer as first-party docs | Makes you citable: the page an agent grounds its answer on and names as its source. | STUDIES82% of answers traced back to a page the agent fetched, and that page was a docs page 47% of the time, more than any other page type. | |||||||||||||||||||||
answer provenance backs:“82% of answers traced back to a page the agent fetched, and that page was a docs page 47% of the time, more than any other page type.” Across 1,033 runs, where did the agent’s final answer come from?
Of the 844 grounded answers, the page types the wording traced to (top 3):
Docs lead every other type; the full 14-way split is in traces.csv. Reproduce over traces.csv: grounded = answer_grounded == 1; page type = answer_ground_kind. browse the dataset → | |||||||||||||||||||||||
| Allow agents and crawlers in robots.txt | Declares which crawlers may fetch which paths. This is the gate to the search indexes. | ORA SCANNERAcross ~50,000 scanned sites, 88% ship a robots.txt, and 80% stay reachable to every major AI crawler. About 1 in 10 block them entirely. | |||||||||||||||||||||
| List your pages in a sitemap.xml | Maps every page you publish for indexing. | STUDIESFetched directly in 4% of runs, one of the files real agents touch least. It is still standard for crawlers and search engines. | |||||||||||||||||||||
sitemap reach backs:“Fetched directly in 4% of runs.”
Reproduce over traces.csv: sitemap_reached == 1. browse the dataset → | |||||||||||||||||||||||
To make information citable, publish it on one canonical, current first-party docs page. The number above is why: your docs are the page agents build their answers from.
That covers what to publish. The crawl policy covers who may read it. Write one rule for all agents instead of an allowlist of named crawlers:
# Apply the default policy to current and future agents.
User-agent: *
# Block low-value public paths only. Do not list secret paths.
Disallow: /search/
Sitemap: https://example.com/sitemap.xmlThe wildcard still leaves you one deliberate choice. The model providers run a separate crawler for each job:
- Training crawlers (GPTBot, ClaudeBot)
- Search-index crawlers (OAI-SearchBot, Claude-SearchBot)
- User-initiated fetchers (ChatGPT-User, Claude-User)
Each obeys its own robots.txt rule, so you can block a training crawler and opt out of training without dropping out of search indexes or agent answers. Two catches: a more specific group such as User-agent: GPTBot overrides your * group, so audit existing rules; and user-initiated fetchers may not consult robots.txt at all.
Then fetch a page with an agent user-agent string to inspect the response:
curl -iL -A 'Claude-User/1.0' https://example.com/your-pageThe request should end with a 200 response; intermediate 301 or 308 redirects are acceptable. The returned HTML should contain the answer. A 403, empty app shell, or JavaScript-only answer prevents fetch-only agents from reading the page.
The curl does not prove much either way: bot blockers weigh where a request comes from more than its user-agent string, so your laptop may pass where the real agent is blocked, or the reverse. The dependable test is your server logs. OpenAI and Anthropic publish their crawlers’ IP ranges (separate per-bot lists from OpenAI, one combined list from Anthropic). Find those requests and confirm they return 200.
llms.txt belongs in the reading section because an agent can request it only after discovering and reaching the site.
§ read
Put the answer where agents read
After reaching a page, an agent must be able to extract the answer from the returned content. In the studies, agents used the same homepage and docs pages as human visitors. The agent-specific files (llms.txt, markdown mirrors, JSON-LD) help agents find, fetch, and use those same answers.
If your site is client-rendered, getting answers into the initial HTML is a real migration (SSR, prerendering, or a hybrid), but it is the prerequisite for agents that fetch rather than run JavaScript. The machinery beyond that (content negotiation, .md endpoints, agent detection, frontmatter) did not change whether agents succeeded in the studies. Links also matter: agents rarely found pages or files that were not linked from content they had already reached.
Agents read the same pages people do
Where agents go on your site, and what lets them pull the answer once there:
| practice | what it does | what the runs show | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Homepage in raw HTML | The front door, with real links to docs, product, and pricing. | STUDIESReached in 69% of runs, and it was the agent’s first step in 92% of them; in 59% of the runs that reached it, the next hop was a docs page. | |||||||||||||||
homepage reach and first hop backs:“Reached in 69% of runs, and it was the agent’s first step in 92% of them. In 59% of the runs that reached it, the next hop was a docs page.” The homepage funnel across 1,033 runs:
Reproduce over traces.csv: homepage_reached, homepage_first_turn, next_hop_docs, each rated against homepage_reached == 1. browse the dataset → | |||||||||||||||||
| Docs pages that answer | The pages agents actually read, where most tasks get resolved. | STUDIESReached in 83% of runs and fetched more than any other page type, about 3.4 docs pages per run. | |||||||||||||||
docs reach and depth backs:“Reached in 83% of runs and fetched more than any other page type, about 3.4 docs pages per run.”
Reproduce over traces.csv: docs_reached == 1; mean of docs_pages_fetched over those runs. browse the dataset → | |||||||||||||||||
| Fetchable without JavaScript | The answer is in the initial HTML, server-rendered or prerendered, rather than injected by a single-page app after load. | STUDIESA JavaScript-hidden answer was one of only two changes that broke an agent. The other was blocking it outright. | |||||||||||||||
fetchability: what broke an agent backs:“A JavaScript-hidden answer was one of only two changes that broke an agent. The other was blocking it outright.” One docs site was served under 19 configurations and probed across 5 topics by two clients, a plain non-JavaScript fetch and a JavaScript-executing one (190 probes). Only three configurations failed, and they reduce to two kinds of change:
A JavaScript-hidden answer fails only the fetch-only client; blocking (bot-block and hostile) fails both. Reproduce over fetchability.csv: success grouped by variant and client. browse the dataset → | |||||||||||||||||
| Fenced code, language-tagged | Turns snippets into examples an agent can lift and use. | STUDIESWhen an agent’s answer included code, 61% of the time it contained lines taken verbatim from a page it fetched on the site. | |||||||||||||||
code lift backs:“When an agent’s answer included code, 61% of the time it contained lines taken verbatim from a page it fetched on the site.” Among the 119 runs whose answer contained code:
Reproduce over traces.csv: among rows where answer_code_matched_fetch is set, share == 1. browse the dataset → | |||||||||||||||||
Link the files that describe your site
STUDIES Agents typically opened these resources after visiting the homepage. Depending on the file type, 86–100% of visits came through links rather than guessed paths. Link each resource from content agents already visited, such as the footer, page metadata like <link rel="alternate"> in the head, or a resources section.
discovery-file linkage
backs:“Depending on the file type, 86–100% of visits came through links rather than guessed paths.”
For each discovery file, the share of fetches that arrived through a link rather than a guessed path:
| file | via link | fetches |
|---|---|---|
| AGENTS.md | 100% | 38 |
| openapi.json | 97% | 122 |
| .well-known/* | 93% | 383 |
| llms.txt | 86% | 416 |
Reproduce over traces.csv: per file, {file}_linked / {file}_fetches.
browse the dataset →| file | what it does | what the runs show | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| llms.txt | A curated, described index of your key pages. | STUDIESReached via links rather than guesses: 86% of its fetches came from a page that pointed to it. One in three agents that read it went on to fetch a page it lists, and 36% drew their final answer from its content. | ||||||||||||||||||
llms.txt behavior backs:“86% of its fetches came from a page that pointed to it. One in three agents that read it went on to fetch a page it lists, and 36% drew their final answer from its content.” How agents reached llms.txt (416 fetches):
What the 329 runs that read llms.txt did next:
Reproduce over traces.csv: via-link = llms_txt_linked / llms_txt_fetches; steering = llms_followed_listing over llms_txt_reached == 1; answer-from-llms = answer_ground_kind == 'llms_txt' over llms_txt_reached == 1. browse the dataset → | ||||||||||||||||||||
| .well-known/* | Protocol and metadata discovery. | STUDIESReached in about 23% of runs across the sites tested. | ||||||||||||||||||
.well-known reach backs:“Reached in about 23% of runs across the sites tested.”
Reproduce over traces.csv: well_known_reached == 1. browse the dataset → | ||||||||||||||||||||
| openapi.json | Machine-readable API contract. | STUDIESOn the sites that ship one, used in 21% of runs. | ||||||||||||||||||
openapi reach backs:“On the sites that ship one, used in 21% of runs.” Restricted to the 7 sites that ship openapi.json (541 runs):
Reproduce over traces.csv: openapi_reached == 1 over site_ships_openapi == 1. browse the dataset → | ||||||||||||||||||||
| JSON-LD | Machine-readable facts and routes in the page. | Markdown converters may omit script blocks, so repeat critical facts in visible text. | ||||||||||||||||||
When shipping an llms.txt, make it a lean, described index:
# Acme
> Acme ships a payments API for developers.
## Docs
- [Quickstart](https://example.com/docs/quickstart): first charge in one request
- [Authentication](https://example.com/docs/auth): API keys, scopes, rotation
## API
- [OpenAPI](https://example.com/openapi.json): full request and response contractInject JSON-LD at strategic places, starting with the homepage, so an agent fetching the raw HTML gets your key facts and routes in one machine-readable block.
Agents request markdown when offered, so make it reachable
STUDIES Agents requested markdown on about 65% of web fetches. When they specified a format, they chose markdown 96% of the time. Format did not determine task success in the studies, so ensure the HTML works before adding a .md mirror.
markdown requests
backs:“Agents requested markdown on about 65% of web fetches. When they specified a format, they chose markdown 96% of the time.”
| calls | share | |
|---|---|---|
| Web fetches requesting markdown | 2,259 | 65% of 3,470 |
| Of fetches that named any format, markdown | 2,259 | 96% of 2,361 |
Reproduce over traces.csv: markdown_calls / web_fetch_calls; markdown_calls / format_set_calls.
browse the dataset →<!-- A mirror nothing points to is a file nothing fetches. -->
<link rel="alternate" type="text/markdown" href="/docs/quickstart.md">The same relation can also be sent as an HTTP Link: header, so a CDN can advertise the mirror without touching page heads.
Return accurate HTTP status codes
Return 404 for a missing path or a valid redirect to a replacement. Do not return 200 for a missing page, even if the body suggests alternatives; agents cannot distinguish that response from a live page. In one observed case, a single-page app returned 200 for every path, making dead URLs appear valid.
The same applies when you throttle: answer with a 429 and a Retry-After header (RFC 6585) rather than a silent challenge page. Agents and crawlers treat 429 as a back-off signal and will return.
By the end of this layer the agent has found you and read you. Whether it can act on what it reads is the final layer: usability.
§ act
Let agents act, not just read
Reading documentation does not let an agent complete a task. To act, an agent needs an operable interface such as an API, MCP server, SDK, or CLI, plus authentication it can complete. These interfaces still depend on discoverable and readable documentation.
| practice | what it does | best practice |
|---|---|---|
| Auth an agent can get through | The first gate of acting. | Self-serve key generation, documented scopes. For user-delegated access, OAuth 2.0 with discoverable metadata under /.well-known (RFC 8414, RFC 9728). |
| Public API with a machine-readable contract | The acting surface itself. | OpenAPI with operation IDs, typed responses and errors, /v1/ versioning, documented rate limits. |
| MCP server | Standard tool protocol for docs search and actions. | Serve over Streamable HTTP at /mcp. Keep the docs MCP public. Gate the product MCP with OAuth (protected-resource metadata at /.well-known/oauth-protected-resource per RFC 9728, with PKCE) and list it in the MCP Registry with a server.json. Server cards for pre-connection discovery are an emerging convention (SEP-2127, a working-group draft that major hosts have begun to support): ship one if your target hosts read it, but expect the exact path to keep moving. |
| MCP Apps | Your UI, rendered inside the agent host. | If your product has a UI, ship an app view (ui:// resource) so the agent can hand a working surface back to the user. |
| SDKs and a CLI | The forms agents act in: code and shell. | Publish SDKs on npm and PyPI and a CLI; show install and first call in the docs. |
That is the full journey: find, read, act. The last step happens only if the first two did.
§ beyond this guide
Beyond this guide
This guide covers the main practices. The ora scanner covers additional agent-readiness checks through its public methodology, per-check breakdown, and leaderboard. The protocol changes as new agent behavior is measured, so checks and weights may change between guide versions.
Scan any domain at ora.ai, or from the CLI:
npx @ora-ai/ax audit https://example.comThe same scan is available from the API:
curl -X POST https://ora.ai/api/scan \
-H 'Content-Type: application/json' \
-d '{"url": "example.com"}'{
"score": 72,
"grade": "B",
"layers": [
{ "id": "accessibility", "score": 43, "maxScore": 62, "checks": [
{ "id": "content-no-js", "status": "pass", "score": 3, "maxScore": 3 },
{ "id": "markdown-link-alternate", "status": "fail", "score": 0, "maxScore": 1,
"recommendation": "Advertise a markdown twin with
<link rel=\"alternate\" type=\"text/markdown\"> …" }
] },
…
]
}Full documentation for the scanner, CLI, and API is at ora.ai/docs.
§ references
- What agents actually reach: the field report behind the trace numbers in this guide, drawing on part of the data used for this spec.
- The state of agent readiness: the scanner report behind the reachability figure.
- ora research: the ongoing research program behind the protocol.
- The agent readiness dataset: the runs and probes behind every [STUDIES] number, with a per-claim breakdown to reproduce them.
§ changelog
v1.0 · August 2026 · first public version.
contribute
AgentReady is developed in the open. The spec source, the dataset behind every STUDIES number, and this site live on GitHub, where discussion and proposals happen. Recommendations are revised as new agent behavior is measured.
MIT · revised as protocols emerge