Essay
16 min readBuilding Faxter · Part 5How to Design AI-Native Software: Three Rules I Refuse to Break
Three rules for designing software where the model is the product, not a feature bolted onto the corner of one.
- AI-native
- Design
A user uploads a stack of receipts to Clerk. Seven photos: a fuel station, a hotel, a restaurant, a stationery store, two from a vendor whose receipts are always slightly out of focus, and one that is a screenshot of a payment confirmation in a language Clerk has not seen this user use before.
Clerk reads them. It links five automatically to bank statement lines that landed in the same week. It asks about the hotel — is this an employee expense, a customer-facing meal, or a personal expense the user wants to track for tax purposes? It asks the user to confirm the vendor name on the two blurry receipts (it has guessed, but it wants to be sure). It tells the user the screenshot looks like a payment to a supplier they have used before, and offers to link it to the recurring purchase order that is currently open.
The user is on a phone. They tap through five questions. Six taps, maybe ninety seconds. Done.
Now imagine the same workflow happening through the agent — the user typing, in the same chat, “I just dropped seven receipts in, please file them and ask me about anything you are not sure about.” Same outcome. Same confirmations. Same questions. Different surface.
Both are real. Both work. Both go through exactly the same code path.
That last sentence is the thing this essay is about.
What “AI-native” actually means
AI-native design does not mean “we put a chatbot in the corner of the dashboard.” It also does not mean “we used AI to build the product.” It means something more specific and more uncomfortable, and almost no software in the wild meets the bar I am about to describe.
What it means is this: the AI is not just a feature in your product. The AI is a user of your product.
When you take that seriously, three design rules fall out of it more or less automatically. They are the rules I have refused to break while building Clerk and Pulse, and they are the rules I think most products that call themselves “AI-native” are quietly violating without realizing what they have given up.
Here they are.
- No templates for anything a human will read.
- Every UI feature must also be an agent tool.
- The end user is the user. Not the expert.
The rest of this essay is what each of these means, why each is harder than it sounds, and how they reinforce each other.
Rule 1: No templates for anything a human will read
The default in software is to template the strings the user sees. “Transaction created successfully.” “Invoice sent to customer.” “Welcome back, [first_name].” The reasons are familiar. Templates are predictable. They are translatable. They are testable. They are cheap to ship and cheap to change. Generations of software engineers have been taught that putting human-language strings in a templates file is the right thing to do.
In an AI-native product, this is wrong. Not because templates are bad in general — they are still right for code, for logs, for machine-readable interfaces — but because the user is reading a system whose entire selling point is that it can talk. The moment the user reads a templated string, the illusion breaks. They can feel the system shift gears, from intelligent collaborator to form ticking a checkbox. It is an unforced error every time.
The rule I have refused to break: anywhere a human reads what the system says, a model writes it.
This sounds like a small thing. It is not. It cascades into a lot of design decisions.
It means there is no “transaction created successfully” message. There is “got it — booked your ₦35,000 office supplies purchase against the GTB account, tagged it as Office Expenses. Two of those vendors haven’t appeared in your books before, so I’ll watch the next few transactions to confirm I’m tagging them right. Anything else for that batch?” The model generates that freshly, every time, informed by what just happened, by what the user has been doing in the last few minutes, by what it has learned about the user’s preferences from past corrections.
It means there is no “Are you sure?” dialog with a yes-and-no button when you are about to do something destructive. There is the model surfacing its actual concern: “This will delete the invoice for Acme. There is a payment of ₦450,000 attached to it that came in last Friday. If I delete the invoice, I will need to either delete that payment or reattach it to a different invoice. Which one do you want?” Specific. Contextual. Often surfaces a problem the user did not know they had.
It means generic error messages die. “Something went wrong” is a violation of the rule. The model knows what went wrong and can say what it tried, what it expected, and what it suggests next. “I tried to send the invoice to acme@acmecorp.com and the email bounced. I think the address might be old — your last successful invoice to Acme went to billing@acmecorp.com. Want me to try that one?”
The cost of this rule is real. Every templated string you delete is now an LLM call you pay for. Every LLM call has latency. Every LLM call can fail. You have to build caching, fallback paths, graceful degradation. You have to think about what the system says when the model is down. You have to make peace with the fact that two users doing the same operation will see slightly different language, which frustrates testing-by-screenshot and breaks the screenshot-driven QA culture most product teams are operating in.
I have come to believe these costs are non-negotiable. The moment you let one templated string back in for cost reasons, you have started down a path where the model is a feature again, not the interface. Within a year you will have fifty templated strings. The user will start to feel them. The product will feel like the kind of AI product they have already gotten used to, which is to say a normal product with an AI bolted on.
The other version of this rule, stated negatively: if you find yourself writing a templates file for user-facing strings in an AI-native product, you have probably misunderstood what AI-native means.
Rule 2: Every UI feature must also be an agent tool
The second rule is the one I think most people who read about AI-native products do not notice, because it is invisible from the outside. From the user’s perspective, an AI-native product looks like a chat that can do things, plus a regular UI for doing those same things. From the inside, the discipline that makes this work is harsh and specific: every feature you build for the UI must also exist as a tool the agent can call. No exceptions. Every. Single. One.
This is what I mean by “the AI is a user.”
Concretely. If your UI lets the user click a button to send an invoice, the agent has a send_invoice tool. If your UI has a date picker for setting payment due dates, the agent has a set_due_date tool. If the UI has a screen for editing the chart of accounts, the agent has tools for reading the chart, adding accounts, deactivating accounts, merging accounts, and explaining what each account means. If the UI lets the user export a balance sheet to PDF, the agent has a generate_balance_sheet_pdf tool. The agent and the UI are talking to the same backend, through the same APIs, with the same permissions, producing the same results.
The cost of this rule is that building a feature is now twice as much work. You have to design the UI. You also have to design the tool surface — the input schema, the docstring (which the LLM reads as part of deciding when to call the tool), the error semantics, the output format. You have to think about how a human would discover the feature in the UI, and how the agent would know when to invoke it from a natural-language request. You have to test both.
This is genuinely painful. There is a constant temptation to ship a UI feature and skip the agent tool, because the UI feature alone “ships value to users.” It does. It also breaks the rule. The moment you have a thing you can do in the UI that the agent cannot do, you have created a hidden menu — a set of capabilities only experts know about, only reachable by clicking. The promise of an AI-native product is that there are no hidden menus. Anything you can do, you can describe in words to the agent and have done. The day that promise stops being true, the product is no longer AI-native.
The flip side is also true. Anything the agent can do, the user must be able to do through the UI. If the agent has a tool to merge two duplicate vendor records and the UI does not expose vendor merging, that is also a violation. The user should be able to discover the capability either way. This is harder than people think — it forces you to expose every agent tool somewhere in the UI surface, even tools that are obscure or specialist, which constrains how cluttered the UI gets and how much of the UI you can hide from new users.
What you get in exchange for paying this cost is a product that holds together philosophically. The user has two ways to interact with the system, and they are equivalent. They can move between them seamlessly. They can start a workflow in the UI and finish it through the agent. They can ask the agent to do something, see what the agent did reflected in the UI, and undo it through whichever surface they prefer. The product feels coherent in a way that AI-bolted-on products fundamentally cannot.
There is one more thing this rule does, which I did not appreciate until I had been operating under it for a year. It forces you to write better tools, because the agent is a more demanding user than the human is. A human can squint at a confusing button and figure out what it does. The agent reads the docstring and acts on it. If your docstring is unclear, the agent calls the tool wrong. If your input schema is loose, the agent passes the wrong types. If your error messages are unhelpful, the agent cannot recover from a failure. The agent is a customer that complains about every interface flaw the human was tolerating in silence. By the time your tools are good enough for the agent, they are much better than the average API. This pays for itself in a hundred ways downstream.
Rule 3: The end user is the user. Not the expert.
The third rule is the one I argue with myself about the most, because it goes against an instinct that runs deep in software design.
Most professional software is designed for the expert who operates it on behalf of someone else. The accountant uses QuickBooks on behalf of the small business owner. The support agent uses Zendesk on behalf of the customer. The recruiter uses Greenhouse on behalf of the hiring manager and the candidate. The consultant uses the analytics dashboard on behalf of the executive who wants the answer. In each case, the person sitting in front of the screen is not the person whose problem is being solved. They are a trained human intermediary.
This intermediary structure is the reason most professional software is brutal to use. The interface assumes you have already done the training. The terminology is the field’s terminology, not the layperson’s. The defaults are the defaults a professional would want, not the defaults a confused first-time user would want. The error messages assume you understand the underlying mechanics. The workflows assume you already know which feature you are looking for and how to get to it. None of this is bad design from the perspective of the person being designed for. It is bad design from the perspective of the end user, who by definition is not the person being designed for.
In an AI-native product, this distinction collapses. The AI is the trained intermediary. The end user can sit in front of the screen directly, and the AI does the translation in both directions. The interface should be designed for the end user — for the small business owner, the customer, the candidate, the executive — and the AI is what bridges them to the underlying complexity.
This sounds obvious. It is not, because the gravitational pull of professional software design is strong, and it pulls hard on AI-native products. The temptation to design Clerk for the accountant is real and constant. Accountants would want a chart-of-accounts editor that lets them see all hundred-and-fifty default accounts at once. A small business owner does not want this. They want to be told, when they are doing something that needs a new account, that a new account would help, and to confirm or override the choice. The accountant wants to see the trial balance with debits and credits laid out in two columns. The small business owner wants to see the answer to the question they actually have, which is usually some form of “is the business OK” or “where did the money go.” The accountant wants to manage tax codes by jurisdiction; the small business owner wants the right tax to just happen.
The rule is that every design decision is made for the end user, not for the trained intermediary, even when the trained intermediary is louder, more knowledgeable, and easier to design for. The accountant is louder because they have specific opinions about what professional accounting software should look like. The small business owner is quieter because they do not know what they do not know. Designing for the louder voice is a category error.
This rule has a corollary I want to name explicitly: the trained intermediary is welcome, but they are a power user, not the primary user. Clerk has accountant-mode features — bulk operations, raw ledger views, the spreadsheet editor with formulas. They are reachable. They are good. They are off the default path. A small business owner running their own books rarely encounters them. An accountant who is helping that small business owner finds them quickly. Both audiences are served, but only one of them is being designed for.
In practice, this rule is the one that argues most directly with rule 2. When you are exposing an agent tool through the UI, the question is: what does the small business owner want to see, not what does the accountant want to see. The accountant version of the UI is allowed. It is just not the default. The default UI, like the default agent behavior, is for the person whose actual problem is being solved.
How the rules reinforce each other
These three rules look like three independent design choices. They are not. They are facets of a single underlying decision, and they reinforce each other in ways I want to point out, because once you see the structure you stop having to remember the rules separately.
Rule 1 (no templates) means the system can respond to context. Rule 2 (every UI feature is an agent tool) means the agent can take the same actions the UI can. Rule 3 (design for the end user) means the system meets the user where they actually are, instead of where a trained operator would be.
When you put them together, what you get is a product where the user describes what happened in plain language, the agent translates the description into actions, the actions are executed against the same backend the UI would have used, the result is reported back in language the user can read, and the UI shows the same result the agent worked with — all of it designed around what the end user actually understands and cares about. There is one experience. There are no hidden menus. There is no professional mode. There is no template gap. There is no “the AI got involved here but the rest of the product is normal” zone.
The thing that breaks all three rules at once, if you let it, is the temptation to “just ship the feature.” A new feature comes along. You want to ship. You add the UI control. You skip the agent tool because that is twice the work. You add a templated success message because writing the LLM prompt felt like polish. You design the new screen the way an expert would expect it because the expert is the one who told you they wanted the feature. Three rules broken in one ticket. The product is now slightly less AI-native than it was last week. Repeat fifty times. The product is now an AI bolted on.
Holding the three rules — and treating them as non-negotiable — is what stops that drift. Not because the rules themselves are sacred, but because each violation makes the next one easier. The first templated string is the hardest one to add. The fiftieth is automatic.
What this means for builders
If you are building something you call AI-native and you are reading this, here is a small audit.
Look at the last user-facing string your product sent to a real user. Was it generated by the model, or was it pulled from a template? If it was a template, write down why. Whatever reason you have for keeping it — speed, cost, predictability, testing — is the reason you are slowly turning your AI-native product into an AI-with-a-product.
Look at the last feature you shipped. Does the agent have a tool for it? Does the docstring on that tool explain when to call it well enough that the model actually uses it? Or did you skip the tool because you were busy? Whatever reason you had for skipping is the reason your product has a hidden menu now.
Look at the last design decision you argued about. Did the louder voice in the conversation belong to the end user, or to the trained intermediary? If it was the intermediary, your product is being shaped by someone whose problem is not the problem you were trying to solve. Whatever felt like clarity in that argument was probably the gravity of professional software pulling you off-target.
I do not think these are hard rules to articulate. I think they are extremely hard rules to live by, because the cost of breaking them is delayed and the cost of holding them is immediate. Every templated string saves five minutes today and costs a slow erosion of the thing that made the product feel different. Every skipped agent tool ships a feature one ticket faster and quietly accumulates into a product that has a hidden menu. Every design decision made for the expert lands faster than the equivalent decision made for the end user, because the expert can articulate what they want and the end user often cannot.
The three rules are bets that the costs you pay today are smaller than the costs you avoid tomorrow. I am betting yes on all three. I am two years into the bet, and I have not yet found a moment where I wish I had broken them. The compound returns of holding the line are larger than I expected, and the products that break the rules — and there are many of them — feel slightly cheaper, slightly more conventional, slightly more like the things they were trying not to be, in a way that is hard to put your finger on but easy to feel.
If you are designing the next AI-native product, I hope you hold all three.
If you only hold one, hold the second. Make every UI feature an agent tool. Make every agent tool a UI feature. The other two rules can be recovered if you slip on them. The parity rule, once broken, is almost impossible to repair after the fact, because every feature you ship without parity is technical debt that compounds against you forever.
I learned that one the hard way. I do not want you to.
