You vibe coded an internal app. Now who owns it?
A dentist we met at a conference had four months of evenings in his own internal system, a user interface he was proud of, and colleagues who wanted to use it. In this post we'll look at the question that arrives at exactly that moment, and at how much of an application an AI should be generating in the first place.
- A dentist built a working internal system for his practice in four months of spare time, in Lovable with Supabase behind it. A few years ago that would have been remarkable. It's now an ordinary thing for a motivated non-developer to do.
- His problem started when it worked. Colleagues wanted in, and the questions turned into who maintains it, who's responsible when it breaks, what happens when he leaves, and whether IT will take responsibility for something nobody has read.
- Vibe coding has made software radically easier to create. It hasn't made software easier to own, and the second problem only shows up because the first one got solved.
- You pay for that twice. Once in inference, because every later change means the AI re-reads and reasons across the codebase it generated, and again in engineering time when somebody has to review it properly.
- The alternative we're building is to move the AI up a layer, so it works inside a constrained application model on a known platform. The model stays readable, shareable and answerable afterwards. That doesn't solve governance or compliance, and it doesn't suit every app. It reduces how much unique software there is to govern.
A while back we got talking to a dentist at a conference. He'd been building an internal system for his own practice on evenings and weekends for about four months, in Lovable with Supabase behind it. He showed us the app on his phone and it looked good, better than some of the software he has to use at work.
Start with the credit, because he's earned it. A dentist with no software background built a working system for his own practice in his spare time. A few years ago that sentence would have been a punchline. Nothing in this post is a warning about what he did.
Then we asked when he was putting it into production, and the conversation changed.
He didn't know. It wasn't a missing feature and it wasn't the design, he was happy with both. It was that he had no idea whether the code was any good. He couldn't tell us how the data was structured underneath, whether the login was solid, or what would happen if two people worked in it at the same time. His own conclusion, and these were close to his words: "I'd probably need a software engineer to go through all of it first."
What changes when it starts working
That's a careful person doing an honest risk assessment of his own work. But the interesting part isn't that the app might have problems. It's why he's suddenly asking.
He's asking because it worked. Colleagues saw it and wanted to use it. Somebody further up thought it should go wider. That's success, and it's the exact moment the questions stop being about features and start being about something else:
- Can we put real data in this?
- Who maintains it?
- What happens when he's on holiday, or when he leaves the organization?
- Who's responsible when it breaks on a Tuesday morning?
- How do people get access, and how do they lose it when they change roles?
- Who else understands how it works?
- What happens when he takes it to IT, and will IT be willing to take responsibility for something that came out of four months of conversations with an AI?
Underneath all of them is one question with no obvious answer: in a practical, operational sense, who owns this thing he built?
That's the gap we keep running into, and it's worth stating plainly. Vibe coding has made software radically easier to create. It hasn't made software easier to own. The second problem is only visible because the first one got solved, and the dentist ran into it because his experiment turned out to be useful, not because he did anything wrong.
The review nobody quotes you for
Take the first of those questions, since it's the one he raised himself. What would that engineer have to check before anyone could sign off?
- The data model - is it structured so that a change in month six is a change, and not a rebuild?
- Authentication and sessions - who's logged in, how long the session lasts, and what happens when it expires halfway through a form.
- Access rules - whether "you only see your own patients" is enforced in the database or filtered in the browser, which are two very different things wearing the same clothes.
- Validation - which layer enforces it. The form, the API, the database, all three with different rules, or nowhere.
- The audit question - who changed this record, and when, and can you show that to somebody who asks.
This is a real piece of work and it costs real money. The dentist can't do it himself, which is no criticism of him, and the awkward part is that he can't evaluate the answer either. He'd be paying for a verdict he has no way to check.
It's also not a one-off. The review is only valid for the version that was reviewed. Ask for a change six months later and whatever the model touches while it's in there is unreviewed again. That's the ownership problem in miniature: the cost recurs for as long as the app is useful.
Taking it to IT
Now sit on the other side of that meeting for a moment, because this is where these apps usually stop.
IT is being asked to take responsibility for an application that is, in a real sense, unique in the world. Its architecture was decided across months of prompts that nobody kept, its dependencies were chosen by a model and will age like everybody else's, and nobody in the building has read it. The person who commissioned it can't explain how it works below the surface, because he was never meant to.
What happens next varies. Some will say no. Some will accept it with conditions, some will ask for a review first, and some will ask for a rebuild, which puts the dentist back in the queue he was trying to get out of. None of those responses is unfair. They're being asked to take on something they had no part in shaping, and to keep owning it after the person who made it moves on.
It would be easy to blame the tools here, and it isn't warranted. Lovable and Supabase did exactly what they promise. A person with no software background described what he needed and came away with a running application, with a real database and a login, in a few months of evenings. That's a genuine achievement of these tools and we'd rather he used them than kept the process in a spreadsheet. The question that's left isn't whether they worked. It's the shape of the artifact he's now holding.
How much of the application should the AI be generating?
This is the question we came home from the conference thinking about, and it's more interesting than any comparison between one AI tool and another.
When you generate a full application from a prompt, the AI is making hundreds of decisions: the tables and their types, the migrations, the query layer, the API endpoints and their shape, the login flow, the session handling, the access policies, where validation lives, how files are uploaded and who can fetch them, the components, the dependencies, the deployment configuration, and all the glue between them. Most of those decisions are invisible, and a mistake in any of them still renders perfectly in the browser.
Better models will make better decisions. That part is improving and it will keep improving. But it doesn't change what you're left holding. A better model produces a better version of the same artifact: a one-off application, with its own architecture, that somebody has to understand and be accountable for. Improving the generation improves the quality of the thing. It doesn't change the kind of thing it is.
Which raises an uncomfortable thought about a whole category of software. Every internal app needs users and roles, storage that doesn't lose data, an audit trail, an API and somewhere to run. We solved those a long time ago. Generating a fresh implementation of them for each new app, then asking somebody to review each one, is a strange way to spend both the tokens and the engineering attention.
Paying twice for the same complexity
There's a second cost here that non-technical builders feel long before anyone mentions ownership, and it has the same root.
The first experiments are remarkably cheap. A weekend of prompting produces something that would have been a quarter of work not long ago, and the bill is a few euros. Then the app grows, and it gets more expensive to change. Not because your prompts got longer, but because the AI now has to read, understand and modify the codebase it produced for you in the first place.
A request that sounds like a small business change is rarely small in that codebase. "Add a field for the referring dentist and show it on the summary" can mean a migration, a change to the API layer, a type definition, a permission check, a form component and a validation rule that exists in two places. The AI has to load enough of that to be safe, reason across it, and put it back. You pay for the context and the reasoning every time, and the pile it reads through keeps growing.
Which is a fair question to ask out loud: why are you paying an AI, over and over again, to understand infrastructure it generated for you in the first place?
That's the same problem as the review, on a different invoice. First you pay a model to create the complexity and then to keep re-reading it every time the business changes. Later, if the app matters enough, you pay engineers to understand it and take responsibility for it. Both bills are for the same thing: how much unique software has to be understood before it can be safely touched.
Moving the AI up a layer
There's another place to put the AI, and it's the bet snill.ai is built on, so read the rest as us describing our own design rather than a neutral survey.
The difference is roughly this:
In Snill the AI works inside a constrained application model. It still does a lot: it interprets what you describe, asks about the parts you left vague, proposes entities and relationships, suggests rules and roles, arranges forms, pages and navigation, and later proposes changes to all of that. What it doesn't do is invent the architecture underneath. Our internal architecture doc puts the constraint in one line: the backend code and frontend code are never modified per app, and if a feature can't be expressed in the application model, it doesn't exist.
What follows from that:
- There's no API to design - the REST API is generated from the model, with an OpenAPI 3.0 spec, scoped keys and a Swagger UI. Add a collection and its endpoints are there.
- There's no login to write - users, roles and identity belong to the platform, and they work the same way in the fifth app as in the first.
- Access rules are part of the model, not code. Roles per collection, ownership per record, and read or edit permission per field are declared, and the backend enforces them. There's no version of this where the rule lives only in the frontend.
- The business logic is declared too - calculated fields, form rules including cross-field validation, workflow transitions, and triggers that fire on a record, on an aggregate crossing a threshold, or on a schedule.
- The interface isn't generated code - the same frontend renders every app from the model. There are no per-app components, no per-app dependencies, and nothing that needs upgrading when React does.
- Changes arrive as patches - you ask for something, the AI proposes a patch to the model, and Develop mode draws it as a colour-coded diff you look at before you click Apply. Every applied version is kept and you can roll back.
That last point is also where the cost curve from the previous section flattens. A change to the business system is a change to the model, so there's no codebase for the AI to load, reason across and put back. We won't put a number on it, since the honest comparison depends entirely on which two apps you pick, but the difference is structural rather than a matter of tuning.
Checking a model against reviewing a codebase
The first is machine checking. Every version of the model, whether the AI wrote it or a person edited it by hand, is validated against a schema before it's saved, and an invalid one doesn't get in. That isn't a claim that conventional software can't be checked. Type systems, tests, static analysis and security scanners catch real classes of problems. The claim is about size: validating a constrained declarative model is a smaller and more tractable problem than assuring an arbitrary codebase, and you solve it once for every app rather than once per app.
The second is human reading, and for the dentist it's the one that matters. Open the Model tab and the whole app is one screen: every collection, every field, its type or relation, its calculation, its trigger. Click a field and everything connected to it lights up in both directions. He can read that in an afternoon and say "no, the severity levels are wrong" or "only the treating dentist should see this." He's the best available reviewer of that, because it's his process the model describes. What he can't review is forty files of generated TypeScript, and neither, honestly, can a stranger with a week and an invoice.
Who has to understand what
This is less about technology than about who is qualified to be responsible for what.
The person who owns the process should own the part they're actually qualified to own: the entities, the relationships between them, the rules, the roles, the workflow and the forms. That's the dentist's expertise and nobody in the building has more of it. He should not need to understand React state, authorization middleware or database migrations to be responsible for his own process, and asking him to is how these projects end up belonging to nobody.
The handover to IT changes shape too. With vibe coding, each app is a software project. Here, each app is an instance of a software platform. IT still has to evaluate that platform, its security, its architecture, its hosting and its compliance posture, and that's a real piece of work. But it's one evaluation that covers every app built on it, rather than treating each tool an employee builds as an entirely new piece of software to assess from scratch.
We should be careful about how far to push that. It doesn't make an app compliant, it doesn't make it secure by itself, and it isn't a governance process. Those questions are still yours. What changes is the volume of unique software that has to be understood and maintained for each new tool.
Something that can still answer questions about it
One of the questions in that list at the top is who else understands how it works, and in most of these projects it has the bleakest answer. Any of these tools can put an assistant next to a running app, and more of them will. The difference is what the assistant has to work with. Pointed at a generated codebase, it has to infer how the app fits together from the code, the same job the engineer was going to be paid for.
When the app is a model, the running system has an explicit, structured description of itself, and that's a much easier thing to reason about. The assistant knows the model and the data in it, so you can ask things that cross collections, which invoices are unpaid this month, what the revenue by customer was last quarter, and get an answer rather than a filter you have to build yourself. Ask for a report and it writes one, with a summary, tables and charts you can export to PDF, CSV or JSON.
It can change things too, and the rule is the same as everywhere else here: it proposes, you approve. Nothing structural takes effect until somebody applies it, structural changes are admin only, and the version history records whether a change came from the AI or from a person. Everybody else can ask questions of the data without being able to alter the app.
For the ownership question, that's the difference between a tool only its author can interrogate and one that anybody with access can.
What reuse looks like when the app is a model
If the dentist spent four months working out a good way to run this process, he isn't the only practice in the country with that process, and most of the others are running it worse. What would be valuable to them isn't his frontend components or his database access code. It's the structure he found: which things exist in the practice, how they relate, who's allowed to see and do what, which rules apply, what the workflow is, and what the forms ask for.
Sharing that through a codebase is awkward. Handing another practice a repository means handing them a deployment, a set of dependencies, an account to pay for, and every implementation decision he and a language model made together. It hands them the review problem a second time, where they know even less about it than he does.
When the app is a model, it's a JSON document. You can export it from the JSON editor today, and starting an app from a model is already how our template gallery works. The other practice gets the structure, running on the platform they already have, and then changes it, because their process isn't quite his. Adapting a model you can read is a different job from modifying an implementation you inherited.
That changes what reuse means in this category. You're not sharing software machinery, you're sharing what somebody learned about how the work should be organized. It's closer to passing on a good way of running a process than to shipping a product, and the receiving end can argue with it, which is the point.
Why a small model is enough
All of which explains something that surprises people when they hear it. Much of this currently runs on Claude Haiku 4.5, one of the small and fast models, on infrastructure in the EU.
The interesting part isn't that Haiku is cheaper, although it is. It's that the architecture deliberately made the AI's job smaller: a schema to conform to, a validator that rejects anything malformed, and a diff a person approves before it takes effect.
It also changes what a better model would be for. If the next generation isn't needed to generate more infrastructure, it can go into understanding what you meant, asking about the case you didn't think to mention, or noticing that the workflow you described has a state nobody can get out of. For this category of software, that's a more useful direction than writing more code faster.
Where the line is
This approach earns its keep by being narrow, so it's only fair to say where it stops.
Declarative logic lives in the model, and that covers more than people expect: the amount is hours times rate, a justification is required over 10,000, an end date has to be after a start date, email the owner 30 days before the contract expires. Anything past that leaves the platform on purpose.
Worth being exact about that boundary, because it's what makes the rest of the argument hold. There's no place inside a Snill app to put code. No functions, no scripts, nothing to deploy, no side door where per app code quietly accumulates. The small pieces of logic that do live in the app, a formula, a rule condition, a template for a printed card, are declarative expressions stored in the model, validated with it and versioned with it.
So when custom code is needed, and plenty of these apps never need any, it's handled by leaving. A change in the data fires an event, the event goes out as an HMAC-signed webhook, your code runs wherever you run it, and it writes its result back through the app's REST API like any other client. Zapier and Make cover most of it without anybody writing anything, and Codehooks or ordinary custom software handles the rest. The specialized code sits where it can be tested, deployed and owned like any other code, and everyone can see that it's there.
And it isn't for every app. If the value of what you're building is the behaviour itself, a pricing engine, a real-time collaborative canvas, a specialized interface, a product you're going to sell with its own design language, then a fixed platform is a ceiling rather than a floor. Vibe coding and conventional development are the right answers there, and we'll say so every time.
What's left is a large category: registers, approvals, checklists, ticketing, inspections, small CRMs, incident reports. It's most of what organizations quietly run on.
The wrong artifact
Which brings us back to the dentist, and to the thing we wish we'd said at the time.
He did not waste four months. He spent four months finding out exactly how his system should work: which things exist in his practice, how they relate, who's allowed to see what, what has to happen before something can be closed, and which awkward step exists only where he works. That knowledge is the expensive part, and no consultant could have produced it for him.
The question is what artifact should be carrying it. Right now it's a large generated codebase he can't evaluate. He can hand over the repository easily enough, but what doesn't transfer with it is the understanding, or anybody's willingness to be responsible for it. The same knowledge could be carried by an application model he can read, argue with, correct, and hand to somebody else along with a platform they already understand.
He's holding the right knowledge in the wrong form. That's a much better problem to have than the one it looks like from the outside, and it's a fixable one.
Summary
The dentist's app isn't a cautionary tale. It's a success that ran into the next problem, and the next problem is ownership rather than code quality. Who maintains it, who's accountable for it, who can understand it, and who takes it when he moves on.
Part of the answer is deciding how much of an application an AI should be generating at all. Generate everything and every app is a one-off that somebody has to own from scratch, and that you keep paying to have re-read. Generate a constrained model on a known platform and the unique part is the part that was always unique, which is your process.
Vibe coding has made it possible for almost anyone to create software. The next few years are going to be about learning to live with all the software we're now creating.