@ontosdk/next 1.2.0 → 1.3.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.
Files changed (53) hide show
  1. package/JSON_LD_GUIDE.md +403 -0
  2. package/LLMS_TXT_GUIDE.md +297 -0
  3. package/ONTOROVIDER_USAGE.md +130 -0
  4. package/QUICKSTART.md +71 -0
  5. package/README.md +253 -0
  6. package/SCHEMA_QUICKSTART.md +97 -0
  7. package/dist/OntoHead.d.mts +27 -0
  8. package/dist/OntoHead.d.ts +27 -0
  9. package/dist/OntoHead.js +2 -0
  10. package/dist/OntoHead.js.map +1 -0
  11. package/dist/OntoHead.mjs +2 -0
  12. package/dist/OntoHead.mjs.map +1 -0
  13. package/dist/OntoProvider.d.mts +52 -0
  14. package/dist/OntoProvider.d.ts +52 -0
  15. package/dist/OntoProvider.js +2 -0
  16. package/dist/OntoProvider.js.map +1 -0
  17. package/dist/OntoProvider.mjs +2 -0
  18. package/dist/OntoProvider.mjs.map +1 -0
  19. package/dist/config.d.mts +85 -0
  20. package/dist/config.d.ts +85 -0
  21. package/dist/config.js +4 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/config.mjs +4 -0
  24. package/dist/config.mjs.map +1 -0
  25. package/dist/index.d.mts +3 -0
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.js +6 -4
  28. package/dist/index.js.map +1 -1
  29. package/dist/index.mjs +6 -4
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/middleware.d.mts +1 -1
  32. package/dist/middleware.d.ts +1 -1
  33. package/dist/middleware.js +4 -2
  34. package/dist/middleware.js.map +1 -1
  35. package/dist/middleware.mjs +4 -2
  36. package/dist/middleware.mjs.map +1 -1
  37. package/dist/schemas.d.mts +73 -0
  38. package/dist/schemas.d.ts +73 -0
  39. package/dist/schemas.js +2 -0
  40. package/dist/schemas.js.map +1 -0
  41. package/dist/schemas.mjs +2 -0
  42. package/dist/schemas.mjs.map +1 -0
  43. package/onto.config.example.ts +111 -0
  44. package/package.json +28 -2
  45. package/src/OntoHead.tsx +59 -0
  46. package/src/OntoProvider.tsx +95 -0
  47. package/src/bots.ts +6 -3
  48. package/src/config.ts +151 -0
  49. package/src/index.ts +14 -0
  50. package/src/middleware.ts +56 -8
  51. package/src/schemas.ts +186 -0
  52. package/tsconfig.json +1 -0
  53. package/tsup.config.ts +2 -2
