From b7a3ecd1c25d51cc037c1713a0e1ad33b3a69021 Mon Sep 17 00:00:00 2001 From: sepehr-safari Date: Thu, 24 Sep 2026 12:08:24 +0300 Subject: [PATCH] feat: serve the site in a form agents can read Every page now has a Markdown twin at its path with .md added, generated at build from the same MDX and linked from the page as a text/markdown alternate. llms.txt indexes the projects and docs, llms-full.txt carries every page in one file, and sitemap.xml and robots.txt are built from content/ so a new page is listed the moment it exists. Each page also carries schema.org JSON-LD saying what it describes: the library as source code, Plaza, Notary and deed as applications, the home page as the organization and the site. The IndexNow key file lets changed pages be announced to search engines directly. --- .gitignore | 4 ++ app/[[...mdxPath]]/page.jsx | 17 +++++- app/layout.jsx | 11 +--- app/robots.js | 10 ++++ app/site-url.js | 10 ++++ app/sitemap.js | 16 ++++++ app/structured-data.js | 58 ++++++++++++++++++++ package.json | 1 + public/07d125e7231655dd8670b5fb9f6f9aed.txt | 1 + public/llms.txt | 31 +++++++++++ scripts/agent-files.mjs | 61 +++++++++++++++++++++ 11 files changed, 209 insertions(+), 11 deletions(-) create mode 100644 app/robots.js create mode 100644 app/site-url.js create mode 100644 app/sitemap.js create mode 100644 app/structured-data.js create mode 100644 public/07d125e7231655dd8670b5fb9f6f9aed.txt create mode 100644 public/llms.txt create mode 100644 scripts/agent-files.mjs diff --git a/.gitignore b/.gitignore index a3ef750..2ebc802 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ next-env.d.ts # pagefind search index (generated at build) /public/_pagefind + +# agent files (generated at build from content/) +/public/*.md +/public/llms-full.txt diff --git a/app/[[...mdxPath]]/page.jsx b/app/[[...mdxPath]]/page.jsx index da021c8..e63c35c 100644 --- a/app/[[...mdxPath]]/page.jsx +++ b/app/[[...mdxPath]]/page.jsx @@ -1,12 +1,23 @@ import { generateStaticParamsFor, importPage } from 'nextra/pages' import { useMDXComponents as getMDXComponents } from '../../mdx-components.js' +import { structuredData } from '../structured-data.js' export const generateStaticParams = generateStaticParamsFor('mdxPath') +// The page's name in content/: `index` for the home page. +function pageName(params) { + return params.mdxPath?.length ? params.mdxPath.join('/') : 'index' +} + export async function generateMetadata(props) { const params = await props.params const { metadata } = await importPage(params.mdxPath) - return metadata + // Every page has a plain Markdown twin, generated at build from the same + // source, for agents and answer engines that would rather not parse HTML. + return { + ...metadata, + alternates: { types: { 'text/markdown': `/${pageName(params)}.md` } }, + } } const Wrapper = getMDXComponents().wrapper @@ -15,8 +26,12 @@ export default async function Page(props) { const params = await props.params const result = await importPage(params.mdxPath) const { default: MDXContent, toc, metadata } = result + const data = structuredData(pageName(params)) return ( + {data && ( +