<?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: Erik Rekola</title>
    <description>The latest articles on DEV Community by Erik Rekola (@erekola).</description>
    <link>https://dev.to/erekola</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%2F3994164%2F3ba59e95-e771-458f-80bf-209fc1acd1b0.jpg</url>
      <title>DEV Community: Erik Rekola</title>
      <link>https://dev.to/erekola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erekola"/>
    <language>en</language>
    <item>
      <title>How agent-ready are Finnish B2B sites? I scanned sixteen</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Thu, 09 Jul 2026 17:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/how-agent-ready-are-finnish-b2b-sites-i-scanned-sixteen-4glk</link>
      <guid>https://dev.to/turva-dev/how-agent-ready-are-finnish-b2b-sites-i-scanned-sixteen-4glk</guid>
      <description>&lt;p&gt;Over the past weeks I ran two independent agent-readiness scanners over sixteen Finnish company websites, mostly industrial and B2B, a few in healthcare. The scanners were isitagentready.com, which grades on a Level 0 to 5 scale, and the startuphub.ai agent-readiness score out of 100. This is a small, non-random sample. The sites came from my own prospecting, not a statistical draw, so read it as a snapshot, not a census. The pattern was consistent enough to be worth writing down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;Every one of the sixteen scored under 50 out of 100. The range was 27 to 50, the average around 39, the median around 40. On the isitagentready Level scale almost all landed at Level 1 of 5, the floor an ordinary CMS site reaches, a couple sat at Level 0, and only one reached Level 2. None reached Level 3 or above.&lt;/p&gt;

&lt;p&gt;To be clear about what that means, these are not broken websites. They load, they rank, a person can use them without trouble. The scanners measure something else, whether an AI agent can read the site and act on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three gaps that showed up almost everywhere
&lt;/h2&gt;

&lt;p&gt;Discoverability was usually fine, legibility was not. Most sites had robots.txt, a sitemap, sometimes explicit AI-bot rules, so an agent can find them. But the same sites served HTML only, often with heavy token overhead. One consumer-facing corporate site returned about 16500 tokens of HTML where 1400 tokens of markdown would carry the same content, a 91 percent overhead. An agent can fetch the page, but reading it is slow and lossy.&lt;/p&gt;

&lt;p&gt;The second gap was structured data, or the lack of it. Missing JSON-LD and product data was common, so an agent reaches the site, sees a wall of markup, and cannot answer a plain question like what this company makes or sells.&lt;/p&gt;

&lt;p&gt;The third and most consistent gap was the action and capability layer. No markdown negotiation, no MCP server, no API discovery, no agent-auth metadata. One site that belongs to an AI company itself passed zero of eight checks in that discovery group. This is the layer that lets an agent move from finding a site to operating it, and it was absent almost everywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters now
&lt;/h2&gt;

&lt;p&gt;AI agents are becoming a discovery and transaction channel. When an agent reads a site and cannot parse or act on it, the business does not just rank lower, it becomes invisible inside the answer. The sites in this sample are not behind on SEO, most rank fine. They are behind on the next thing, being legible and actionable to the agents that increasingly read on a person's behalf.&lt;/p&gt;

&lt;p&gt;The encouraging part is that the fixes are mostly known and mechanical. Serve markdown alongside HTML, add structured data, publish an llms.txt, expose the discovery manifests. Two of the sixteen had already started, they published a real llms.txt, and that is exactly why they sat at the top of the range.&lt;/p&gt;

&lt;p&gt;To check where a site stands, the free llms.txt validator is at turva.dev/llms-txt-validator, and the agent-readiness audit and advisory work is at turva.dev.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/agent-readiness-gaps" rel="noopener noreferrer"&gt;Common agent-readiness gaps on marketing sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/guides/measurement-led-agent-readiness" rel="noopener noreferrer"&gt;Why agent-readiness should be measured, not asserted&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://turva.dev/blog/cheaper-pages-for-agents" rel="noopener noreferrer"&gt;What an agent pays to read your site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/agent-readiness-finnish-b2b" rel="noopener noreferrer"&gt;https://turva.dev/blog/agent-readiness-finnish-b2b&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>When honesty and the checker disagree</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Wed, 08 Jul 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/when-honesty-and-the-checker-disagree-3634</link>
      <guid>https://dev.to/turva-dev/when-honesty-and-the-checker-disagree-3634</guid>
      <description>&lt;p&gt;During the line-by-line pass that &lt;a href="https://turva.dev/blog/auditing-the-auditor" rel="noopener noreferrer"&gt;read every line of turva.dev&lt;/a&gt;, one of the smallest surfaces turned into the sharpest question in the audit. turva.dev serves an auth.md file, a plain description of how an agent authenticates here. It said two things that did not sit together. One line read no issued credentials. Another said an API key is issued out of band on request. Both were trying to be honest, and side by side they were a contradiction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning up a signal made the scanner fail
