jekyll-llms-output 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +8 -0
- data/LICENSE +21 -0
- data/README.md +126 -0
- data/lib/jekyll-llms-output/full_builder.rb +85 -0
- data/lib/jekyll-llms-output/generator.rb +69 -0
- data/lib/jekyll-llms-output/index_builder.rb +120 -0
- data/lib/jekyll-llms-output/version.rb +7 -0
- data/lib/jekyll-llms-output.rb +8 -0
- metadata +122 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 77bd6b72574803bc37691dc39fed7ae2630293858a717ffcdff715df1d950a7a
|
|
4
|
+
data.tar.gz: cbf85998d24ee83072793940c227902068ae4cec56a767ec54eece3cde62ca1e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d8ad8e05490ecbeb45d9b3ea064473fdb40e6d4989b9349719c45340c9ed378e21bee730ffac30477d28e0f6c3765131aa7af9ea7dcc11b527bacd66767afa2a
|
|
7
|
+
data.tar.gz: 51f71c2b80c5ec81f48c173ea9e7f9746ed3b633ccc27c1a90cd9c39ee9a8e0768a4c4357fada0d95ea6966cf357253af7d9cf4e11ab7ca6d13b8d41e6823d1b
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-05-05
|
|
4
|
+
|
|
5
|
+
- Initial release.
|
|
6
|
+
- Generates `/llms.txt` from `_data/llms.yml` (curated) or auto from collections.
|
|
7
|
+
- Generates `/llms-full.txt` by concatenating source bodies (Liquid rendered).
|
|
8
|
+
- Per-document opt-out for `llms-full.txt` via `llms_output: false` in frontmatter.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abhinav Saxena
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# jekyll-llms-output
|
|
2
|
+
|
|
3
|
+
A Jekyll plugin that generates two files agents and LLM crawlers expect:
|
|
4
|
+
|
|
5
|
+
- **`/llms.txt`** - an index of your content following the [llmstxt.org](https://llmstxt.org) format. Hand-curate it via `_data/llms.yml`, or let the plugin auto-generate from your collections.
|
|
6
|
+
- **`/llms-full.txt`** - a single concatenated dump of all your post bodies (Liquid rendered, source markdown). Useful for agents that want to ingest your whole site in one fetch.
|
|
7
|
+
|
|
8
|
+
Pairs nicely with [`jekyll-markdown-output`](https://github.com/abhinavs/jekyll-markdown-output), which writes per-page `.md` siblings.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
group :jekyll_plugins do
|
|
14
|
+
gem "jekyll-llms-output"
|
|
15
|
+
end
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
plugins:
|
|
20
|
+
- jekyll-llms-output
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Configure
|
|
24
|
+
|
|
25
|
+
Defaults are sensible for a typical blog. Override via `_config.yml`:
|
|
26
|
+
|
|
27
|
+
```yaml
|
|
28
|
+
llms_output:
|
|
29
|
+
enabled: true # global on/off
|
|
30
|
+
|
|
31
|
+
index:
|
|
32
|
+
enabled: true # write /llms.txt
|
|
33
|
+
output: /llms.txt
|
|
34
|
+
data: llms # reads _data/llms.yml if it exists
|
|
35
|
+
title: ~ # default: site.title
|
|
36
|
+
description: ~ # default: site.description
|
|
37
|
+
collections: [posts] # used in auto mode (no data file)
|
|
38
|
+
|
|
39
|
+
full:
|
|
40
|
+
enabled: true # write /llms-full.txt
|
|
41
|
+
output: /llms-full.txt
|
|
42
|
+
collections: [posts]
|
|
43
|
+
pages: false
|
|
44
|
+
page_extensions: [.md, .markdown]
|
|
45
|
+
separator: "\n\n---\n\n"
|
|
46
|
+
include_url: true
|
|
47
|
+
include_date: true
|
|
48
|
+
respect_markdown_output: false # if true, also honor jekyll-markdown-output's opt-out flag
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## `/llms.txt` modes
|
|
52
|
+
|
|
53
|
+
### Curated (recommended)
|
|
54
|
+
|
|
55
|
+
Drop a `_data/llms.yml` in your site:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
title: Abhinav Saxena
|
|
59
|
+
description: |
|
|
60
|
+
Personal website of Abhinav Saxena, a generalist with interests in
|
|
61
|
+
entrepreneurship, software engineering, and engineering leadership.
|
|
62
|
+
|
|
63
|
+
sections:
|
|
64
|
+
- heading: Agent Resources
|
|
65
|
+
links:
|
|
66
|
+
- title: agents.md
|
|
67
|
+
url: https://www.abhinav.co/.well-known/agents.md
|
|
68
|
+
description: Context and instructions for coding agents
|
|
69
|
+
- title: skills.md
|
|
70
|
+
url: https://www.abhinav.co/.well-known/skills.md
|
|
71
|
+
description: Decision table mapping needs to specific posts
|
|
72
|
+
|
|
73
|
+
- heading: Featured Writing
|
|
74
|
+
links:
|
|
75
|
+
- title: Terminal is having a second life
|
|
76
|
+
url: https://www.abhinav.co/terminal-second-life
|
|
77
|
+
description: Why agentic tooling has pulled the terminal back to the centre of the dev workflow
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The plugin renders this exact structure to `/llms.txt`. Curation is preserved, you can section by topic, and you control which links appear.
|
|
81
|
+
|
|
82
|
+
### Auto
|
|
83
|
+
|
|
84
|
+
If `_data/llms.yml` is absent, the plugin generates from `index.collections` - one `## Section` per collection, one bullet per document, with the `summary` (or excerpt) as the description.
|
|
85
|
+
|
|
86
|
+
## `/llms-full.txt`
|
|
87
|
+
|
|
88
|
+
Concatenates the source body of every document in `full.collections` (and pages if `full.pages: true`), with a `# Title` header per item and a `---` separator between them.
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
# Hello World
|
|
92
|
+
|
|
93
|
+
URL: https://example.com/2024/01/01/hello
|
|
94
|
+
Date: 2024-01-01T09:00:00+00:00
|
|
95
|
+
|
|
96
|
+
This is the body of the post.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
# Another Post
|
|
101
|
+
...
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Per-document opt-out
|
|
105
|
+
|
|
106
|
+
Skip a single document from `llms-full.txt`:
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
---
|
|
110
|
+
title: Draft thinking
|
|
111
|
+
llms_output: false
|
|
112
|
+
---
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Compatibility
|
|
116
|
+
|
|
117
|
+
- Jekyll 3.7+ and 4.x
|
|
118
|
+
- Ruby 2.7+
|
|
119
|
+
|
|
120
|
+
### GitHub Pages
|
|
121
|
+
|
|
122
|
+
GitHub Pages restricts plugins to a whitelist; this gem isn't on it. Build your site in CI (Actions, Netlify, Cloudflare Pages, Vercel) and deploy `_site/` to GH Pages.
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
MIT. See `LICENSE`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module LlmsOutput
|
|
5
|
+
# Builds the body of /llms-full.txt: a concatenation of every document's
|
|
6
|
+
# source markdown, separated by a configurable delimiter, each with a
|
|
7
|
+
# small header (title + url) for context.
|
|
8
|
+
class FullBuilder
|
|
9
|
+
attr_reader :site, :options
|
|
10
|
+
|
|
11
|
+
def initialize(site, options)
|
|
12
|
+
@site = site
|
|
13
|
+
@options = options
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def build
|
|
17
|
+
chunks = []
|
|
18
|
+
|
|
19
|
+
Array(options["collections"]).each do |coll_name|
|
|
20
|
+
collection = site.collections[coll_name.to_s]
|
|
21
|
+
next unless collection
|
|
22
|
+
collection.docs.each { |doc| chunks << render_doc(doc) }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
if options["pages"]
|
|
26
|
+
exts = Array(options["page_extensions"]).map(&:downcase)
|
|
27
|
+
site.pages.each do |page|
|
|
28
|
+
next unless exts.include?(File.extname(page.path).downcase)
|
|
29
|
+
chunks << render_doc(page)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
chunks.compact.join(options["separator"] || "\n\n---\n\n") + "\n"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def render_doc(doc)
|
|
39
|
+
return nil if doc.data["llms_output"] == false
|
|
40
|
+
return nil if doc.data["markdown_output"] == false && options["respect_markdown_output"]
|
|
41
|
+
|
|
42
|
+
url = absolute_url(doc.url)
|
|
43
|
+
title = doc.data["title"] || url
|
|
44
|
+
body = source_body(doc).strip
|
|
45
|
+
body = render_liquid(doc, body) if doc.data["render_with_liquid"] != false
|
|
46
|
+
|
|
47
|
+
header = +"# #{title}\n"
|
|
48
|
+
header << "\nURL: #{url}\n" if options["include_url"]
|
|
49
|
+
header << "Date: #{doc.data["date"].iso8601}\n" if options["include_date"] && doc.data["date"].respond_to?(:iso8601)
|
|
50
|
+
header << "\n"
|
|
51
|
+
|
|
52
|
+
header + body
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def source_path(doc)
|
|
56
|
+
File.expand_path(doc.path.to_s, site.source)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def source_body(doc)
|
|
60
|
+
raw = File.read(source_path(doc), encoding: "UTF-8")
|
|
61
|
+
parts = raw.split(/^---\s*$\n/, 3)
|
|
62
|
+
parts.length >= 3 ? parts[2] : raw
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def render_liquid(doc, body)
|
|
66
|
+
info = {
|
|
67
|
+
filters: [Jekyll::Filters],
|
|
68
|
+
registers: { site: site, page: doc.to_liquid },
|
|
69
|
+
}
|
|
70
|
+
template = site.liquid_renderer.file(source_path(doc)).parse(body)
|
|
71
|
+
template.render!(site.site_payload.merge("page" => doc.to_liquid), info)
|
|
72
|
+
rescue StandardError => e
|
|
73
|
+
rel = doc.respond_to?(:relative_path) ? doc.relative_path : doc.path
|
|
74
|
+
Jekyll.logger.warn("LlmsOutput:", "render failed for #{rel}: #{e.message}")
|
|
75
|
+
body
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def absolute_url(url)
|
|
79
|
+
site_url = site.config["url"]
|
|
80
|
+
return url if url.to_s.start_with?("http")
|
|
81
|
+
site_url ? "#{site_url}#{url}" : url
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
|
|
5
|
+
module Jekyll
|
|
6
|
+
module LlmsOutput
|
|
7
|
+
DEFAULTS = {
|
|
8
|
+
"enabled" => true,
|
|
9
|
+
"index" => {
|
|
10
|
+
"enabled" => true,
|
|
11
|
+
"output" => "/llms.txt",
|
|
12
|
+
"data" => "llms",
|
|
13
|
+
"title" => nil,
|
|
14
|
+
"description" => nil,
|
|
15
|
+
"collections" => ["posts"],
|
|
16
|
+
},
|
|
17
|
+
"full" => {
|
|
18
|
+
"enabled" => true,
|
|
19
|
+
"output" => "/llms-full.txt",
|
|
20
|
+
"collections" => ["posts"],
|
|
21
|
+
"pages" => false,
|
|
22
|
+
"page_extensions" => [".md", ".markdown"],
|
|
23
|
+
"separator" => "\n\n---\n\n",
|
|
24
|
+
"include_url" => true,
|
|
25
|
+
"include_date" => true,
|
|
26
|
+
"respect_markdown_output" => false,
|
|
27
|
+
},
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
def self.config_for(site)
|
|
31
|
+
user = site.config["llms_output"] || {}
|
|
32
|
+
merged = deep_merge(DEFAULTS, user)
|
|
33
|
+
merged
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.deep_merge(a, b)
|
|
37
|
+
a.merge(b) do |_, av, bv|
|
|
38
|
+
av.is_a?(Hash) && bv.is_a?(Hash) ? deep_merge(av, bv) : bv
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.write_all(site)
|
|
43
|
+
config = config_for(site)
|
|
44
|
+
return unless config["enabled"]
|
|
45
|
+
|
|
46
|
+
if config["index"]["enabled"]
|
|
47
|
+
body = IndexBuilder.new(site, config["index"]).build
|
|
48
|
+
write_file(site, config["index"]["output"], body)
|
|
49
|
+
Jekyll.logger.info("LlmsOutput:", "wrote #{config["index"]["output"]}")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if config["full"]["enabled"]
|
|
53
|
+
body = FullBuilder.new(site, config["full"]).build
|
|
54
|
+
write_file(site, config["full"]["output"], body)
|
|
55
|
+
Jekyll.logger.info("LlmsOutput:", "wrote #{config["full"]["output"]}")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.write_file(site, output_path, body)
|
|
60
|
+
path = File.join(site.dest, output_path)
|
|
61
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
62
|
+
File.write(path, body)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
Jekyll::Hooks.register :site, :post_write do |site|
|
|
68
|
+
Jekyll::LlmsOutput.write_all(site)
|
|
69
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Jekyll
|
|
4
|
+
module LlmsOutput
|
|
5
|
+
# Builds the body of /llms.txt.
|
|
6
|
+
#
|
|
7
|
+
# Two modes:
|
|
8
|
+
# 1. Data-driven: site.data[<key>] holds a hash with title / description /
|
|
9
|
+
# sections. The plugin renders that structure to llmstxt.org format.
|
|
10
|
+
# 2. Auto: no data hash present. The plugin generates one section per
|
|
11
|
+
# configured collection with a bullet for each document.
|
|
12
|
+
#
|
|
13
|
+
# llmstxt.org spec we follow:
|
|
14
|
+
# # Title
|
|
15
|
+
# > Optional one-line description
|
|
16
|
+
# ## Section heading
|
|
17
|
+
# - [Title](url): optional description
|
|
18
|
+
class IndexBuilder
|
|
19
|
+
attr_reader :site, :options
|
|
20
|
+
|
|
21
|
+
def initialize(site, options)
|
|
22
|
+
@site = site
|
|
23
|
+
@options = options
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def build
|
|
27
|
+
data_key = options["data"]
|
|
28
|
+
data_hash = data_key && site.data[data_key.to_s]
|
|
29
|
+
|
|
30
|
+
if data_hash.is_a?(Hash) && data_hash["sections"]
|
|
31
|
+
render_from_data(data_hash)
|
|
32
|
+
else
|
|
33
|
+
render_auto
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def render_from_data(data)
|
|
40
|
+
out = +""
|
|
41
|
+
title = data["title"] || site.config["title"]
|
|
42
|
+
description = data["description"] || site.config["description"]
|
|
43
|
+
|
|
44
|
+
out << "# #{title}\n\n" if title && !title.to_s.empty?
|
|
45
|
+
if description && !description.to_s.empty?
|
|
46
|
+
out << "> #{description.to_s.strip}\n\n"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
Array(data["sections"]).each do |section|
|
|
50
|
+
heading = section["heading"] || section["title"]
|
|
51
|
+
next unless heading
|
|
52
|
+
out << "## #{heading}\n\n"
|
|
53
|
+
Array(section["links"]).each do |link|
|
|
54
|
+
out << format_link(link["title"], link["url"], link["description"])
|
|
55
|
+
end
|
|
56
|
+
out << "\n"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
out.strip + "\n"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def render_auto
|
|
63
|
+
out = +""
|
|
64
|
+
title = options["title"] || site.config["title"]
|
|
65
|
+
description = options["description"] || site.config["description"]
|
|
66
|
+
|
|
67
|
+
out << "# #{title}\n\n" if title && !title.to_s.empty?
|
|
68
|
+
if description && !description.to_s.empty?
|
|
69
|
+
out << "> #{description.to_s.strip}\n\n"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Array(options["collections"]).each do |coll_name|
|
|
73
|
+
collection = site.collections[coll_name.to_s]
|
|
74
|
+
next unless collection && !collection.docs.empty?
|
|
75
|
+
out << "## #{section_heading_for(coll_name)}\n\n"
|
|
76
|
+
docs_in_render_order(collection.docs).each do |doc|
|
|
77
|
+
url = absolute_url(doc.url)
|
|
78
|
+
out << format_link(doc.data["title"] || url, url, summary_for(doc))
|
|
79
|
+
end
|
|
80
|
+
out << "\n"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
out.strip + "\n"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def docs_in_render_order(docs)
|
|
87
|
+
# Newest first when docs have a date.
|
|
88
|
+
docs.sort_by { |d| d.respond_to?(:date) && d.date ? d.date : Time.at(0) }.reverse
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def section_heading_for(name)
|
|
92
|
+
# "posts" -> "Posts", "design_notes" -> "Design notes"
|
|
93
|
+
s = name.to_s.tr("_-", " ")
|
|
94
|
+
s.empty? ? "Items" : s[0].upcase + s[1..]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def format_link(title, url, description)
|
|
98
|
+
line = "- [#{title}](#{url})"
|
|
99
|
+
line += ": #{description.to_s.strip}" if description && !description.to_s.empty?
|
|
100
|
+
line + "\n"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def summary_for(doc)
|
|
104
|
+
s = doc.data["summary"]
|
|
105
|
+
return s.strip if s.is_a?(String) && !s.strip.empty?
|
|
106
|
+
excerpt = doc.data["excerpt"]
|
|
107
|
+
return nil if excerpt.nil?
|
|
108
|
+
text = excerpt.respond_to?(:content) ? excerpt.content : excerpt
|
|
109
|
+
text = text.to_s.gsub(/<[^>]+>/, "").strip
|
|
110
|
+
text.empty? ? nil : text.split(/\n\n/).first.to_s.strip
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def absolute_url(url)
|
|
114
|
+
site_url = site.config["url"]
|
|
115
|
+
return url if url.to_s.start_with?("http")
|
|
116
|
+
site_url ? "#{site_url}#{url}" : url
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: jekyll-llms-output
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Abhinav Saxena
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-05-05 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: jekyll
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '3.7'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '5.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '3.7'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '5.0'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: kramdown-parser-gfm
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.1'
|
|
40
|
+
type: :development
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.1'
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: rake
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '13.0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '13.0'
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: rspec
|
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '3.12'
|
|
68
|
+
type: :development
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '3.12'
|
|
75
|
+
description: |
|
|
76
|
+
A Jekyll plugin that writes /llms.txt (an index following llmstxt.org)
|
|
77
|
+
and /llms-full.txt (a concatenated full-text dump of your content).
|
|
78
|
+
Supports a hand-curated _data/llms.yml structure or auto-generation
|
|
79
|
+
from configured collections.
|
|
80
|
+
email:
|
|
81
|
+
- abhinav061@gmail.com
|
|
82
|
+
executables: []
|
|
83
|
+
extensions: []
|
|
84
|
+
extra_rdoc_files: []
|
|
85
|
+
files:
|
|
86
|
+
- CHANGELOG.md
|
|
87
|
+
- LICENSE
|
|
88
|
+
- README.md
|
|
89
|
+
- lib/jekyll-llms-output.rb
|
|
90
|
+
- lib/jekyll-llms-output/full_builder.rb
|
|
91
|
+
- lib/jekyll-llms-output/generator.rb
|
|
92
|
+
- lib/jekyll-llms-output/index_builder.rb
|
|
93
|
+
- lib/jekyll-llms-output/version.rb
|
|
94
|
+
homepage: https://github.com/abhinavs/jekyll-llms-output
|
|
95
|
+
licenses:
|
|
96
|
+
- MIT
|
|
97
|
+
metadata:
|
|
98
|
+
homepage_uri: https://github.com/abhinavs/jekyll-llms-output
|
|
99
|
+
source_code_uri: https://github.com/abhinavs/jekyll-llms-output/tree/main
|
|
100
|
+
bug_tracker_uri: https://github.com/abhinavs/jekyll-llms-output/issues
|
|
101
|
+
changelog_uri: https://github.com/abhinavs/jekyll-llms-output/blob/main/CHANGELOG.md
|
|
102
|
+
rubygems_mfa_required: 'true'
|
|
103
|
+
post_install_message:
|
|
104
|
+
rdoc_options: []
|
|
105
|
+
require_paths:
|
|
106
|
+
- lib
|
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
108
|
+
requirements:
|
|
109
|
+
- - ">="
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: 2.7.0
|
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
requirements: []
|
|
118
|
+
rubygems_version: 3.5.22
|
|
119
|
+
signing_key:
|
|
120
|
+
specification_version: 4
|
|
121
|
+
summary: Generate /llms.txt and /llms-full.txt for a Jekyll site.
|
|
122
|
+
test_files: []
|