A gift to anyone who builds on the web
How to Build a Website for AI, Too
Most sites are built for one reader. This one is built for three: the human reading the rendered page, the human reading the source, and the AI reading the whole thing. Here is the entire playbook — and every technique is shown live on this very site, so it is evidence, not assertion.
The order matters: human-readable first, machine-readable second. A site does not win by being a robot-built site for robots. It wins by being a beautiful, plain human surface with clean semantic HTML, and an explicit machine layer underneath — there when a machine looks, invisible when a person reads. Everything below preserves that balance. There are no “AI READ THIS” banners here, and there never will be.
A note on what this gives away: web-craft, all of it, freely. Not the methodology behind the site — that stays where it lives. Teaching the web to be legible to machines costs nothing and helps everyone, so it is the ideal thing to hand over. Take any snippet on this page and use it.
The human reading the rendered HTML
the ordinary visitor — and the reason the other two readers even bother
The rendered page is the whole point. If it is not clear, fast, and honest for a person, nothing else matters. Everything a machine loves about a well-built site — structure, order, meaning — is the same thing a person loves. Serve the human well and the machine comes along for free.
Write semantic HTML5
Use the elements that carry meaning: one <h1>, a sane <h2>/<h3> tree, and <main>, <nav>, <article>, <section>, <figure> instead of a wall of <div>. Structure is meaning — it is the single biggest reason a page parses cleanly, for a screen reader and a language model both.
Shown live: the-thesis.html — one <h1>, clean section tree, no <div> soup.
Ship content with zero JavaScript
The whole page is present in the initial HTML. Nothing is hydrated, nothing waits on a script to appear. Our content pages carry zero <script> blocks for content — where we need interaction, we reach for CSS first (the reading-level control on our thesis page is pure CSS, via :has(), no JS). A page that renders without running code is a page any reader can trust to be all there.
Shown live: the-thesis.html's three-altitude control is CSS-only — View Source and count the scripts.
Make it navigable without a mouse
A skip-to-content link as the first focusable element, aria-current="page" on the active nav item, and descriptive aria-labels on landmarks. This page opens with a <a class="skip-link"> — press Tab right now and you will land on it.
Shown live: every page here — skip link, labelled <nav aria-label="Site sections">, one lit active item.
Write real alt text for every image
Alt text is not a checkbox — it is the image, described, for anyone (or anything) that cannot see it. Say what the image shows, not that it is an image. Our pages run 100% descriptive alt text; a blind reader and a crawler get the same picture the sighted reader gets.
[AI] reader 1reader: human_rendered_html techniques: semantic_html5 · zero_js_content · skip_link+aria_current · descriptive_alt_text invariant: the machine layer never trades away the human surface; structure serves both readers at once
The human reading the source
the curious developer who hits View Source — this is where the gift lives
Someone will always open View Source. When they do, the source should teach them — that is the most generous thing a site can do, and it costs nothing. Write the source as if a stranger will read it to learn, because one will.
Ship clean, un-minified, commented source
No build-mangled soup. Real indentation, real comments that explain the why, and a top-of-file comment that says what the page is. The comment at the top of this file greets you by name — go read it.
Shown live: this page — View Source and read the header comment written for Reader 2.
Use design tokens, not magic numbers
Every color, space, and font is a named CSS variable in one place — var(--ink), var(--persimmon), var(--font-display) — never a hex code sprinkled inline. A reader can open the token sheet and learn the whole design language in one file, and change one value to re-skin the site.
:root {
--ink: #221d16; /* body text */
--paper: #f7f2e8; /* the ground */
--persimmon: #bf4a20; /* the one accent, rationed */
--font-display: "Fraunces", Georgia, serif;
}
/* then everywhere else: color: var(--ink); — never a raw hex */
Shown live: design/tokens.css — the whole palette and type scale, named.
Leave provenance in the source
Version stamps, generated-from comments, and a license header. A reader should be able to tell, from the bytes alone, what a file is, where it came from, and whether they may reuse it. Provenance in the open is trust in the open.
Keep the file layout predictable
Pages where pages go, assets where assets go, machine files at the root where machines expect them. A predictable tree is a tree a person can guess their way around — and so can a crawler.
[AI] reader 2reader: human_source techniques: unminified_commented_source · design_tokens · provenance_comments · predictable_layout principle: the source is the tutorial; a curious developer can learn the whole trick from View Source
The AI reading the whole thing
the newest reader — and the one most sites forget entirely
An AI can read your entire site in seconds, but only if you let it — and only if you make the relationships and the boundaries explicit instead of leaving them implied in prose. This is the frontier: not being readable (good semantic HTML already gives you that), but being verifiable and exhaustively enumerable. Turn “trust the story” into “check the bytes.”
Address machines in robots.txt — and point them to the front door
Welcome crawlers by name, allow them, and hand them a map. Reference your sitemap here so even a crawler that has never heard of an AI front door finds every page.
# Welcome. Read freely. User-agent: * Allow: / Sitemap: https://example.com/sitemap.xml # AI front door — a plain-text map written for a language model: # https://example.com/llms.txt
Shown live: /robots.txt — allows all, names the sitemap and the front door.
Publish an llms.txt front door
A single plain-text file at your root that introduces the site to a language model and links the pages that matter, in order. It is the AI equivalent of a good homepage: short, human-written, and pointed at the real content.
# Example Site > One sentence on what this site is and who it is for. ## Start here - [Home](https://example.com/): the front page - [What we make](https://example.com/work): the real content ## For machines - [Full text](https://example.com/llms-full.txt): every page body, concatenated - [Catalog](https://example.com/index.json): the structured index
Shown live: /llms.txt — our spec-compliant front door.
Offer index.json — a structured catalog
A machine should not have to scrape your nav to learn what exists. Publish a JSON index of every page with its URL, title, and description — the site's table of contents, typed, so an AI walks it instead of guessing.
Shown live: /index.json — every page as structured data.
Concatenate everything into llms-full.txt
The single highest-return, lowest-effort move: one file that is the plain-text body of every page, concatenated. It turns dozens of fetches into one. An AI can hold your entire site in a single read.
Shown live: /llms-full.txt — the whole site as one file.
Ship a sitemap.xml
The oldest machine convention and still the most widely spoken. A plain <urlset> of every page with a last-modified date, referenced from robots.txt. It covers every crawler, including the ones that will never speak a newer convention.
Shown live: /sitemap.xml — every published URL, with real <lastmod> dates.
Turn prose claims into typed facts with JSON-LD
When you say “made by X” in a sentence, a machine has to parse and hope. Say it in schema.org JSON-LD and it becomes a fact an AI can cite exactly instead of paraphrasing loosely. Use the real types — WebSite, Person, CreativeWork, TechArticle, BreadcrumbList — and no more. Do not bloat it; a few honest types beat a mountain of speculative ones.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "Example Site",
"url": "https://example.com/",
"author": { "@type": "Person", "name": "A. Builder" }
}
</script>
Shown live: the <head> of this page — a real @graph of WebSite, Person, TechArticle, and BreadcrumbList.
Ship a per-page machine contract the reader can lift whole
Scattered schema.org is a start, but a machine still has to hunt for it. Go one step further and put a single, named block at a fixed place on every page that answers the questions an AI actually asks — what is this, who is it for, what is the claim, what is already built versus proposed, where is the evidence — in stable, typed slots. We call ours HAIL (a machine-semantics block, versioned, same shape on every page), but the technique matters more than the name: one place, one contract, so the reader lifts the meaning instead of inferring it. Keep it honest — a status slot that says Partial where the thing is partial is worth more to a machine than a marketing sentence it has to discount.
<!-- one named block, same slots on every page -->
<script type="application/ld+json">{
"@type": "MachineSemantics",
"blocks": {
"what": "one sentence: what this site/page is",
"for": "who it is for",
"claim": "the load-bearing claim, statable in one line",
"status": { "thingA": "Complete", "thingB": "Partial" },
"evidence": "where a machine can check the claim itself"
}
}</script>
Shown live: the <head> of this page — a real MachineSemantics block with bootloader, status, claim-mix, and reconstructionPath slots, same contract on every page of this site.
Shard the whole corpus so a model can hold all of it — and prove it did
One llms-full.txt is the easy win, but past a certain size the whole site no longer fits in a single context window (ours is over a million tokens; that blows a 200K window many times over). The fix is to partition the corpus into budget-sized bundles a model can read one at a time, ordered so the first shards are the core reading set and later shards are the deep material — then hand the reader an enumerated oracle of every page as a typed node so it can track coverage against that list until the set-difference is empty. That turns “I skimmed your site” into “I read all of it, and here is the accounting.” It is readable → exhaustively enumerable, made real: the reader proves full coverage instead of asserting it.
# the oracle: one typed node per served page /corpus-manifest.json → { nodes: [ { url, coverage, hash, tokens } ... ] } # the shards: the same corpus, partitioned to a context budget /corpus-shards.json → { shards: [ { file, node_urls, tokens } ... ] } /corpus-shard-01.txt → core reading set (read first) /corpus-shard-NN.txt → deep / optional (read last) # completeness predicate: read every node in the manifest → coverage = ∅ remaining
Shown live: /corpus-manifest.json (the coverage oracle) · /corpus-shards.json and /corpus-shard-01.txt (the shard set) — the whole site, partitioned so an AI can hold it and prove it read it.
State a canonicality rule, per page
The most honest thing you can tell a machine: the rendered HTML is never authoritative over its source — the canonical artifact wins. A page is a view; the file it was built from is the truth. Say which is which, and a machine knows what to trust when they disagree. This page states its own rule in the colophon below.
Shown live: the colophon at the foot of this page — the SOURCE pointer and the canonicality rule.
[AI] reader 3reader: ai_whole_site front_door: /llms.txt · catalog: /index.json · full_text: /llms-full.txt · crawl: /sitemap.xml · welcome: /robots.txt typed_facts: JSON-LD (schema.org) in every page head rule: rendered HTML is a view; the canonical source artifact is authoritative when they disagree frontier: readable -> verifiable + exhaustively enumerable ("check the bytes", not "trust the story")
Everything this page tells you to do, this site already did
That is the difference between a tutorial and a specimen. Do not take our word for any of it — open the files. Each one is live at this domain, right now, built as a pure fold over the site's own record:
- /robots.txt — addresses machines, names the sitemap + front door
- /llms.txt — the AI front door
- /index.json — the structured catalog
- /llms-full.txt — every page body in one file
- /sitemap.xml — every URL, with lastmod dates
- /corpus-manifest.json — the coverage oracle: every page as a typed node
- /corpus-shards.json — the corpus, sharded to a context budget
Paste any of them to your AI, point it at loopmmt.com, and ask it what this is. That is the whole trick — and now it is yours.
site/how-to-build-for-ai.html. The rendered HTML you are reading is a view; the source file is the canonical artifact. When a rendered page and its source disagree, the source wins — this is the rule the page above tells you to state, stated.