Skip to content
Select theme

llms.txt file format

The llms.txt format under v2 of the proposal - the one required heading, the order of parts, link lists, files in subpaths, Markdown page versions, and what the proposal does not include

Edition
v2, August 10, 2026
Author
Jeremy Howard, Answer.AI
Format
Markdown
Required part
the H1 heading only

What changed since the first edition is on the Changes in v2 page.

From a question to the right page
  1. Sitepublishes the file at a known address
  2. GETllms.txt/llms.txtname, description, lists of links
  3. readsAgentpicks links for its question
  4. follows a linkMarkdown page/docs/page.mdclean text without layout
  5. Contextonly what the answer needs

The file does not retell the site. It shows where to go.

One line with a heading is enough to conform to the proposal. In practice the minimum looks like this:

llms.txt
# Project name
> One or two sentences: what it is and who it is for
## Documentation
- [Quick start](https://example.com/quickstart.md): first steps in five minutes

The parts come in a strict order. Only the first one is required.

llms.txtfive parts in order
  1. # FastHTML

    H1 headingrequired

    The name of the project or site. Without it the file does not conform to the proposal. There is one heading.

  2. > FastHTML is a Python library for
    > server-rendered web apps built on HTMX.

    Descriptionoptional

    A blockquote with a short description: what the rest of the file cannot be understood without.

  3. Important:
    - the syntax is not compatible with FastAPI
    - React, Vue and Svelte are not supported

    Detailsoptional

    Any Markdown blocks except headings: paragraphs, lists, code.

  4. ## Documentation
    - [Quick start](https://example.com/quickstart.md): first steps
    - [API reference](https://example.com/api.md)

    Section with linksoptional

    An H2 heading and a list. An item is a link and an optional note after a colon.

  5. ## Optional
    - [Changelog](https://example.com/changelog.md)

    Optional sectionoptional

    A convention for secondary links: an agent may skip them when it needs a shorter context.

Links should lead to content that suits a model: Markdown versions of pages first of all. External addresses are fine when they help to understand the material.

The file can sit in the site root or in any subpath. The second edition defines what that means.

  • llms.txt covers the whole site
  • Directorydocs/
    • llms.txt covers everything in /docs/
    • guide.html
    • Directoryapi/
      • llms.txt covers everything in /docs/api/
      • users.html
  • Directoryblog/
    • post.html
Which file an agent takes

Page/docs/api/users.html

  1. Three files applyroot, /docs/ and /docs/api/
  2. The most specific one wins/docs/api/llms.txt

Page/blog/post.html

  1. One file applies/blog/ has no file of its own
  2. The root file is used/llms.txt

So someone who controls only part of another domain, such as a GitHub Pages project, can take part too.

The author of the proposal rejected a /.well-known/ address: such addresses exist only at the domain root, while llms.txt describes the path it sits in.

The proposal suggests serving a clean Markdown version of a page next to the regular one. Two address forms are allowed.

Page First form Second form
/page.html /page.html.md /page.md
/docs/ /docs/index.html.md /docs/index.md

The second edition recommends two standard relations. The first leads from a page to its Markdown version, the second to the llms.txt that covers the page.

Two relations for discovery

rel="alternate"type text/markdown

  1. HTML page/docs/page.html
  2. alternateMarkdown version/docs/page.html.md

rel="describedby"

  1. HTML page/docs/page.html
  2. describedbyllms.txt of the section/docs/llms.txt

The relations can be sent in the page markup or in a response header. The second way also works for files that are not HTML.

page.html
<link rel="alternate" type="text/markdown" href="/docs/page.html.md">
<link rel="describedby" href="/docs/llms.txt">

Many sites publish llms-full.txt and llms-small.txt, and it is a useful practice. But the proposal cannot be cited as its source.

The index and the full text

llms.txt

a map: where to go

namedescriptionlinks

  • Described in the proposal
  • Small: fits into the context as a whole
  • The content sits behind the links

llms-full.txt

a corpus: everything in one file

pagepagepage

  • Not in the proposal: a practice of docs platforms
  • Can be very large: 67 MB at Cloudflare
  • Handy when the whole text is needed without hops
What Status
llms-small.txt not in the proposal; a shortened version of the full text
llms-ctx.txt, llms-ctx-full.txt were tied to the llms_txt2ctx tool; removed from the second edition
Access control the file forbids nothing; robots.txt does that
Security rules the proposal text has none; the question is discussed in the repository
llms.txt
# FastHTML
> FastHTML is a Python library for server-rendered web apps
> built on HTMX.
Important:
- the syntax is not compatible with FastAPI
- React, Vue and Svelte are not supported
## Documentation
- [Quick start](https://example.com/quickstart.md): first steps in five minutes
- [API reference](https://example.com/api.md): all methods and parameters
## Optional
- [Changelog](https://example.com/changelog.md)
- [Contributing](https://example.com/contributing.md)

Three places are highlighted, the ones an agent looks at first: the name, the description and the main links.

The format is made for simple processing: regular expressions are enough.

parse_llms_txt.py
import re
def parse_llms_txt(content: str) -> dict:
result = {'title': '', 'description': '', 'sections': {}}
h1 = re.search(r'^# (.+)$', content, re.MULTILINE)
if h1:
result['title'] = h1.group(1)
quote = re.search(r'^> (.+)$', content, re.MULTILINE)
if quote:
result['description'] = quote.group(1)
section = None
for line in content.split('\n'):
if line.startswith('## '):
section = line[3:].strip()
result['sections'][section] = []
elif line.startswith('- [') and section:
link = re.match(r'- \[(.+?)\]\((.+?)\)(?:: (.+))?', line)
if link:
result['sections'][section].append({
'title': link.group(1),
'url': link.group(2),
'notes': link.group(3) or '',
})
return result
  1. The file opens at its address with status 200 and is served as text, not as an HTML page.
  2. The first heading is H1, and there is only one.
  3. There are no headings between the description and the first section.
  4. Every link opens.
  5. Links lead to content that suits a model.

A detailed list and typical mistakes are in Best practices.