All Field Notes

From Prompting to Engineering: The Maturity Curve of AI-Built Apps

A practical maturity model for moving AI-built apps from fast prompting to guarded repos, production ownership, and learning systems.

AI-assisted developmentProduct maturityEngineering practice

AI-built apps do not need the same kind of help at every stage. Early on, the main job is discovery: figure out whether the product can exist, get a rough interface in front of someone, and see what sticks. Later, the job shifts to keeping what works alive while everything around it keeps changing — even though the tooling looks identical the whole time. Prompting your way through a new feature and engineering a system that can survive the next ten features are fundamentally different activities. (For a scorecard that helps you spot the shift in your own product, see How to Know When Your Vibe-Coded App Has Outgrown the Vibe.)

We reviewed an app recently that had accumulated a remarkable amount of operational machinery: manual scripts, memory notes, reusable agent skills, cron jobs, webhook glue, an internal SQL bridge, a dashboard server, and a handful of systemd units. Individually, none of that was wrong. It showed the team was doing real work and solving real problems. But the operating model had outgrown the way changes were being made. Automation was everywhere; ownership, gates, and observability were not.

That gap is what the maturity curve is about. The useful intervention moves from "prompt better" to "make the repo, runtime, and release process retain what the product has already learned."

Stage 1: Prompting

You're here if: you're still deciding whether the idea works, and every session starts with re-explaining the product to the agent.

This is pure product discovery: figure out whether the idea works, not how it scales. A sharp prompt and a rough description of the target user teach you more here than an architecture diagram — a founder can have a form, a dashboard, and a webhook handler before a traditional team finishes the first requirements call.

The danger is that prompting creates decisions faster than anyone writes them down. A workflow works because the person who prompted it still remembers why. Domain language drifts between sessions, and a script meant to fix one dataset can quietly become the only way to prepare a release — nobody notices until that person is unavailable.

Do not freeze the app too early. But do capture enough to avoid losing the lesson: a short README, named domain terms, the commands that must run, and a line between "throwaway experiment" and "flow we intend to keep."

Stage 2: Prototype

You're here if: a few flows are worth protecting, but "do not break this" still lives in your head instead of a test.

The prototype stage starts when a few flows are worth preserving — users still internal, UI still rough, but the team can point at something and say "do not break this."

Prompt quality still matters, but executable memory matters more: types for the important states, seed data that makes the happy path reproducible, and at least a smoke check so a broken login or import gets caught before someone clicks through the whole app again.

This is also where source-of-truth drift shows up. In the reference app, memory notes described one intended data model while the running system depended on another — normal in a fast prototype, expensive once agents build on whichever note is closest instead of what's actually true.

The right move is not a rewrite. It is a repo map: which table owns this state, which markdown file is just reference material, which script is the approved write path for production data, and which manual steps are still acceptable while the business is actively learning.

Stage 3: Guarded Repo

You're here if: "the agent changed it" no longer feels like a good enough answer to "why did this ship?"

The guarded repo stage begins when every meaningful change needs to be reviewable. "The agent changed it" is no longer a sufficient audit trail.

The major coding-agent platforms have already converged on this idea. GitHub's Copilot coding agent works inside pull requests by design; Anthropic's Claude Code workflows emphasize planning and automation hooks that gate what ships; OpenAI's Agents SDK treats guardrails as first-class primitives. The common thread: agents produce changes, but the repository decides what is acceptable.

In practice, a guarded repo means a default branch that nobody pushes to directly, short-lived feature branches, pull requests with typecheck, lint, tests, and build gates, and project-level instructions that tell agents what they may and may not touch. Whether that instruction layer actually exists in your repo — committed, current, and specific enough for an agent to follow — is exactly what the free Post Code Labs repo audit scores. Equally important are stopping rules. If a change crosses a trust boundary, alters a data shape, modifies deployment config, or touches billing, the agent should be working inside a review path rather than applying changes to the running system.

This is the stage where many AI-built apps feel slow for the first time. That slowdown is not a failure. The product is trading implicit human memory for explicit checks that every future contributor, human or agent, can rely on.

Stage 4: Production Product

You're here if: a bad deploy could hurt a real user, and you're not fully sure what happens when a job fails halfway through.

A production product has users who can be harmed by a bad deploy. Data needs protection. Workflows need to recover predictably when something fails. The question is no longer whether the agent can build the feature — it is whether the team can operate what has been built.

The reference app had an internal SQL bridge protected by bearer authentication and a webhook path that handed work to systemd units — a reasonable shape for internal tooling, but only if the contract is narrow enough to reason about: scoped permissions, request validation, idempotent apply steps, clear logs, and a failure path that does not silently half-apply work. When we see these patterns without those constraints, the automation has usually grown faster than the operational thinking around it.

Release health also becomes measurable at this stage. The DORA metrics — deployment frequency, change lead time, change failure rate, failed deployment recovery time — are worth tracking because they shift the conversation from how impressive a demo looked to how safely the team ships changes to production.

