# 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.

By: Necati Doğrul · 2026-09-13 · https://necatidogrul.dev/en/notes/markdown-twins-llms-txt · seo, geo, ai

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.

---
Necati Doğrul · https://necatidogrul.dev
