What I found when I stopped reading about AI

AI development becomes more reliable when models work from a clearly governed source of truth instead of scattered prompts and files. An atomic design approach gives those models reusable, predictable building blocks. Together, source-of-truth models, atomic design, and design systems turn AI output into a coherent product practice.

For the first time in years, I had nothing on my calendar. My last job had ended, a sabbatical had started, and for once the most demanding thing on my schedule was deciding what to do after the morning surf. I had spent the previous decade managing design — at one point running it for one of the largest UX consultancies in the country, with around a hundred and twenty-five designers and full responsibility for everything that carried the word design or research on it. That job teaches you many things. Building things with your own hands is not one of them.
So I did something slightly stupid on my first free morning. I decided to build a new portfolio in a language I didn't know, on a framework I had never touched, and to use AI as both my contractor and my teacher. I want to be honest about why, because the why turns out to matter more than anything I built. I was not trying to prove a thesis to the industry. I was trying to find out, for myself, what this technology actually feels like once you take away the conference slides and the quarterly reports and the breathless threads, and you simply sit down and ask it to make something real with you. I had spent a long time being briefed on AI. I wanted to be surprised by it.
There is a particular kind of person this essay is written by, and I should name it so you can calibrate your skepticism accordingly. I started out as a creative developer in the Flash era, moving freely between drawing something and making it move, back when that was an ordinary thing for one person to do. Two decades of specialization slowly took that away. My roles got bigger, my hands got further from the work, and the ability to explain an idea and then immediately turn it into something you could click became a memory I was a little nostalgic about. Not nostalgic enough to spend a cold winter relearning to code from scratch. But nostalgic enough that, given an open calendar and a head full of other people's opinions about AI, I wanted to see whether the machine could give that ability back.
What follows is not a manifesto. I am not going to tell you how software must be built from now on. I built one thing, alone, at a deliberately small scale, and most of what I have to offer is a set of field notes from someone who went further down a strange path than was strictly reasonable, because time, for once, did not matter. Take it as that. If it is useful, use it. If it is obvious to you, you have probably already lived it.

The barrier fell, and that was the least interesting part

The beginning was almost insultingly smooth. I opened the editor, connected the account, and before my coffee was gone the workspace existed, routing worked, pages rendered, and I could start hanging actual functionality on the skeleton. The entry barriers that normally make learning a new stack a grind — the setup, the boilerplate, the thousand small unfamiliar decisions — mostly evaporated. I chose SolidJS and TypeScript and a single-page architecture with a dual-slot arrangement for clean transitions, mostly because it sounded right, and the machine simply rolled with it. For about a month I played. Animations, shaders, transitions, type effects, particles, a little physics, the whole how-does-this-even-work phase that I had not been allowed to indulge in for years. It was pure joy, and I am suspicious of pure joy, so eventually I made myself stop playing and try to be productive. That is where it got interesting, which is a polite way of saying that is where it got hard.
I want to be careful here, because the smoothness of that first month is exactly the part everyone writes about, and it is the part that matters least. Yes, the barrier to entry has fallen through the floor. A person with no working knowledge of a language can stand up a real application in an afternoon. That is genuinely remarkable and also, by now, genuinely unremarkable — everyone has seen the demo, everyone has felt the rush, and the rush tells you almost nothing about whether you can build something you would be willing to put your name on. The honeymoon is real. It is also not the story. The story starts the moment you decide the thing has to be good, and good repeatedly, and good in a way you can defend three weeks later when you have forgotten why you made half the decisions you made.

Quality in equals quality out, until that stops being true