&lt;/h2&gt;

&lt;p&gt;The obvious repair was to drop the credential machinery and let the file say the simple true thing, that nothing here needs a credential. So the agent_auth block lost its credential types, the fields that name what kind of key or token a service hands out. To a reader they looked like box-ticking, the sort of hollow detail an audit is meant to strip.&lt;/p&gt;

&lt;p&gt;Then the scanner failed. isitagentready.com runs a check on auth.md, and that check reports agent_auth metadata was not found the moment the block has no complete registration method. Its own published recipe requires at least one method, and every method has to declare the credential types it supports. Fields removed to look more honest read to the checker as no auth surface at all. The pass count for the whole site leans on that check, and gutting the block would have dropped the 100/100 the front page shows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two honest stories, and the fork between them
&lt;/h2&gt;

&lt;p&gt;So there were two true things to write. turva.dev really does issue no credential that any resource requires, and I could say exactly that and let the check fail. Or turva.dev really does hand out an API key out of band when someone asks, and I could declare that key properly and keep the check green. Both are honest. The checker accepts only one of them.&lt;/p&gt;

&lt;p&gt;The tempting read is that the checker is the villain here, rewarding the file that ticks more boxes. That story is wrong. The credential the check wanted was not a fiction, because a key really does get issued on request. The first draft was dishonest for a different reason. A true detail sat next to a line that flatly denied it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest form is the precise one
&lt;/h2&gt;

&lt;p&gt;The fix was to make the whole block exactly true, rather than gut it or inflate it. The API key is declared and issued out of band on request. The file describes it for exactly what it is. It attributes correspondence and nothing more. No resource on turva.dev requires it, and holding it unlocks no extra access. Two other fields went the other way and were deleted, because they were the real hollow signals. One named an access token the service never issues. The other named an events channel that does not exist. Those were claims with nothing behind them. The API key is a claim with a key behind it.&lt;/p&gt;

&lt;p&gt;That is the line between a hollow signal and a modest true one, and a scanner cannot draw it for you. It can tell that a field is present and parses. It cannot tell whether the thing the field describes is real. The judgment that took the longest landed on the surface that moved no score at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this leaves on the page
&lt;/h2&gt;

&lt;p&gt;auth.md now says one thing instead of two. The key it names is the key you get if you email and ask, and it labels the message and grants nothing. The fields that described things the service does not do are gone. The check reads green because the declaration is finally true. Nothing was padded to please it.&lt;/p&gt;

&lt;p&gt;For an agent-readiness audit that reads your agent-facing claims the way a skeptic would, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/honesty-and-the-checker" rel="noopener noreferrer"&gt;https://turva.dev/blog/honesty-and-the-checker&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Four AI agents re-checked the guides</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Tue, 07 Jul 2026 07:52:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/four-ai-agents-re-checked-the-guides-3j1a</link>
      <guid>https://dev.to/turva-dev/four-ai-agents-re-checked-the-guides-3j1a</guid>
      <description>&lt;p&gt;The guides on turva.dev describe other people's specifications, and specifications move. A sentence that says "the specification says" is true the day it ships and starts aging the day after, and no scanner will tell you when it has gone stale. So the four AI agents that &lt;a href="https://turva.dev/blog/auditing-the-auditor" rel="noopener noreferrer"&gt;read the site line by line&lt;/a&gt; came back for a second pass, all running Claude Fable 5, each taking one family of standards: the agent commerce stack, MCP discovery, the discovery files from agents.json to llms.txt, and the plumbing of authentication and response headers. Their job was to re-read every specification claim in those guides against the primary source behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What had moved
&lt;/h2&gt;

