Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9d0c98b
Add SEO.LLMs.Provider behaviour for llms.txt sections
dbernheisel Apr 12, 2026
869fc1f
Add SEO.LLMs.render/1 for llms.txt markdown generation
dbernheisel Apr 12, 2026
4e0cf81
Add Plug behaviour to SEO.LLMs for serving llms.txt responses
dbernheisel Apr 12, 2026
6fa81d9
Add tests for provider-based Plug and SEO config integration
dbernheisel Apr 12, 2026
cb7947e
docs: add SEO.LLMs to ex_doc module groups
dbernheisel Apr 12, 2026
bd66935
Add SEO.LLMs.Build protocol with Any fallback
dbernheisel Apr 12, 2026
d662816
Add SEO.LLMs.Entry struct with build and group_by_section helpers
dbernheisel Apr 12, 2026
86311df
Add Build protocol impl for MyApp.Article and integration tests
dbernheisel Apr 12, 2026
41d9769
Add render_content/2 helper for serving markdown via Build protocol
dbernheisel Apr 12, 2026
538b5cf
docs: add SEO.LLMs.Entry and SEO.LLMs.Build to ex_doc groups
dbernheisel Apr 12, 2026
325d6c4
refactor: replace Build protocol with behaviour on view modules
dbernheisel Apr 12, 2026
9436957
docs: comprehensive moduledoc with full usage example and MDEx integr…
dbernheisel Apr 12, 2026
baf26a8
docs: add MDEx with Phoenix guide to SEO.LLMs moduledoc
dbernheisel Apr 12, 2026
d133ce5
test: comprehensive integration tests with sample app
dbernheisel Apr 12, 2026
47b316b
test: full Phoenix sample app integration with format negotiation and…
dbernheisel Apr 12, 2026
2505c71
resolve warnings
dbernheisel Apr 12, 2026
662e70a
feat: support nested sub-sections (H3) and inline markdown in sections
dbernheisel Apr 12, 2026
435f74d
fix: resolve all credo warnings, use VerifiedRoutes in moduledoc exam…
dbernheisel Apr 12, 2026
c0d4966
docs: add LLMs.txt section to README
dbernheisel Apr 12, 2026
50eb3e6
fix: replace deprecated use Plug.Test with import
dbernheisel Apr 12, 2026
97ec3e8
fix: remove mdex test dep to support blend tests against LV 0.18
dbernheisel Apr 12, 2026
39407ad
blend with newer phoenix liveview
dbernheisel Apr 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,6 @@ jobs:
- run: mix blend.get
- run: BLEND=phoenix_live_view_v0_18 mix test
- run: BLEND=phoenix_live_view_v0_19 mix test
- run: BLEND=phoenix_live_view_v0_20 mix test
- run: BLEND=phoenix_live_view_v0_20 mix test
- run: BLEND=phoenix_live_view_v1_0 mix test
- run: BLEND=phoenix_live_view_v1_1 mix test
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,69 @@ Alternatively, you may selectively render components. For example:
</head>
```

## LLMs.txt

Serve an `/llms.txt` file per the [llmstxt.org](https://llmstxt.org) spec so
LLMs can discover and understand your site's content.

```elixir
# In your router
forward "/llms.txt", SEO.LLMs,
config: MyAppWeb.SEO,
provider: MyAppWeb.LLMsProvider
```

Create markdown view modules (`FooMD`) — the markdown equivalent of `FooHTML` —
that implement the `SEO.LLMs` behaviour:

```elixir
defmodule MyAppWeb.ArticleMD do
@behaviour SEO.LLMs
use MyAppWeb, :verified_routes

# Phoenix view function — called when format is "md"
def show(%{article: article}) do
"""
# #{article.title}

#{article.body}
"""
end

# llms.txt entry — called by your Provider
@impl SEO.LLMs
def entry(article) do
SEO.LLMs.Entry.build(
section: "Articles",
title: article.title,
url: ~p"/articles/#{article}",
description: article.summary
)
end
end
```

Then register the `"md"` format in your pipeline and controller:

```elixir
pipeline :browser do
plug :accepts, ["html", "md"]
end

defmodule MyAppWeb.ArticleController do
use MyAppWeb, :controller
plug :put_view, html: MyAppWeb.ArticleHTML, md: MyAppWeb.ArticleMD

def show(conn, %{"slug" => slug}) do
article = Blog.get_article_by_slug!(slug)
render(conn, :show, article: article)
end
end
```

See `SEO.LLMs` module docs for the full guide, including MDEx `~MD` sigil
integration, nested sub-sections, and inline markdown content.

## FAQ

> #### Question: What do I do for non-show routes, like for index routes? {: .info}
Expand Down
4 changes: 3 additions & 1 deletion blend.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
%{
phoenix_live_view_v0_18: [{:phoenix_live_view, "~> 0.18.0"}],
phoenix_live_view_v0_19: [{:phoenix_live_view, "~> 0.19.0"}],
phoenix_live_view_v0_20: [{:phoenix_live_view, "~> 0.20.0"}]
phoenix_live_view_v0_20: [{:phoenix_live_view, "~> 0.20.0"}],
phoenix_live_view_v1_0: [{:phoenix_live_view, "~> 1.0.0"}],
phoenix_live_view_v1_1: [{:phoenix_live_view, "~> 1.1.0"}]
}
Loading
Loading