My first real mistake was trying to build while the design was still moving. Terrible idea, and the machine punished it immediately, though not in the way I expected. It did not refuse. It did not flag the ambiguity. It simply filled every gap I had left open with a decision of its own, cheerfully and confidently, and so my layouts drifted, my patterns wandered, components evolved in directions I had never asked for, and the output kept being not wrong, exactly, but not mine.
After a few painful restarts the first lesson arrived, and it arrived with the weight of something obvious in hindsight. The quality of what came out was governed, almost ruthlessly, by the quality of what went in — and not just visually. Structurally. The designs had to be finished. The auto layouts had to be clean. The tokens needed real semantic meaning rather than decorative names. The naming had to be consistent, the rules had to be explicit, the file structure had to be predictable. Every increase in discipline on my side produced a visible increase in quality on the machine's side. For a while this was deeply encouraging, because it was fair. It behaved like a contract I understood. The better the system I handed over, the better the implementation I got back, and there were even stretches that felt luxurious — building configuration panels for genuinely complicated animation behavior in a fraction of the time it would have taken me to learn how to do it by hand.
And then the contract quietly broke. The more I refined the input, the more I started to notice that the models were not learning my system. They were following it. There is a difference, and the difference is the whole problem. Following holds right up until the moment it doesn't, and there is no warning at the boundary. Even with highly structured input, the thing would drift. It left dead code behind. It accumulated small debts that compounded. It made architectural choices that solved the paragraph in front of it while quietly damaging the chapter. And so I refactored. Again, and then again, and then again after that, until refactoring started to feel less like maintenance and more like a tax I was paying for the privilege of progress.
Eventually I understood that I had been blaming the wrong thing. It was not, by then, a question of input quality. I had made the input very good. The real issue was that the goal had grown more complex than the system that was supposed to guide it. There were too many decisions, too many dependencies, too many edge cases living in the gaps where I had not written an explicit rule — and wherever a rule did not exist, the machine wrote one for me, on the spot, according to logic I could not see and would not have agreed to. Sometimes the results were surprisingly good. Most of the time they were simply different from what I intended, which is its own kind of expensive.
That was the moment my curiosity changed direction. I stopped being interested in the model and started being interested in everything around the model. Because the model was doing what it does. The thing that was missing was the environment it was doing it in.

A raw and undesigned thing

I should be precise about what I was actually touching, because it took me a while to name it and the name matters. When you sit in a developer's editor and drive a model through a chat panel, you are not talking to some considered, designed product with a point of view about how you should feel while using it. You are pressed up against something far more raw. The conversation has not been shaped for anything beyond the brute fact that an input produces an output. There is no real sense of orientation, no interactive scaffolding, no quiet usability work underneath you of the kind that fifty years of interface design taught us to expect. Even a purely text-driven surface could offer a sense of control, of safety, of knowing where you are — and almost none of that is present. What you are using is, functionally, undesigned access to the raw technology. Usability virginity, fully attested.
I do not say this as an insult, and this is the part I most want to get right, because it is easy to mistake for one. The polished mainstream chat products — the ones built for everyone — have this scaffolding precisely because they are built for everyone. What I had crawled into was the layer underneath that, the specialist's layer, the place where nothing has been smoothed over because smoothing it over for one general audience would foreclose the possibility of shaping it for many specific ones. Raw is, in that sense, a feature. Its neutrality is the thing that makes it possible to build a hundred different purpose-built environments on top of it. The price of that neutrality is that it ships to you with no manners, and if you want manners you have to bring them yourself. If you simply want to use the thing as it comes, you are better off in the mainstream chat. Going to the raw layer is a choice, and it asks for effort up front. Knowing that, I decided to pay the effort and see what was actually down there.
What was down there was a problem far more interesting than rough edges. The real difficulty was not the missing polish. It was the instability of the outcomes, the absence of steering, and above all the absence of visibility. An enormous amount happens on layers the model never shows you, and once you cannot trust the status it reports or the completeness it claims, everything downstream becomes complicated in a way that compounds.
Let me make that concrete, because abstractions do this point no justice. Picture the ordinary setup for building against a design: the editor talks to the design tool through a bridge, you hand the model a reference to a specific node, and it can reach across that bridge with a small set of tools. It can ask for a snapshot and receive back a picture of what you would see. It can walk the structure. It can read style attributes and values. Most of this is invisible to you. The chat tells you, briefly, that a call was made while a task was running, and then when the task completes it tidies that away, so the evidence of how the work was actually done disappears along with the work. Now the model builds something that does not match the reference, which is normal, and the reasons it does not match are many and mutually indistinguishable from where you sit. Maybe it ignored your explicit instruction to use the proper tool and quietly built toward the screenshot instead, because matching a picture is easier than reading a tree. Maybe it used the right tool but didn't read deeply enough into the structure. Maybe the bridge dropped something in transit. What you actually see is simply a wrong result. And the thing you are negotiating with to understand why is not an oracle; it is closer to a free spirit, and every step it takes is a little unpredictable.
To get anywhere, you have to start surfacing what the system hides. You learn to build your own crude instruments — to fold steps into the work whose only purpose is to make the invisible leave a trace, to force the machine to call a tool and write down what it got back so that you, the human, can finally see which tool returns which data and whether it was even used. And even with perfect access to all the right data and a precise definition of the task, the probability that something inside a single step is incomplete or subtly wrong stays uncomfortably high. Telling the machine no does not guarantee no. That sentence sounds like a joke until you have lived inside it for a few weeks.
I will give you the extreme version, because it is the one that finally convinced me the environment was the real work. At one point I spent a full week chasing a single inconsistency. I had a sixty-thousand-line export describing a set of components with their token bindings, produced by a plugin I was building, and the file disagreed with what the design tool was showing on screen. To find the disagreement I had to navigate, simultaneously, an internal token layer that is mostly invisible and only partly reachable with non-native tools; the possibility of a quietly broken connection anywhere in the file; the way the model chose and applied its tools; recursion I was reading and recursion I was writing inside the plugin; and a possible transmission fault in the bridge itself. Every one of those sources was hidden. The whole thing sat well over the model's usable context, which meant more failed attempts than successful ones, and each attempt needed a fresh test setup that cost a few minutes to stand up before it could fail again. A week. One inconsistency. The lesson did not need underlining.
There are good reasons, I decided, to stop pouring that effort into the thing you happen to be building today and to start building the thing that makes the hidden visible — so that the next time the machine makes a mistake, you can see where, and understand why, and build something that prevents it. That sentence is the hinge of the entire experience. Everything I did afterward grew out of it.

