The pattern behind every AI-built mess

AI writes the code.
Nobody writes the architecture.

It doesn't matter which tool wrote it: code generated prompt by prompt accumulates without structure until, somewhere around month six, velocity goes negative. One developer's retrospective after six months of vibe coding ended with 40% of the codebase rewritten and technical debt up 340%. The tools automated coding — not software engineering. useDeploy supplies the engineering: architecture as enforced walls, contracts as CI gates, and a foundation agents can build on without being able to dissolve.

The debt curve every AI codebase rides

The pattern is tool-agnostic because the cause is. A language model generates code that is locally plausible — each function reasonable on its own — with no global design connecting one generation to the next. Structure is exactly the thing prompting can't accumulate. The debt this creates doesn't announce itself: "Tech debt isn't paid down, it's being added to, and at some point in the future it will need to be collected" (news.ycombinator.com). The collection date comes fast — one developer's widely shared retrospective after six months of vibe coding ended with 40% of the codebase being rewritten while technical debt grew 340% — and when it arrives, the tools can't help: past a certain size, the AI that built the codebase can no longer reliably refactor it, because it has outgrown the model's effective context window (morphllm.com). A Hacker News thread compressed the whole situation into one line: "We have automated coding, but not software engineering" (news.ycombinator.com). The engineering is the missing input. It has to come from somewhere the model isn't.

The universal symptoms

Velocity turns negative

Features that took an hour in month one take a week in month six — the widely reported arc where teams end up slower than before they adopted AI tooling.

Change amplification

Every feature touches everything, because nothing was ever isolated. The cost of a change tracks the size of the codebase, not the size of the change.

Duplication as the default

With no visible structure to reuse, each generation re-solves solved problems — slightly differently — until no two code paths agree on anything.

Logic without an address

Ask where pricing is decided and the honest answer is 'everywhere'. No canonical home means every bug hunt is a full-codebase search.

The refactor that can't happen

The human never read all the code; the agent can no longer fit it in context. Nobody left in the loop can restructure the system safely — so nobody does.

Walls, gates, and one address for everything

Every failure mode on this page has the same root: logic without an address, and edits without a gate. A bounded context solves the first — pricing rules live in billing's domain layer, and ESLint fails the build if that layer reaches for Express or Prisma. The CI gates solve the second: boundary lint, the api-types-fresh contract check, 450+ tests, and a Playwright end-to-end suite run on every PR, so an agent's edit either respects the structure or never merges. Walls plus gates is the entire trick — and neither one is a convention.

modules/billing — one bounded context
 1  modules/billing/
 2  ├── domain/            # pricing rules, invariants
 3  │     · no express, no @prisma/client —
 4  │       ESLint fails the build on contact
 5  ├── application/       # use cases + ports
 6  ├── infrastructure/    # Prisma repos, providers
 7  └── interfaces/http/   # routes + Zod schemas
 8  
 9  gates on every PR:
10    ✓ boundary lint    ✓ api-types-fresh
11    ✓ 450+ tests       ✓ Playwright E2E

What useDeploy ships against each failure mode

Against drift: walls in the linter

ESLint flat-config enforces the DDD layering — domain code importing express, @prisma/client, or infrastructure fails CI. Architecture stops being a suggestion.

Against payload rot: contracts in CI

Shared Zod schemas in @app/contracts, a typed openapi-fetch client, and the api-types-fresh gate that blocks merges when server and client payloads diverge.

Against regression: a suite with teeth

450+ tests plus a Playwright end-to-end gate. Every merge proves the system still works; nothing ships on vibes.

Against inline side effects: the outbox

An event bus with a durable outbox moves emails, webhooks, and syncs out of request handlers — durable, retryable, observable.

Against sprawl: bounded contexts

iam, tenancy, billing, storage, ai, and webhooks as separate modules with four layers each. Every piece of logic gets exactly one address.

Against context loss: written architecture

An operative CLAUDE.md and docs at /docs mean every agent session starts from the system's actual rules — not from the model's statistical defaults.

The way out, whatever tool got you here

The playbook is the same whether the mess came from an app builder, an editor agent, or a CLI. First, stop compounding: every prompt against the old base adds interest to the debt. Second, inventory behavior, not code — list what the app does for users, because that list is what you're preserving; the code was never the asset. Third, stand up the foundation: useDeploy ships the commodity layers — auth, orgs, billing, storage, AI plumbing, webhooks — as tested modules, so the port starts from 'features only'. Fourth, move product logic one domain at a time, driven by whatever agent you already use; the boundary lint, the contract gate, and the test suite verify each step, which is precisely the verification the original build never had. Keep your favorite tool for the front-end; keep prompting; keep the speed. What changes is the division of labor: the agent builds what you're building, and the foundation decides how it's built.

Frequently asked questions

Is AI-generated code inherently bad?+
Line by line, it's usually fine — plausible, idiomatic, locally correct. What's missing is global structure: no consistent patterns connect one generation to the next, and as one Hacker News commenter put it, when consistency does appear "its by pure chance that won't repeat". The gap isn't coding skill; it's engineering.
Can't I prompt the AI to refactor its own mess?+
This is the doom loop: by the time the mess is worth refactoring, the codebase has outgrown the model's effective context window (morphllm.com) — the agent can no longer see enough of the system to restructure it safely. Refactoring requires a global view; generation never needed one. That asymmetry is why the debt collects instead of clearing.
Why a structured base instead of paying someone to clean up?+
Cleanup shops typically quote their rescues in the thousands of dollars — and without structural enforcement, the same debt re-accrues the day you resume prompting. A base with walls fixes the cause: the agent keeps building, and the boundaries, contract gates, and test suite keep the structure from dissolving again.
Which AI tools does this work with?+
All of them, because the walls are tool-agnostic. ESLint boundaries, the api-types-fresh contract gate, and the test suite run in CI no matter who — or what — wrote the diff. The repo also ships an operative CLAUDE.md plus architecture docs at /docs, so agents start each session from the rules instead of their defaults.

One license. Two ways to own it.

CORE

Founder

$99one-time

A frozen snapshot of UseDeploy. Yours forever, no updates.

  • Frozen-version zip download
  • Full source, commercial use, unlimited projects
  • All 800+ tests · all docs pages
  • 14-day refund
RECOMMENDED

LATEST + UPDATES

Lifetime

$199$249one-time

Always the latest UseDeploy. Re-download every release, free.

  • Latest-version zip — re-downloadable forever
  • Every future release at no extra charge
  • Priority Discord support
  • All 800+ tests · all docs pages
  • 14-day refund

Automate the coding. Keep the engineering.

useDeploy is the foundation the agents skip: DDD modules, lint-enforced boundaries, typed contracts, 450+ tests, and an E2E gate — so month six looks like month one.