Complemento de Discourse a Markdown

discourse-to-markdown es un nuevo plugin que devuelve el contenido del foro en formato Markdown cuando el cliente envía Accept: text/markdown o añade .md al final de cualquier URL de contenido.

Lo estamos ejecutando en nuestro propio foro en https://discourse.roots.io:

curl -H "Accept: text/markdown" https://discourse.roots.io/latest
curl https://discourse.roots.io/t/serve-your-wordpress-posts-as-markdown/30321.md

El HTML es costoso de alimentar a un LLM, y servir Markdown que solo contiene el contenido suele reducir el uso de tokens entre 3 y 5 veces. Esto significa llamadas a la API más económicas, respuestas más rápidas y más margen en la ventana de contexto para que el modelo razone. Consulta https://acceptmarkdown.com para una presentación más detallada y una verificación de compatibilidad para cualquier sitio.

Cómo los clientes solicitan Markdown

Tres puntos de entrada:

  1. Cabecera Accept: text/markdown (ideal para LLMs)
  2. Sufijo de URL .md
  3. Detección (cada respuesta HTML anuncia su hermano Markdown mediante Link: <...>; rel="alternate"; type="text/markdown" y una etiqueta <link rel="alternate"> en <head>, los feeds RSS incluyen un <atom:link> que apunta a la equivalente en Markdown)

Rutas compatibles

Ruta HTML Markdown
Tema /t/:slug/:id /t/:slug/:id.md
Publicación única /t/:slug/:id/:post_number /t/:slug/:id/:post_number.md
Categoría /c/:slug/:id /c/:slug/:id.md
Etiqueta /tag/:tag /tag/:tag.md
Último /latest /latest.md
Top /top /top.md
Popular /hot /hot.md
Actividad de usuario /u/:username/activity /u/:username/activity.md

Instalación

Añade el plugin a tu app.yml:

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/roots/discourse-to-markdown.git

Reconstruye el contenedor:

cd /var/discourse
./launcher rebuild app

Luego actívalo en Admin → Configuración → Plugins → Salida Markdown.

Notas sobre la conversión

El plugin convierte el HTML cooked de Discourse —la representación renderizada que ven los lectores, con oneboxes expandidos, menciones enlazadas y citas atribuidas—, no el raw. Esto preserva lo que realmente ven los lectores y mantiene la salida portable en cualquier renderizador compatible con GFM. Las construcciones específicas de Discourse (citas, oneboxes, detalles, menciones, hashtags, emojis, lightboxes, encuestas) se reescriben de manera lógica antes de la conversión.

El Markdown convertido se almacena en caché en Redis por publicación, usando como clave post.id + post.updated_at, y las ediciones invalidan automáticamente la caché.

Configuración

Configuración Valor predeterminado Propósito
discourse_to_markdown_enabled false Interruptor principal del plugin
discourse_to_markdown_md_urls_enabled true Aceptar sufijos de URL .md como hermanos de la ruta HTML
discourse_to_markdown_strict_accept false Devolver 406 Not Acceptable cuando la cabecera Accept del cliente excluye tanto text/html como text/markdown
discourse_to_markdown_emit_vary true Emitir Vary: Accept en respuestas Markdown y 406 para que las cachés no sirvan representaciones cruzadas
discourse_to_markdown_include_post_metadata true Incluir URL, categoría, etiquetas, autor y marcas de tiempo en la representación Markdown

Recursos

8 Me gusta

¡Esto es genial, gracias por publicarlo!

Este es también un enfoque bastante interesante. Ofrece un Markdown más rico que la salida cruda, ya que se beneficia de la infraestructura de “cocción” de Discourse.

2 Me gusta

¡Dios mío, es exactamente lo que he estado buscando, qué timing tan fantástico! Usamos la API o MCP con frecuencia y siempre nos molestaba que el contenido sin procesar no tuviera las URLs de las imágenes resueltas.

¡Gracias por el trabajo!

Edición: ¿Se podría usar de alguna manera con Discourse MCP también?

1 me gusta

¡Me alegra que sea útil!

Discourse MCP podría añadir la negociación de contenido como una ruta opcional. No necesitaría requerir este plugin; podría solicitar Accept: text/markdown desde la URL canónica del tema/publicación y, si el sitio no admite Markdown, volver al comportamiento actual de la API JSON.

Este plugin es solo una forma de que un sitio de Discourse satisfaga esa solicitud hoy. Sin este plugin o un soporte equivalente en el núcleo de Discourse, la cabecera Accept por sí sola no cambiaría la salida de la API JSON.

Por lo tanto, la integración ideal de MCP podría ser: intentar primero text/markdown en la URL del contenido y, si no funciona, recurrir a /t/:id.json?include_raw=true.

1 me gusta

Es curioso que lo digas, ya que Claude lo resolvió exactamente de esa manera…