The early agent-readiness reports I saved for this site said 5/100 and 7/100.

The next production scan said 100/100.

All useful work stayed inside the existing website. I made it easier for an agent to enter, read, understand, and recover from. OpenAPI and developer-portal work stayed out because this site has no public product API.

What the score measures

Is Agentic is the public report I used to inspect the site. It estimates whether an AI agent can discover, access, understand, and use a public website.

Ora runs the scan and scores the individual checks. Is Agentic groups those results into a readable report. Its methodology splits the result into three groups:

  • Essential checks share 80 points.
  • Recommended checks share 20 points.
  • Bonus signals can add up to 5 points.

Checks for APIs, OAuth, GraphQL, MCP, and similar surfaces should count only when the scanner finds evidence that the surface exists.

That last detail mattered. This is a personal site and blog. It has no public product API. Adding an empty OpenAPI file would have made the site more confusing, even if it pleased one scan.

The first report mixed real failures with wrong assumptions

The 7/100 report said agents could not reach the homepage. It listed GPTBot, ChatGPT-User, ClaudeBot, Google-Extended, DeepSeekBot, and Ora’s own agent as blocked.

It also reported these gaps:

  • Accept: text/markdown still returned HTML.
  • The response did not include Vary: Accept.
  • /sitemap.xml was missing.
  • llms.txt did not explain when an agent should use the site.
  • /about, /contact, and /privacy did not have enough useful text.
  • Missing pages did not give an agent a clear recovery path.

Those were good findings.

The same report asked for OpenAPI, JSON API errors, function-calling schemas, rate-limit headers, and a developer portal. Those requests did not fit the site. I left them out.

The fix started with a basic question: what does a normal HTTP client receive?

First, prove that agents can enter

The homepage is rendered by Astro on Cloudflare Workers. Its useful content already exists in the HTML response. An agent does not need to run the page’s JavaScript to find the H1, biography, experience, or links.

I checked the production response with an agent user agent:

curl -A GPTBot -I https://abhiigatty.com/

The important result is boring:

HTTP/1.1 200 OK
Content-Type: text/html
Vary: Accept, Accept-Encoding

I added a smoke test that requests the homepage as six agents. Each response must return HTTP 200, contain an H1, include more than 500 visible characters, and preserve the core metadata.

for (const userAgent of [
  "GPTBot",
  "ChatGPT-User",
  "ClaudeBot",
  "Google-Extended",
  "DeepSeekBot",
  "ora-agent",
]) {
  const response = await request.get("/", {
    headers: { "User-Agent": userAgent },
  });
  expect(response.status()).toBe(200);
}

This turned a scanner claim into a repeatable production requirement.

Serve Markdown when an agent asks for it

HTML is fine for most agents. Markdown is cheaper to parse and removes layout noise.

The homepage now follows the Accept Markdown pattern. A normal request gets HTML. A request with Accept: text/markdown gets the site’s llms.txt representation.

curl -i \
  -H "Accept: text/markdown" \
  https://abhiigatty.com/

The production response now starts like this:

HTTP/1.1 200 OK
Content-Type: text/markdown; charset=utf-8
Vary: Accept, Accept-Encoding

Vary is the easy part to miss. Without Vary: Accept, a CDN can cache the HTML response and return it to a client that asked for Markdown. The reverse can also happen.

My first implementation worked in the development server and failed in the production preview. The homepage was being served as a static asset before Worker middleware could negotiate the response.

The production fix was two route settings:

---
export const prerender = false;
---

I applied that to the homepage and llms.txt route. Then I moved the smoke suite from the development server to the production preview. A negotiation test that never reaches the production routing layer is not testing the risky part.

Make the site explain itself

The llms.txt file already listed the site. It needed instructions that helped an agent decide when to use it.

I added a plain section named When to use this site. It tells an agent where to look for work history, technical writing, browser tools, and contact details. It also states that this portfolio is not a public API.

That final sentence prevents the exact mistake the first report made.

I also added three trust pages:

  • /about explains who I am and what the site contains.
  • /contact explains how to send a useful request and what not to send.
  • /privacy explains Cloudflare request data, browser storage, external assets, and email handling.

Each page contains enough real text to answer a question. A thin page with a heading and one sentence would pass a route check but fail the actual job.

The discovery layer got smaller fixes:

  • /sitemap.xml now returns a valid sitemap index.
  • robots.txt points to that exact URL.
  • The human sitemap links to llms.txt, the XML sitemap, RSS, and crawler rules.
  • The footer links to the trust pages on every page.
  • Existing canonical, language, Open Graph, and Person JSON-LD metadata remain in the raw HTML.

A 404 should help the next request

An agent will guess routes. The 100-point scan tried /work, /projects, /services, and /consulting while it assembled an answer.

Missing routes must keep their real HTTP 404 status. They can still explain what to do next.

When a client asks for Markdown, the site now returns this shape:

# Page not found

The requested page does not exist.

- Read the site guide: https://abhiigatty.com/llms.txt
- Browse the sitemap: https://abhiigatty.com/sitemap
- Return home: https://abhiigatty.com/

The response stays a 404 and varies by Accept. A browser gets the visual 404 page. An agent gets short recovery links.

The score reached 100 before every check passed

The final report recorded this score:

GroupResultPoints
Essential7 of 7 passed80 / 80
Recommended7 of 9 passed17.8 / 20
Bonus signals9 positive+2.3

The raw total is 100.1, and the displayed score is capped at 100.

The public website surface still says 94%, with 14 of 16 mature checks passed. The report still recommends more complete JSON-LD and Organization schema.

This is why I read the evidence instead of treating the large number as a certificate. The homepage already contains Person JSON-LD, but that scan did not award the check. Organization completeness is also a strange fit for a personal homepage. GattyWorks is the organization, and it has its own website.

The scan snapshot is another useful warning. It was captured at 3:13 PM UTC. At that moment, the agent received 404 responses for /services and /consulting. Those pages went live later that day. They improved the site, but they did not cause the 100 score.

Automated audits observe one run. Their own methodology says they can produce false positives, false negatives, and partial results.

The changes that mattered

The core production changes landed in three pull requests. The first merged at 2:38 PM UTC. The 100-point snapshot arrived at 3:13 PM UTC.

The useful work was small:

  1. Verify six agent user agents receive useful server-rendered HTML.
  2. Negotiate Markdown correctly and include Vary: Accept, Accept-Encoding.
  3. Publish a stable sitemap and point robots.txt at it.
  4. Give llms.txt clear when-to-use guidance.
  5. Add useful About, Contact, and Privacy pages.
  6. Return a recoverable Markdown 404 without changing its status.
  7. Test the production preview, because local routing hid the first bug.

I skipped the API-shaped recommendations because the site has no public API.

If you want to check your own site, start with four requests before adding any new system:

curl -A GPTBot -I https://example.com/
curl -H "Accept: text/markdown" -I https://example.com/
curl -I https://example.com/sitemap.xml
curl -H "Accept: text/markdown" -I https://example.com/a-missing-page

Those four responses reveal most of the expensive failures: blocked entry, wrong content negotiation, missing discovery, and dead-end navigation.

Then run the scanner again. Keep the fixes that make the site clearer. Leave out the ones that ask your website to pretend it is a different product.