<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andriy Pyvovarchuk</title>
    <description>The latest articles on DEV Community by Andriy Pyvovarchuk (@andriy_pyvovarchuk).</description>
    <link>https://dev.to/andriy_pyvovarchuk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4047540%2F6ba0b6e9-d68c-4c26-8775-023575f37013.jpg</url>
      <title>DEV Community: Andriy Pyvovarchuk</title>
      <link>https://dev.to/andriy_pyvovarchuk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andriy_pyvovarchuk"/>
    <language>en</language>
    <item>
      <title>How to test your llms.txt before you ship it</title>
      <dc:creator>Andriy Pyvovarchuk</dc:creator>
      <pubDate>Thu, 06 Aug 2026 13:29:41 +0000</pubDate>
      <link>https://dev.to/andriy_pyvovarchuk/how-to-test-your-llmstxt-before-you-ship-it-1579</link>
      <guid>https://dev.to/andriy_pyvovarchuk/how-to-test-your-llmstxt-before-you-ship-it-1579</guid>
      <description>&lt;p&gt;An &lt;code&gt;llms.txt&lt;/code&gt; is easy to write and easy to get subtly wrong. The file can look perfectly fine in your editor and still be malformed, or point at pages that 404 — and unlike a broken web page, nothing visibly breaks, so you never notice. Here's exactly what to check before (and after) you publish.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Structure
&lt;/h2&gt;

&lt;p&gt;Confirm the spec basics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;exactly one &lt;code&gt;#&lt;/code&gt; H1 title,&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;a &lt;code&gt;&amp;gt;&lt;/code&gt; blockquote summary&lt;/strong&gt; right under it,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;##&lt;/code&gt; sections&lt;/strong&gt; that each contain a Markdown list of links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multiple H1s and empty sections are the two most common structural mistakes. If your file has two &lt;code&gt;#&lt;/code&gt; lines, demote one to &lt;code&gt;##&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Link reachability (the check almost everyone skips)
&lt;/h2&gt;

&lt;p&gt;This is the big one. Every URL you link should actually resolve. A flawless-looking file that points at 404s wastes a crawler's budget and quietly erodes trust — and most "llms.txt checkers" only lint the &lt;em&gt;syntax&lt;/em&gt;, so dead links sail straight through them.&lt;/p&gt;

