For AI-native developers
The SaaS base
your AI agent can't break
You're not buying code your agent can already write. You're buying the guardrails it can't write for itself: the walls that stop it breaking your login when it touches payments — enforced by the compiler and CI, not a soft convention it can rationalize past.
The agent sees a slice, and edits confidently anyway
Every session, your agent sees only part of the project — so it changes code without knowing what elsewhere depends on it. Month one feels electric. By month six the same tool is slower than before, because tech debt isn't paid down, it's added to, and eventually collected. A blank repo makes it worse: with no patterns to hold on to, the agent drifts toward its own defaults and quietly erodes the architecture. By prompt 50 it's spaghetti.
In the words of people shipping with agents
Debt that gets collected later
"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)
No consistent patterns to hold
"llm code has none of that [consistent patterns], if yes its by pure chance that won't repeat." — kakacik, Hacker News (item 45405177)
The security edge cases it misses
AI agents "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." — MakerKit blog
Walls the agent physically can't cross
Point your agent at the domain layer and tell it to just import Prisma there. It can't — ESLint fails the build. Compiler-and-lint-enforced DDD boundaries mean domain code cannot import Express, Prisma, or infrastructure. This isn't a soft AGENTS.md suggestion the agent can reason its way around. It's a wall in CI.
1 modules/billing/domain/subscription.ts
2 import { prisma } from '@prisma/client'
3 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 error no-restricted-imports
5 domain/ must remain framework-agnostic.
6 See ADR-001.
7
8 ✖ 1 problem — CI blocked
Payload drift, caught before it ships
The agent renames a field on the server and forgets the client. Type drift a compiler catches. But payload drift — the form sends fullName, the server wants name — sails through typecheck and 400s in production. Here, client Zod schemas import from a shared @app/contracts package, and openapi-fetch types are regenerated and gated by the api-types-fresh CI check. The generated surface and the server can't disagree without turning CI red.
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 changed — types are stale
7 ✖ api-types-fresh failed — regenerate & commit
The three bugs a blank repo ships every time — already closed here
Sessions that outlive a reset
The recurring bug security reviews keep finding in AI-generated apps: sessions that do not log out on password change — you reset your password, but the old login token still works. Here sessions are server-side rows in Postgres — every one can be revoked on demand, and ending concurrent sessions on a credential change is a documented flag, not a rewrite.
Webhooks that double-charge
The other classic is the webhook handler that is not idempotent: when Stripe sends the same message twice (which it does), the app charges or credits the user twice. Purchases here are idempotent on externalOrderId, delivered through a durable outbox event bus.
Tenant data that leaks
AI agents "generate RLS policies that accidentally expose data to other tenants" (makerkit.dev). Here an org-scoped tenant-isolation guard — org-scoped repos plus a Prisma query guard — returns 404 across orgs. No RLS to forget.
A harness your agent can vibe-check itself against
E2E Playwright CI gate
Golden-path flows run on every PR (bun run e2e:golden). The code → test → code loop the agent needs to self-correct — with a validate step that reflects what you actually want, not what looks plausible.
DDD boundaries, lint-enforced
The layering is ESLint rules, not documentation: domain and application layers cannot import frameworks, and cross-context runtime imports are forbidden. The wall the agent keeps hitting is the wall keeping your architecture intact.
A CLAUDE.md of enforced rules
A CLAUDE.md ships in the repo — DDD layering, the contracts rule, commit and PR discipline — so the agent inherits your long-term thinking instead of averaging the public internet. TypeScript is strict end to end.
Solved once, so your agent only builds what is yours
Auth
BetterAuth — 2FA, magic-link, OAuth, email verification, password reset. Sessions and flows already wired and tested.
Billing
Stripe, MercadoPago, and Polar behind one typed interface — checkout, customer portal, plan changes, signed webhooks.
Orgs & RBAC
Organizations, members, invitations, role-based permissions, and API keys — real multi-tenancy, not a users table with a role column.
Jobs
BullMQ queues, processors, and schedulers, with a Bull Board dashboard to watch them.
Events
A durable outbox event bus so domain events survive a crash and deliver reliably.
Observability
OpenTelemetry, Sentry (@sentry/bun), Pino, /metrics — each boots to a no-op until you configure it.
Questions from people who ship with agents
Isn't a CLAUDE.md or AGENTS.md enough?+
Do you sell speed?+
What stack is it?+
Which agents does it work with?+
Point your agent at this, not a blank repo.
A blank repo forces the agent to invent architecture and repeat the same three security bugs. Give it walls it can't cross instead.