Para devs AI-native

La base SaaS
que tu agente no puede romper

No estás comprando código que tu agente ya sabe escribir. Estás comprando los guardrails que no puede escribir solo: las paredes que le impiden romperte el login cuando toca pagos — enforzadas por el compilador y CI, no una convención blanda que puede racionalizar.

El agente ve una porción, y edita con confianza igual

En cada sesión tu agente ve solo una parte del proyecto — así que cambia código sin saber qué depende de eso en otro lado. El mes uno se siente eléctrico. Al mes seis la misma herramienta va más lenta que antes, porque la deuda técnica no se paga: se acumula, y en algún momento se cobra. Un repo vacío lo empeora: sin patrones a los que agarrarse, el agente driftea hacia sus propios defaults y erosiona la arquitectura en silencio. Para el prompt 50 es spaghetti.

En las palabras de quienes shippean con agentes

Deuda que se cobra más tarde

"Tech debt isn't paid down, it's being added to, and at some point in the future it will need to be collected." — antihipocrat, Hacker News (item 45405177)

Ningún patrón consistente al que agarrarse

"llm code has none of that [consistent patterns], if yes its by pure chance that won't repeat." — kakacik, Hacker News (item 45405177)

Los edge cases de seguridad que se le escapan

Los agentes IA "generate RLS policies that accidentally expose data to other tenants, forget to validate webhook signatures on payment events, create permission checks that authenticated users can bypass." — blog de MakerKit

Paredes que el agente físicamente no puede cruzar

Apuntá tu agente a la capa domain y decile que importe Prisma ahí nomás. No puede — ESLint rompe el build. Fronteras DDD enforzadas por el compilador y el lint: el código de domain no puede importar Express, Prisma ni infraestructura. Esto no es una sugerencia blanda de un AGENTS.md que el agente razonea y esquiva. Es una pared en CI.

eslint · domain boundary
 1  modules/billing/domain/subscription.ts
 2    import { prisma } from '@prisma/client'
 3           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 4    error  no-restricted-imports
 5    domain/ debe seguir framework-agnostic.
 6    Ver ADR-001.
 7  
 8  ✖ 1 problem — CI bloqueado

Payload drift, atrapado antes de shippear

El agente renombra un campo en el server y se olvida del cliente. El type drift lo atrapa el compilador. Pero el payload drift — el form manda fullName, el server espera name — pasa el typecheck y tira 400 en producción. Acá los schemas Zod del cliente importan desde un paquete compartido @app/contracts, y los tipos de openapi-fetch se regeneran y quedan gateados por el check de CI api-types-fresh. La superficie generada y el server no pueden discrepar sin poner el CI en rojo.

ci · api-types-fresh
 1  $ bun run generate:api
 2  $ git diff --exit-code \
 3      apps/server/openapi.json \
 4      apps/client/lib/api/openapi-types.ts
 5  
 6    openapi.json cambió — los tipos están viejos
 7  ✖ api-types-fresh falló — regenerá y commiteá

Los tres bugs que un repo vacío shippea siempre — acá ya cerrados

Sesiones que sobreviven un reset

El bug recurrente que los reviews de seguridad encuentran en apps generadas por IA: sesiones que no se cierran al cambiar la contraseña — resetéas tu password y el login viejo sigue funcionando. Acá las sesiones son filas server-side en Postgres — cualquiera se puede revocar on demand, y cerrar las sesiones concurrentes al cambiar la credencial es un flag documentado, no un rewrite.

Webhooks que cobran dos veces

El otro clásico es el webhook handler sin idempotencia: cuando Stripe manda el mismo mensaje dos veces (y lo hace), la app cobra o acredita dos veces. Acá las compras son idempotentes sobre externalOrderId, entregadas por un event bus con outbox durable.

Datos de tenant que se filtran

Los agentes IA "generate RLS policies that accidentally expose data to other tenants" (makerkit.dev). Acá un tenant-isolation guard scopeado por org — repos org-scoped más un query guard de Prisma — devuelve 404 entre orgs. Sin RLS que olvidar.

Un harness contra el que tu agente puede auto-verificarse

E2E Playwright en CI

Los flujos golden-path corren en cada PR (bun run e2e:golden). El loop code → test → code que el agente necesita para autocorregirse — con un paso de validación que refleja lo que realmente querés, no lo que parece plausible.

Fronteras DDD, lint-enforced

El layering son reglas de ESLint, no documentación: domain y application no pueden importar frameworks, y los imports cross-context en runtime están prohibidos. La pared que el agente choca es la pared que mantiene tu arquitectura intacta.

Un CLAUDE.md de reglas enforzadas

Un CLAUDE.md viene en el repo — layering DDD, la regla de contratos, disciplina de commits y PRs — para que el agente herede tu pensamiento de largo plazo en vez de promediar el internet público. TypeScript estricto de punta a punta.

Resuelto una vez, para que tu agente solo construya lo tuyo

Auth

BetterAuth — 2FA, magic-link, OAuth, verificación de email, password reset. Sesiones y flujos ya cableados y testeados.

Billing

Stripe, MercadoPago y Polar detrás de una interfaz tipada — checkout, customer portal, cambios de plan, webhooks firmados.

Orgs y RBAC

Organizaciones, miembros, invitaciones, permisos por rol y API keys — multi-tenancy real, no una tabla users con una columna role.

Jobs

Colas, processors y schedulers de BullMQ, con un dashboard de Bull Board para mirarlos.

Events

Un event bus con outbox durable para que los domain events sobrevivan un crash y se entreguen confiablemente.

Observabilidad

OpenTelemetry, Sentry (@sentry/bun), Pino, /metrics — cada uno bootea a no-op hasta que lo configures.

Preguntas de quienes shippean con agentes

¿No alcanza con un CLAUDE.md o un AGENTS.md?+
Eso ya es table stakes — todos los kits shippean uno, y un agente razonea y esquiva una convención blanda. La diferencia acá es el enforcement: las fronteras DDD son reglas de ESLint y el contrato client-server queda gateado en CI. El agente físicamente no puede importar infraestructura desde domain ni driftar el contrato de la API sin poner el build en rojo.
¿Venden velocidad?+
No. Este segmento viene quemado de velocidad sin columna. Estás comprando control: paredes, contratos tipados y CI gates que mantienen al agente adentro. El punto no es ir más rápido el día uno — es no ir más lento al mes seis.
¿Qué stack es?+
Bun + Express + Prisma en el server, Next.js App Router en el cliente, layered en DDD y TypeScript estricto de punta a punta. Un backend de verdad con separación de responsabilidades, no API routes atornilladas a un frontend.
¿Con qué agentes anda?+
Con cualquiera. Los guardrails viven en ESLint, el compilador y CI — no en el archivo de reglas de una sola herramienta — así que Claude Code, Cursor o lo que uses construyen adentro de las mismas paredes.

Apuntá tu agente acá, no a un repo vacío.

Un repo vacío obliga al agente a inventar arquitectura y a repetir los mismos tres bugs de seguridad. Dale paredes que no puede cruzar.