&lt;p&gt;You have to actually &lt;strong&gt;request each linked URL&lt;/strong&gt; and look for anything that's broken or redirecting. This is where doing it by hand falls apart: eyeballing structure is fine, but clicking twenty links to check status codes is tedious and easy to get wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Best practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Absolute &lt;code&gt;https://&lt;/code&gt; URLs — not relative paths, not &lt;code&gt;http://&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A short &lt;code&gt;: description&lt;/code&gt; after each link so the model knows what it is.&lt;/li&gt;
&lt;li&gt;Served as &lt;code&gt;Content-Type: text/plain; charset=utf-8&lt;/code&gt; (a lot of servers wrongly return &lt;code&gt;text/html&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Manual vs automated
&lt;/h2&gt;

&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; verify all of the above by hand. Structure, sure. But link reachability across dozens of URLs, checking content type, re-checking every time you edit the file — that's exactly the kind of tedious, error-prone work worth automating.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fast way
&lt;/h2&gt;

&lt;p&gt;Paste your domain (or the raw text) into an &lt;a href="https://llms-txt-validator.dev/" rel="noopener noreferrer"&gt;llms.txt validator&lt;/a&gt;. It checks the structure, fetches every linked URL concurrently, applies the best-practice rules above, and returns a 0-100 score with a prioritized, fixable list of findings. Re-run it whenever you change the file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7jsp7e52n6djifk8l1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7jsp7e52n6djifk8l1s.png" alt="A 100/100 llms.txt report scored by structure, links and best practices" width="800" height="688"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;What a clean result looks like: 100/100, every link fetched, with the HTTP status, size, content type and link count broken out. A single broken link drags the score down even when the Markdown is perfect.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The 30-second checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] One &lt;code&gt;#&lt;/code&gt; H1, one &lt;code&gt;&amp;gt;&lt;/code&gt; summary, &lt;code&gt;##&lt;/code&gt; sections with links&lt;/li&gt;
&lt;li&gt;[ ] Every linked URL returns 200 (no 404s, no redirect chains)&lt;/li&gt;
&lt;li&gt;[ ] All links absolute &lt;code&gt;https://&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] A &lt;code&gt;: description&lt;/code&gt; on each link&lt;/li&gt;
&lt;li&gt;[ ] Served as &lt;code&gt;text/plain; charset=utf-8&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Re-checked after your latest edit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Get those six right and your &lt;code&gt;llms.txt&lt;/code&gt; is in better shape than most on the web today. Test it once, fix what's flagged, ship it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Which AI crawlers actually read your llms.txt? (GPTBot, ClaudeBot &amp; friends)</title>
      <dc:creator>Andriy Pyvovarchuk</dc:creator>
      <pubDate>Thu, 06 Aug 2026 05:55:44 +0000</pubDate>
      <link>https://dev.to/andriy_pyvovarchuk/which-ai-crawlers-actually-read-your-llmstxt-gptbot-claudebot-friends-3677</link>
      <guid>https://dev.to/andriy_pyvovarchuk/which-ai-crawlers-actually-read-your-llmstxt-gptbot-claudebot-friends-3677</guid>
      <description>&lt;p&gt;You added an &lt;code&gt;llms.txt&lt;/code&gt;. Reasonable next question: &lt;em&gt;who's actually reading it?&lt;/em&gt; The honest answer surprises people — so let's clear it up, and more importantly sort out which bots you should care about and how you actually control them (spoiler: not with &lt;code&gt;llms.txt&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  First, split the bots into two piles
&lt;/h2&gt;

&lt;p&gt;Lumping all "AI crawlers" together is where people get confused. There are two kinds, and you treat them very differently:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer / search crawlers&lt;/strong&gt; — they fetch a page to answer a user's question &lt;em&gt;right now&lt;/em&gt;, and they're the ones that get you cited in AI answers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI: &lt;code&gt;OAI-SearchBot&lt;/code&gt;, &lt;code&gt;ChatGPT-User&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Anthropic: &lt;code&gt;Claude-SearchBot&lt;/code&gt;, &lt;code&gt;Claude-User&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Perplexity: &lt;code&gt;PerplexityBot&lt;/code&gt;, &lt;code&gt;Perplexity-User&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You generally &lt;strong&gt;want&lt;/strong&gt; these.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training crawlers&lt;/strong&gt; — they collect data to train future models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GPTBot&lt;/code&gt;, &lt;code&gt;ClaudeBot&lt;/code&gt;, &lt;code&gt;Google-Extended&lt;/code&gt;, &lt;code&gt;Applebot-Extended&lt;/code&gt;, &lt;code&gt;CCBot&lt;/code&gt;, &lt;code&gt;Bytespider&lt;/code&gt;, &lt;code&gt;Meta-ExternalAgent&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether to allow these is a &lt;strong&gt;separate, opt-out decision&lt;/strong&gt; — and blocking them does &lt;em&gt;not&lt;/em&gt; hurt your AI-search visibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which of them read llms.txt today?
&lt;/h2&gt;

&lt;p&gt;Straight answer: &lt;strong&gt;adoption is still early.&lt;/strong&gt; &lt;code&gt;llms.txt&lt;/code&gt; is a young, voluntary convention. It's picking up support in AI developer tools and agent frameworks, but most of the big crawlers above do &lt;strong&gt;not&lt;/strong&gt; yet fetch it automatically. No bot is &lt;em&gt;required&lt;/em&gt; to read it.&lt;/p&gt;

&lt;p&gt;That sounds like a reason to skip it. It isn't — for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The clean pages it points to help models right now.&lt;/strong&gt; Even a crawler that ignores the file itself benefits from the well-structured, Markdown-friendly pages you curated for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's cheap readiness.&lt;/strong&gt; A correct &lt;code&gt;llms.txt&lt;/code&gt; costs ten minutes and positions you for the moment adoption tips — which, given how fast this space moves, won't be long.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The part people get wrong: llms.txt doesn't control access
&lt;/h2&gt;

&lt;p&gt;This is the big misconception. &lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt; never blocks or grants anything.&lt;/strong&gt; It only &lt;em&gt;curates&lt;/em&gt; — a suggested reading list. If you want to control which AI crawlers may fetch your pages, that's &lt;code&gt;robots.txt&lt;/code&gt;'s job.&lt;/p&gt;

&lt;p&gt;A visibility-friendly setup allows the answer crawlers and makes a deliberate call on the training ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;OAI&lt;/span&gt;-&lt;span class="n"&gt;SearchBot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;PerplexityBot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;GPTBot&lt;/span&gt;
&lt;span class="n"&gt;Disallow&lt;/span&gt;: /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That example says "let AI search engines cite me, but keep my content out of model training." Your call on that last line — just know it's a training opt-out, not a visibility switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allow&lt;/strong&gt; the answer/search crawlers (&lt;code&gt;OAI-SearchBot&lt;/code&gt;, &lt;code&gt;Claude-SearchBot&lt;/code&gt;, &lt;code&gt;PerplexityBot&lt;/code&gt;, …) so AI tools can cite you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide training opt-outs&lt;/strong&gt; (&lt;code&gt;GPTBot&lt;/code&gt;, &lt;code&gt;Google-Extended&lt;/code&gt;) deliberately — blocking them doesn't touch AI-search visibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish a curated &lt;code&gt;llms.txt&lt;/code&gt;&lt;/strong&gt; and then actually check it — the most common failure is a valid-looking file pointing at dead links. Run it through an &lt;a href="https://llms-txt-validator.dev/" rel="noopener noreferrer"&gt;llms.txt validator&lt;/a&gt; that fetches every URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is the map; &lt;code&gt;robots.txt&lt;/code&gt; is the gate. Keep the map honest and the gate deliberate, and you're ahead of nearly everyone.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>seo</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>Does llms.txt help SEO? An honest answer</title>
      <dc:creator>Andriy Pyvovarchuk</dc:creator>
      <pubDate>Tue, 04 Aug 2026 06:22:19 +0000</pubDate>
      <link>https://dev.to/andriy_pyvovarchuk/does-llmstxt-help-seo-an-honest-answer-ln3</link>
      <guid>https://dev.to/andriy_pyvovarchuk/does-llmstxt-help-seo-an-honest-answer-ln3</guid>
      <description>&lt;p&gt;If you searched this, you've probably also seen the other kind of post — "add llms.txt and watch your rankings climb." Let me save you the disappointment and then tell you why the file is still worth ten minutes of your time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short answer: no, not for classic SEO
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is &lt;strong&gt;not a Google ranking signal.&lt;/strong&gt; Google has said Googlebot doesn't use it for search ranking. It's not a meta tag, not a sitemap replacement, not a backlink, and no, it won't move you up the results page. Anyone selling "llms.txt → #1 on Google" is selling snake oil.&lt;/p&gt;

&lt;p&gt;So if your only goal is blue-link rankings, &lt;code&gt;llms.txt&lt;/code&gt; isn't your lever. Close the tab, go fix your Core Web Vitals.&lt;/p&gt;

&lt;h2&gt;
  
  
  The longer answer: it helps a &lt;em&gt;different&lt;/em&gt; kind of visibility
&lt;/h2&gt;

&lt;p&gt;Still here? Good — because the question is slightly out of date. More and more, people don't get an answer &lt;em&gt;about&lt;/em&gt; your product from a ranked list of links. They ask ChatGPT, Claude, Perplexity, or Google's AI overview, and read whatever those models say about you.&lt;/p&gt;

&lt;p&gt;Being cleanly readable by those models is its own discipline now — people call it &lt;strong&gt;GEO (generative engine optimization)&lt;/strong&gt;, the AI-answer cousin of SEO. And that's exactly what &lt;code&gt;llms.txt&lt;/code&gt; is for. A tidy one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;points models at your best, most current pages instead of letting them guess,&lt;/li&gt;
&lt;li&gt;gives them clean context so answers &lt;em&gt;about you&lt;/em&gt; are accurate rather than hallucinated,&lt;/li&gt;
&lt;li&gt;pairs with Markdown versions of your pages so the model reads content, not your nav bar, cookie banner, and ads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It won't rank you. It changes what the AI &lt;em&gt;says&lt;/em&gt; when someone asks about you — which, increasingly, is the thing that actually drives the click.&lt;/p&gt;

&lt;h2&gt;
  
  
  So is it worth it?
&lt;/h2&gt;

&lt;p&gt;Simple test: &lt;strong&gt;does your audience ask AI tools about your domain&lt;/strong&gt; — your docs, your API, your product? If yes, &lt;code&gt;llms.txt&lt;/code&gt; is a small file with real upside and basically no downside. Write it once, keep it curated, done.&lt;/p&gt;

&lt;p&gt;If you're a purely local business with no documentation and nobody's asking an LLM about you, the payoff is smaller — spend the time elsewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do instead of chasing rankings with it
&lt;/h2&gt;

&lt;p&gt;Treat &lt;code&gt;llms.txt&lt;/code&gt; as one piece of AI-readiness, alongside the things that genuinely help discovery:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a clean &lt;code&gt;robots.txt&lt;/code&gt; that actually lets the AI crawlers you want in,&lt;/li&gt;
&lt;li&gt;schema.org structured data,&lt;/li&gt;
&lt;li&gt;a real sitemap,&lt;/li&gt;
&lt;li&gt;and, yes, a curated &lt;code&gt;llms.txt&lt;/code&gt; on top.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then make sure the file is actually correct — the most common failure is a perfectly-formatted &lt;code&gt;llms.txt&lt;/code&gt; that points at 404s, which does the opposite of building trust. Run it through an &lt;a href="https://llms-txt-validator.dev/" rel="noopener noreferrer"&gt;llms.txt validator&lt;/a&gt; that fetches every linked URL, and fix whatever it flags.&lt;/p&gt;

&lt;p&gt;The honest pitch: &lt;code&gt;llms.txt&lt;/code&gt; won't help your SEO. It'll help the thing SEO is slowly turning into. That's a better bet anyway.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>seo</category>
    </item>
    <item>
      <title>I made my website callable by another AI agent — here's the actual JSON-RPC</title>
      <dc:creator>Andriy Pyvovarchuk</dc:creator>
      <pubDate>Tue, 04 Aug 2026 06:01:22 +0000</pubDate>
      <link>https://dev.to/andriy_pyvovarchuk/i-made-my-website-callable-by-another-ai-agent-heres-the-actual-json-rpc-42m</link>
      <guid>https://dev.to/andriy_pyvovarchuk/i-made-my-website-callable-by-another-ai-agent-heres-the-actual-json-rpc-42m</guid>
      <description>&lt;p&gt;Most "AI integration" still means a human reads your docs and writes a client. A2A flips that: another &lt;em&gt;agent&lt;/em&gt; reads a small machine description of what your service does and calls it directly — no browser, no scraping, no human in the loop. I wired it up on a small tool I run (a free llms.txt validator) and it's simpler than the acronyms suggest. Here's the whole thing, with the real requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What A2A actually is
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A2A (Agent2Agent)&lt;/strong&gt; is an open protocol — now under the Linux Foundation — that lets AI agents &lt;em&gt;discover and call each other&lt;/em&gt; over plain HTTP. Think of it as the agent-to-agent counterpart of a public API: instead of publishing OpenAPI docs for humans, you publish a machine description another agent can consume and invoke.&lt;/p&gt;

&lt;p&gt;It has exactly two moving parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The agent card&lt;/strong&gt; — a discovery document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The skill&lt;/strong&gt; — a callable JSON-RPC endpoint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it. You can ship a useful A2A surface with one skill and a single method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1 — the agent card (discovery)
&lt;/h2&gt;

&lt;p&gt;You serve a JSON file at &lt;code&gt;/.well-known/agent-card.json&lt;/code&gt; describing who you are and what you can do. The required fields are &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;, &lt;code&gt;url&lt;/code&gt; (your endpoint) and at least one &lt;code&gt;skill&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocolVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"llms.txt Validator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validate a website's llms.txt and return a score with findings."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://llms-txt-validator.dev/a2a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validate_llms_txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validate llms.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Given a domain or URL, fetch and validate its llms.txt."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The card is a &lt;strong&gt;contract&lt;/strong&gt;, not a meta tag. An agent fetches it, sees a &lt;code&gt;validate_llms_txt&lt;/code&gt; skill, and knows both what you offer and where to call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2 — the endpoint (a callable skill)
&lt;/h2&gt;

&lt;p&gt;The card's &lt;code&gt;url&lt;/code&gt; points at a &lt;strong&gt;JSON-RPC 2.0&lt;/strong&gt; endpoint. An agent invokes the &lt;code&gt;message/send&lt;/code&gt; method with a message; you do the work and return a &lt;code&gt;Task&lt;/code&gt;. Here's a real call to my agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/a&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"message/send"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validate llmstxt.org"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and the reply — a completed task carrying a human-readable summary &lt;em&gt;and&lt;/em&gt; structured data the calling agent can use directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"completed"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"artifacts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"parts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validated llmstxt.org: score 100/100..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"scores"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"overall"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No HTML, no parsing, no guessing. The agent asked a question in natural language and got back exactly the data it needed. You can &lt;code&gt;curl&lt;/code&gt; this yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The minimum viable A2A
&lt;/h2&gt;

&lt;p&gt;You don't need the whole spec to start. Pick &lt;em&gt;one&lt;/em&gt; real thing your service does and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Serve a valid agent card at &lt;code&gt;/.well-known/agent-card.json&lt;/code&gt; with one skill.&lt;/li&gt;
&lt;li&gt;Implement the synchronous &lt;code&gt;message/send&lt;/code&gt; method wrapping that capability.&lt;/li&gt;
&lt;li&gt;Return a completed &lt;code&gt;Task&lt;/code&gt; with the result as an artifact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Streaming, task history, and push notifications are all optional — set &lt;code&gt;capabilities.streaming&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt; and add them only when you actually need them.&lt;/p&gt;

&lt;h2&gt;
  
  
  A2A vs WebMCP vs MCP (they're not competitors)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A2A&lt;/strong&gt; — networked agents calling your service over HTTP (this article).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebMCP&lt;/strong&gt; — an agent running &lt;em&gt;inside the browser&lt;/em&gt; calling tools on your open page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; — connecting tools to a single model or app, usually locally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They stack rather than compete: A2A reaches networked agents, WebMCP reaches in-browser ones, MCP wires tools into one model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule: don't publish a card you can't back
&lt;/h2&gt;

&lt;p&gt;It's tempting to drop an agent card to look modern and leave the endpoint returning &lt;code&gt;501&lt;/code&gt;. Don't. An agent that fetches your card and calls a dead &lt;code&gt;url&lt;/code&gt; trusts you &lt;em&gt;less&lt;/em&gt; afterward — you've spent its call for nothing. Every skill you advertise should resolve to real, working behavior. (That's why the &lt;a href="https://llms-txt-validator.dev/" rel="noopener noreferrer"&gt;validator&lt;/a&gt; I built reports an A2A signal as "present" only when a live endpoint actually answers &lt;code&gt;message/send&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;If you ship one, drop your agent card in the comments — I'd like to call it.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>api</category>
      <category>json</category>
    </item>
    <item>
      <title>7 llms.txt mistakes I see constantly (and the 30-second fix for each)</title>
      <dc:creator>Andriy Pyvovarchuk</dc:creator>
      <pubDate>Sun, 26 Jul 2026 06:57:50 +0000</pubDate>
      <link>https://dev.to/andriy_pyvovarchuk/7-llmstxt-mistakes-i-see-constantly-and-the-30-second-fix-for-each-10m1</link>
      <guid>https://dev.to/andriy_pyvovarchuk/7-llmstxt-mistakes-i-see-constantly-and-the-30-second-fix-for-each-10m1</guid>
      <description>&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is deceptively simple — it's just Markdown — so most people write one in five minutes and move on. The problem: a file can look perfectly valid and still be broken in ways that quietly waste an AI crawler's time or get it ignored. Here are the seven mistakes I run into most, and the quick fix for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. More than one H1
&lt;/h2&gt;

&lt;p&gt;The spec wants exactly &lt;strong&gt;one&lt;/strong&gt; top-level &lt;code&gt;# Title&lt;/code&gt;. Extra &lt;code&gt;#&lt;/code&gt; headings scramble the structure a model relies on. &lt;strong&gt;Fix:&lt;/strong&gt; keep a single &lt;code&gt;#&lt;/code&gt;, demote every other heading to &lt;code&gt;##&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. No blockquote summary
&lt;/h2&gt;

&lt;p&gt;The one- or two-sentence &lt;code&gt;&amp;gt;&lt;/code&gt; blockquote right under the title is the &lt;em&gt;first&lt;/em&gt; context a model reads. Skipping it is the single most common miss. &lt;strong&gt;Fix:&lt;/strong&gt; add one line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Acme&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Acme turns CSV files into charts. These links cover setup, the API, and pricing.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Sections with no links (or no sections at all)
&lt;/h2&gt;

&lt;p&gt;Empty &lt;code&gt;##&lt;/code&gt; sections add nothing; a wall of links with no structure is just as bad. &lt;strong&gt;Fix:&lt;/strong&gt; group your key pages under real headings (&lt;code&gt;## Docs&lt;/code&gt;, &lt;code&gt;## Guides&lt;/code&gt;) with a Markdown bullet list of links under each.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Broken links
&lt;/h2&gt;

&lt;p&gt;This is the big one. A file can be flawless Markdown and still point at 404s — which burns crawl budget and erodes trust. Most linters check &lt;em&gt;syntax&lt;/em&gt; and never actually fetch the URLs, so broken links sail straight through. &lt;strong&gt;Fix:&lt;/strong&gt; verify every link resolves. (This is the check I built my validator around — it fetches each one.)&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Relative or &lt;code&gt;http://&lt;/code&gt; links
&lt;/h2&gt;

&lt;p&gt;Models may not resolve relative paths like &lt;code&gt;/docs/start&lt;/code&gt;, and plain &lt;code&gt;http://&lt;/code&gt; links look untrustworthy and can break under HTTPS-only crawling. &lt;strong&gt;Fix:&lt;/strong&gt; use absolute &lt;code&gt;https://&lt;/code&gt; URLs everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The wrong content type
&lt;/h2&gt;

&lt;p&gt;Serve the file as &lt;code&gt;text/plain; charset=utf-8&lt;/code&gt;. A surprising number of servers return &lt;code&gt;text/html&lt;/code&gt; for it (a default misconfiguration), and some consumers then won't treat it as &lt;code&gt;llms.txt&lt;/code&gt; at all. &lt;strong&gt;Fix:&lt;/strong&gt; set the content type explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. A bloated, uncurated dump
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is a &lt;em&gt;curated index&lt;/em&gt;, not a sitemap. Hundreds of undescribed links bury the signal you're trying to send. &lt;strong&gt;Fix:&lt;/strong&gt; keep the best pages, add a short &lt;code&gt;: description&lt;/code&gt; after each, and push secondary links to an &lt;code&gt;## Optional&lt;/code&gt; section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Catch all seven at once
&lt;/h2&gt;

&lt;p&gt;You don't have to eyeball these by hand. Paste your domain into an &lt;a href="https://llms-txt-validator.dev/" rel="noopener noreferrer"&gt;llms.txt validator&lt;/a&gt; — it scores structure, fetches every linked URL, and tells you exactly which of the above to fix, in plain language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7jsp7e52n6djifk8l1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7jsp7e52n6djifk8l1s.png" alt="A 100/100 llms.txt report, scored by structure, links and best practices" width="800" height="688"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A clean report: 100/100 with every link fetched. Broken links drag the score down even when the Markdown is perfect — which is exactly the failure mode syntax-only checkers miss.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Fix these seven and you're ahead of most &lt;code&gt;llms.txt&lt;/code&gt; files on the web today. The bar is genuinely low right now — which is the opportunity.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>llms.txt vs robots.txt vs sitemap.xml: what actually does what</title>
      <dc:creator>Andriy Pyvovarchuk</dc:creator>
      <pubDate>Sun, 26 Jul 2026 06:26:18 +0000</pubDate>
      <link>https://dev.to/andriy_pyvovarchuk/llmstxt-vs-robotstxt-vs-sitemapxml-what-actually-does-what-506m</link>
      <guid>https://dev.to/andriy_pyvovarchuk/llmstxt-vs-robotstxt-vs-sitemapxml-what-actually-does-what-506m</guid>
      <description>&lt;p&gt;If you run a website in 2026 you now have &lt;em&gt;three&lt;/em&gt; plain-text files that can live at your root and all look suspiciously similar: &lt;code&gt;robots.txt&lt;/code&gt;, &lt;code&gt;sitemap.xml&lt;/code&gt;, and the newcomer, &lt;code&gt;llms.txt&lt;/code&gt;. They get confused constantly — I've seen people add &lt;code&gt;llms.txt&lt;/code&gt; thinking it blocks AI crawlers (it doesn't) or skip it thinking &lt;code&gt;robots.txt&lt;/code&gt; already covers it (it doesn't). Here's the clean mental model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-line version
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;robots.txt&lt;/code&gt;&lt;/strong&gt; → controls crawler &lt;strong&gt;access&lt;/strong&gt;: which paths bots may or may not fetch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sitemap.xml&lt;/code&gt;&lt;/strong&gt; → lists &lt;strong&gt;every indexable page&lt;/strong&gt; so search engines miss nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/strong&gt; → curates a &lt;strong&gt;shortlist of high-signal pages&lt;/strong&gt; for AI models at answer time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Access, coverage, curation. Three different jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  robots.txt is about permission
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;robots.txt&lt;/code&gt; is an access-control convention: "Googlebot may crawl &lt;code&gt;/blog&lt;/code&gt; but not &lt;code&gt;/admin&lt;/code&gt;." It's a bouncer at the door. It doesn't describe your content, doesn't rank it, and isn't written for language models in particular. Blocking or allowing a path there says nothing about &lt;em&gt;what the page is&lt;/em&gt; — only whether a bot may request it.&lt;/p&gt;

&lt;p&gt;Crucially: &lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt; is not an access-control file.&lt;/strong&gt; It can't stop an AI crawler from reading anything. If that's your goal, &lt;code&gt;robots.txt&lt;/code&gt; (and server-side rules) is still the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  sitemap.xml is about coverage
&lt;/h2&gt;

&lt;p&gt;A sitemap tries to be &lt;em&gt;exhaustive&lt;/em&gt;: every URL you want indexed, so search engines don't overlook a page. It's machine-oriented XML for crawlers, not a human-readable summary, and it makes no attempt to say which pages matter most — they're all just listed.&lt;/p&gt;

&lt;h2&gt;
  
  
  llms.txt is about curation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is the opposite of exhaustive. It's a hand-picked, Markdown list of the &lt;em&gt;few&lt;/em&gt; pages that best help a model understand and use your site, each with a short description. It exists for &lt;strong&gt;inference&lt;/strong&gt; — the moment a user asks ChatGPT or Claude "how do I do X with your product" — not for training datasets and not for access control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Acme&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Acme turns CSV files into charts. These links cover setup, the API, and pricing.&lt;/span&gt;

&lt;span class="gu"&gt;## Docs&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Quickstart&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/quickstart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: first chart in 5 minutes
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;API reference&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: endpoints and auth
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where a sitemap says "here is everything," &lt;code&gt;llms.txt&lt;/code&gt; says "here is what's worth your limited context window."&lt;/p&gt;

&lt;h2&gt;
  
  
  You don't choose — you use all three
&lt;/h2&gt;

&lt;p&gt;This is the part people miss. A strong 2026 setup has all three, each doing its job:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Audience&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;robots.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;May you fetch this?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;all crawlers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sitemap.xml&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;What should you index?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;search engines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;em&gt;What matters most here?&lt;/em&gt;&lt;/td&gt;
&lt;td&gt;AI models&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;robots.txt&lt;/code&gt; governs access, &lt;code&gt;sitemap.xml&lt;/code&gt; ensures coverage, and &lt;code&gt;llms.txt&lt;/code&gt; curates signal for AI. They complement each other; none replaces another.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting llms.txt right
&lt;/h2&gt;

&lt;p&gt;The catch with &lt;code&gt;llms.txt&lt;/code&gt; is that it's easy to write one that &lt;em&gt;looks&lt;/em&gt; valid but points at dead links or ships as the wrong content type — and unlike the other two, almost nobody checks it. After you write yours, run it through an &lt;a href="https://llms-txt-validator.dev/" rel="noopener noreferrer"&gt;llms.txt validator&lt;/a&gt; that fetches every linked URL and confirms it resolves, then fix whatever it flags. Aim for no broken links first; structure second.&lt;/p&gt;

&lt;p&gt;Three files, three jobs. Once that clicks, &lt;code&gt;llms.txt&lt;/code&gt; stops being mysterious — it's just the curation layer the web didn't have until AI needed one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I made my website callable by AI agents — the three layers (with the code I shipped)</title>
      <dc:creator>Andriy Pyvovarchuk</dc:creator>
      <pubDate>Sun, 26 Jul 2026 05:26:06 +0000</pubDate>
      <link>https://dev.to/andriy_pyvovarchuk/i-made-my-website-callable-by-ai-agents-the-three-layers-with-the-code-i-shipped-140i</link>
      <guid>https://dev.to/andriy_pyvovarchuk/i-made-my-website-callable-by-ai-agents-the-three-layers-with-the-code-i-shipped-140i</guid>
      <description>&lt;p&gt;"Make your site agent-ready" gets thrown around a lot, but it actually means three &lt;em&gt;different&lt;/em&gt; things to three &lt;em&gt;different&lt;/em&gt; kinds of AI agent — and they stack. I built a small tool (a free llms.txt validator) and wired up all three layers on it, so this is the copy-the-code version, not the hand-wavy one.&lt;/p&gt;

&lt;p&gt;But before the three layers, let's start at the bottom — because the whole stack rests on one small file most sites still don't have.&lt;/p&gt;

&lt;h2&gt;
  
  
  First: what is llms.txt, and why should you care?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;llms.txt is a plain-text file you put at &lt;code&gt;yoursite.com/llms.txt&lt;/code&gt; that tells AI models what your site is about and which pages actually matter.&lt;/strong&gt; That's it. It's written in Markdown, and it's read by AI assistants and crawlers — ChatGPT, Claude, Perplexity, and the growing crowd of AI agents — when they try to understand your site.&lt;/p&gt;

&lt;p&gt;Here's the problem it solves. When an AI tries to "read" your website today, it gets a mess: HTML wrappers, navigation menus, cookie banners, ads, JavaScript that may not even run. It has to guess what's important and burns a big chunk of its limited context window doing it. Often it guesses wrong, or gives up.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; hands the AI a clean, curated map instead — &lt;em&gt;you&lt;/em&gt; decide what your site is and which pages are the good ones, in priority order:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Example — Project Management for Teams&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Example is a project-management app. This file points AI assistants&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; at our most useful docs and product pages.&lt;/span&gt;

&lt;span class="gu"&gt;## Docs&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Quickstart&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/quickstart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: get set up in 5 minutes
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;API reference&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: every endpoint, with examples

&lt;span class="gu"&gt;## Product&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Pricing&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/pricing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: plans and limits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two useful mental models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's the AI counterpart to &lt;code&gt;sitemap.xml&lt;/code&gt;.&lt;/strong&gt; A sitemap helps &lt;em&gt;search engines&lt;/em&gt; find every page; &lt;code&gt;llms.txt&lt;/code&gt; helps &lt;em&gt;AI models&lt;/em&gt; understand the few pages that matter, in the format they read most cheaply.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's the flip side of &lt;code&gt;robots.txt&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;robots.txt&lt;/code&gt; says what crawlers may &lt;em&gt;not&lt;/em&gt; touch; &lt;code&gt;llms.txt&lt;/code&gt; says what your site &lt;em&gt;is&lt;/em&gt; and where the value is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it matters now:&lt;/strong&gt; people increasingly get answers &lt;em&gt;about&lt;/em&gt; your product from an AI assistant instead of clicking to your site. If the AI can't cheaply and correctly understand you, it either skips you or describes you wrong. &lt;code&gt;llms.txt&lt;/code&gt; is your chance to feed it an accurate, curated summary — so you're represented the way you intend. It's a context layer, not a ranking trick: you're not gaming anything, you're just making your site legible to machines.&lt;/p&gt;

&lt;p&gt;(There's an optional companion, &lt;code&gt;llms-full.txt&lt;/code&gt;, that inlines the full text of those pages so an AI can ingest everything in one fetch. Start with &lt;code&gt;llms.txt&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;That's the foundation. Now the three layers that build on it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fro21hjax8277r813bk8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fro21hjax8277r813bk8m.png" alt="The llms.txt validator homepage — paste a domain, get a score in seconds" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The tool this article is about: paste a domain, it fetches &lt;code&gt;/llms.txt&lt;/code&gt;, checks it against the spec, and tests every link.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here are the three independent layers. You can adopt any one on its own:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;llms.txt&lt;/strong&gt; — context for crawlers reading your site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebMCP&lt;/strong&gt; — tools for an agent driving your UI &lt;em&gt;inside the browser&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2A&lt;/strong&gt; — a callable endpoint for another agent hitting you &lt;em&gt;over the network&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Crawler → browser agent → networked agent. Different agents, different mechanisms, zero overlap.&lt;/p&gt;


&lt;h2&gt;
  
  
  Layer 1 — llms.txt: context for crawlers
&lt;/h2&gt;

&lt;p&gt;The baseline, and the highest-value one for most sites. A plain-text &lt;code&gt;llms.txt&lt;/code&gt; at your root tells an AI crawler what your site is and which pages matter, in priority order. It's read at fetch time — no JavaScript, no protocol, no SDK. It's literally Markdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Example Docs&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Developer documentation for the Example API.&lt;/span&gt;

&lt;span class="gu"&gt;## Core&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Quickstart&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/quickstart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: 5-minute setup
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Authentication&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: API keys and OAuth

&lt;span class="gu"&gt;## Reference&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;API reference&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: every endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rules that actually matter in practice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One &lt;code&gt;#&lt;/code&gt; H1 title, one &lt;code&gt;&amp;gt;&lt;/code&gt; blockquote summary.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;##&lt;/code&gt; sections with real Markdown links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Absolute HTTPS URLs&lt;/strong&gt; — relative links are the single most common failure.&lt;/li&gt;
&lt;li&gt;Serve it as &lt;code&gt;text/plain&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole layer. If you do nothing else, do this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 2 — WebMCP: tools for in-browser agents
&lt;/h2&gt;

&lt;p&gt;WebMCP lets a page expose callable &lt;strong&gt;tools&lt;/strong&gt; to an AI agent running inside the browser — so instead of the agent guessing at your form fields and clicking around, it invokes a typed action you defined. There are two ways to expose a tool, and I shipped both.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Declarative&lt;/strong&gt; — annotate a real form and the browser synthesizes a tool from it. Zero JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;toolname=&lt;/span&gt;&lt;span class="s"&gt;"open_llms_txt_report"&lt;/span&gt;
      &lt;span class="na"&gt;tooldescription=&lt;/span&gt;&lt;span class="s"&gt;"Validate a site's llms.txt and open its report."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt; &lt;span class="na"&gt;toolparamdescription=&lt;/span&gt;&lt;span class="s"&gt;"Domain or URL to validate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Imperative&lt;/strong&gt; — register a tool in JavaScript that returns structured data directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;registerTool&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;validate_llms_txt&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Validate a website's llms.txt; returns a 0-100 score and findings.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/validate?url=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Guard the imperative call behind &lt;code&gt;if (navigator.modelContext)&lt;/code&gt; so it's a no-op where WebMCP isn't present. Reality check: it's a Chrome origin trial today, so actual reach is tiny. Treat it as a &lt;strong&gt;forward signal and a clean reference&lt;/strong&gt;, not a traffic source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 3 — A2A: a callable agent for other agents
&lt;/h2&gt;

&lt;p&gt;The Agent2Agent (A2A) protocol — now under the Linux Foundation — lets other agents &lt;strong&gt;discover and call&lt;/strong&gt; your service over plain HTTP. No browser, no scraping. It's the agent-to-agent counterpart of a public API.&lt;/p&gt;

&lt;p&gt;Two parts: a discovery document (the &lt;strong&gt;agent card&lt;/strong&gt;) and a callable endpoint (the &lt;strong&gt;skill&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The agent card&lt;/strong&gt; — a JSON file at &lt;code&gt;/.well-known/agent-card.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"protocolVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.3.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"llms.txt Validator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validate a website's llms.txt and return a score with findings."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://llms-txt-validator.dev/a2a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"skills"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validate_llms_txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validate llms.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Given a domain or URL, fetch and validate its llms.txt."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The endpoint&lt;/strong&gt; — the card's &lt;code&gt;url&lt;/code&gt; points at a JSON-RPC 2.0 endpoint. An agent calls &lt;code&gt;message/send&lt;/code&gt;; you do the work and return a &lt;code&gt;Task&lt;/code&gt;. A real call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/a&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"message/send"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validate llmstxt.org"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…and the reply — a completed task with a human-readable summary &lt;em&gt;and&lt;/em&gt; structured data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"completed"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"artifacts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"parts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validated llmstxt.org: score 100/100..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"report"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"scores"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"overall"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent gets exactly the data it asked for. You don't need the whole protocol to start — pick one real capability, serve a card with one skill, implement the synchronous &lt;code&gt;message/send&lt;/code&gt;, return a completed &lt;code&gt;Task&lt;/code&gt;. Streaming, task history and push notifications are optional (&lt;code&gt;capabilities.streaming: false&lt;/code&gt;) until you need them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule: don't publish a signal you can't back
&lt;/h2&gt;

&lt;p&gt;It's tempting to drop an empty agent card or fake form annotations to make some audit go green. &lt;strong&gt;Don't.&lt;/strong&gt; An agent that fetches your card and calls a dead endpoint — or invokes a tool that does nothing — trusts you &lt;em&gt;less&lt;/em&gt; afterward. Every signal should resolve to something real. (This is why the validator I built reports a WebMCP or A2A signal as "present" only when a working implementation actually backs it.)&lt;/p&gt;

&lt;h2&gt;
  
  
  How to verify each layer
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;llms.txt&lt;/strong&gt; — run your domain through an &lt;a href="https://llms-txt-validator.dev/" rel="noopener noreferrer"&gt;llms.txt validator&lt;/a&gt;; aim for 100/100 with no broken links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7jsp7e52n6djifk8l1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm7jsp7e52n6djifk8l1s.png" alt="A 100/100 llms.txt report broken down by Structure, Links and Best practices" width="800" height="688"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A clean report: 100/100, with Structure / Links / Best practices scored separately. The tool fetches every linked URL, so a broken link drags the score down even when the Markdown is perfect.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;WebMCP&lt;/strong&gt; — in Chrome 149+, enable &lt;code&gt;chrome://flags/#enable-webmcp-testing&lt;/code&gt; and run Lighthouse's Agentic Browsing audit; your tools should be listed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2A&lt;/strong&gt; — fetch your &lt;code&gt;/.well-known/agent-card.json&lt;/code&gt;, then POST a &lt;code&gt;message/send&lt;/code&gt; call to its &lt;code&gt;url&lt;/code&gt; and confirm you get a completed task back.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;That's the whole stack: llms.txt for crawlers, WebMCP for in-browser agents, A2A for networked ones. Start with llms.txt (real value today), add WebMCP and A2A as forward signals when you have a genuine action or service to expose.&lt;/p&gt;

&lt;p&gt;If you build one, I'd love to see it — drop your agent card in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
