seoLlmsTxt function

String seoLlmsTxt({
  1. required String siteBase,
  2. List<SeoRoute>? routes,
  3. List<SeoResolvedPage>? pages,
  4. String? title,
  5. String? description,
  6. List<String> additionalPaths = const [],
})

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();
}