seoLlmsTxt function
Generates an llms.txt from the SEO route table.
llms.txt (https://llmstxt.org) is the emerging convention for making
a site legible to AI assistants: a markdown manifest at /llms.txt
that names the site and lists its pages with one-line descriptions —
the AI-crawler counterpart to sitemap.xml.
Pass exactly one of routes and pages — see seoSitemapXml
for the same contract. With routes the table is resolved
synchronously and a SeoRoute.dynamic throws a StateError; with a
pre-resolved pages snapshot every table works.
Site title and description default to the metadata of the root
page (/); every listed page uses its own meta title and
description. Pages that resolve to a redirect, a non-200, or opt out
of the sitemap are skipped.
final txt = seoLlmsTxt(routes: seoRoutes, siteBase: 'https://x.dev');
// # Esen Software
// > Flutter Apps mit echtem SEO.
//
// ## Pages
//
// - [Home](https://x.dev/): Flutter Apps mit echtem SEO.
// - [Docs](https://x.dev/docs): So funktioniert esen_seo.
Implementation
String seoLlmsTxt({
required String siteBase,
List<SeoRoute>? routes,
List<SeoResolvedPage>? pages,
String? title,
String? description,
List<String> additionalPaths = const [],
}) {
final base = siteBase.endsWith('/')
? siteBase.substring(0, siteBase.length - 1)
: siteBase;
final resolved = pagesForGenerator(
routes: routes,
pages: pages,
additionalPaths: additionalPaths,
canonicalBase: siteBase,
);
final rootMeta = _rootMeta(resolved);
final siteTitle = title ?? rootMeta?.title ?? Uri.parse(base).host;
final siteDescription = description ?? rootMeta?.description;
final buffer = StringBuffer()..writeln('# ${_singleLine(siteTitle)}');
if (siteDescription != null && siteDescription.isNotEmpty) {
buffer.writeln('> ${_singleLine(siteDescription)}');
}
buffer
..writeln()
..writeln('## Pages')
..writeln();
for (final page in resolved) {
if (!page.isIndexable) continue;
final meta = page.document!.meta;
final url = page.path == '/' ? '$base/' : '$base${page.path}';
final pageTitle = _linkLabel(meta.title ?? page.path);
final pageDescription = meta.description;
buffer
..write('- [$pageTitle](${_linkTarget(url)})')
..writeln(pageDescription == null || pageDescription.isEmpty
? ''
: ': ${_singleLine(pageDescription)}');
}
return buffer.toString();
}