Skip to main content
The formatter module converts crawled page data into the llms.txt markdown format. It handles URL cleaning, markdown file detection, content organization by sections, and automatic tagging.

Overview

The formatter takes a list of PageInfo objects and generates a structured markdown file following the llms.txt specification:
  • Site title and summary from homepage
  • Pages organized by URL path sections
  • Optional markdown file linking (.md variants)
  • Automatic content tagging
  • Primary/secondary content separation

Core Functions

format_llms_txt()

Generates the complete llms.txt formatted output.
str
required
The base URL of the crawled site
list[PageInfo]
required
List of crawled pages (first page should be homepage)
Dict[str, str]
default:"None"
Optional mapping from HTML URLs to markdown URLs
str
Formatted llms.txt content as a string
Output Format:

URL Processing

clean_url()

Removes query parameters and fragments from URLs.
str
required
URL to clean
str
URL with only scheme, netloc, and path
Example:

get_md_url()

Converts an HTML URL to its potential markdown equivalent.
str
required
Original URL
str
Converted markdown URL path
Conversion Rules:
  • page.htmlpage.html.md
  • /docs//docs/index.html.md
  • /about/about.md
Example:

check_md_exists()

Checks if a markdown version of a URL exists.
str
required
URL to check
float
default:"5.0"
Request timeout in seconds
bool
True if markdown version returns 200

get_md_url_map()

Builds a mapping of HTML to markdown URLs for all pages.
list[PageInfo]
required
List of pages to check
Dict[str, str]
Mapping from clean HTML URLs to markdown URLs (or original if no .md found)
Behavior:
  • Sends HEAD requests concurrently for all pages
  • Checks for markdown content types
  • Falls back to original URL if no markdown exists
  • Uses asyncio.gather for parallel requests

Text Processing

truncate()

Truncates text to specified length with ellipsis.
str
required
Text to truncate
int
default:"150"
Maximum character length
str
Text truncated with ”…” if exceeded length, otherwise original

get_site_title()

Extracts site title from homepage, with fallback to domain name.
PageInfo
required
Homepage page info
str
required
Site base URL
str
Site title (max 80 chars)
Logic:
  • Uses homepage title if meaningful
  • Falls back to cleaned domain name for generic titles (“Home”, “Welcome”, “Index”)
  • Truncated to 80 characters

get_summary()

Extracts site summary from homepage.
PageInfo
required
Homepage page info
str
Site summary (max 200 chars)
Precedence:
  1. Homepage description
  2. Homepage snippet
  3. “No description available”

Section Processing

clean_section_name()

Cleanlifies section names for display.
str
required
Raw section name from URL path
str
Capitalized, human-readable section name
Transformations:
  • Replaces hyphens and underscores with spaces
  • Capitalizes words
  • Uppercases known abbreviations (API, REST, GraphQL, SDK, CLI, UI, UX, FAQ, RSS)
  • Defaults to “Main” for empty names
Examples:

is_secondary_section()

Determines if a section is secondary/optional content.
str
required
Section name to check
bool
True if section matches secondary patterns
Secondary Patterns:
  • Legal: privacy, terms, legal, cookie, disclaimer
  • Meta: sitemap, changelog, release
  • Community: contributing, code-of-conduct, governance, license
  • Company: about, team, career, job, contact, company
  • Social: twitter, github, linkedin, facebook, social
  • Archive: archive, old, legacy, deprecated

Usage Examples

Basic Formatting

Output:

With Markdown URL Mapping

Section Organization

Content Tagging

The formatter integrates with the tagger module:
Tags appear inline in descriptions:
  • crawler - Provides PageInfo objects
  • tagger - Assigns and formats content tags
  • storage - Saves formatted output to R2