The roles got reversed, and that was the real discovery

Somewhere in the middle of all this I caught myself doing something absurd, and once I saw it I could not unsee it. I was spending my days making documentation, briefing notes, architectural guidelines, component descriptions, lists of exceptions and edge cases — an ever-growing apparatus whose entire function was to keep a machine consistent. The better I wanted the result to be, the longer my prompts became, and behind the prompts grew a second project made entirely of instructions for the first. I had, without quite deciding to, become my own model's assistant. The better I performed in that role, the closer the output came to my vision, which is exactly the kind of reward loop that keeps you in a role you never agreed to take.
Maybe I am old-school, but this struck me as completely backwards. In the world I came from, machines are supposed to handle consistency, and humans are supposed to decide where creativity matters, where judgment matters, and what is safe to automate. Somehow we had arrived at the opposite arrangement, where the human repeats himself endlessly and the machine is the one forever wandering off toward some more creative path of its own. The whole picture had the elements I expected, simply turned upside down. I was the one ignoring alerts and hitting snooze. The machine was the one improvising at three in the morning.
I do not want to dress this up as more than it is, so let me be careful about the claim, because the honest version is stronger than the dramatic one. The work did not vanish. It moved. The heavy lifting shifted to the front of the process and changed shape. Preparing a genuinely clean system, defining the tokens, writing the contracts, deciding the validation gates — that is real work, and it is not less work than coding, it is different work, sitting at a different altitude. What changed was not the amount of effort but where the effort lived and what it bought. I was no longer generating. I was specifying, and then judging. And the more I sat with that, the more it stopped feeling like a complaint and started feeling like the actual finding. If the machine is going to improvise wherever you leave a gap, then the leverage is not in out-typing it. The leverage is in building an environment where the gaps are closed, the consistency is owned by the system, and the human is left with the two things humans are actually good at: deciding what should exist, and judging whether what came back is good enough.
That is the role I wanted. Not the assistant. The one who sets the conditions and gives the final nod.

