Add llms.txt support with markdown format negotiation#20
Merged
dbernheisel merged 22 commits intomainfrom Apr 13, 2026
Merged
Conversation
Define the callback interface that providers implement to return structured sections for generating llms.txt files per the llmstxt.org spec. Includes initial test with a static provider module.
Renders llms.txt-compliant markdown from a map of options including title, description, body, and categorized link sections.
Implements init/1 and call/2 so SEO.LLMs can be used directly as a Plug (e.g. via `forward "/llms.txt", SEO.LLMs, opts`). Sections can be provided statically or resolved from a provider module at request time. Includes resolve_config/1 for deriving title/description from a SEO config module.
- Test that provider module sections are resolved and rendered via the Plug - Test that config module derives title from open_graph.site_name and description from site.description - Test that explicit title/description options override config values
Define the Build protocol for LLMs entries, following the same pattern as SEO.OpenGraph.Build and other existing Build protocols. The Any fallback returns nil since there is no sensible default for LLMs entries.
Entry represents a single resource in an llms.txt file with section, title, url, description, and content fields. The group_by_section/1 function converts entries into the tuple format expected by render/1.
Add SEO.LLMs.Build implementation for MyApp.Article in test support, along with tests for the Build protocol (including Any fallback) and a full protocol-driven provider integration test that exercises the flow from protocol through provider to plug rendering.
Controllers can call SEO.LLMs.render_content/2 to serve a resource's markdown content as text/markdown. Supports string and zero-arity function content fields, returning 406 when unimplemented.
Remove SEO.LLMs.Build protocol and render_content/2 in favor of a behaviour callback on SEO.LLMs. Markdown view modules (FooMD) implement the behaviour's entry/1 callback to provide llms.txt entries, following Phoenix's convention of format-specific view modules (FooHTML, FooJSON).
…ation Show the complete setup: router pipeline, FooMD view modules, controller registration, provider assembly. Include MDEx sigil example for markdown templates alongside standard string interpolation approach.
Cover setup, the ~MD sigil as markdown's equivalent of ~H, when to use compile-time templates vs runtime interpolation, and converting HTML content to markdown.
… MDEx Sets up a minimal Phoenix endpoint, router, and controllers to validate the complete format negotiation flow (Accept: text/markdown → ArticleMD/PageMD view dispatch), the llms.txt plug endpoint, MDEx ~MD sigil rendering, and the provider behaviour contract.
Section entries can now be:
- {name, url} — a link
- {name, url, description} — a link with description
- {name, entries} — a sub-section rendered as H3
- "string" — inline markdown rendered as-is
Consecutive links are joined with single newlines; strings and
sub-sections are separated by double newlines. This matches
real-world patterns from sites like Vercel, Vite, Turso, and NVIDIA.
…ples - Replace Enum.map |> Enum.join with Enum.map_join - Add alias SEO.LLMs.Entry throughout test files and support modules - Update moduledoc examples to use ~p sigil for VerifiedRoutes
MDEx requires phoenix_live_view ~> 1.0, which conflicts with blend tests against older LV versions. MDEx usage is documented in the moduledoc but not tested directly — that's MDEx's responsibility.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SEO.LLMsPlug that serves/llms.txtper the llmstxt.org specFooMDview module convention for serving resources as markdown, following Phoenix'sFooHTML/FooJSONpatternsite_name,description) for the llms.txt title and summary~MDsigil for markdown templatesNew modules
SEO.LLMs/llms.txt+@callback entry/1behaviour for FooMD view modulesSEO.LLMs.Entrygroup_by_section/1helperSEO.LLMs.ProviderHow it works