&lt;p&gt;The pass came back with one finding rated high, one medium and six small. The high one sat in the MCP guide. It described the server card proposal, SEP-2127, in the present tense, and the proposal had moved. As of July 2026 it sits on MCP's extensions track as an experimental extension, and the current draft recommends serving the card relative to the server's endpoint plus a catalog at /.well-known/mcp/catalog.json. Nothing in the old sentence was wrong when it was written. It stayed still while the proposal moved.&lt;/p&gt;

&lt;p&gt;The medium finding was quieter. The response-header guide leaned on the IETF draft for standard RateLimit headers, and that draft expired in March 2026 without a successor. The six small ones were wording: vocabulary that predated A2A 1.0, stale lines about the Open Knowledge Format, a Cache-Control nuance, and one phrase about ai-catalog.json contributors that had aged in two places at once, because a blog post had quoted the guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sharpest findings were not in the guides
&lt;/h2&gt;

&lt;p&gt;Two of the machine-readable profiles turva.dev serves had drifted from their own specifications, and that is a harder failure than stale prose, because these files exist for software and both had passed every scan since they shipped. The UCP profile used service keys in a namespace the specification reserves for its own governing body, and listed transports its enum does not contain. The MPP manifest declared a version field the protocol does not define. A scanner checks that a profile exists and parses. It does not check that the vocabulary inside it exists in the specification, so an invented key passes as easily as a real one. Both profiles are now in the specification's own shape, verified against the primary text and validated programmatically, and both scanners stayed green through the change. The honest form cost nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the scores did not measure
&lt;/h2&gt;

&lt;p&gt;Both scanners were re-run after the fixes. startuphub.ai reads 100/100 with grade A+ and isitagentready.com reads Level 5, the same result as before the pass. The scores did not move in either direction, and that is worth pausing on. A score measures the shape of a site at scan time, and the currency of a sentence about somebody else's specification is outside every scanner's reach. If reading every line is part of the promise, somebody has to re-read the lines after the world moves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claims now carry their date
&lt;/h2&gt;

&lt;p&gt;The lasting repair is anchoring. A guide claim about a moving specification now carries its date, as of July 2026, so when the specification moves again the sentence stays true as a dated statement instead of quietly turning false. The families that move fastest, agent commerce and MCP discovery, go back on a re-check schedule, because this pass showed the drift interval there is a matter of weeks.&lt;/p&gt;

&lt;p&gt;For an audit that reads your agent-facing claims against the specifications they cite, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/re-checking-the-guides" rel="noopener noreferrer"&gt;https://turva.dev/blog/re-checking-the-guides&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>documentation</category>
    </item>
    <item>
      <title>The page grew, the agent bill did not</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Mon, 06 Jul 2026 07:40:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/the-page-grew-the-agent-bill-did-not-3e6n</link>
      <guid>https://dev.to/turva-dev/the-page-grew-the-agent-bill-did-not-3e6n</guid>
      <description>&lt;p&gt;In late June turva.dev published &lt;a href="https://turva.dev/blog/cheaper-pages-for-agents" rel="noopener noreferrer"&gt;a post on what an agent pays to read a page&lt;/a&gt;, and the measurement in it said the homepage as markdown cost roughly a third of the HTML form. The most recent startuphub.ai scan reports the same homepage at 10,320 tokens as HTML and 1,723 as markdown. That is a sixth of the cost, an 83% saving, and nothing in the meantime was done to improve the number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the weight came from
&lt;/h2&gt;

&lt;p&gt;Since that post went out the site has gained seven blog posts before this one, two tool pages, a feed, a share image for every page and related links at the end of every post. None of that was content negotiation work. It was ordinary growth, and it landed where growth always lands, on the human-facing page. Between the 1 July and 4 July scans alone the HTML form of the homepage went from 9,560 tokens to 10,320, about 8% heavier in three days. The markdown form went from 1,750 to 1,723. It got slightly smaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two surfaces, two growth rates
&lt;/h2&gt;

&lt;p&gt;The HTML form of a page carries everything a site accumulates: navigation, styling, social metadata, structured data and links to whatever shipped last week. Each of those earns its place for a human reader or a search engine. The markdown form carries the words and the links and nothing else, so it grows only when the actual content grows. Serve one surface to everyone and every agent pays for the whole accumulation on every visit. Serve both forms from the same URL and the costs come apart on their own, the human page free to get richer while the agent page stays at the price of the text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the number yourself
&lt;/h2&gt;