Building the environment instead of fighting the model

When I went looking at what other people had concluded about all this, the consensus annoyed me. The general settlement seemed to be that AI is wonderful for prototypes, for brainstorming, for accelerating the early scrappy part, and questionable the moment your quality bar goes up. I found that bizarre. We are running a technology that costs a fortune to train and a fortune to operate, and the use case we have agreed to admire is producing throwaway prototypes that live for a day? That did not read to me like an answer. It read like a temporary limitation that everyone had quietly accepted as permanent because accepting it was easier than questioning it.
So I asked a different question, and it is the only genuinely strategic move in this whole story. Instead of waiting for the model to get better, what happens if you make the environment around it better? Design systems already exist, after all, to keep products consistent across many hands and many years. They encode structure, behavior, naming, relationships, rules. They are, in a real sense, consistency machines built for humans. If they already do that for people, why could they not become part of the operating environment for the model — the place that holds the line the model keeps drifting across?
That question became the second project, and I built it the way the first project taught me to. The thing I want you to take from the build is not its architecture but its center of gravity, so I will keep the mechanics brief and tell you what they were for. The source of truth in the system is not the design tool and it is not only the code. It is the combination — code, tokens, contracts, and the design data exported as structured JSON, all kept connected as a single thing rather than as four separate versions of reality that slowly drift apart. That last failure mode is the one every organization knows in its bones: the design says one thing, the code says another, the documentation describes a third product that never quite shipped. The entire point of binding them together was to make that drift structurally difficult instead of merely discouraged.
From a brand definition and a baseline library, the system generates a starting design system with both a design layer and an implementation layer, and from there a workflow opens up that is, frankly, calmer than anything I experienced in the first project. A system can be generated and pushed into the design tool, where a designer works in the familiar way and changes things, extends things, even redesigns more radically, as long as the underlying structure and token logic survive. Then it comes back in as structured data. What already exists gets updated. What is new enters a queue to be built. Familiar patterns need almost no guidance; genuinely novel ones need a short, precise specification. The crucial property is that none of these changes dissolve into loose interpretation. They are pulled back into the same connected body of code, tokens, contracts, and design data, every time. I should say plainly that this part leaned hard on the bridge between the editor and the design tool; with only an education license to work from, those connections were what made the round trips possible to prototype at all. The goal was never to automate the design decisions. The goal was to stop a human from explaining the same decision to a machine for the rest of his natural life.

Generation got cheap, so trust became the whole job

The deeper I went, the more clearly I could see that I had been measuring the wrong thing all along. I had been impressed by how quickly something could be produced. By the end I did not care how fast it appeared. I cared, almost exclusively, about what happened to it afterward. Could I trust it? Would it still be coherent three iterations later? Was it quietly accruing debt? Was it introducing inconsistencies I would only discover much later, at the worst possible moment? Did it still match the system, the tokens, the contracts, the implementation rules? Generating things, it turns out, is becoming easy. Generating things you can trust is not, and the gap between those two sentences is where nearly all of my remaining work went.
So most of the later architecture exists to answer that gap rather than to produce anything. Every generated artifact passes through stages that check whether it still aligns with the source of truth, whether the contracts are intact, whether the design and code layers still agree, whether the review coverage is actually complete. When something fails, it does not move forward. It gets repaired, rebuilt, reviewed, and validated again, and only when everything is green does it become eligible for a human to approve. Looking back, that is where the bulk of the effort landed — not in teaching the machine to make things, but in making sure it could fail safely, so that the system stayed responsible for consistency instead of quietly handing that responsibility back to me.
I owe you an honesty here, because a loop that repairs its own failures is exactly the kind of thing that sounds magical and behaves treacherously. Automated fix-and-retry loops do not always converge. Sometimes they spiral, or hallucinate a fix that breaks something adjacent, or regress in a circle. The point of the gates was never to pretend the machine always gets there. It was to make sure that when it doesn't, the failure is caught and surfaced rather than waved through — and that the impasse gets kicked back to a human instead of being smoothed over with false confidence. Machines are genuinely good at running the same rigorous check ten thousand times without getting bored. They are genuinely bad at knowing when they are stuck. The environment has to assume both of those things are true at once.
As all of this matured, the prompting that had once consumed my days quietly disappeared. The contexts, the instructions, the refinement loops became something the system generated and maintained rather than something I hand-fed. That was the moment the project stopped feeling like an experiment and started feeling like a tool. And I should be equally honest about the scope at which I can claim any of this, because the honesty is what makes the claim worth anything. I proved it to myself on a deliberately small set — thirty-two components, chosen small on purpose to keep the build-and-validate cycles fast enough to actually study. The approach behind it, building a system element by element until a clean baseline exists and then composing upward, is old and well understood and known to scale. But I tested it at the scale a single curious person can hold in his head over a sabbatical, and I am not going to dress that up as a controlled proof of anything universal. It is a worked example. It is one person, one domain, one open calendar, going further than was sensible because nothing was stopping him.

