·
20 min read
The AI Dream, Hold the Spaghetti
There is a common picture of AI-assisted software development now: a developer describes a feature in plain English, an agent writes the code, updates the schema, adds tests, deploys the result, and hands back something that is close enough to production to be useful immediately. That picture is not fiction. Enough pieces of it are already real that it has moved well beyond demo territory.
What is still easy to miss is where the real constraint lives. The limiting factor is usually not the model’s ability to generate code. The limiting factor is whether the repository, deployment process, test suite, and review workflow can absorb a higher rate of change without becoming unstable. In other words, the important question is not whether AI can write code quickly. It clearly can. The more useful question is whether your system can stay coherent when more code arrives, more often, from more contributors, human or otherwise.

The more time I spend using AI in real projects, the less I think prompt engineering is the central story. Clear prompts matter, examples help, and good constraints improve results. But the strongest multiplier is still the environment around the prompt: the repo structure, the conventions, the test boundaries, the deployment path, the branch strategy, and the review standard. Those are the things that define what “acceptable change” means.
If those systems are weak, AI can still increase output, but it will often increase entropy at the same time. If those systems are solid, AI becomes much more useful because it is operating inside a framework that narrows the range of bad decisions. That is the core argument of this post: a structured foundation is the difference between a scalable repository and a spaghetti mess. AI does not reduce the need for discipline. It increases the value of discipline because it increases the speed at which changes can enter the codebase.
I started from a cautious place
I did not arrive at this as an evangelist. My starting point was skepticism, and I still think skepticism is the right default. AI coding tools are often presented through highly compressed demos that show a successful first draft without showing the operational cost of trusting the result. They show code appearing quickly, but not the ongoing maintenance cost, the review load, or the quality of the surrounding architecture.
Because of that, I started with tasks where the downside was relatively contained. One of the first places I used AI seriously was test generation. That was a comfortable entry point because test code often contains a lot of repetition and setup, and because the review boundary is usually clearer than it is for production logic. If I already understood the behavior that needed to be specified, AI could often draft a useful first pass: arrange inputs, stub dependencies, generate cases, and save time on boilerplate.
The important part was not that the first pass was perfect. The important part was that the output was easy to evaluate. I could ask whether the test captured the intended behavior, whether the edge cases were relevant, whether the assertions were meaningful, and whether the resulting test increased confidence or merely added noise. That distinction matters because one of the first practical lessons I learned was that AI is easiest to use safely when the output enters a system that already has a clear definition of “correct enough.”
Tests gave me that definition. A test either described the right behavior or it did not. It either failed in a useful way or it did not. It either improved the suite or made it noisier. That made AI much easier to use productively, and it moved me from broad skepticism to cautious interest.
The safest early use of AI is usually not where it is most impressive. It is where the output can be checked against a clear, pre-existing standard.
The first clear wins were integration work
The next place AI became genuinely useful was third-party integration work. Integration tasks are often less about inventing new algorithms and more about translation. You read vendor documentation, map their terminology to your own domain model, work through authentication details, reconcile payload shapes, set up retries and webhook handling, and gradually build an internal interface that makes the external system feel native inside your codebase.
That is a strong use case for AI, not because the model understands the business better than the developer, but because it can help process a large amount of external detail quickly. It can summarize docs, draft adapter code, sketch event handling, propose schemas, and surface the kinds of follow-up questions that need to be answered before an implementation is ready. In practice, it can save a substantial amount of time during the “get me to something reviewable” phase.
This was where I first started seeing real leverage. AI could take a pile of documentation and produce a draft integration layer that was not production-ready, but was often much better than a blank file. That is a meaningful difference in delivery work. The key, again, was that the result still entered an existing system with naming conventions, type expectations, deployment assumptions, and a human reviewer who understood what “done” actually meant.
At that point, I was no longer asking whether AI had value in software delivery. It clearly did. The question changed into something more operational: how do you scale that value without letting the repository lose its shape?
| Use case | Why AI helped | Why it stayed manageable |
|---|---|---|
| Test drafting | Reduced repetitive setup and case scaffolding | Behavior could be checked against expected outcomes |
| Third-party integrations | Accelerated translation from docs to internal code | Existing repo conventions and review standards narrowed acceptable solutions |
| Small implementation spikes | Produced a fast first pass for bounded work | Branches and tests made it easy to compare and reject bad approaches |
The real constraint is change management
People often talk about AI as though the main goal is simply more code per hour. That is not wrong, but it becomes misleading as soon as the project matters. Most teams do not slow down because they run out of ideas or because physically typing code is the bottleneck. They slow down because changing the system feels risky. Releases are tense, bugs are expensive, regressions are hard to isolate, and parts of the repository become politically difficult to touch.
AI changes the economics of generating code, but it does not remove the economics of maintaining a codebase. In practice, it can make them more visible. A human engineer can only create so many large, inconsistent, partially reviewed changes in a day. An AI-assisted workflow can produce far more. If the repository is not built to absorb that velocity, the extra output does not translate into durable progress. It translates into review fatigue, hidden breakage, and a gradual loss of trust in the codebase.
This is where a lot of AI discourse becomes too shallow for real delivery work. It treats code generation as the win condition. In practice, code generation is just the opening move. The real win condition is whether the software can continue to change without becoming fragile. The more AI I used, the more obvious it became that the repository itself was becoming the key piece of infrastructure: the conventions, the scripts, the CI checks, the deployment process, the branch boundaries, the defaults, and the quality of the debugging feedback. That is the sandbox in which AI operates, and if the sandbox is poor, the best prompt in the world will not save the result.
AI increases the rate of change. If the surrounding system cannot process change cleanly, the speedup is mostly cosmetic.

