Stacks & DNA DARE¶
DARE genera proyectos greenfield a partir de un catálogo de 11 stacks — 7 backend y 4 de servidores MCP. Cada generador (StackScaffold) se registra de forma lazy en el registry (packages/cli/src/stacks/registry.ts): el módulo solo se carga cuando eliges ese stack, manteniendo dare --help frío y rápido.
Independientemente del stack, todo generador entrega el mismo conjunto invariante de 7 artefactos — el DNA DARE — validado en un test (dna.spec.ts).
Los 11 stacks¶
Backend (7)¶
| Stack | Status | Framework | Libs principales |
|---|---|---|---|
ruby-rails-8 |
stable | Rails 8 | rswag (OpenAPI), Action Cable (WS), RFC 7807 Problem Details, ActiveRecord, rake dare:metrics |
node-nestjs |
stable | NestJS 10 | Prisma + Postgres, JWT auth, Swagger en /openapi.json, Throttler (rate limit), class-validator + class-transformer, Pino |
python-fastapi |
stable | FastAPI | Pydantic v2, SQLAlchemy 2.0 + Alembic, slowapi (rate limit), uvicorn[standard] |
php-laravel |
stable | Laravel 11 | Sanctum + FormRequest, Eloquent, Reverb (WS) + Pail, ThrottleRequests, l5-swagger, LlmProvider (Dummy + OpenAI), Pest |
rust-axum |
stable | Axum 0.7 | Tokio, tower-http (CORS/trace) + tower-governor (rate limit), utoipa (OpenAPI), sqlx + Postgres, axum::extract::ws |
go-gin |
stable | Gin | sqlc + pgx, golang-jwt + bcrypt, gorilla/websocket, golang.org/x/time/rate, swag (OpenAPI) |
go-stdlib |
stable | net/http 1.22 ServeMux | pgx + schema compatible con sqlc, golang-jwt + bcrypt, golang.org/x/time/rate, github.com/coder/websocket (filosofía mínimo-deps) |
MCP — Model Context Protocol (4)¶
| Stack | Status | SDK / Runtime | Transports |
|---|---|---|---|
mcp-node-ts |
stable | @modelcontextprotocol/sdk (TypeScript) |
stdio · sse · http (Streamable HTTP) |
mcp-python |
stable | mcp[cli] (FastMCP, Python 3.11+) |
stdio · sse · http (vía uvicorn) |
mcp-rust |
beta | rmcp (SDK oficial de Rust) |
stdio · sse · http (vía axum) |
mcp-go |
beta | github.com/mark3labs/mcp-go (SDK comunitario) |
stdio · sse · http |
Transport de los MCP
Los tres transports vienen juntos en todo generador MCP. El transport efectivo se elige en runtime por la flag --transport o por la env MCP_TRANSPORT; el generador preselecciona el default del usuario (opts.mcp.transport) para que start "simplemente funcione".
Ordenación del registry
list() ordena por categoría (backend antes de mcp) y luego por id, de forma determinista. resolve(id) hace el import lazy y lo memoiza; un id inválido genera UnknownStackError con la lista de ids disponibles.
El DNA DARE — 7 artefactos invariantes¶
Todo StackScaffold llama a emitDefaults() temprano en generate() para satisfacer el contrato de DNA y luego sobrescribe cada artefacto con la versión específica del stack. El tipo DareDnaArtifact y la constante DARE_DNA (en stacks/types.ts) listan los 7; el test dna.spec.ts falla si alguno falta.
| # | Artefacto (DareDnaArtifact) |
Qué es | Cómo se garantiza |
|---|---|---|---|
| 1 | Layered Design | Separación en capas (handlers/controllers → services → repositories → models) | Estructura emitida por cada generador (común a los 11 stacks). |
| 2 | llms.txt |
Manifiesto para agentes de IA (setup, comandos, endpoints) | emit('llms-txt') → llms.txt. |
| 3 | OpenAPI | Contrato HTTP (openapi.json / /openapi.json en runtime) |
emit('openapi') → openapi.json (skeleton 3.1.0; el generador sobrescribe). |
| 4 | --json |
Flag de salida JSON en la CLI generada | Declarativo: el generador lo declara vía dnaEmitted; validado por grep estructural sobre el fuente generado. |
| 5 | Rate limit | Middleware de límite por minuto, dirigido por env (RATE_LIMIT_PER_MIN) |
Declarativo: ídem --json; validado por grep. |
| 6 | .env.example sin secretos |
Ejemplo de entorno sin credenciales reales | emit('env-example') valida cada valor contra SECRET_PATTERNS (base64 ≥40, hex ≥32, PEM, sk-…, AKIA…) y lanza EnvSecretError si casa. |
| 7 | .dare/skills.yml |
Registro del skill del stack para el IDE | emit('skills-yml') mapea stack → skill (p. ej.: skill-nestjs-api, skill-fastapi-api; todos los MCP → skill-mcp-server). |
| — | .github/workflows/dare-ci.yml |
CI (audit + lint + test) | emit('github-ci') → workflow con jobs audit/lint/test (placeholders por ecosistema). |
Declarativo vs. emitido
Cinco artefactos son emitidos en disco (llms-txt, openapi, env-example, skills-yml, github-ci). Dos — cli-json-flag (la flag --json) y rate-limit — son declarativos: el generador retorna que los satisfizo en dnaEmitted, y dna.spec.ts lo confirma vía grep sobre el código generado. emitDefaults() retorna el conjunto completo DARE_DNA (los 7).
Protección de secretos en .env.example¶
validateEnvExample() recorre el archivo línea a línea, ignora comentarios/líneas vacías y rechaza cualquier valor que case con un patrón de secreto:
export const SECRET_PATTERNS: ReadonlyArray<RegExp> = [
/[A-Za-z0-9+/]{40,}={0,2}/, // base64 ≥40 chars (provável chave)
/[a-f0-9]{32,}/, // hex ≥32 chars (hash / chave)
/-----BEGIN [A-Z ]+ PRIVATE KEY-----/, // bloco PEM
/sk-[A-Za-z0-9]{40,}/, // chave estilo OpenAI
/AKIA[0-9A-Z]{16}/, // AWS access key
];
Los valores-placeholder (replace-me-in-prod, postgresql://user:pass@localhost...) pasan; los secretos reales hacen fallar el build con EnvSecretError apuntando a la línea.
Toolchain (auto / native / docker)¶
Todo generador recibe un ScaffoldOpts.toolchain del tipo ToolchainMode:
| Modo | Comportamiento |
|---|---|
native |
Usa las herramientas instaladas localmente (Node, Python, Rust, Go, etc.). |
docker |
Empaqueta la toolchain en contenedor — sin depender de lo que hay en la máquina. |
auto |
Decide entre native y docker según el entorno. |
Cada generate() recibe además: dir (directorio destino ya creado y vacío), projectName (slug kebab-case), features (subconjunto del DARE_DNA, default = los 7), llm opcional (providers), realtime opcional (ws/sse), mcp (transport — obligatorio para la categoría mcp) e isMonorepo. Retorna ScaffoldResult: filesWritten, postInstallSteps (comandos a ejecutar a continuación), warnings y dnaEmitted (los artefactos DNA satisfechos — comprobados por dna.spec.ts).
flowchart TD
G[generate(opts)] --> E[emitDefaults()<br/>7 artefactos DNA]
E --> O[overlay específico del stack<br/>OpenAPI real, llms.txt, etc.]
O --> R[ScaffoldResult<br/>filesWritten · postInstallSteps · dnaEmitted]
R --> V[dna.spec.ts valida los 7]