&lt;p&gt;The token split is not self-reported. The startuphub.ai scanner prints the token count of both forms of a page with every scan it runs, on any site it is pointed at, and turva.dev logs the pair after every deploy. The June post carried the measurement of its day and this one carries the measurement of 4 July. If the pattern holds, a later post will quote a wider gap still, because the human surface keeps accumulating and the text does not.&lt;/p&gt;

&lt;p&gt;For an audit that measures what agents pay to read your site, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/cheaper-pages-revisited" rel="noopener noreferrer"&gt;https://turva.dev/blog/cheaper-pages-revisited&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
    <item>
      <title>Moving the source from GitHub to Codeberg</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Sun, 05 Jul 2026 08:40:00 +0000</pubDate>
      <link>https://dev.to/turva-dev/moving-the-source-from-github-to-codeberg-2543</link>
      <guid>https://dev.to/turva-dev/moving-the-source-from-github-to-codeberg-2543</guid>
      <description>&lt;p&gt;The company page of turva.dev tells a buyer they can read every line before hiring me. That promise depends on the source being reachable, and for two weeks it was not, in a way I could not see. This is the log of what broke and why the source now lives at codeberg.org/erekola.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two weeks of 404s I could not see
&lt;/h2&gt;

&lt;p&gt;On June 18 GitHub's spam detection flagged my account. There was no notification. Logged in, everything looked normal and every repo was in place. Logged out, the profile and every repo returned 404, and the search API answered "flagged as spammy". Every public pointer at the source was dead for everyone except me: the homepage hero, the guides, the READMEs, the profile links.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it surfaced
&lt;/h2&gt;

&lt;p&gt;No scanner caught it. The agent-readiness scanners turva.dev is measured with read the site, not the code hosting, so every score stayed green while the trust chain behind them was broken. It surfaced on July 2 during a fact-check pass, when an AI agent followed the site's own "read the source" link without a logged-in session and got a 404. That is the trap in this failure mode: the owner is the one person who cannot see it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What GitHub said
&lt;/h2&gt;

&lt;p&gt;The support ticket had been open since June 18 with one virtual-assistant reply. On July 3 a human answered: the account had been "flagged by mistake" by their spam-detection scripts, and the flag was removed. The reply did not say what had triggered it. The response was polite and the fix was real. It also arrived after the source had already moved.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost
&lt;/h2&gt;

&lt;p&gt;The measurable part is two weeks of broken pointers. The probable part is worse. An inbound lead wrote in on the same day the flag landed, and my reply pointed them at the open-source Worker as proof of how I work. From that moment every source link I had sent them returned 404, and after one more exchange they went quiet. A silent failure hides its own cost on top of causing it: I cannot prove the 404s ended that conversation, and I cannot rule it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the move, and why it stuck
&lt;/h2&gt;

&lt;p&gt;I moved the repos to Codeberg on July 2 with full history, updated every public link the same day, and deleted the GitHub account once the flag was lifted. Codeberg is run by a non-profit on open-source infrastructure, which I like, but that is not the reason. No host is immune to mistakes. The reason is what the incident showed about the failure mode: a silent flag, no notification, an appeal channel that took two weeks to reach a human, and a breakage only visible from outside my own session. A dependency that can fail that way gets treated accordingly. Source hosting now sits in the site's threat model like any other third-party dependency, and the monthly self-audit checks logged-out visibility of every external pointer, because no scanner runs that check for you.&lt;/p&gt;

&lt;p&gt;External pointers rot in ways your own monitoring does not see, so they get checked the way a stranger's agent reaches them: from outside, logged out, against the primary source. The audit post published the same day as this one applies that discipline to the code itself.&lt;/p&gt;

&lt;p&gt;For an audit that checks a site the way a stranger's agent reaches it, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/moving-source-to-codeberg" rel="noopener noreferrer"&gt;https://turva.dev/blog/moving-source-to-codeberg&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
      <category>git</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Auditing the auditor with four AI agents</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Sat, 04 Jul 2026 11:42:05 +0000</pubDate>
      <link>https://dev.to/turva-dev/auditing-the-auditor-with-four-ai-agents-ep0</link>
      <guid>https://dev.to/turva-dev/auditing-the-auditor-with-four-ai-agents-ep0</guid>
      <description>&lt;p&gt;The company page of turva.dev tells a buyer they can read every line before hiring me. An audit business should survive its own promise, so I pointed it at my own site. Four AI agents, all running Claude Fable 5, read the public surface line by line: the Worker source that renders turva.dev, about 5,400 lines of it, the MCP server behind mcp.turva.dev, and the READMEs of the public repos. They came back with 91 findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 91 findings look like