@@ -0,0 +1,403 @@
1
+ # Automatic JSON-LD Schema Injection Guide
2
+
3
+ The OntoProvider now automatically injects JSON-LD structured data schemas based on your page configuration. **Zero manual JSON-LD writing required** - just configure your routes and the SDK does the rest.
4
+
5
+ ## Why JSON-LD Matters for AI
6
+
7
+ JSON-LD (JavaScript Object Notation for Linked Data) is a lightweight format that helps AI agents:
8
+ - **Understand your content** with high confidence
9
+ - **Extract structured data** (pricing, products, methodology)
10
+ - **Reduce hallucinations** by providing authoritative schema markup
11
+ - **Score higher** on AIO metrics (worth 25 points in our scoring algorithm)
12
+
13
+ ## Quick Start
14
+
15
+ ### 1. Import Your Config
16
+
17
+ ```tsx
18
+ // app/layout.tsx
19
+ import { OntoProvider } from '@ontosdk/next/provider';
20
+ import config from '../onto.config';
21
+
22
+ export default function RootLayout({ children }) {
23
+ return (
24
+ <OntoProvider baseUrl="https://example.com" config={config}>
25
+ <html>
26
+ <head />
27
+ <body>{children}</body>
28
+ </html>
29
+ </OntoProvider>
30
+ );
31
+ }
32
+ ```
33
+
34
+ ### 2. Configure Page Types
35
+
36
+ ```typescript
37
+ // onto.config.ts
38
+ import type { OntoConfig } from '@ontosdk/next';
39
+
40
+ const config: OntoConfig = {
41
+ name: 'My Site',
42
+ summary: 'Description',
43
+ baseUrl: 'https://example.com',
44
+
45
+ routes: [
46
+ {
47
+ path: '/score',
48
+ description: 'AIO Score Calculator',
49
+ pageType: 'scoring' // ← Automatically injects Methodology schema
50
+ },
51
+ {
52
+ path: '/about',
53
+ description: 'About us',
54
+ pageType: 'about' // ← Automatically injects Organization schema
55
+ }
56
+ ],
57
+
58
+ organization: {
59
+ name: 'My Company',
60
+ description: 'What we do',
61
+ url: 'https://example.com',
62
+ logo: 'https://example.com/logo.png'
63
+ }
64
+ };
65
+
66
+ export default config;
67
+ ```
68
+
69
+ ### 3. That's It!
70
+
71
+ The OntoProvider automatically:
72
+ 1. Detects the current page path
73
+ 2. Matches it against your route configuration
74
+ 3. Generates the appropriate JSON-LD schema
75
+ 4. Injects it into the page `<head>`
76
+
77
+ No manual `<script type="application/ld+json">` tags needed!
78
+
79
+ ## Supported Page Types
80
+
81
+ ### `pageType: 'scoring'`
82
+
83
+ **Use for**: AIO score calculators, methodology pages, scoring tools
84
+
85
+ **Generates**: [HowTo Schema](https://schema.org/HowTo) explaining the AIO scoring methodology
86
+
87
+ **Includes**:
88
+ - 4-step methodology (Content Negotiation, Token Efficiency, Structured Data, Semantic HTML)
89
+ - Standard AIO weights (40%, 35%, 25%, bonus)
90
+ - Detailed explanations for each metric
91
+
92
+ **Example output**:
93
+ ```json
94
+ {
95
+ "@context": "https://schema.org",
96
+ "@type": "HowTo",
97
+ "name": "AIO Score Calculation Methodology",
98
+ "description": "AI Optimization (AIO) Score measures how well a website is optimized for AI agents...",
99
+ "step": [
100
+ {
101
+ "@type": "HowToStep",
102
+ "name": "Content Negotiation",
103
+ "text": "Check if the site responds to Accept: text/markdown header. Weight: 40%...",
104
+ "position": 1
105
+ },
106
+ // ... 3 more steps
107
+ ]
108
+ }
109
+ ```
110
+
111
+ **When to use**:
112
+ - `/score` - Score calculator pages
113
+ - `/methodology` - Explanation of scoring system
114
+ - `/calculator` - Any page with a scoring/grading tool
115
+
116
+ ### `pageType: 'about'`
117
+
118
+ **Use for**: About pages, company info, team pages
119
+
120
+ **Generates**: [AboutPage Schema](https://schema.org/AboutPage) + [Organization Schema](https://schema.org/Organization)
121
+
122
+ **Includes**:
123
+ - Organization name, description, URL
124
+ - Logo, founding date (if provided)
125
+ - Nested organization entity
126
+
127
+ **Example output**:
128
+ ```json
129
+ {
130
+ "@context": "https://schema.org",
131
+ "@type": "AboutPage",
132
+ "name": "About My Company",
133
+ "url": "https://example.com/about",
134
+ "description": "Company description from config",
135
+ "mainEntity": {
136
+ "@context": "https://schema.org",
137
+ "@type": "Organization",
138
+ "name": "My Company",
139
+ "url": "https://example.com",
140
+ "description": "What we do",
141
+ "logo": "https://example.com/logo.png",
142
+ "foundingDate": "2024-01-01"
143
+ }
144
+ }
145
+ ```
146
+
147
+ **When to use**:
148
+ - `/about` - Company about page
149
+ - `/about-us` - Team/company info
150
+ - `/company` - Organization details
151
+
152
+ ### `pageType: 'default'` (or omitted)
153
+
154
+ **Use for**: All other pages
155
+
156
+ **Generates**: Nothing - no automatic JSON-LD injection
157
+
158
+ Use this for pages where you want to manually control JSON-LD or don't need structured data.
159
+
160
+ ## Configuration Reference
161
+
162
+ ### Route Configuration
163
+
164
+ ```typescript
165
+ interface OntoRoute {
166
+ path: string; // URL path (e.g., '/score')
167
+ description: string; // What this page contains
168
+ pageType?: PageType; // 'scoring' | 'about' | 'default'
169
+ }
170
+ ```
171
+
172
+ ### Organization Configuration
173
+
174
+ Required for `pageType: 'about'` to work properly:
175
+
176
+ ```typescript
177
+ organization?: {
178
+ name: string; // Required: Organization name
179
+ description?: string; // Optional: What you do
180
+ url?: string; // Optional: Company website
181
+ logo?: string; // Optional: Logo URL (use absolute URL)
182
+ foundingDate?: string; // Optional: ISO date format (YYYY-MM-DD)
183
+ }
184
+ ```
185
+
186
+ ## Complete Example
187
+
188
+ ```typescript
189
+ // onto.config.ts
190
+ import type { OntoConfig } from '@ontosdk/next';
191
+
192
+ const config: OntoConfig = {
193
+ name: 'BuildOnto',
194
+ summary: 'Next.js infrastructure for AI-optimized websites',
195
+ baseUrl: 'https://buildonto.dev',
196
+
197
+ routes: [
198
+ {
199
+ path: '/',
200
+ description: 'Homepage',
201
+ pageType: 'default'
202
+ },
203
+ {
204
+ path: '/score',
205
+ description: 'AIO Score Calculator - grade your AI optimization',
206
+ pageType: 'scoring'
207
+ },
208
+ {
209
+ path: '/about',
210
+ description: 'About BuildOnto and our mission',
211
+ pageType: 'about'
212
+ },
213
+ {
214
+ path: '/docs',
215
+ description: 'Documentation and guides'
216
+ // No pageType = 'default', no automatic JSON-LD
217
+ }
218
+ ],
219
+
220
+ organization: {
221
+ name: 'BuildOnto',
222
+ description: 'Making websites AI-ready with zero-config infrastructure',
223
+ url: 'https://buildonto.dev',
224
+ logo: 'https://buildonto.dev/logo.png',
225
+ foundingDate: '2024-01-01'
226
+ }
227
+ };
228
+
229
+ export default config;
230
+ ```
231
+
232
+ ```tsx
233
+ // app/layout.tsx
234
+ import { OntoProvider } from '@ontosdk/next/provider';
235
+ import config from '../onto.config';
236
+
237
+ export default function RootLayout({ children }) {
238
+ return (
239
+ <OntoProvider baseUrl="https://buildonto.dev" config={config}>
240
+ <html lang="en">
241
+ <head />
242
+ <body>{children}</body>
243
+ </html>
244
+ </OntoProvider>
245
+ );
246
+ }
247
+ ```
248
+
249
+ Now visit `/score` or `/about` and view source - you'll see the JSON-LD automatically injected!
250
+
251
+ ## AIO Scoring Weights
252
+
253
+ The `pageType: 'scoring'` schema includes the official AIO scoring methodology:
254
+
255
+ | Metric | Weight | Max Penalty | Description |
256
+ |--------|--------|-------------|-------------|
257
+ | **Content Negotiation** | 40% | -30 points | Accept: text/markdown support |
258
+ | **Token Efficiency** | 35% | -30 points | HTML size vs visible text ratio |
259
+ | **Structured Data** | 25% | -25 points | JSON-LD presence (this feature!) |
260
+ | **Semantic HTML** | Bonus | -15 points | `<main>`, `<article>` tags |
261
+
262
+ By using this SDK with automatic JSON-LD injection, you instantly gain **+25 points** on the AIO score!
263
+
264
+ ## Validation
265
+
266
+ ### Test Your Schema
267
+
268
+ 1. Visit your page in development: `http://localhost:3000/score`
269
+ 2. View page source (Ctrl+U / Cmd+U)
270
+ 3. Look for `<script type="application/ld+json">`
271
+ 4. Copy the JSON content
272
+ 5. Validate at [Google's Rich Results Test](https://search.google.com/test/rich-results)
273
+
274
+ ### Check with cURL
275
+
276
+ ```bash
277
+ # Fetch as an AI bot
278
+ curl -H "User-Agent: GPTBot" http://localhost:3000/score | grep "application/ld+json"
279
+ ```
280
+
281
+ ## Advanced Usage
282
+
283
+ ### Manual Schema Generation
284
+
285
+ If you need custom schemas beyond the built-in types:
286
+
287
+ ```typescript
288
+ import { generateAIOMethodologySchema } from '@ontosdk/next';
289
+
290
+ const schema = generateAIOMethodologySchema(config, 'https://example.com/score');
291
+ console.log(JSON.stringify(schema, null, 2));
292
+ ```
293
+
294
+ ### Custom Page Types
295
+
296
+ Want to add your own page types? Extend the config:
297
+
298
+ ```typescript
299
+ // Create a custom schema generator
300
+ function generateProductSchema(config, url) {
301
+ return {
302
+ '@context': 'https://schema.org',
303
+ '@type': 'Product',
304
+ name: config.name,
305
+ url: url
306
+ };
307
+ }
308
+
309
+ // Use it manually in your component
310
+ import { serializeSchema } from '@ontosdk/next';
311
+
312
+ const jsonLd = serializeSchema(generateProductSchema(config, pageUrl));
313
+
314
+ return (
315
+ <script
316
+ type="application/ld+json"
317
+ dangerouslySetInnerHTML={{ __html: jsonLd }}
318
+ />
319
+ );
320
+ ```
321
+
322
+ ## Migration from Manual JSON-LD
323
+
324
+ If you currently have manual JSON-LD:
325
+
326
+ **Before** (manual):
327
+ ```tsx
328
+ export default function AboutPage() {
329
+ return (
330
+ <>
331
+ <script
332
+ type="application/ld+json"
333
+ dangerouslySetInnerHTML={{
334
+ __html: JSON.stringify({
335
+ '@context': 'https://schema.org',
336
+ '@type': 'AboutPage',
337
+ name: 'About Us',
338
+ // ... lots of manual JSON
339
+ })
340
+ }}
341
+ />
342
+ <main>{/* content */}</main>
343
+ </>
344
+ );
345
+ }
346
+ ```
347
+
348
+ **After** (automatic):
349
+ ```tsx
350
+ // onto.config.ts
351
+ routes: [
352
+ { path: '/about', description: 'About us', pageType: 'about' }
353
+ ]
354
+
355
+ // app/layout.tsx - just wrap once
356
+ <OntoProvider config={config} baseUrl="https://example.com">
357
+ {children}
358
+ </OntoProvider>
359
+ ```
360
+
361
+ ## Benefits
362
+
363
+ ✅ **Zero Manual Work**: Configure once, works everywhere
364
+ ✅ **Type-Safe**: Full TypeScript support with intellisense
365
+ ✅ **Consistent**: Same schema structure across all pages
366
+ ✅ **Maintainable**: Update in one place (config) instead of per-page
367
+ ✅ **AIO Optimized**: Schemas designed specifically for AI agents
368
+ ✅ **Schema.org Compliant**: Follows official standards
369
+ ✅ **Validation Ready**: Works with Google Rich Results Test
370
+
371
+ ## Troubleshooting
372
+
373
+ ### Schema not appearing?
374
+
375
+ 1. **Check config path**: Make sure you're importing the config correctly
376
+ 2. **Verify route match**: Path must exactly match (including trailing slashes)
377
+ 3. **Check pageType**: Must be explicitly set to 'scoring' or 'about'
378
+ 4. **Organization missing**: For 'about' pages, ensure `organization` is configured
379
+
380
+ ### Wrong schema type?
381
+
382
+ - Double-check the `pageType` value in your route config
383
+ - Ensure you're passing the config prop to OntoProvider
384
+
385
+ ### TypeScript errors?
386
+
387
+ ```bash
388
+ npm install @ontosdk/next@latest
389
+ ```
390
+
391
+ Make sure you're on the latest version with schema support.
392
+
393
+ ## Resources
394
+
395
+ - [Schema.org: HowTo](https://schema.org/HowTo)
396
+ - [Schema.org: AboutPage](https://schema.org/AboutPage)
397
+ - [Schema.org: Organization](https://schema.org/Organization)
398
+ - [Google Rich Results Test](https://search.google.com/test/rich-results)
399
+ - [AIO Score Documentation](https://buildonto.dev/docs/aio-score)
400
+
401
+ ---
402
+
403
+ **Next Steps**: Check out [LLMS_TXT_GUIDE.md](./LLMS_TXT_GUIDE.md) for automatic llms.txt generation!
@@ -0,0 +1,297 @@
1
+ # Dynamic llms.txt Generation Guide
2
+
3
+ The Onto middleware now supports **dynamic llms.txt generation** from your `onto.config.ts` file. This means you never have to manually create or update an `llms.txt` file—it's generated on-the-fly from your configuration.
4
+
5
+ ## What is llms.txt?
6
+
7
+ `llms.txt` is a standardized file format that provides AI agents (like ChatGPT, Claude, and Perplexity) with a concise, structured overview of your website. It follows a simple Markdown format and helps AI systems understand:
8
+
9
+ - What your site is about
10
+ - Where the most important content is located
11
+ - What resources are available
12
+
13
+ **Key Benefits:**
14
+ - AI agents get accurate, up-to-date information about your site
15
+ - No manual file maintenance—generated from config
16
+ - Follows the official llms.txt specification
17
+ - Automatically served to AI crawlers by the middleware
18
+
19
+ ## Setup
20
+
21
+ ### 1. Create `onto.config.ts`
22
+
23
+ Create a file named `onto.config.ts` in your project root:
24
+
25
+ ```typescript
26
+ import { OntoConfig } from '@ontosdk/next';
27
+
28
+ const config: OntoConfig = {
29
+ name: 'My Project',
30
+ summary: 'A brief description of what your project does and who it serves.',
31
+ baseUrl: 'https://example.com',
32
+
33
+ routes: [
34
+ { path: '/', description: 'Homepage' },
35
+ { path: '/docs', description: 'Documentation' },
36
+ { path: '/api', description: 'API reference' }
37
+ ]
38
+ };
39
+
40
+ export default config;
41
+ ```
42
+
43
+ ### 2. Middleware Configuration
44
+
45
+ If you've already installed the Onto middleware, you're done! The middleware automatically:
46
+ 1. Detects requests to `/llms.txt`
47
+ 2. Loads your `onto.config.ts`
48
+ 3. Generates the llms.txt content dynamically
49
+ 4. Returns it with proper headers (`Content-Type: text/plain`)
50
+
51
+ No additional configuration needed.
52
+
53
+ ## Configuration Schema
54
+
55
+ ### Required Fields
56
+
57
+ #### `name` (string)
58
+ The name of your project or website. Used as the H1 heading in llms.txt.
59
+
60
+ ```typescript
61
+ name: 'Acme Corp Documentation'
62
+ ```
63
+
64
+ #### `summary` (string)
65
+ A concise summary of your project. Should contain key information that helps AI agents understand the purpose and scope of your site. Displayed as a blockquote in llms.txt.
66
+
67
+ ```typescript
68
+ summary: 'Comprehensive documentation for the Acme API. Includes REST endpoints, SDKs, and integration guides for Python, JavaScript, and Go.'
69
+ ```
70
+
71
+ #### `baseUrl` (string)
72
+ The base URL of your website. Used to construct full URLs for routes.
73
+
74
+ ```typescript
75
+ baseUrl: 'https://docs.acme.com'
76
+ ```
77
+
78
+ ### Optional Fields
79
+
80
+ #### `routes` (array)
81
+ Key routes that AI agents should know about. Each route includes:
82
+ - `path`: The URL path (e.g., `/docs/api`)
83
+ - `description`: What this route contains
84
+
85
+ ```typescript
86
+ routes: [
87
+ {
88
+ path: '/docs/getting-started',
89
+ description: 'Quick start guide for new developers'
90
+ },
91
+ {
92
+ path: '/docs/api/reference',
93
+ description: 'Complete API endpoint reference'
94
+ },
95
+ {
96
+ path: '/blog',
97
+ description: 'Technical blog and release notes'
98
+ }
99
+ ]
100
+ ```
101
+
102
+ #### `externalLinks` (array)
103
+ Links to external resources like GitHub, status pages, or community forums.
104
+
105
+ ```typescript
106
+ externalLinks: [
107
+ {
108
+ title: 'GitHub Repository',
109
+ url: 'https://github.com/acme/sdk',
110
+ description: 'Source code and issue tracker'
111
+ },
112
+ {
113
+ title: 'API Status',
114
+ url: 'https://status.acme.com'
115
+ }
116
+ ]
117
+ ```
118
+
119
+ #### `sections` (array)
120
+ Custom markdown sections to add additional context. Each section has:
121
+ - `heading`: The section title
122
+ - `content`: Markdown content
123
+
124
+ ```typescript
125
+ sections: [
126
+ {
127
+ heading: 'About',
128
+ content: 'Acme provides cloud infrastructure for modern applications...'
129
+ },
130
+ {
131
+ heading: 'Key Features',
132
+ content: `- **Fast**: Sub-millisecond response times
133
+ - **Secure**: SOC 2 Type II certified
134
+ - **Scalable**: Handles millions of requests per second`
135
+ }
136
+ ]
137
+ ```
138
+
139
+ ## Example Output
140
+
141
+ With the following config:
142
+
143
+ ```typescript
144
+ const config: OntoConfig = {
145
+ name: 'Acme Documentation',
146
+ summary: 'API docs and guides for Acme Cloud Platform',
147
+ baseUrl: 'https://docs.acme.com',
148
+ routes: [
149
+ { path: '/api', description: 'API reference' },
150
+ { path: '/guides', description: 'Integration guides' }
151
+ ]
152
+ };
153
+ ```
154
+
155
+ The generated `/llms.txt` will be:
156
+
157
+ ```markdown
158
+ # Acme Documentation
159
+
160
+ > API docs and guides for Acme Cloud Platform
161
+
162
+ ## Key Routes
163
+
164
+ - [/api](https://docs.acme.com/api): API reference
165
+ - [/guides](https://docs.acme.com/guides): Integration guides
166
+ ```
167
+
168
+ ## Advanced Usage
169
+
170
+ ### TypeScript Support
171
+
172
+ Full TypeScript support with type checking:
173
+
174
+ ```typescript
175
+ import type { OntoConfig } from '@ontosdk/next';
176
+
177
+ const config: OntoConfig = {
178
+ name: 'My Site',
179
+ summary: 'Description',
180
+ baseUrl: 'https://example.com',
181
+ // TypeScript will validate all fields
182
+ };
183
+
184
+ export default config;
185
+ ```
186
+
187
+ ### Environment-Specific Configuration
188
+
189
+ Use environment variables for different deployment environments:
190
+
191
+ ```typescript
192
+ const config: OntoConfig = {
193
+ name: 'My App',
194
+ summary: 'A great application',
195
+ baseUrl: process.env.NEXT_PUBLIC_BASE_URL || 'https://example.com',
196
+
197
+ routes: [
198
+ { path: '/', description: 'Home' },
199
+ ...(process.env.NODE_ENV === 'production'
200
+ ? [{ path: '/enterprise', description: 'Enterprise features' }]
201
+ : []
202
+ )
203
+ ]
204
+ };
205
+
206
+ export default config;
207
+ ```
208
+
209
+ ### Dynamic Routes
210
+
211
+ Generate routes programmatically:
212
+
213
+ ```typescript
214
+ const docPages = ['getting-started', 'authentication', 'webhooks'];
215
+
216
+ const config: OntoConfig = {
217
+ name: 'API Docs',
218
+ summary: 'Developer documentation',
219
+ baseUrl: 'https://api.example.com',
220
+
221
+ routes: [
222
+ { path: '/', description: 'API overview' },
223
+ ...docPages.map(page => ({
224
+ path: `/docs/${page}`,
225
+ description: `Guide: ${page.replace('-', ' ')}`
226
+ }))
227
+ ]
228
+ };
229
+
230
+ export default config;
231
+ ```
232
+
233
+ ## Fallback Behavior
234
+
235
+ The middleware implements intelligent fallback:
236
+
237
+ 1. **With config**: Generates llms.txt dynamically from `onto.config.ts`
238
+ 2. **Without config**: Falls back to static `public/llms.txt` if it exists
239
+ 3. **On error**: Logs error and attempts to serve static file
240
+
241
+ This ensures your site always has an llms.txt, even if configuration fails.
242
+
243
+ ## Caching
244
+
245
+ Generated llms.txt responses include optimal cache headers:
246
+
247
+ ```
248
+ Content-Type: text/plain; charset=utf-8
249
+ Cache-Control: public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400
250
+ ```
251
+
252
+ This means:
253
+ - Cached for 1 hour in browsers/CDNs
254
+ - Stale content can be served for up to 24 hours while revalidating
255
+ - Reduces server load and improves response times
256
+
257
+ ## Debugging
258
+
259
+ To verify your llms.txt is being generated correctly:
260
+
261
+ 1. **Start your dev server**: `npm run dev`
262
+ 2. **Visit**: `http://localhost:3000/llms.txt`
263
+ 3. **Check console**: Look for `[Onto] Failed to generate llms.txt:` errors
264
+
265
+ If you see your generated content, you're all set!
266
+
267
+ ## Migration from Static llms.txt
268
+
269
+ If you currently have a static `public/llms.txt` file:
270
+
271
+ 1. Create `onto.config.ts` with your site information
272
+ 2. Test that `/llms.txt` is being generated correctly
273
+ 3. Delete `public/llms.txt` (optional—it's used as fallback)
274
+
275
+ The middleware will automatically prefer the dynamic version.
276
+
277
+ ## Specification Compliance
278
+
279
+ This implementation follows the official llms.txt specification:
280
+
281
+ - ✅ H1 with project name (required)
282
+ - ✅ Blockquote with summary (required)
283
+ - ✅ Additional markdown sections (optional)
284
+ - ✅ Proper content type (`text/plain`)
285
+ - ✅ UTF-8 encoding
286
+
287
+ ## Resources
288
+
289
+ - [llms.txt Official Site](https://llmstxt.org/)
290
+ - [llms.txt Specification](https://llmstxt.org/spec)
291
+ - [Example Sites](https://llmstxt.org/examples)
292
+
293
+ ## Support
294
+
295
+ For questions or issues:
296
+ - GitHub: [onto-sdk/issues](https://github.com/anthropics/onto-sdk/issues)
297
+ - Docs: [buildonto.dev/docs](https://buildonto.dev/docs)