The failure modes showed up quickly
In actual use, two categories of failure kept showing up.
The first was overly broad code changes. AI tends to be “helpful” in a way that often looks like a quiet refactor. You ask for one feature and it decides that adjacent patterns could be standardized, naming could be cleaned up, duplication could be reduced, validation could be moved to a different layer, or some shared helper could be introduced. Sometimes those changes are reasonable in isolation. Sometimes they are even improvements. But a codebase is not maintained in isolation. It is maintained inside real timelines, review limits, deployment expectations, and the existing mental model of the team. A change can be technically cleaner and still be operationally worse if it expands the review surface or makes it harder to tell whether the original request was actually completed.
The second category was configuration drift presented as confidence. This is often more subtle and, in some cases, more expensive. AI will sometimes suggest or apply configuration changes that look modern or convenient but carry real consequences later. It might alter build scripts, change tool defaults, add assumptions about a specific hosting model, introduce operating-system-specific path handling, or lean toward a managed dependency simply because that pattern appears frequently in its training distribution. None of those choices are necessarily wrong on their own, but they are often made without enough awareness of the project’s operational constraints.
The important point is that these two failure modes are best solved the same way. The answer is not endless prompting tricks. The answer is a repository with clear boundaries, meaningful tests, predictable scripts, deliberate configuration, and a deployment path that everyone respects. That does not eliminate bad changes, but it narrows the range of bad changes and makes them easier to spot.
| Failure mode | How it usually appears | What reduces the risk |
|---|---|---|
| Scope creep in code changes | One requested feature turns into a partial refactor | Smaller tasks, tighter branch boundaries, disciplined review |
| Configuration drift | ”Helpful” changes to scripts, tooling, or hosting assumptions | Explicit deployment model, documented conventions, stable scripts |
| Shallow validation | Tests exist, but only satisfy appearances | Meaningful test boundaries and reviewers who understand behavior |
| Dependency creep | New package or service added for a narrow problem | Architectural standards and a bias toward simpler defaults |

What a practical foundation actually looks like
When people hear “strong code foundation,” they sometimes imagine heavyweight process or enterprise architecture theater. That is not what I mean. In most cases, a useful foundation is much more practical and much less glamorous.
It starts with repository structure. People should be able to tell where things belong. Features should follow recognizable patterns. Shared code should live in obvious places. Naming should be consistent enough that new work does not feel like a negotiation every time.
It includes a real deployment path. Not a vague intention to deploy later, but a repeatable route from source control to a running environment. A project that only “works on one machine” is not ready for AI to increase its change volume.
It includes tests where they create leverage. That does not mean flooding the codebase with low-value checks. It means having enough coverage around important behavior that the project can answer “what broke?” with something better than guesswork.
It also means configuration is deliberate. Scripts are understandable, dependencies exist for a reason, and environment assumptions are known. Cross-platform issues are handled intentionally rather than by accident.
Finally, it means review is real. A branch should be scoped narrowly enough that a reviewer can understand what changed, why it changed, and whether the result matches the request. If review turns into skimming a giant AI-generated diff and hoping the tests are enough, governance has already weakened.
One more piece matters here and tends to be undervalued: feedback quality. Logs, error messages, build output, and CI failures should be informative enough to support debugging quickly. If AI is going to help accelerate change, the system has to emit useful signals when that change goes wrong.
AI is best understood as an amplifier of repository standards. If the standards are good, the upside compounds. If the standards are weak, the confusion compounds.
The workflow change that made AI more useful
The biggest shift in my own use of AI happened when I stopped thinking of it as a single assistant and started thinking of it as a set of contributors that needed management. That sounds simple, but it changed the workflow substantially.
Instead of asking for broad, all-at-once implementations inside one context window, I moved toward isolated workspaces, separate branches, and reviewable chunks. I wanted to compare alternatives without polluting the main branch. I wanted each piece of work to have a clear objective and a clear boundary. I wanted something that looked much closer to how healthy software teams already operate.
That made AI dramatically more useful. Once branches became the default unit of isolation, the output became much easier to reason about. A well-scoped branch says that one contributor, human or agent, worked on one problem in one bounded space with one clear success condition. That makes it much easier to inspect the result, run tests, reject bad approaches, and merge good ones without inheriting a surprise theory of how the entire codebase should be reorganized.
This is also how it becomes possible to have multiple agents working asynchronously on the same machine without creating constant overlap. One agent can draft tests, another can spike an integration, another can explore an implementation option in a sandbox, and another can update supporting docs or content. The point is not parallelism for its own sake. The point is that each agent has a lane, and the lane keeps the resulting work reviewable.
I increasingly think this is the right mental model: treat AI agents more like employees than like vending machines. A capable contributor still needs context, constraints, standards, and review. In fact, the more capable the contributor, the more important the surrounding operating model becomes. Good engineering organizations are not built by hoping everyone improvises in the same direction. They are built by giving smart contributors a structure in which their output becomes additive instead of chaotic.