What I think I actually found

Here is the part where, if I am not careful, I will start selling you something, so I am going to stay very close to what I can defend. I set out to answer a personal question, and I had two quieter hypotheses riding along with it, and I want to tell you what happened to them rather than what they imply for the world.
The first hypothesis was simply that design systems would sit at the center of any serious future in which AI builds real software, and not as a nice-to-have but as the load-bearing structure — the consistency machine the model needs in order to be trustworthy. Everything I lived through pushed me toward that. The model is not the scarce resource. The environment that holds it to a standard is. The second hypothesis is the one I find harder to let go of, and it is the one I would most like other people to argue with me about. The most expensive, most stubborn, most quietly miserable friction in building products is the handover between design and development — the endless translation of intent into specs, tickets, implementations, reviews, corrections, clarifications, all of it necessary, all of it costly, all of it concentrated at the exact seam where one discipline hands the work to another. I went into this wondering whether a designer, properly equipped, could stop handing over a picture and start handing over the thing itself: an approved component, in code, generated and validated against a shared source of truth, standing on its own without a paragraph of explanation attached.
I cannot find the blocker. I have looked, honestly, with a skeptic's eye, and I cannot find the structural reason this should not work. A component, unlike a spec, stands for itself. It does not need a one-time document describing what it is supposed to become, because it already is that thing. It does not need a meeting to align on interpretation, because there is nothing left to interpret. If you build the environment correctly, the single largest source of friction in production has a real chance of collapsing into something almost anticlimactic — a notification, marking the arrival of a new element in the library. That is the outcome I keep turning over. Not that designers become engineers or engineers become designers, but that both get to spend more of their time inside their actual expertise, while the machine carries the translation and the consistency that neither of them ever enjoyed carrying in the first place.
Whether that is realistic, or far too conservative, or still hopelessly ambitious, I genuinely do not know, and I would rather end on that honest uncertainty than on a conclusion I would have to defend past the edge of what I tested. What I will say without hedging is this: I never prompt for components anymore, and I never start a system from scratch again. For my own work, that is already enough to call it a success, on the narrow personal terms I set out with.
I am not turning the thing into a product. I have no roadmap, no waitlist, nothing to sell you at the bottom of this page. What I have is a locally running experiment, a head full of field notes, and the slightly unfashionable belief that the most interesting question in this whole space is not how clever the model can be but how much of the boring, repetitive, consistency-keeping work we can finally move off the humans and into the system — and whether, having done that, we might actually get back some of the enjoyment that made a lot of us want to build things in the first place. I came out of this remembering why I liked it, two decades ago, when explaining an idea and making it real were the same motion. That, more than any architecture diagram, is the result I would want someone else to chase.
If you work anywhere near this — design systems, design operations, frontend architecture, AI-assisted development, source-of-truth problems — I would genuinely rather hear where you think I am wrong than be told I am right. I built one thing, alone, because for once I had the time. The interesting part starts when someone with different constraints tells me what breaks.