Agent instructions change too. "Implement this feature" is not enough for a production codebase. The instruction needs to name who owns the workflow, which tests to add, which migrations to verify, what observability to preserve, and under what conditions the agent should stop and ask a human.

Stage 5: Learning System

You're here if: you're prompting less and instrumenting more, and repeated mistakes are turning into rules instead of repeated prompts.

There is no "finished" stage. The final level is a system that learns from production instead of relying on folklore and tribal knowledge.

Observability sits at the center here. OpenTelemetry provides a vendor-neutral framework for traces, metrics, and logs, and it matters because AI-built systems tend to fail at the joins between components: a queued job retries too often, a webhook receives an unexpected shape, a dashboard reads stale data, an agent fixes the visible error while leaving the workflow underneath it brittle. Without instrumentation, each failure looks like a new problem. With it, patterns emerge.

What makes a system actually learn is connecting those signals back to the codebase. A failed job should produce an alert, a trace, and eventually a regression test. A repeated support issue should turn into a typed state transition or a validation rule. An agent mistake should become a project instruction or a forbidden pattern in the linter. The repo improves because production keeps handing it evidence about what breaks and why.

In the reference app, an agent kept satisfying new dashboard cards by writing a fresh query straight against the investor table, forgetting that project scope had to be resolved first. Three different route handlers picked up the same missing filter over two months. The fix that stuck wasn't a longer prompt. It was an import-boundary lint rule blocking the raw database client outside the scope resolver, plus one line in the project's agent instructions: Route handlers must call resolveProjectScope() before querying investor or pipeline tables; do not query them directly. The next time an agent reached for the shortcut, the build failed before anyone had to notice the missing filter.

At this level the team is still prompting, but prompts are just one interface into an engineering system that has its own memory. The maturity curve loops: discovery feeds back into the repo, and the repo feeds back into better discovery.

A Compact Maturity Map

The most useful maturity model is not a label for the whole app. It is a working map of which subsystem is allowed to move fast, which subsystem now needs gates, and which subsystem must already behave like production.

SubsystemStageEvidenceNext question
Customer dashboard4 · Production ProductRelease gates, scoped data access, an owner, a rollback path, logs tied to user painCan a broken deploy be traced from user symptom to owner, fix, and recovery?
Internal admin tool2 · PrototypeSmall user set, manual checks, a clear "may break" boundary, no billing writesWhat must be true before this tool is allowed to mutate production records?
Nightly enrichment cron3 · Guarded RepoReviewed config, typed inputs, a dry-run command, idempotent writes, an alert targetWhat happens on a missed run, duplicate run, or half-applied batch?
Webhook-to-worker path4 · Production ProductRequest validation, replay protection, queue visibility, structured failuresDoes every accepted webhook either finish safely or leave a retryable record?
Reusable agent skills and memory notes5 candidate · Learning SystemMistakes become tests, instructions, lint rules, or runbook updatesWhich repeated agent error has not yet become a repo-level guard?

The map is intentionally uneven. A production dashboard next to a prototype admin panel is not automatically a problem. The problem is pretending they deserve the same controls. During a diagnostic, the map tells us where to protect the product, where to preserve learning speed, and where an informal workflow has quietly become infrastructure.

How We Score This in a Diagnostic

When we run a Post Code Labs diagnostic, we are not trying to decide whether an app counts as "AI generated" or "real engineering." We are trying to figure out which maturity stage each part of the system is actually in.

We look for evidence across architecture, type safety, runtime validation, tests, CI/CD, agent instructions, security boundaries, deployment, observability, and developer workflow. That review is the full Post Code Labs consultation, which scores twelve categories this way: each area gets a pass, partial, or gap, with the associated risk and a concrete next action. The output is a 30-60-90 plan: what to keep moving, what to guard right now, and what to consolidate before the next round of features.

Almost every app we review is a mix — a production-critical dashboard next to a prototype admin tool, a cron job with better discipline than the webhook that triggers it. The diagnostic is useful precisely because it stops treating the whole codebase as if it were at one maturity level.

What to Do Next Monday

Start with a small audit, not a rewrite.

  1. List every operational entry point: manual scripts, cron jobs, webhooks, background jobs, dashboards, SQL consoles, agent skills, and systemd or platform units.
  2. For each critical workflow, name the source of truth and the only approved write path.
  3. Put agent work behind a branch and pull request loop for any change that affects users, data, billing, deployment, or security.
  4. Add one release gate before adding another feature: typecheck, lint, a smoke test, a migration check, or a build step.
  5. Instrument one critical path so a future failure leaves traces, metrics, logs, and a clear owner rather than another prompt archaeology session.

None of this means you should stop prompting. The goal is to make prompting one part of a system that keeps its promises long after the original prompt is forgotten.

References