Why We Stopped Letting AI Paint on a Blank Canvas
We rely heavily on AI to write the code for our website and our upcoming mobile app. Using tools like the Kiro CLI gives a small team like ours incredible speed, letting us build out pages and features at a pace that used to require a whole department. But as we kept building page after page, we ran into a frustrating, silent time-killer that anyone engineering with AI eventually hits: design and structural drift.
Because front-end code is inherently heavy—bloated with HTML structure, CSS styling, and JavaScript logic—the files get massive quickly. And the honest truth that nobody tells you is that you can never trust the AI 100%. It will build a beautiful page but randomly forget to include a critical JavaScript library, or completely miss a required header tag. Our QA and manual testing effort became incredibly high. We were spending way too much time reviewing code just to make sure the AI hadn't silently broken something. This was especially painful on mobile, where even a small deviation—a shifted button, a missing dependency—can make your whole site feel broken.
We tried feeding the AI our existing pages as examples, telling it to copy the style, but it would still introduce these tiny, frustrating deviations. It felt like playing a never-ending game of whack-a-mole.
That's when we had a really important realization. Passing a giant page as an example just gives the model too much noise to sift through. It tries to replicate the whole canvas instead of understanding the individual strokes. Left to its own devices, AI loves to reinvent the wheel every single time. The breakthrough didn't come from writing a better prompt; it came from changing how we architected our code.
We realized that if we wanted absolute consistency and a lower testing burden, we had to stop letting the AI work on a blank canvas. We had to modularize our components across both the UI and the backend. We started identifying the common pieces that kept repeating—a specific card layout, a form handler, a data structure—and refactoring them into clean, standalone modules.
The moment we established just one or two of these common patterns in the codebase, the AI's behavior changed instantly. When you present it with a massive, un-modularized file, it handles it with a high degree of randomness. But when the codebase is highly modularized, the AI naturally locks onto those structures. Now, when it needs to write a new page with a similar HTML structure, it doesn't try to invent it from scratch or forget the libraries. It just grabs that existing module. The JavaScript and headers are already baked into the component, so the AI can't leave them out.
By taking the time to refactor early and break our system into modular pieces, we essentially built tracks for the AI to run on. The coding deviations dropped to almost zero, and our testing headache disappeared.
We wanted to share this because we know there are other scrappy developers and small nonprofits out there trying to leverage AI to make a big impact on a tight budget. The lesson we learned is that to achieve true consistency with AI, you can't just let it write raw code. You have to design the patterns first. Once those structural boundaries exist, the AI stops creating chaos and becomes an absolute precision machine, allowing us to keep our web experience perfectly dialed in on any screen while we prepare to launch our dedicated mobile app.