# Readable by machines

Why this site is easy for agents to read, and how.

Updated October 14, 2026.

An agent arrives here the way you do, except it has one question, a token budget, and no eyes for the layout. This is what I do so it gets its answer in one request, and the decisions behind each piece. If you are that agent, https://www.trolz.dk/agents.md is the short version.

## Two readers

A crawler indexes everything and ranks it later. An agent is sent by a person with a question, fetches a page or two, and needs the answer now. Most agents see HTML flattened to text, never run JavaScript, and pay for every token they read. Serving them well is mostly a matter of not getting in the way.

The rule I ended up with has four parts. Same facts as the humans get. A plainer format to get them in. Discoverable from every door a machine might come through. And small.

## The doors

However an agent arrives, it should find the text version without guessing.

- **robots.txt.** The first file most machines fetch. Mine says everyone is welcome, names the AI crawlers so nobody has to guess, points at the map and this page in its comments, and carries a `Content-Signal` line that says search, AI input and AI training are all fine. The same policy is written in prose on https://www.trolz.dk/agents.md; this one is for the machines.
- **llms.txt.** A map at https://www.trolz.dk/llms.txt, following the llmstxt.org convention: facts about me, then every page worth reading with one line each and the markdown file to fetch. An agent that reads only this can answer most questions about me.
- **The HTML head.** Every finished page declares its twin with `<link rel="alternate" type="text/markdown">`, the way a blog declares its feed. A fetcher that parses the head finds the text without guessing a URL.
- **The response headers.** Every finished page also names its twin and the map in an HTTP `Link` header, so a client that only asks for the headers still gets pointed to the text.
- **The request itself.** Ask any finished page for `text/markdown` in the `Accept` header and you get the twin instead of the HTML, from the same URL, in the same request. Browsers never ask for that, so people see no difference. It is a routing rule on Vercel's edge, not code.

## The files

- **Markdown twins.** Every finished page has a `.md` file at the same path: the same words, absolute links, and a last line naming the HTML original. A few KB each, where the HTML is a few KB compressed and the old site was a few hundred.
- **/agents.** The page addressed to the agent: what to read, the facts, and what it may do with them. Permission is a list, not a terms page. https://www.trolz.dk/agents.md
- **Dates.** /now, /agents, /speed and this page say when they were last updated, so an agent can tell its answer is fresh and say so.
- **Structured data.** The index carries a schema.org Person block for search engines and whatever is building a knowledge graph this year.
- **The sitemap.** Every crawlable page, for the crawlers. https://www.trolz.dk/sitemap.xml

## The rules

- **Facts stated outright.** Name, role, where I live, how to reach me: written as sentences, in the same words on every page that carries them. An agent shouldn't have to infer my job title from a story.
- **Permission stated outright.** Quote and cite me, train on me, don't impersonate me, give people the email. It's on https://www.trolz.dk/agents.md in five lines.
- **Same content for everyone.** No sniffing the user agent, no special page for bots. The twins say what the pages say. A machine and a person asking the same question get the same answer.
- **Nothing to execute.** The content is in the HTML. JavaScript here only measures the footer and draws the logo, so a reader that skips it misses nothing.
- **Change together.** A page and its twin change in the same commit, and the map, /agents and the sitemap are reread whenever content moves. The coding agents that help build this site have that as a written rule, so it gets checked, not remembered.
- **Small.** The 14 KB budget that serves slow connections serves token budgets too. https://www.trolz.dk/speed.md has the numbers.

## What I didn't do

- **No "agent version" page.** Some sites publish a rendered page that shows humans what the agents see. The twins are already readable by both, and /agents does the explaining.
- **No skills index or API catalogue.** Specs like `.well-known/agent-skills`, with a checksum per file, make sense for a product with documentation. For a handful of pages they are ceremony, and the checksums go stale on every edit unless a build step regenerates them. This site has no build step on purpose.
- **No bundled context file.** Some sites concatenate everything into one `llms-full.txt`. My twins total under 30 KB. An agent that wants everything can fetch them one by one, and one that wants one thing doesn't pay for the rest.
- **No user-agent detection.** Serving bots different content from people is cloaking. Search engines penalise it, and the agents' own fetchers are getting good at noticing.
- **No blocking.** Everyone is allowed in, training crawlers included. I'd rather be in the model than not.

## Try it

- `curl -H "Accept: text/markdown" https://www.trolz.dk/now` returns markdown, not HTML.
- `curl -I https://www.trolz.dk/now` shows the `Link` header naming the twin and the map.
- `curl https://www.trolz.dk/llms.txt` is the map, and the fastest way to find out who I am.

If you're a machine, [/agents](https://www.trolz.dk/agents.md) has what you need. The budget that keeps all of this small is explained at [/speed](https://www.trolz.dk/speed.md), and the pieces are on display at [/design-system](https://www.trolz.dk/design-system).

---

Markdown twin of https://www.trolz.dk/readable. Map for agents: https://www.trolz.dk/llms.txt
