Un asistente de IA que lee tu web recibe HTML: menús, scripts, pie de página, mucho ruido alrededor del texto que le interesa. Una versión en Markdown de cada artículo le da solo lo importante: el título, el resumen y el contenido. En este sitio, añadir .md a la URL de un artículo o proyecto lo devuelve. Así está hecho.
Si quieres ver el resultado, prueba con este mismo artículo: /servir-tus-paginas-en-markdown-para-agentes-de-ia.md.
Las tres piezas
- Una reescritura en el proxy: cualquier URL que termina en
.mdse envía a una ruta interna. - Un route handler que busca el contenido y responde con
text/markdown. - Una función que convierte el contenido a Markdown.
Pieza 1: el proxy
En proxy.ts, antes de la lógica de idiomas:
// Versión Markdown para agentes: /<articulo>.md y /projects/<slug>.md
if (pathname.endsWith('.md')) {
const name = rest.at(-1)?.slice(0, -3);
const section =
rest.length === 1 ? 'blog' : rest.length === 2 ? matchSegment(locale, rest[0])?.internal : undefined;
if (!name || (section !== 'blog' && section !== 'projects')) return NextResponse.next();
return NextResponse.rewrite(new URL(join('md', locale, section, name), req.url));
}Los artículos viven en la raíz (/mi-articulo), así que una URL con un solo segmento es un artículo (blog). Con dos segmentos, el primero indica la sección, por ejemplo projects. Lo que no encaja sigue su camino normal.
Pieza 2: el route handler
En app/md/[locale]/[section]/[slug]/route.ts:
const markdown = (body: string) =>
new Response(body, {
headers: {
'Content-Type': 'text/markdown; charset=utf-8',
'X-Robots-Tag': 'noindex',
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400',
},
});
export async function GET(_req: NextRequest, { params }: Ctx) {
const { locale, section, slug } = await params;
if (!isLocale(locale)) return new Response('Not found', { status: 404 });
if (section === 'blog') {
const post = await getPost({ slug, locale });
return post ? markdown(postMarkdown(post, locale)) : new Response('Not found', { status: 404 });
}
// …lo mismo para projects
}Dos decisiones:
X-Robots-Tag: noindex. La versión Markdown no debe competir con la página HTML en Google. Es para máquinas, no para el buscador.- Caché pública de una hora. El texto cambia poco, y un agente que pide muchas páginas no debería golpear la base de datos cada vez.
Pieza 3: de Lexical a Markdown
El contenido de nuestros artículos vive en Payload, que usa el editor Lexical, y lo guarda como un árbol JSON. Hay que recorrerlo y escribir Markdown. Nuestra función postMarkdown arma el documento:
export function postMarkdown(post: Post, locale: Locale): string {
return join([
`# ${post.title}`,
`> ${post.excerpt}`,
[
`URL: ${SITE_URL}${postPath(locale, post.slug)}`,
`${category.title} · ${post.publishedAt?.slice(0, 10)} · ${author.name}`,
].join('\n'),
lexicalToMarkdown(post.content.root),
]);
}Título, resumen en cita, una línea con la URL original, la categoría, la fecha y el autor, y luego el cuerpo. La URL original sirve para que quien lea la versión Markdown sepa dónde está la canónica.
lexicalToMarkdown recorre los nodos y devuelve encabezados, citas, listas, tablas, imágenes, enlaces y bloques de código con su lenguaje. Si tu contenido está en Markdown desde el principio (por ejemplo, un CMS basado en Markdown), te saltas esta pieza y devuelves el archivo.
Un complemento: llms.txt
Además de las versiones .md, servimos llms.txt y llms-full.txt en la raíz: índices en texto con la descripción del sitio y los enlaces a servicios, proyectos y artículos. Es una convención reciente, y no hay garantía de que todos los agentes la lean. Cuesta poco mantenerla, porque se genera desde la misma base de datos.
Qué no hace
Esto no garantiza que ningún modelo te cite ni mejora tu posición en Google. Lo que hace es facilitar la lectura a quien decida leerte, y es un trabajo pequeño: un proxy, una ruta y un conversor.
Si estás preparando una web para ser leída por máquinas, también te servirá auditar el SEO técnico en 30 minutos.
Escrito por
Derian Pinto
Founder & Full Stack Developer
Fundador de Codegea. Desarrolla sitios, tiendas y plataformas a medida, e integra y da soporte a Arc XP para medios.