Inkan
↑↓ move↵ open
GitHub

AI and data · ADR

0001: llms.txt and llms-full.txt

Date

Context#

A decision archive is the best context a coding assistant can have about a codebase: it says what was chosen and why. HTML pages are a poor way to feed it. An agent has to crawl, strip navigation and guess which page is a record. The llms.txt convention gives a site one plain-text entry point that lists its content with short descriptions, and a companion file with the full text.

Decision#

Two text endpoints are part of every build:

  • /llms.txt: the site title and description, the record types and statuses, and one line per record grouped by project, each linking to the raw Markdown of the record.
  • /llms-full.txt: the full body of every record, newest first, each preceded by a YAML block of metadata.

Both are built from the same collection as the HTML pages, so they can never list a record the site does not have.

How to use it#

Nothing to configure. After inkan build the files are in dist/llms.txt and dist/llms-full.txt; in dev they are served at the same paths. The landing page lists them in its “For agents” section, and the right rail of every record links to llms.txt.

Set url in the config: every link inside the files is absolute and built from it.

inkan.config.ts
export default defineConfig({
title: 'Acme Decisions',
description: 'Central, searchable record of architecture decisions (ADR) and proposals (RFC).',
url: 'https://decisions.acme.dev',
});

What llms.txt contains#

# Acme Decisions
> Central, searchable record of architecture decisions (ADR) and proposals (RFC).
Types: adr (Architecture Decision Record), rfc (Request for Comments).
Statuses: draft, proposed, in-review, accepted, implemented, rejected, withdrawn, deprecated, superseded. Only "accepted"/"implemented" records describe the current state; "superseded" ones point to their replacement.
Full text of every record: https://decisions.acme.dev/llms-full.txt. Machine-readable index: https://decisions.acme.dev/decisions.json.
Every link below points to the raw Markdown of the record; drop the ".md" suffix and add "/" for the HTML page.
## Payments (payments)
Checkout, billing and payment providers.
- [PAYMENTS-ADR-0001: Use Stripe as the primary payment provider](https://decisions.acme.dev/payments/adr/0001-use-stripe.md) [accepted]: One provider for cards and wallets.
## Pages
- [Decision handbook](https://decisions.acme.dev/handbook.md): How Acme writes, reviews and retires architecture decisions.

Line by line:

PartSource
# title and > descriptiontitle and description from the config
Types:docTypes, key and description
Statuses:the keys of statuses
One ## per project_project.yml name and id, in order; the description when there is one
One - per recordref (or title) and title, link to the .md copy, [status], then the front-matter description
## PagesMarkdown pages from pagesDir, only when there are any

Records inside a project are in the same order as getDecisions(): newest date first, then by path. Records without a status show [n/a].

What llms-full.txt contains#

One block per record, separated by --- lines:

# Use Stripe as the primary payment provider
```yaml
ref: PAYMENTS-ADR-0001
type: adr
project: payments
status: accepted
date: 2026-01-18
authors: piotr.nowak
deciders: tomasz.wojcik
tags: payments, vendor
url: https://decisions.acme.dev/payments/adr/0001-use-stripe/
markdown: https://decisions.acme.dev/payments/adr/0001-use-stripe.md
source: decisions/payments/adr/0001-use-stripe.md
```
## Context
...

The YAML block holds ref, type, project, status, date, authors, deciders, reviewers, rfc_review (RFC review status), tags, supersedes, superseded_by, url, markdown and source; empty fields are left out. The body is the record’s Markdown as written, without its front matter. Only records are included, not pages or project intros. For a record pulled from another repository with sources, source is the file’s web URL in that repository instead of a local path (see Records from other repositories).

Pointing an assistant at it#

Give the assistant the llms.txt URL and let it follow links, or paste llms-full.txt into a context window for a question about the whole archive. The starter AGENTS.md already tells agents where these files are. An agent with tool support does better with the MCP server, which filters and returns single records over the same published files.

Note

Drafts (draft: true) are excluded from production builds and therefore from both files. Records with status: superseded are included; the superseded_by line tells the reader where to look instead.

llms-full.txt adds a name: value line for each custom field a record has. See Custom metadata fields.

Consequences#

  • An assistant gets the whole archive in one or two requests, with the same freshness as the site.
  • llms-full.txt grows with the archive. Thousands of records make a file too large for one context window; decisions.json, the per-record .md copies and inkan mcp are the way to fetch less.
  • Absolute links depend on url being correct. The default http://localhost:4321 is fine for dev and wrong for production.
  • The format is plain Markdown by convention, not a schema. Tools that need types read decisions.json.

History 1

  1. ImplementedInkan maintainers9e5e535 commit diff