How to create beautiful user-centric products with AI Growomat, a product built with AI coding tools Claude and Codex, outlines a development process that prioritizes a 'harness' of principles, user stories, and testing gates over the models themselves. Citing Stack Overflow's 2025 developer survey, two thirds of respondents cite 'almost right, but not quite' output as a top frustration, while Sonar's State of Code survey reports 96% of developers don't fully trust AI-generated code and barely half consistently verify it. The company's approach includes four principles, a strict user story template, and mandatory end-to-end testing before any feature ships. How to create beautiful user-centric products with AI The models are the easy part. What keeps a product user-centric is the harness around them, from principles and stories to prototypes, tests and gates. Most teams we talk to are stuck on the same question. The new coding tools write code faster than anyone can review it properly, so how do you keep the speed without giving up quality and security? The numbers are worse than most people admit. Stack Overflow's latest developer survey https://stackoverflow.blog/2025/12/29/developers-remain-willing-but-reluctant-to-use-ai-the-2025-developer-survey-results-are-here/ puts the top frustration at output that is almost right, but not quite , named by two thirds of respondents. Sonar's State of Code survey https://www.sonarsource.com/company/press-releases/sonar-data-reveals-critical-verification-gap-in-ai-coding/ found that 96 percent of developers don't fully trust what these tools produce, yet barely half of them consistently check the output before committing it. Writing code stopped being the bottleneck. Verifying it became one, and most teams' processes never caught up. We build Growomat this way every day. Claude and Codex write a large share of our code, and we care a great deal about the product staying beautiful, intuitive and reliable. So here is how we actually work: what we tell the models, what we make them produce before any code exists, and what stands between their output and our customers. We're writing it down so other teams can borrow the parts that work. The short version: the model is the easy part. Everything that matters lives in the harness around it. Four principles It's easy to get lost in the technical detail of software development. Models, prompting tricks, testing frameworks. We start somewhere else, with four principles: Make the complex simple for our users. Every feature is designed with simplicity in mind, and simplicity is verified rather than assumed. Test cases cover web and mobile in each language, we check the screenshots, and we run persona walkthroughs more on those below . Intuitive design. No one reads manuals. Each feature should guide the user and give them a beautiful interface, so navigation makes sense on first contact. Keep documentation and code current. Coding assistants love to add : more code, more docs, another helper with every feature. That means context bloat and more surface area for bugs. Update what exists instead of adding alongside it. Strictly gate every feature on end-to-end testing, security, internationalisation and regressions. We work fast. Nothing ships around the gates. These sit at the very top of our CLAUDE.md, the first file the model reads in every session. Your team's principles will be different. What matters is putting them where your tooling actually picks them up, rather than in a wiki no model will ever open. Directly below them we keep two more things: Structure. The layout of our repositories, the interfaces between them, and where the documentation lives. Scripts and tools. How to start, stop and debug the application, and how to run each of the end-to-end scenarios. Every session then starts the same way. The model knows where everything is, how to run it, how to test it, and what we value. The story comes first, and the test plan comes before the story is done We don't open a feature with technical instructions. We describe the problem we're solving for the customer, and the first thing we ask for is questions: every clarifying question the model has, before it forms any opinion about a solution. That conversation produces a user story on a strict template. The story in one sentence. As a user type , I want goal , so that benefit . If we can't write that line, we've learned something important before writing any code. Context. The problem, the current state of the product, and for fixes, the root cause. Acceptance criteria with IDs , including a No regressions list of existing behaviour that must not break. Internationalisation. Every new user-facing string, named up front with its English value. Test coverage, written before the acceptance criteria are final. The part most teams skip. If we could only keep one section of the template, we'd keep this one. That last one deserves an explanation. The template's default answer is "update an existing spec", not "write a new one". Before a story is accepted we search the suites for the surfaces it touches and name the exact spec files that will change. A new spec file needs justification, which usually means a genuinely new surface with no coverage today. "New specs: none" is a good and common answer, and we state it explicitly so a reviewer can see the question was asked. Two things fall out of this. If nobody can name the tests that will prove a feature, then nobody understands the feature yet, and that is much cheaper to discover before the code exists. The second effect is subtler. The suite stops growing a file per feature, which is the difference between tests that map your product and tests that map your history. Prototype before code Anything with an interface gets a clickable prototype alongside the story: a throwaway page with the real layout, the real copy and fake data. The model builds one in minutes. Design review happens here. Moving a control on a prototype costs nothing, moving it after implementation costs a story. It's also where principle one gets its first real test. If the prototype needs explaining, so will the feature, and no amount of implementation quality will rescue it. The prototype is disposable by design. It never becomes the implementation. It becomes the specification for one. Tests move with the code Code written this fast will rot a test suite that's organised by history, the "tests we added for that feature" pattern. Ours are organised by behaviour instead. Both suites, backend and frontend, use one layout: e2e/ ├── journeys/ FEW: ordered, cross-feature user flows ├── components/