Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions docs/app/llms-full.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { source } from '@/lib/source';
import { getLLMText } from '@/lib/get-llm-text';

export const revalidate = false;

export async function GET() {
const pages = source.getPages();
const scanned = await Promise.all(pages.map(getLLMText));
return new Response(scanned.join('\n\n'), {
Comment on lines +8 to +9
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty pages included in concatenated output

getLLMText returns '' when page.data.getText is unavailable or returns undefined. Joining those empty strings with '\n\n' leaves blank sections in the output, which reduces quality for consumers. Unlike llms.txt/route.ts which has a '# No pages found' fallback, this route also has no fallback for an entirely empty result.

Consider filtering and adding a fallback:

Suggested change
const scanned = await Promise.all(pages.map(getLLMText));
return new Response(scanned.join('\n\n'), {
const scanned = (await Promise.all(pages.map(getLLMText))).filter(Boolean);
return new Response(scanned.join('\n\n') || '# No content available', {

headers: {
'Content-Type': 'text/markdown',
},
});
}
27 changes: 27 additions & 0 deletions docs/app/llms.txt/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { source } from '@/lib/source';

export const revalidate = false;

export function GET() {
const pages = source.getPages();
const lines: string[] = [];

for (const page of pages) {
const url = page.url;
const data = page.data as { title?: string; description?: string };
const title = data.title ?? 'Page';
const description = data.description ?? '';
lines.push(`## ${title}`);
if (description) {
lines.push(`> ${description}`);
}
lines.push(`- Source: ${url}\n`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relative URL limits AI agent usability

page.url returns a path like /installation, not an absolute URL (e.g., https://docs.emdash.dev/installation). AI agents consuming llms.txt follow the links to retrieve content — a relative path without a known origin is not navigable. Additionally, the standard llms.txt link format uses a markdown hyperlink [Page Title](URL) rather than a bare Source: /path label.

Consider reading the canonical base URL from an environment variable or Next.js config:

Suggested change
lines.push(`- Source: ${url}\n`);
lines.push(`- [${title}](${process.env.NEXT_PUBLIC_SITE_URL ?? ''}${url})\n`);

}

const result = lines.join('\n');
return new Response(result || '# No pages found', {
headers: {
'Content-Type': 'text/markdown',
},
});
Comment on lines +6 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing top-level H1 header required by llms.txt spec

The llms.txt specification requires a top-level # Project Name H1 heading followed by an optional blockquote tagline at the very top of the file before any ## sections. Without the H1, AI agents and tools that parse llms.txt may fail to identify the project or treat the output as malformed.

The current output starts directly with ## Title sections. A spec-compliant header section should be prepended:

Suggested change
const pages = source.getPages();
const lines: string[] = [];
for (const page of pages) {
const url = page.url;
const data = page.data as { title?: string; description?: string };
const title = data.title ?? 'Page';
const description = data.description ?? '';
lines.push(`## ${title}`);
if (description) {
lines.push(`> ${description}`);
}
lines.push(`- Source: ${url}\n`);
}
const result = lines.join('\n');
return new Response(result || '# No pages found', {
headers: {
'Content-Type': 'text/markdown',
},
});
export function GET() {
const pages = source.getPages();
const lines: string[] = [
'# Emdash',
'',
'> An Open Source Agentic Development Environment (ADE)',
'',
];
for (const page of pages) {
const url = page.url;
const data = page.data as { title?: string; description?: string };
const title = data.title ?? 'Page';
const description = data.description ?? '';
lines.push(`## ${title}`);
if (description) {
lines.push(`> ${description}`);
}
lines.push(`- Source: ${url}\n`);
}
const result = lines.join('\n');
return new Response(result || '# No pages found', {
headers: {
'Content-Type': 'text/markdown',
},
});
}

}
9 changes: 9 additions & 0 deletions docs/lib/get-llm-text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { source } from '@/lib/source';
import type { InferPageType } from 'fumadocs-core/source';

type Page = InferPageType<typeof source>;

export async function getLLMText(page: Page): Promise<string> {
const processed = await page.data.getText?.('processed');
return processed ?? '';
}
5 changes: 5 additions & 0 deletions docs/source.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import lastModified from 'fumadocs-mdx/plugins/last-modified';

export const docs = defineDocs({
dir: 'content/docs',
docs: {
postprocess: {
includeProcessedMarkdown: true,
},
},
});

export default defineConfig({
Expand Down
Loading