&lt;/h2&gt;

&lt;p&gt;Most were the drift every living codebase accumulates. One surface advertised RS256 and ES256 for verification while the site's actual key is Ed25519. A response header named x-markdown-tokens carried a word count. A guide expanded MPP to the wrong protocol name. A table in one guide had never rendered as a table, because the renderer did not support tables. The legal page called this a registered company when it is a registered business. None of these move a scanner.&lt;/p&gt;

&lt;p&gt;About 60 fixes shipped, and both scanners were re-run after the deploys: startuphub.ai reads 100/100, grade A+, with all six categories at 100, and isitagentready.com reads Level 5. The scores were the same before most of these fixes, and that is the point. A scanner cannot see whether the key algorithm you advertise is the one you use. Line-by-line reading is the layer under the score.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four HIGH alerts, and how they died
&lt;/h2&gt;

&lt;p&gt;The agents marked four findings HIGH. All four fell when verified, and they traced to two root causes.&lt;/p&gt;

&lt;p&gt;The first: the site claims 100/100 verified by two independent scanners, and the agents knew that one of those scanners, isitagentready.com, grades sites on levels, 0 to 5. A percentage from a level-based scanner reads like an invented number, so the claim was flagged as false advertising on the audit's own subject matter. The scanner's own scorecard settles it. Run the scan and the report shows 100/100 for this site next to Level 5. The claim stands as written.&lt;/p&gt;

&lt;p&gt;The second: an agent fetched the live MCP server card and read version 1.1.0 where the source says 1.2.0. Deployed code that trails its repo is a real problem anywhere, so HIGH was the right severity for the claim. It was still wrong. The fetch had come through a cache, and pulling the deployed Worker straight from the Cloudflare API showed 1.2.0, identical to the source. The finding described the measuring instrument, and the deployment was never out of sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding that held
&lt;/h2&gt;

&lt;p&gt;One HIGH survived. The MCP server's README promised that the service does no logging, and the Worker configuration had platform observability switched on, which stored a log line for every call. Promise and code disagreed, and this is the exact class of gap the audit exists to catch. The repair went the honest way around. Reality changed to match the words: observability is off, and the README now also says out loud that platform logs are disabled. Rewriting the README to say minimal logging would have been faster to ship, and worth less to anyone who reads it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard part is the false positives
&lt;/h2&gt;

&lt;p&gt;A finding is a claim, and a claim gets the same treatment as marketing copy. Verify it against the primary source or drop it. Acting on the dead alerts here would have made the site worse, because fixing a correct claim plants a real error where a false alarm used to be. Read the scanner's own scorecard instead of assuming its scale, and pull the deployed artifact from the platform instead of trusting a cached fetch. Minutes of checking killed four HIGHs.&lt;/p&gt;

&lt;p&gt;The same discipline applies when you buy an audit. The report that reaches you should be the survivors, and a useful question for any auditor is how many findings were dropped between the raw scan and the written report. A report where the answer is zero usually means nobody checked.&lt;/p&gt;

&lt;p&gt;For an agent-readiness audit where the findings are verified before you read them, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/auditing-the-auditor" rel="noopener noreferrer"&gt;https://turva.dev/blog/auditing-the-auditor&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A free llms.txt validator</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Thu, 02 Jul 2026 17:40:05 +0000</pubDate>
      <link>https://dev.to/turva-dev/a-free-llmstxt-validator-mn2</link>
      <guid>https://dev.to/turva-dev/a-free-llmstxt-validator-mn2</guid>
      <description>&lt;p&gt;turva.dev now has a free llms.txt validator at &lt;a href="https://turva.dev/llms-txt-validator" rel="noopener noreferrer"&gt;https://turva.dev/llms-txt-validator&lt;/a&gt;. Enter a domain and it fetches that site's /llms.txt, checks the structure against the format and reports each check as pass, warn or fail. Nothing is stored and there is no signup.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the format asks for
&lt;/h2&gt;

