Across my previous articles, I’ve kept coming back to one central argument:
Once UI rendering no longer owns the entire data flow, State, Derived State, Effects, and Async Work can no longer be carelessly compressed into the lifecycle of a single component.
At first, this might sound like a frontend architecture problem:
setState
when it completes, tying its lifecycle directly to the UIBut as I began using AI agents more extensively to implement, refactor, and validate systems, I arrived at a broader conclusion:
Whether an agent understands the semantic boundaries of a system matters far more than how much code it can generate.
Modern AI agents can generate code at remarkable speed. They can create directory structures, complete TypeScript types, write tests, generate reducers, hooks, adapters, and API clients, and even connect an entire feature through a seemingly coherent implementation.
On the surface, this looks very close to automated software development. The danger, however, is usually hidden inside code that works while leaving its semantic boundaries ambiguous.
The code works on the first run, yet nobody can clearly answer a fundamental question:
Who actually owns the data?
Once ownership becomes unclear, several architectural questions turn into invisible time bombs:
When these boundaries are not explicitly defined, a more productive agent does not create a better system. It simply builds an unmaintainable one faster.
If developers themselves do not have a clear understanding of the system’s architectural boundaries, an AI agent will not automatically invent those boundaries for them.
Instead, it will usually follow the most direct and intuitive implementation path:
Data arrives
→ Put it into component state
The data needs to be shared
→ Move it into a global store
Something must stay synchronized
→ Add an effect
Duplicate requests must be avoided
→ Patch together a cache
A race condition appears
→ Add a boolean flag
Stale data becomes a problem
→ Add another timestamp
In isolation, each step seems reasonable. Taken together, however, they gradually erode the structure of the system. State becomes a catch-all container. Effects become a dumping ground for unrelated side effects and synchronization patches. The lifecycle of async work becomes tightly coupled to the UI.
This is one of the biggest blind spots in current AI coding workflows:
We obsess over what AI can write, while ignoring whether it knows what should never be written together.
Many assume that sufficiently detailed prompts will produce a great architecture. That’s only half true. Requirements tell an AI what to do. Architectural boundaries define what must stay separated.
I ran into this distinction repeatedly while building my open-source project, signal-kernel
. When the core semantics of a system are explicit, the improvement goes beyond faster code generation. The agent operates within a much clearer decision space, while the architecture provides a set of natural guardrails.
In signal-kernel
, I deliberately removed control of the data flow from the UI framework:
Once these semantics are encoded into the infrastructure, an AI agent is far less likely to place every responsibility into the same layer. It does not need to guess where state belongs. It does not need to use Effects to repair synchronization gaps. It is less likely to confuse a cache with derived state.
The system’s semantic map already constrains what a valid implementation looks like.
I am not opposed to AI-generated code. Its value in rapid exploration, concept validation, and reducing repetitive implementation work is undeniable.
My main concern with so-called vibe coding has never been that it might produce bugs. Bugs can often be caught through testing. Architectural trade-offs that were never consciously made are much harder to detect. They quietly erode the system over time.
An AI-assembled system often does not hold up under sustained questioning:
If the reasoning behind these decisions cannot be verified or explained, the system is already carrying architectural debt. Such a system may be built extremely quickly while the business logic remains simple.
But once the data flow becomes more complex, the team grows, or the system encounters edge cases involving async timing and cross-boundary synchronization, the architecture begins to collapse.
The system does not lack code. It lacks boundaries.
AI agents have undeniably reshaped software development workflows, but they have not made architectural thinking obsolete. If anything, they've made it far more critical.
As the marginal cost of producing code approaches zero, the value of engineering shifts upward—from producing implementations to defining the constraints those implementations must follow.
Previously, the scarce capability was:
Who can implement the feature?
The increasingly scarce capability is:
Who can define data-flow boundaries, design invalidation contracts, and provide a semantic map that both humans and AI agents can follow?
This is why my work began with the design of a reactive library, moved into questions of Ownership, Render Boundaries, and Async Correctness, and eventually connected to AI agents.
These topics may appear unrelated on the surface.
At the architectural level, however, they all point to the same principle:
In an era when AI can help us write more code, we need to become much clearer about which code should never be written together.