Review becomes more important, not less
There is a recurring fantasy that better models will eventually remove the need for review. There may be narrow classes of work where that becomes partly true, but for most application development I think review is becoming more valuable, not less.
The reason is straightforward: local correctness is not the same thing as system correctness. A piece of code can compile, pass a narrow test, and still be a poor fit for the repository. It can violate conventions, quietly increase coupling, add an unnecessary dependency, or solve the immediate task in a way that makes the next six tasks harder. Review is where those issues get caught.
This is also why change size matters so much. Large AI-generated diffs are not just annoying. They weaken review quality because they make deep understanding unrealistic. If a change touches twenty files, rewrites configuration, updates tests, and introduces a new helper pattern all at once, most reviewers will skim rather than fully inspect it. The tests may pass, but that does not mean the system is becoming easier to maintain.
Small pull requests are not just good git hygiene. They are one of the main ways to keep AI-assisted development from overwhelming the governance of the codebase. If a reviewer can read the diff, understand the intent, verify the behavior, and merge confidently, AI has saved time. If the reviewer has to reverse engineer what the agent thought it was doing, the supposed time savings disappear quickly.
The deployment process is part of the prompt
One of the most useful mental models I have adopted is that the deployment process is not downstream from the coding workflow. It is part of the coding workflow. In practical terms, that means AI should not be working against an imaginary future environment. It should be working inside a repository whose route to production already exists.
That matters because deployment constraints shape good code. If the application will run on a VPS, that matters. If the business wants low recurring costs, that matters. If the system needs to remain portable across hosting providers, that matters. If multiple developer operating systems need to be supported, that matters. A surprising amount of “nice looking” code turns out to be a poor fit once it collides with the environment that actually has to run it.
A lot of bad software decisions happen because implementation is treated as an abstract exercise while deployment is deferred into a vague “later” phase. AI can make that mistake very efficiently. It is optimized to complete the task in front of it, not to feel discomfort about future operational complexity. If nobody tells it that portability, simplicity, or hosting constraints are core requirements, it may produce something that is locally elegant and operationally awkward.
A repository with a real deployment process changes that. It teaches both humans and AI what counts as an acceptable change. It narrows the solution space, and that is usually a good thing.
| If this is undefined… | AI tends to optimize for… | What usually happens later |
|---|---|---|
| Hosting model | Familiar patterns from common stacks | Hidden lock-in or avoidable infrastructure complexity |
| Cross-platform support | Whatever works in the local example | Friction across Windows, macOS, or Linux workflows |
| Cost constraints | Convenience and integration speed | Higher recurring spend and harder migrations |
| CI and deployment rules | Fast local completion | Breakage or drift between local and production environments |
This is also why I think many teams are going to rediscover the value of simpler infrastructure. If AI reduces the cost of feature implementation, then operational complexity becomes a larger share of the real problem. The code arrives faster, which means the surrounding system needs to be calmer, not noisier.

