notes · 2026-09-13 · 3 min read · seo · geo · ai

A .md twin for every page, and llms.txt: a site for AI engines

Google, ChatGPT and Perplexity read the same page differently. The method I put on eight sites: a Markdown twin of every page, one llms.txt, and schema generated from the same data. What it does, and what it does not.

Every page on this site also exists as Markdown: /en.md, /notes/agent-loops.en.md, /work/kaloro.en.md. And there is an llms.txt at the root. Why?

The problem: one page, three readers

Three kinds of systems read a page today. Google's classic index understands HTML well; it reads JSON-LD and heading hierarchy. AI search engines (ChatGPT search, Perplexity, Claude) feed the page to a language model: menus, cookie bars, repeated footers, empty elements added for animation are all noise. The third reader is a person, on a phone.

You can write HTML that serves all three, but it is expensive. The cheaper path: keep content in one source and give each reader its own format.

What the Markdown twin does

The .md file is the page without noise: a title, a one-paragraph summary, lists, links. No CSS, no script. A language model reading it knows what it is within ten words. It is also quotable: "Necati Doğrul is a software engineer based in Antalya" is one line in plain text and three nested tags in HTML.

On this site the twins are not written by hand. scripts/generate-md.mjs runs before every build; it reads the app list, experience, notes and case studies from the same data files the site renders, and writes them under public/. HTML and Markdown cannot drift; what you add to one is in the other.

What llms.txt does

robots.txt tells a crawler where it may go. llms.txt tells a language model whose site this is, what it is about, and which pages matter. A short introduction, then links to the .md files. My file's first paragraph deliberately carries the sentence: I am not the writer Necati Doğru. Name confusion is the easiest mistake a language model makes.

Honest note: how much it works

Google has said plainly that llms.txt is not needed for its AI features; for Google what still matters is good HTML and schema. On the ChatGPT and Perplexity side, .md and llms.txt are fetched, but nobody reports "read it, cited it". What has been measured: more than half of AI citations go to community platforms and Wikipedia. Your own site helps when it is the consistent hub those sources point to.

So the .md twin is not a trick on its own; it is one part of a set:

  1. Person schema: alternateName, disambiguatingDescription, a wide sameAs (LinkedIn, GitHub, X, the App Store developer page).
  2. A visible FAQ: the answer to "Who is Necati Doğrul?" is a single sentence on the page; the same sentence is in FAQPage schema.
  3. Same name, same photo, same one-liner on every profile. Entity consistency counts for more than technical signals.
  4. .md twins plus llms.txt: noise-free, quotable text.
  5. Explicit permission for AI crawlers in robots.txt.

How to do it

On a static site, the easiest: next to every page.html, a page.html.md. In something like Next.js: keep content in data files, write to public/ with a prebuild script, and have the same script generate llms.txt. A hand-written twin goes stale in two weeks; a generated one cannot.

I applied the same method to eight app sites. One of them had no twins, no comparison article, no llms.txt; a week later, searching the app's name on Perplexity started surfacing the site as a source. One data point, not a causal claim; but the moment something with zero cost started paying.