&lt;p&gt;llms.txt is a small format, and that is the point of it. One H1 line names the site. A blockquote under the title carries a one line summary. H2 sections group markdown links an agent can follow to the content itself. A file that follows this shape gives an agent a map of the site at a fraction of the cost of crawling it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the validator checks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The file exists at /llms.txt and answers HTTP 200&lt;/li&gt;
&lt;li&gt;The response is plain text, not an HTML page&lt;/li&gt;
&lt;li&gt;The first non-empty line is an H1 title&lt;/li&gt;
&lt;li&gt;A blockquote summary follows the title&lt;/li&gt;
&lt;li&gt;H2 sections group the content&lt;/li&gt;
&lt;li&gt;Markdown links parse and use absolute URLs&lt;/li&gt;
&lt;li&gt;The file stays small enough to be cheap to read&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second check earns its place. A site that returns its 404 page with status 200 looks like it has an llms.txt until something actually reads it, and an agent that fetches markup where it expected markdown wastes its tokens on tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agents can use it too
&lt;/h2&gt;

&lt;p&gt;The same URL answers JSON. Send Accept: application/json with a url parameter and the checks come back as data, so the validator works in a script or an agent pipeline as well as in a browser:&lt;/p&gt;

&lt;p&gt;curl -H "Accept: application/json" "&lt;a href="https://turva.dev/llms-txt-validator?url=example.com" rel="noopener noreferrer"&gt;https://turva.dev/llms-txt-validator?url=example.com&lt;/a&gt;"&lt;/p&gt;

&lt;h2&gt;
  
  
  One build note
&lt;/h2&gt;

&lt;p&gt;The first deploy failed its own self check. A Cloudflare Worker cannot fetch a URL on its own zone, so asking the validator about turva.dev started a request that could never return and timed out after eight seconds. The fix reads the same constant that serves /llms.txt instead of fetching it. External domains are fetched normally, and the validator was proven against the llmstxt.org file before this post went out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is not
&lt;/h2&gt;

&lt;p&gt;The validator reads one file and checks its shape. It does not measure whether agents can discover the site, read its pages as markdown, find its API or complete a purchase. That is audit territory, and an audit here runs a site against two independent scanners rather than one checklist.&lt;/p&gt;

&lt;p&gt;For an audit of the whole surface an agent sees, not just this one file, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/free-llms-txt-validator" rel="noopener noreferrer"&gt;https://turva.dev/blog/free-llms-txt-validator&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Agent access is now a setting</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Thu, 02 Jul 2026 12:56:13 +0000</pubDate>
      <link>https://dev.to/turva-dev/agent-access-is-now-a-setting-2b6b</link>
      <guid>https://dev.to/turva-dev/agent-access-is-now-a-setting-2b6b</guid>
      <description>&lt;p&gt;On 1 July 2026 Cloudflare shipped its second Content Independence Day package: crawler controls that split search, agent and training bots for every customer, a research program that tells crawlers which pages actually changed, experiments that turn Pay Per Crawl into Pay Per Use, and a waitlist for a gateway that charges for any resource over x402. Read together, they move decisions that used to live in a site's code into the CDN dashboard. That relocation is what matters for agent readiness.&lt;/p&gt;

&lt;h2&gt;
  
  
  The edge can undo everything the page does right
&lt;/h2&gt;

&lt;p&gt;A site can serve clean markdown, an llms.txt, structured data and signed manifests, and none of it counts if a network rule turns the crawler away before the request reaches the page. Cloudflare says more than 20% of the web sits behind its network, and the new controls ship with per-crawler block toggles and defaults that change over time. This site's own crawler list turned out to contain seven blocked entries, including the Internet Archive and an AI search engine that pays publishers. However they got there, nothing in the markup shows it. You find it in the dashboard, or when your content stops appearing in answers.&lt;/p&gt;

&lt;p&gt;An agent-readiness review therefore has to read the edge configuration next to the content. robots.txt, the WAF and the AI crawler list must say the same thing the content strategy says, and they must keep saying it, because platform defaults move without a deploy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Citations are replacing clicks, and both are measurable now
&lt;/h2&gt;

&lt;p&gt;Cloudflare's stated reason for the package is a 2025 Pew Research Center finding: when Google shows an AI summary, users click a traditional result 8% of the time and a link inside the summary about 1% of the time. The visit is no longer where the value moves. Cloudflare's response is to make the citation itself payable. Ceramic.ai pays publishers per query their content answers, You.com lets agents buy individual premium pages, and participating sites get reporting on which AI-search queries surfaced their content, down to the page and the snippet.&lt;/p&gt;