What goes wrong when people skip this step
If AI is used aggressively inside a codebase with weak boundaries, the results can look productive for a while. Features appear, demos happen, and the backlog moves. The problem is that the second-order effects take longer to show up.
Patterns begin to drift because no default was ever made explicit. Tests become shallow because the path of least resistance is to generate enough assertions to satisfy appearances. Build scripts accumulate exceptions. Configuration starts depending on undocumented local assumptions. The application may continue to work, but the internal logic of the repository becomes harder to explain and harder to trust.
Eventually the team feels this everywhere. Pull requests slow down because reviewers do not trust the surface area. Bugs take longer to isolate because the system has too many surprising pathways. Infrastructure changes feel riskier than they should. Nobody can fully tell which decisions were deliberate and which were accidental byproducts of a productive session with an assistant.
That is what I mean by the spaghetti problem. It is not just ugly code. It is organizational confusion made visible in a repository. Work still gets done, but every future change drags more uncertainty behind it. AI does not create that risk from scratch. Teams have always been capable of building messy systems. What AI changes is the rate of accumulation. It becomes much easier to add more code before the project has developed the discipline required to absorb it.
This is why I think the mature question is not “How do we get AI to write more code?” The mature question is “What kind of repository can safely metabolize AI-generated change?”
The human role becomes more managerial
I like this framing because it is honest about where the human still adds the most value. The human decides what problem is worth solving, what trade-offs are acceptable, what standards define quality in this repository, and what work is safe to merge. The human sees when a local optimization hurts the broader system, when a dependency is unnecessary, when a refactor is mistimed, or when a configuration change quietly locks the team into a corner.
That is management work. It is technical management, but it is management all the same. For experienced engineers, that should not sound foreign. A large portion of software work already involves decomposition, prioritization, code review, environment design, and risk control. AI simply makes those skills more central because raw code production is becoming less scarce.
That does not mean coding skill stops mattering. It still matters a great deal. Someone still needs enough technical depth to recognize good structure, spot weak assumptions, and correct subtle mistakes. But the leverage shifts toward the engineer who can create a clean repository, define effective constraints, write meaningful tests, break work into reviewable units, and manage multiple contributors inside a disciplined workflow.
The durable advantage is not having the most aggressive AI workflow. It is having a repository and operating model that make aggressive workflows safe.
This is why Seraph Peak’s offer looks the way it does
This is also why Seraph Peak’s offer looks the way it does. We are not especially interested in building software that looks good in a launch announcement and becomes frustrating to maintain six months later. We are interested in building the kind of core that continues to pay off as the product grows, the team changes, and the tooling around it keeps evolving.
That means we care a great deal about the foundation before encouraging anyone to scale up AI-assisted development around it. We care about having a real deployment process early, choosing the simplest infrastructure that fits the actual problem, maintaining type safety and meaningful tests, and keeping conventions clear enough that the repository can be operated and extended without tribal knowledge.
This matters especially for small businesses and early-stage products. Those teams feel pressure from both directions. They need to move quickly and prove that the product is viable, but they are also being told that if they are not automating aggressively with AI, they are already behind. I think both extremes are mistakes. Rejecting AI entirely leaves useful leverage on the table. Piling AI on top of a weak foundation creates a brittle system faster.
The better approach is to build an environment where AI can be useful without becoming destabilizing. For some clients, that means a simple static site and content workflow. For others, it means a full-stack application with clear domain boundaries, repeatable deployments, and strong review practices. For others, it means corporate infrastructure that needs to remain reliable and understandable while the business grows.
The common thread is not a specific framework or hosting provider. The common thread is that the foundation has to be structured enough to support growth, change, and increasing use of AI tooling without dissolving into confusion. In plain terms, we try to build the kind of environment where AI becomes an asset instead of a liability.
The opportunity is real, but it needs structure
I do think the opportunity here is real. We are moving into a world where one person, or a very small team, can coordinate a surprising amount of output. AI will continue to improve at drafting, scaffolding, exploring options, writing tests, and implementing bounded tasks inside established systems. Asynchronous agent-based workflows are likely to become normal in more teams.
But the teams that benefit most from that shift will not be the ones that let AI touch everything first. They will be the ones that build repositories and deployment pipelines capable of channeling AI output into something coherent. That is the difference between speed as a demo and speed as an operational advantage.
If I were reducing the whole argument of this post to one practical question, it would be this: if the rate of change entering your repository doubled tomorrow, would the system become stronger or shakier? If the honest answer is “shakier,” that is not a reason to avoid AI. It is a reason to invest in the foundation before the mess compounds.
That work is not especially glamorous, but I think it is one of the highest-return decisions a team can make right now. The future is not simply faster code generation. The future is faster change, and faster change only becomes an advantage when the underlying system can hold its shape.
If you want help building that kind of foundation, whether for a static site, a full-stack product, or the infrastructure around a growing business, email us at [email protected]. Seraph Peak can help you create the codebase, deployment process, and operating model that let your idea scale without turning into spaghetti.