Si construyes agentes LLM, probablemente escribes el mismo prompt más de una vez. Un archivo de configuración Markdown para una herramienta, un archivo de reglas para otra, y luego los mensajes [{role, content}] reales que tu SDK envía. Las instrucciones son las mismas. Los formatos no lo son, así que copias, ajustas y ves cómo se desvían.
No soy el único — hay gente que construye pipelines completos de generación de código para lidiar con esto. Un repositorio popular, wshobson/agents, genera configuraciones de agente para seis plataformas (Claude Code, Codex, Cursor, OpenCode, Gemini, Copilot) desde una única fuente de verdad en Markdown, usando un Makefile. Eso es mucha maquinaria artesanal para “escríbelo una vez, emítelo en todas partes”. Yo quería eso sin tener que mantener un script de build, así que escribí un compilador pequeño.
Qué es MDS
MDS (Markdown Script) es un lenguaje de plantillas para ingeniería de prompts componible. Escribes Markdown con imports, variables, funciones y condicionales, y se compila anticipadamente a Markdown limpio, o a un array JSON de mensajes de chat. No hay runtime. La salida compilada es exactamente lo que tu herramienta o SDK lee, así que no corre nada nuevo dentro del bucle de tu agente.
Componiendo un prompt a partir de partes
Las variables vienen del frontmatter y se interpolan con llaves simples:
---
lang: TypeScript
---
Eres un revisor de código senior en {lang}.
Define una pieza reutilizable una vez con una función:
@define revisor(lang):
Eres un revisor de código senior en {lang}. Señala errores de corrección primero, luego estilo. Sé conciso.
@end
Luego impórtala donde la necesites, bajo un alias:
@import "./_persona.mds" as p
{p.revisor("TypeScript")}
Los archivos con prefijo _ son parciales: dependencias que nunca se emiten solas. Cambia la persona en un lugar y todo lo que la importa se recompila.
La parte que importa para los agentes: @message
La misma fuente puede compilarse al array de mensajes que tu SDK envía, usando bloques @message:
@import "./_persona.mds" as p
@message system:
{p.revisor("TypeScript")}
@end
@message user:
Revisa este diff:
{diff}
@end
Ejecutando mds build revision.mds produce JSON:
[
{ "role": "system", "content": "Eres un revisor de código senior en TypeScript. Señala errores de corrección primero, luego estilo. Sé conciso." },
{ "role": "user", "content": "Revisa este diff:\n..." }
]
Una plantilla que contiene bloques @message se compila a JSON. Todo lo demás compila a Markdown. El formato de salida lo decide el contenido, no una bandera de línea de comandos. Así que el prompt que compones en Markdown se convierte en los mensajes que tu código pasa al modelo, en lugar de concatenar strings en Python.
Generando configuraciones para cada plataforma
Como una persona o conjunto de reglas es solo un import, una fuente puede alimentar varios destinos. Tu archivo de Claude Code y tus reglas de Cursor pueden importar el mismo _rules.mds, cada uno agregando solo lo específico. Edita la regla compartida una vez, reconstruye, y ambos quedan correctos. @extends y @block permiten que una plantilla hija herede de una base y sobrescriba solo las partes que difieren, que es cómo colapsas una familia de archivos de agente casi idénticos a una base más pequeños deltas.
El build también falla en cosas que el texto plano nunca detecta: variables indefinidas, ciclos de importación, y funciones llamadas con el número incorrecto de argumentos. Un prompt roto se convierte en un build fallido en lugar de un bug silencioso que un agente lee en tiempo de ejecución.
Instalación
El CLI está en Rust:
cargo install mds-cli
mds build sistema.mds # escribe sistema.md, o sistema.json si tiene bloques @message
mds watch . # recompila al guardar
mds check . # valida sin renderizar
Si prefieres quedarte en JS/TS, el compilador también se distribuye como librería y plugins para bundlers:
npm install @mdscript/mds
import { compile } from '@mdscript/mds'
// o importa un archivo .mds directamente via el plugin de Vite/Webpack/Rollup/Rspack:
import systemPrompt from './prompts/system.mds'
¿Qué sigue?
Está en v0.3 y es un proyecto pequeño. Sin editor ni soporte LSP aún, así que editas .mds sin autocompletado. La sintaxis de funciones y condicionales sigue siendo mínima, y los bindings para Python aún no se publicaron. Lo he usado principalmente contra mis propios agentes, así que los proyectos reales sacarán a relucir casos que no he cubierto.
Si hoy compones o generas prompts para agentes, ya sea a mano, con Jinja, o con un Makefile como el de wshobson, me gustaría saber si compilarlos anticipadamente encaja en tu flujo de trabajo. El repositorio es github.com/dean0x/mdscript. Issues y estrellas me ayudan a priorizar.
Sigue explorando estos temas en el blog de DojoFullStack — tenemos guías prácticas sobre agentes de IA, automatización de flujos de trabajo y las mejores herramientas para desarrolladores LATAM.