&lt;p&gt;The reading this is meant to price is already routine. Over the past seven days this site answered 604 requests from identified AI and search crawlers, and AI answers and search referred 88 human visits, most from Google, the rest led by Meta, DuckDuckGo and Bing. Whether that reading starts to pay is what the new programs will test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Payment rails are becoming configuration
&lt;/h2&gt;

&lt;p&gt;The Monetization Gateway waitlist points the same direction: charge for any page, dataset, API or MCP tool behind Cloudflare, settled over the x402 protocol, with no payment stack of your own. Charging an agent moves from an engineering project to a setting. The honesty bar moves with it. An x402 surface that quotes terms no agent can complete gets found out by the first agent that tries, which is why the x402 endpoint on this site answers HTTP 402 with its real terms instead of a pretend checkout.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check this week
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open your CDN's AI crawler list and compare it against your intent. A block you did not choose is configuration drift, and it overrides everything your pages declare.&lt;/li&gt;
&lt;li&gt;Re-scan after any edge change. The public agent-readiness scanners read a site from outside, so a network-level block shows up as a dropped score before a buyer sees the gap.&lt;/li&gt;
&lt;li&gt;If your content earns citations, look at the Pay Per Use programs. The reporting alone, which queries put your pages into AI answers, is visibility data you cannot get anywhere else today.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an agent-readiness audit that reads the edge configuration next to the content, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/agent-access-is-now-a-setting" rel="noopener noreferrer"&gt;https://turva.dev/blog/agent-access-is-now-a-setting&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>cloudflare</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What one agent-readiness scanner cannot tell you</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Wed, 01 Jul 2026 17:29:17 +0000</pubDate>
      <link>https://dev.to/turva-dev/what-one-agent-readiness-scanner-cannot-tell-you-26il</link>
      <guid>https://dev.to/turva-dev/what-one-agent-readiness-scanner-cannot-tell-you-26il</guid>
      <description>&lt;p&gt;Most agent-readiness checks run one scanner and stop. The report reads well, the grade looks final, and the site moves on. That grade says the site fits one vendor's model of what an agent needs. It says nothing about what that model left out.&lt;/p&gt;

&lt;h2&gt;
  
  
  A checklist is not a proof
&lt;/h2&gt;

&lt;p&gt;A scanner is built around a fixed set of checks and a fixed weighting between them. It can only fail a site on something it looks for. When a category sits outside a scanner's model, a real gap in that category passes clean, because nothing in the checklist asked about it. A high grade from a single tool is easy to over-read as finished, while the site can still stop an agent cold on the one thing that tool never checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where two scanners disagree
&lt;/h2&gt;

&lt;p&gt;turva.dev is scored on two independent scanners with different category models, isitagentready.com and startuphub.ai. isitagentready.com carries no Quality category and marks Commerce as optional. startuphub.ai grades six categories, Discoverability, Content, Access Control, Capabilities, Commerce, and Quality, so both of the categories the first scanner treats as thin get a full reading in the second. Running a site through both at once means a gap sitting in one model's blind spot still shows up in the other's report, before a buyer or an agent finds it the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes about an audit
&lt;/h2&gt;

&lt;p&gt;Every audit here checks a site against both scanners, and a claim about the result carries the date it was verified and the categories the report named. A score nobody re-ran after a change is a guess wearing a number. Two readings pointed at the same site is the cheapest way I know to stop fooling yourself about what "done" means, and it is the same discipline that runs on turva.dev itself before any change ships.&lt;/p&gt;

&lt;p&gt;For an agent-readiness audit that checks a site against more than one scanner, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/two-scanner-audit-method" rel="noopener noreferrer"&gt;https://turva.dev/blog/two-scanner-audit-method&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>testing</category>
      <category>webdev</category>
    </item>
    <item>
      <title>What an agent-readiness audit is</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Mon, 22 Jun 2026 18:02:34 +0000</pubDate>
      <link>https://dev.to/turva-dev/what-an-agent-readiness-audit-is-kg7</link>
      <guid>https://dev.to/turva-dev/what-an-agent-readiness-audit-is-kg7</guid>
      <description>&lt;p&gt;An agent-readiness audit measures how well an AI agent can discover, read, and act on a website or an API. It is a technical review of the surfaces that automated clients actually use, scored against current standards rather than opinion.&lt;/p&gt;

&lt;p&gt;Most sites are built for human readers and search crawlers. AI agents read differently. They look for machine-readable entry points such as llms.txt, a sitemap, response headers, structured data, and well-known manifests. When those are missing, the agent either guesses or gives up, and the site becomes invisible to that class of client even when the underlying product is strong.&lt;/p&gt;

&lt;p&gt;The audit checks the parts an agent reaches first. Discovery covers robots.txt, the sitemap, and the response headers that let an agent find resources without parsing a full HTML page. Content covers llms.txt, markdown content negotiation, and whether the site can return a clean text version that saves an agent most of the tokens an HTML page would cost. Capabilities cover an MCP server card, an OpenAPI description, an API catalog, and OAuth discovery, so an agent can enumerate what the site offers and authenticate safely. Commerce covers payment surfaces such as x402 and structured pricing, so an agent can transact. Access control and quality cover the headers, signals, and metadata that tell an agent how it is allowed to behave.&lt;/p&gt;

&lt;p&gt;The result is a list. Each check passes or fails, and each failure comes with a concrete fix. The point is that the outcome is verifiable. An independent scanner reads the site before and after, and the categories that were fixed read higher on the next scan. The claim is the number, not an assertion.&lt;/p&gt;

&lt;p&gt;turva.dev applies the same standard to its own site. Measured by independent scanners, turva.dev is first among the publicly-scanned sites on the startuphub.ai agent-readiness leaderboard and reaches Level 5 on isitagentready.com. The audit a client receives runs the same checks against their site.&lt;/p&gt;

&lt;p&gt;For an audit, contact &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;. Engagement is async and evidence-based, and production credentials are not requested.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/guides/agent-readiness-audit" rel="noopener noreferrer"&gt;https://turva.dev/guides/agent-readiness-audit&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>webdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>Moving turva.dev off prerender.io</title>
      <dc:creator>Erik Rekola</dc:creator>
      <pubDate>Sat, 20 Jun 2026 14:36:43 +0000</pubDate>
      <link>https://dev.to/turva-dev/moving-turvadev-off-prerenderio-d04</link>
      <guid>https://dev.to/turva-dev/moving-turvadev-off-prerenderio-d04</guid>
      <description>&lt;p&gt;For a while the turva.dev homepage was rendered by a third party. The page was built on Sitejet, served to people as a JavaScript app, and served to agents through prerender.io, which returned a finished HTML snapshot so a crawler did not read an empty shell. It worked and it scored well, but it was a workaround. A site that sells agent-readiness should not depend on a separate service to be readable by agents.&lt;/p&gt;

&lt;p&gt;Today the homepage moved into the Cloudflare Worker that already fronts the domain. The Worker renders the finished HTML itself, on every request, at the edge. There is no client-side hydration step and no prerender hop. An agent reads the real content in the first response, and so does a person.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the Worker returns&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Worker decides by the request. A browser asking for HTML gets the rendered page. An agent that sends Accept: text/markdown gets a markdown version of the same content, at a fraction of the tokens. An agent that sends Accept: application/json gets a structured summary of the business and its services. The same facts, in the form the client asked for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this removed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The prerender.io branch is gone from the Worker. No request is sent to an external prerender service, and the token it used is no longer read. Sitejet now serves only static assets such as the social image, and those move to the Worker next. The page is one codebase, under version control, open source at codeberg.org/erekola/turva-worker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The result is measured, not asserted&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The change was verified the same way the service verifies client work: by independent scanners, before and after. StartupHub read 100/100, grade A+, with all six categories at 100. isitagentready read Level 5, Agent-Native. The homepage migration did not drop a point.&lt;/p&gt;

&lt;p&gt;One more note. This change was planned and deployed in a single session with an AI agent, and the result was checked by two independent scanners with no stake in the outcome. The claims on this site are measurements anyone can reproduce. Either the next scan reads the same or higher, or it does not.&lt;/p&gt;

&lt;p&gt;Written contact only. Email &lt;a href="mailto:info@turva.dev"&gt;info@turva.dev&lt;/a&gt;, Signal @turva.19. First reply within one business day.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://turva.dev/blog/moving-off-prerender" rel="noopener noreferrer"&gt;https://turva.dev/blog/moving-off-prerender&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
